@adia-ai/web-components 0.4.3 → 0.4.5
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/components/alert/alert.a2ui.json +17 -2
- package/components/alert/alert.js +100 -9
- package/components/alert/alert.test.js +180 -0
- package/components/alert/alert.yaml +30 -2
- package/components/badge/badge.a2ui.json +4 -0
- package/components/badge/badge.js +1 -0
- package/components/badge/badge.yaml +4 -0
- package/components/button/button.a2ui.json +14 -4
- package/components/button/button.js +1 -0
- package/components/button/button.yaml +18 -3
- package/components/calendar-picker/calendar-picker.js +1 -1
- package/components/check/check.a2ui.json +8 -1
- package/components/check/check.js +1 -1
- package/components/check/check.yaml +11 -2
- package/components/code/code.a2ui.json +4 -0
- package/components/code/code.js +1 -0
- package/components/code/code.yaml +4 -0
- package/components/col/col.a2ui.json +5 -0
- package/components/col/col.js +1 -0
- package/components/col/col.yaml +5 -0
- package/components/field/field.a2ui.json +17 -6
- package/components/field/field.test.js +8 -2
- package/components/field/field.yaml +50 -8
- package/components/index.js +1 -0
- package/components/input/input.a2ui.json +20 -0
- package/components/input/input.js +9 -9
- package/components/input/input.yaml +15 -0
- package/components/link/link.a2ui.json +166 -0
- package/components/link/link.css +102 -0
- package/components/link/link.js +177 -0
- package/components/link/link.test.js +143 -0
- package/components/link/link.yaml +162 -0
- package/components/option-card/option-card.js +1 -1
- package/components/otp-input/otp-input.js +3 -3
- package/components/radio/radio.a2ui.json +8 -1
- package/components/radio/radio.js +1 -1
- package/components/radio/radio.yaml +11 -2
- package/components/range/range.js +3 -3
- package/components/rating/rating.js +1 -1
- package/components/row/row.a2ui.json +5 -0
- package/components/row/row.js +1 -0
- package/components/row/row.yaml +5 -0
- package/components/search/search.js +2 -2
- package/components/select/select.a2ui.json +15 -0
- package/components/select/select.js +2 -2
- package/components/select/select.yaml +14 -0
- package/components/slider/slider.js +4 -4
- package/components/slider/slider.test.js +105 -0
- package/components/switch/switch.a2ui.json +8 -1
- package/components/switch/switch.js +1 -1
- package/components/switch/switch.yaml +11 -2
- package/components/table/table.a2ui.json +10 -0
- package/components/table/table.yaml +8 -0
- package/components/tag/tag.a2ui.json +4 -0
- package/components/tag/tag.js +1 -0
- package/components/tag/tag.yaml +4 -0
- package/components/text/text.a2ui.json +5 -0
- package/components/text/text.js +1 -0
- package/components/text/text.yaml +5 -0
- package/components/textarea/textarea.a2ui.json +5 -0
- package/components/textarea/textarea.js +2 -2
- package/components/textarea/textarea.yaml +4 -0
- package/components/upload/upload.js +1 -1
- package/package.json +2 -1
- package/styles/design-tokens-export.js +554 -0
|
@@ -81,6 +81,11 @@
|
|
|
81
81
|
"type": "boolean",
|
|
82
82
|
"default": false
|
|
83
83
|
},
|
|
84
|
+
"options": {
|
|
85
|
+
"description": "Option list. Array of {value, label, disabled?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children.",
|
|
86
|
+
"type": "array",
|
|
87
|
+
"default": []
|
|
88
|
+
},
|
|
84
89
|
"pattern": {
|
|
85
90
|
"description": "Regex pattern for validation",
|
|
86
91
|
"type": "string",
|
|
@@ -101,6 +106,16 @@
|
|
|
101
106
|
"type": "boolean",
|
|
102
107
|
"default": false
|
|
103
108
|
},
|
|
109
|
+
"size": {
|
|
110
|
+
"description": "Sizing scale via universal `[size]` attribute system (packages/web-components/styles/tokens.css). Matches Input's sizing tokens so a Select rendered alongside an Input feels coherent in a form row.",
|
|
111
|
+
"type": "string",
|
|
112
|
+
"enum": [
|
|
113
|
+
"sm",
|
|
114
|
+
"md",
|
|
115
|
+
"lg"
|
|
116
|
+
],
|
|
117
|
+
"default": "md"
|
|
118
|
+
},
|
|
104
119
|
"value": {
|
|
105
120
|
"description": "Currently selected option value",
|
|
106
121
|
"type": "string",
|
|
@@ -46,7 +46,7 @@ class UISelect extends UIFormElement {
|
|
|
46
46
|
this.open = false;
|
|
47
47
|
this.#query = '';
|
|
48
48
|
this.syncValue(opt.value);
|
|
49
|
-
this.dispatchEvent(new
|
|
49
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
connected() {
|
|
@@ -293,7 +293,7 @@ class UISelect extends UIFormElement {
|
|
|
293
293
|
this.#query = '';
|
|
294
294
|
this.open = false;
|
|
295
295
|
this.syncValue?.(q);
|
|
296
|
-
this.dispatchEvent(new
|
|
296
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
|
|
297
297
|
} else {
|
|
298
298
|
this.open = false;
|
|
299
299
|
}
|
|
@@ -17,6 +17,16 @@ props:
|
|
|
17
17
|
type: string
|
|
18
18
|
default: default
|
|
19
19
|
enum: [default, outline, ghost, soft]
|
|
20
|
+
size:
|
|
21
|
+
description: >-
|
|
22
|
+
Sizing scale via universal `[size]` attribute system
|
|
23
|
+
(packages/web-components/styles/tokens.css). Matches Input's
|
|
24
|
+
sizing tokens so a Select rendered alongside an Input feels
|
|
25
|
+
coherent in a form row.
|
|
26
|
+
type: string
|
|
27
|
+
default: md
|
|
28
|
+
enum: [sm, md, lg]
|
|
29
|
+
reflect: true
|
|
20
30
|
required:
|
|
21
31
|
description: Marks the field as required for form validation
|
|
22
32
|
type: boolean
|
|
@@ -70,6 +80,10 @@ props:
|
|
|
70
80
|
type: boolean
|
|
71
81
|
default: false
|
|
72
82
|
reflect: true
|
|
83
|
+
options:
|
|
84
|
+
description: "Option list. Array of {value, label, disabled?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children."
|
|
85
|
+
type: array
|
|
86
|
+
default: []
|
|
73
87
|
pattern:
|
|
74
88
|
description: Regex pattern for validation
|
|
75
89
|
type: string
|
|
@@ -110,7 +110,7 @@ class UISlider extends UIFormElement {
|
|
|
110
110
|
#setValue(v) {
|
|
111
111
|
if (v === this.value) return;
|
|
112
112
|
this.value = v;
|
|
113
|
-
this.dispatchEvent(new
|
|
113
|
+
this.dispatchEvent(new CustomEvent('input', { bubbles: true, detail: { value: this.value } }));
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
#onPointerDown = (e) => {
|
|
@@ -132,13 +132,13 @@ class UISlider extends UIFormElement {
|
|
|
132
132
|
this.#thumbEl.releasePointerCapture(e.pointerId);
|
|
133
133
|
this.#thumbEl.removeEventListener('pointermove', this.#onPointerMove);
|
|
134
134
|
this.#thumbEl.removeEventListener('pointerup', this.#onPointerUp);
|
|
135
|
-
this.dispatchEvent(new
|
|
135
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
|
|
136
136
|
};
|
|
137
137
|
|
|
138
138
|
#onTrackClick = (e) => {
|
|
139
139
|
if (this.disabled || e.target === this.#thumbEl) return;
|
|
140
140
|
this.#setValue(this.#valueFromX(e.clientX));
|
|
141
|
-
this.dispatchEvent(new
|
|
141
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
|
|
142
142
|
};
|
|
143
143
|
|
|
144
144
|
#onKey = (e) => {
|
|
@@ -155,7 +155,7 @@ class UISlider extends UIFormElement {
|
|
|
155
155
|
}
|
|
156
156
|
e.preventDefault();
|
|
157
157
|
this.#setValue(this.#snap(v));
|
|
158
|
-
this.dispatchEvent(new
|
|
158
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
|
|
159
159
|
};
|
|
160
160
|
|
|
161
161
|
disconnected() {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import '../../core/element.js';
|
|
3
|
+
import './slider.js';
|
|
4
|
+
|
|
5
|
+
const tick = () => new Promise((r) => queueMicrotask(r));
|
|
6
|
+
|
|
7
|
+
function mount(html) {
|
|
8
|
+
const wrap = document.createElement('div');
|
|
9
|
+
wrap.innerHTML = html;
|
|
10
|
+
document.body.appendChild(wrap);
|
|
11
|
+
return wrap.firstElementChild;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('slider-ui', () => {
|
|
15
|
+
beforeEach(() => { document.body.innerHTML = ''; });
|
|
16
|
+
|
|
17
|
+
it('renders thumb at correct % for initial value', async () => {
|
|
18
|
+
const s = mount('<slider-ui value="50" min="0" max="100"></slider-ui>');
|
|
19
|
+
await tick();
|
|
20
|
+
const thumb = s.querySelector('[slot="thumb"]');
|
|
21
|
+
expect(thumb.style.left).toBe('50%');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Property reactivity contract — locks in the behavior that consumer
|
|
25
|
+
// feedback (FEEDBACK-adia-packages.md §5, 2026-05-12) incorrectly
|
|
26
|
+
// claimed was broken. UIElement's signal-backed property setters
|
|
27
|
+
// (core/element.js:31-50) trigger the host's render effect on every
|
|
28
|
+
// property change; slider-ui's render() reads this.value and updates
|
|
29
|
+
// [slot="thumb"].style.left. This test catches any regression that
|
|
30
|
+
// would break undo/redo or any other programmatic-value flow.
|
|
31
|
+
it('moves thumb when .value is set programmatically', async () => {
|
|
32
|
+
const s = mount('<slider-ui value="50" min="0" max="100"></slider-ui>');
|
|
33
|
+
await tick();
|
|
34
|
+
const thumb = s.querySelector('[slot="thumb"]');
|
|
35
|
+
expect(thumb.style.left).toBe('50%');
|
|
36
|
+
|
|
37
|
+
s.value = 75;
|
|
38
|
+
await tick();
|
|
39
|
+
expect(thumb.style.left).toBe('75%');
|
|
40
|
+
|
|
41
|
+
s.value = 10;
|
|
42
|
+
await tick();
|
|
43
|
+
expect(thumb.style.left).toBe('10%');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('moves thumb when attribute is set imperatively', async () => {
|
|
47
|
+
const s = mount('<slider-ui value="50" min="0" max="100"></slider-ui>');
|
|
48
|
+
await tick();
|
|
49
|
+
const thumb = s.querySelector('[slot="thumb"]');
|
|
50
|
+
|
|
51
|
+
s.setAttribute('value', '25');
|
|
52
|
+
await tick();
|
|
53
|
+
expect(thumb.style.left).toBe('25%');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('updates [slot="value"] readout text when .value changes', async () => {
|
|
57
|
+
const s = mount('<slider-ui value="50" min="0" max="100"></slider-ui>');
|
|
58
|
+
await tick();
|
|
59
|
+
const readout = s.querySelector('[slot="value"]');
|
|
60
|
+
expect(readout.textContent).toBe('50');
|
|
61
|
+
|
|
62
|
+
s.value = 88;
|
|
63
|
+
await tick();
|
|
64
|
+
expect(readout.textContent).toBe('88');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('emits CustomEvent("change") with detail.value on keyboard step', async () => {
|
|
68
|
+
const s = mount('<slider-ui value="50" min="0" max="100" step="1"></slider-ui>');
|
|
69
|
+
await tick();
|
|
70
|
+
|
|
71
|
+
let captured = null;
|
|
72
|
+
s.addEventListener('change', (e) => { captured = e; });
|
|
73
|
+
|
|
74
|
+
s.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true }));
|
|
75
|
+
await tick();
|
|
76
|
+
|
|
77
|
+
expect(captured).not.toBeNull();
|
|
78
|
+
expect(captured).toBeInstanceOf(CustomEvent);
|
|
79
|
+
expect(captured.detail).toEqual({ value: 51 });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('emits CustomEvent("input") with detail.value on internal value change', async () => {
|
|
83
|
+
const s = mount('<slider-ui value="50" min="0" max="100" step="1"></slider-ui>');
|
|
84
|
+
await tick();
|
|
85
|
+
|
|
86
|
+
let captured = null;
|
|
87
|
+
s.addEventListener('input', (e) => { captured = e; });
|
|
88
|
+
|
|
89
|
+
s.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true }));
|
|
90
|
+
await tick();
|
|
91
|
+
|
|
92
|
+
expect(captured).not.toBeNull();
|
|
93
|
+
expect(captured.detail).toEqual({ value: 51 });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('reflects value to [aria-valuenow] for screen readers', async () => {
|
|
97
|
+
const s = mount('<slider-ui value="50" min="0" max="100"></slider-ui>');
|
|
98
|
+
await tick();
|
|
99
|
+
expect(s.getAttribute('aria-valuenow')).toBe('50');
|
|
100
|
+
|
|
101
|
+
s.value = 80;
|
|
102
|
+
await tick();
|
|
103
|
+
expect(s.getAttribute('aria-valuenow')).toBe('80');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -69,7 +69,14 @@
|
|
|
69
69
|
],
|
|
70
70
|
"unevaluatedProperties": false,
|
|
71
71
|
"x-adiaui": {
|
|
72
|
-
"anti_patterns": [
|
|
72
|
+
"anti_patterns": [
|
|
73
|
+
{
|
|
74
|
+
"description": "Wrapping a switch-ui in field-ui. The widget already self-labels.",
|
|
75
|
+
"right": "<switch-ui label=\"Email notifications\"></switch-ui>\n",
|
|
76
|
+
"rule": "Use [label] on switch-ui directly; do not wrap in field-ui.",
|
|
77
|
+
"wrong": "<field-ui inline label=\"Email notifications\">\n <switch-ui></switch-ui>\n</field-ui>\n"
|
|
78
|
+
}
|
|
79
|
+
],
|
|
73
80
|
"category": "layout",
|
|
74
81
|
"events": {
|
|
75
82
|
"change": {
|
|
@@ -35,7 +35,7 @@ class UISwitch extends UIFormElement {
|
|
|
35
35
|
#toggle = () => {
|
|
36
36
|
if (this.disabled) return;
|
|
37
37
|
this.checked = !this.checked;
|
|
38
|
-
this.dispatchEvent(new
|
|
38
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value, checked: this.checked } }));
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
#onKey = (e) => {
|
|
@@ -83,8 +83,17 @@ tokens:
|
|
|
83
83
|
--toggle-track-width:
|
|
84
84
|
description: Track width
|
|
85
85
|
a2ui:
|
|
86
|
-
rules:
|
|
87
|
-
|
|
86
|
+
rules:
|
|
87
|
+
- "Self-labeling widget — use the [label] attribute directly; do NOT wrap in <field-ui>. The widget renders its own label inline via CSS attr() pattern. For settings rows (label-left, switch-right), put the descriptive text in switch-ui's own [label] attribute; do not introduce a field-ui wrapper. For descriptive helper text below the switch, use <text-ui variant='caption'> as a sibling — not field-ui's hint slot."
|
|
88
|
+
anti_patterns:
|
|
89
|
+
- description: Wrapping a switch-ui in field-ui. The widget already self-labels.
|
|
90
|
+
wrong: |
|
|
91
|
+
<field-ui inline label="Email notifications">
|
|
92
|
+
<switch-ui></switch-ui>
|
|
93
|
+
</field-ui>
|
|
94
|
+
right: |
|
|
95
|
+
<switch-ui label="Email notifications"></switch-ui>
|
|
96
|
+
rule: Use [label] on switch-ui directly; do not wrap in field-ui.
|
|
88
97
|
examples:
|
|
89
98
|
- name: notification-preferences
|
|
90
99
|
description: Notification preferences card with toggle switches for different notification channels
|
|
@@ -13,9 +13,19 @@
|
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"properties": {
|
|
16
|
+
"columns": {
|
|
17
|
+
"description": "Column definitions. Array of {key, label, type?, width?, minWidth?, maxWidth?, flex?, sortable?, resizable?, filterable?, pinned?, hidden?, accessor?, format?, render?, sortFn?, filterType?, meta?}. Alternative to declarative <col-def> children.",
|
|
18
|
+
"type": "array",
|
|
19
|
+
"default": []
|
|
20
|
+
},
|
|
16
21
|
"component": {
|
|
17
22
|
"const": "Table"
|
|
18
23
|
},
|
|
24
|
+
"data": {
|
|
25
|
+
"description": "Row records. Array of plain objects keyed to columns[].key.",
|
|
26
|
+
"type": "array",
|
|
27
|
+
"default": []
|
|
28
|
+
},
|
|
19
29
|
"density": {
|
|
20
30
|
"description": "Controls cell padding and row height. 'compact' for dense data, 'standard' for default spacing, 'comfortable' for spacious rows.",
|
|
21
31
|
"type": "string",
|
|
@@ -9,6 +9,14 @@ version: 1
|
|
|
9
9
|
description: Data table with sorting, selection, pagination, search, column resize, keyboard nav,
|
|
10
10
|
cell types, and CSV export. CSS grid + ARIA grid roles.
|
|
11
11
|
props:
|
|
12
|
+
columns:
|
|
13
|
+
description: Column definitions. Array of {key, label, type?, width?, minWidth?, maxWidth?, flex?, sortable?, resizable?, filterable?, pinned?, hidden?, accessor?, format?, render?, sortFn?, filterType?, meta?}. Alternative to declarative <col-def> children.
|
|
14
|
+
type: array
|
|
15
|
+
default: []
|
|
16
|
+
data:
|
|
17
|
+
description: Row records. Array of plain objects keyed to columns[].key.
|
|
18
|
+
type: array
|
|
19
|
+
default: []
|
|
12
20
|
density:
|
|
13
21
|
description: Controls cell padding and row height. 'compact' for dense data, 'standard' for default
|
|
14
22
|
spacing, 'comfortable' for spacious rows.
|
|
@@ -40,6 +40,10 @@
|
|
|
40
40
|
"type": "string",
|
|
41
41
|
"default": ""
|
|
42
42
|
},
|
|
43
|
+
"textContent": {
|
|
44
|
+
"description": "Tag label. Renderer routes this to the `text` attribute, rendered via CSS attr(text) on ::after.",
|
|
45
|
+
"$ref": "common_types.json#/$defs/DynamicString"
|
|
46
|
+
},
|
|
43
47
|
"variant": {
|
|
44
48
|
"description": "Semantic variant — `default | info | success | warning | danger`.",
|
|
45
49
|
"type": "string",
|
package/components/tag/tag.js
CHANGED
|
@@ -16,6 +16,7 @@ import { UIElement } from '../../core/element.js';
|
|
|
16
16
|
class UITag extends UIElement {
|
|
17
17
|
static properties = {
|
|
18
18
|
text: { type: String, default: '', reflect: true },
|
|
19
|
+
textContent: { type: String, default: '' },
|
|
19
20
|
variant: { type: String, default: 'default', reflect: true },
|
|
20
21
|
size: { type: String, default: 'md', reflect: true },
|
|
21
22
|
removable: { type: Boolean, default: false, reflect: true },
|
package/components/tag/tag.yaml
CHANGED
|
@@ -28,6 +28,10 @@ props:
|
|
|
28
28
|
description: Tag text content.
|
|
29
29
|
type: string
|
|
30
30
|
default: ""
|
|
31
|
+
textContent:
|
|
32
|
+
description: Tag label. Renderer routes this to the `text` attribute, rendered via CSS attr(text) on ::after.
|
|
33
|
+
type: string
|
|
34
|
+
dynamic: true
|
|
31
35
|
variant:
|
|
32
36
|
description: Semantic variant — `default | info | success | warning | danger`.
|
|
33
37
|
type: string
|
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
"type": "number",
|
|
22
22
|
"default": 0
|
|
23
23
|
},
|
|
24
|
+
"strong": {
|
|
25
|
+
"description": "When true, applies stronger emphasis (heavier weight + accent color). Styled via :scope[strong] in text.css. Use instead of variant=heading when you want a single emphasized word inline in body copy.",
|
|
26
|
+
"type": "boolean",
|
|
27
|
+
"default": false
|
|
28
|
+
},
|
|
24
29
|
"textContent": {
|
|
25
30
|
"description": "Display text content. The main payload field for Text components extracted from HTML.",
|
|
26
31
|
"$ref": "common_types.json#/$defs/DynamicString"
|
package/components/text/text.js
CHANGED
|
@@ -16,6 +16,7 @@ import { UIElement } from '../../core/element.js';
|
|
|
16
16
|
class UIText extends UIElement {
|
|
17
17
|
static properties = {
|
|
18
18
|
variant: { type: String, default: 'body', reflect: true },
|
|
19
|
+
strong: { type: Boolean, default: false, reflect: true },
|
|
19
20
|
truncate: { type: Boolean, default: false, reflect: true },
|
|
20
21
|
lines: { type: Number, default: 0, reflect: true },
|
|
21
22
|
};
|
|
@@ -12,6 +12,11 @@ props:
|
|
|
12
12
|
description: Multi-line clamp count (0 = no clamp)
|
|
13
13
|
type: number
|
|
14
14
|
default: 0
|
|
15
|
+
strong:
|
|
16
|
+
description: When true, applies stronger emphasis (heavier weight + accent color). Styled via :scope[strong] in text.css. Use instead of variant=heading when you want a single emphasized word inline in body copy.
|
|
17
|
+
type: boolean
|
|
18
|
+
default: false
|
|
19
|
+
reflect: true
|
|
15
20
|
truncate:
|
|
16
21
|
description: Single-line truncation with ellipsis. Ignored when `lines` is set.
|
|
17
22
|
type: boolean
|
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
"type": "string",
|
|
27
27
|
"default": ""
|
|
28
28
|
},
|
|
29
|
+
"name": {
|
|
30
|
+
"description": "Form control name for form data submission. Inherited from UIFormElement.",
|
|
31
|
+
"type": "string",
|
|
32
|
+
"default": ""
|
|
33
|
+
},
|
|
29
34
|
"placeholder": {
|
|
30
35
|
"description": "Placeholder text shown when textarea is empty.",
|
|
31
36
|
"type": "string",
|
|
@@ -76,7 +76,7 @@ class UITextarea extends UIFormElement {
|
|
|
76
76
|
this.value = text;
|
|
77
77
|
this.#textEl.toggleAttribute('data-empty', !text);
|
|
78
78
|
this.syncValue(text);
|
|
79
|
-
this.dispatchEvent(new
|
|
79
|
+
this.dispatchEvent(new CustomEvent('input', { bubbles: true, detail: { value: this.value } }));
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
#onKeydown = (e) => {
|
|
@@ -88,7 +88,7 @@ class UITextarea extends UIFormElement {
|
|
|
88
88
|
};
|
|
89
89
|
|
|
90
90
|
#onBlur = () => {
|
|
91
|
-
this.dispatchEvent(new
|
|
91
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
|
|
92
92
|
};
|
|
93
93
|
|
|
94
94
|
#onPaste = (e) => {
|
|
@@ -16,6 +16,10 @@ props:
|
|
|
16
16
|
description: Label text displayed above the textarea.
|
|
17
17
|
type: string
|
|
18
18
|
default: ""
|
|
19
|
+
name:
|
|
20
|
+
description: Form control name for form data submission. Inherited from UIFormElement.
|
|
21
|
+
type: string
|
|
22
|
+
default: ""
|
|
19
23
|
placeholder:
|
|
20
24
|
description: Placeholder text shown when textarea is empty.
|
|
21
25
|
type: string
|
|
@@ -168,7 +168,7 @@ class UIUpload extends UIFormElement {
|
|
|
168
168
|
}
|
|
169
169
|
this.internals.setFormValue(fd);
|
|
170
170
|
|
|
171
|
-
this.dispatchEvent(new
|
|
171
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value, files: this.files } }));
|
|
172
172
|
this.render();
|
|
173
173
|
}
|
|
174
174
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/web-components",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "AdiaUI web components — vanilla custom elements. A2UI runtime (renderer, registry, streams, wiring) lives in @adia-ai/a2ui-runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"./core/*": "./core/*.js",
|
|
11
11
|
"./components": "./components/index.js",
|
|
12
12
|
"./components/*": "./components/*/*.js",
|
|
13
|
+
"./components/*.css": "./components/*/*.css",
|
|
13
14
|
"./styles/*": "./styles/*",
|
|
14
15
|
"./traits": "./traits/index.js",
|
|
15
16
|
"./traits/*": "./traits/*.js",
|