@adia-ai/web-components 0.6.17 → 0.6.19
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 +140 -0
- package/USAGE.md +6 -0
- package/components/button/button.a2ui.json +8 -1
- package/components/button/button.yaml +13 -1
- package/components/button/class.js +36 -0
- package/components/chart/chart.a2ui.json +5 -0
- package/components/chart/chart.d.ts +2 -0
- package/components/chart/chart.yaml +13 -0
- package/components/chart/class.js +13 -0
- package/components/drawer/class.js +60 -2
- package/components/drawer/drawer.a2ui.json +11 -1
- package/components/drawer/drawer.d.ts +2 -0
- package/components/drawer/drawer.yaml +26 -1
- package/components/segmented/class.js +23 -0
- package/components/segmented/segmented.a2ui.json +11 -4
- package/components/segmented/segmented.yaml +52 -6
- package/components/stat/stat.a2ui.json +7 -1
- package/components/stat/stat.d.ts +2 -0
- package/components/stat/stat.js +34 -5
- package/components/stat/stat.test.js +108 -0
- package/components/stat/stat.yaml +9 -0
- package/components/table/class.js +43 -8
- package/components/table/table.a2ui.json +2 -1
- package/components/table/table.css +20 -4
- package/components/table/table.d.ts +1 -1
- package/components/table/table.test.js +174 -0
- package/components/table/table.yaml +6 -2
- package/components/text/class.js +14 -4
- package/components/text/text.a2ui.json +46 -0
- package/components/text/text.css +41 -0
- package/components/text/text.d.ts +6 -0
- package/components/text/text.test.js +90 -0
- package/components/text/text.yaml +36 -0
- package/components/textarea/textarea.a2ui.json +25 -0
- package/components/textarea/textarea.yaml +23 -0
- package/components/toggle-scheme/class.js +6 -0
- package/components/toggle-scheme/toggle-scheme.yaml +7 -1
- package/core/element.js +13 -0
- package/css-module.d.ts +6 -0
- package/package.json +18 -5
|
@@ -13,6 +13,20 @@
|
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"properties": {
|
|
16
|
+
"color": {
|
|
17
|
+
"description": "Override the variant's color token. Permissive: unknown values are no-ops (variant color wins). Added v0.6.18 (FB-10).",
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": [
|
|
20
|
+
"default",
|
|
21
|
+
"subtle",
|
|
22
|
+
"strong",
|
|
23
|
+
"accent",
|
|
24
|
+
"danger",
|
|
25
|
+
"success",
|
|
26
|
+
"warning"
|
|
27
|
+
],
|
|
28
|
+
"default": ""
|
|
29
|
+
},
|
|
16
30
|
"component": {
|
|
17
31
|
"const": "Text"
|
|
18
32
|
},
|
|
@@ -21,11 +35,32 @@
|
|
|
21
35
|
"type": "number",
|
|
22
36
|
"default": 0
|
|
23
37
|
},
|
|
38
|
+
"size": {
|
|
39
|
+
"description": "Override the variant's font-size on the body ladder. Maps to --a-body-sm / --a-body-md / --a-body-lg. Permissive: unknown values are no-ops (variant size wins). Added v0.6.18 (FB-10).",
|
|
40
|
+
"type": "string",
|
|
41
|
+
"enum": [
|
|
42
|
+
"sm",
|
|
43
|
+
"md",
|
|
44
|
+
"lg"
|
|
45
|
+
],
|
|
46
|
+
"default": ""
|
|
47
|
+
},
|
|
24
48
|
"strong": {
|
|
25
49
|
"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
50
|
"type": "boolean",
|
|
27
51
|
"default": false
|
|
28
52
|
},
|
|
53
|
+
"text-align": {
|
|
54
|
+
"description": "Override text alignment. Note: text-ui defaults to display:inline, so this only takes effect when text-ui is block-like (wrapping or parent display:block/grid). Added v0.6.18 (FB-10).",
|
|
55
|
+
"type": "string",
|
|
56
|
+
"enum": [
|
|
57
|
+
"start",
|
|
58
|
+
"center",
|
|
59
|
+
"end",
|
|
60
|
+
"justify"
|
|
61
|
+
],
|
|
62
|
+
"default": ""
|
|
63
|
+
},
|
|
29
64
|
"textContent": {
|
|
30
65
|
"description": "Display text content. The main payload field for Text components extracted from HTML.",
|
|
31
66
|
"$ref": "common_types.json#/$defs/DynamicString"
|
|
@@ -67,6 +102,17 @@
|
|
|
67
102
|
"section": "Inline form-group / navlist heading (visual rank H4). Small-cap. Use for form group labels, nav list headings.",
|
|
68
103
|
"subsection": "Sub-landmark within a section (visual rank H3). 14px / semibold. Use for card titles within a section."
|
|
69
104
|
}
|
|
105
|
+
},
|
|
106
|
+
"weight": {
|
|
107
|
+
"description": "Override the variant's font-weight. Maps to --a-weight / --a-weight-medium / --a-weight-semibold / --a-weight-bold. Permissive: unknown values are no-ops (variant weight wins). Added v0.6.18 (FB-10).",
|
|
108
|
+
"type": "string",
|
|
109
|
+
"enum": [
|
|
110
|
+
"regular",
|
|
111
|
+
"medium",
|
|
112
|
+
"semibold",
|
|
113
|
+
"bold"
|
|
114
|
+
],
|
|
115
|
+
"default": ""
|
|
70
116
|
}
|
|
71
117
|
},
|
|
72
118
|
"required": [
|
package/components/text/text.css
CHANGED
|
@@ -61,6 +61,47 @@
|
|
|
61
61
|
:scope[variant="deck"] { --text-family: var(--a-deck-family); --text-weight: var(--a-deck-weight); --text-size: var(--a-deck-size); --text-leading: var(--a-deck-leading); --text-tracking: var(--a-deck-tracking); --text-case: var(--a-deck-case); --text-color: var(--a-deck-color); }
|
|
62
62
|
:scope[variant="metric"] { --text-family: var(--a-metric-family); --text-weight: var(--a-metric-weight); --text-size: var(--a-metric-size); --text-leading: var(--a-metric-leading); --text-tracking: var(--a-metric-tracking); --text-case: var(--a-metric-case); --text-color: var(--a-metric-color); }
|
|
63
63
|
|
|
64
|
+
/* ── v0.6.18 (FB-10) — finer-control overrides on top of `variant` ──
|
|
65
|
+
The skill always documented an overlay API (color="subtle",
|
|
66
|
+
size="sm", weight="semibold", text-align="center"). Pre-v0.6.18 these
|
|
67
|
+
attributes existed only as documentation — text-ui ignored them and
|
|
68
|
+
rendered the variant default. v0.6.18 implements them as attribute
|
|
69
|
+
selectors that override the `--text-*` CSS variables set by [variant].
|
|
70
|
+
Each is intentionally permissive: unknown values fall back to the
|
|
71
|
+
variant's value rather than throwing. Authoring `<text-ui color="...">`
|
|
72
|
+
with an unknown color = no-op (variant color wins). */
|
|
73
|
+
|
|
74
|
+
/* size — sm | md | lg (md is the body default ~15-16px) */
|
|
75
|
+
:scope[size="sm"] { --text-size: var(--a-body-sm); }
|
|
76
|
+
:scope[size="md"] { --text-size: var(--a-body-md); }
|
|
77
|
+
:scope[size="lg"] { --text-size: var(--a-body-lg); }
|
|
78
|
+
|
|
79
|
+
/* color — default | subtle | strong | accent | danger | success | warning
|
|
80
|
+
(no value = variant default; "default" is an explicit reset). */
|
|
81
|
+
:scope[color="default"] { --text-color: var(--a-fg); }
|
|
82
|
+
:scope[color="subtle"] { --text-color: var(--a-fg-muted); }
|
|
83
|
+
:scope[color="strong"] { --text-color: var(--a-fg-strong); }
|
|
84
|
+
:scope[color="accent"] { --text-color: var(--a-accent); }
|
|
85
|
+
:scope[color="danger"] { --text-color: var(--a-danger-bg); }
|
|
86
|
+
:scope[color="success"] { --text-color: var(--a-success-bg); }
|
|
87
|
+
:scope[color="warning"] { --text-color: var(--a-warning-bg); }
|
|
88
|
+
|
|
89
|
+
/* weight — regular | medium | semibold | bold */
|
|
90
|
+
:scope[weight="regular"] { --text-weight: var(--a-weight); }
|
|
91
|
+
:scope[weight="medium"] { --text-weight: var(--a-weight-medium); }
|
|
92
|
+
:scope[weight="semibold"] { --text-weight: var(--a-weight-semibold); }
|
|
93
|
+
:scope[weight="bold"] { --text-weight: var(--a-weight-bold); }
|
|
94
|
+
|
|
95
|
+
/* text-align — start | center | end | justify */
|
|
96
|
+
:scope[text-align="start"] { text-align: start; }
|
|
97
|
+
:scope[text-align="center"] { text-align: center; }
|
|
98
|
+
:scope[text-align="end"] { text-align: end; }
|
|
99
|
+
:scope[text-align="justify"] { text-align: justify; }
|
|
100
|
+
/* Note: `<text-ui>` defaults to display:inline. text-align only takes
|
|
101
|
+
effect when text-ui itself is block-like (e.g. via wrapping or a
|
|
102
|
+
`display: block`/`grid` parent). The override-attribute pattern keeps
|
|
103
|
+
the inline default but lets consumers flip alignment with one attr. */
|
|
104
|
+
|
|
64
105
|
/* ── Truncation (single-line) ── */
|
|
65
106
|
:scope[truncate] {
|
|
66
107
|
overflow: hidden;
|
|
@@ -39,8 +39,12 @@ export type UITextVariant =
|
|
|
39
39
|
| 'code';
|
|
40
40
|
|
|
41
41
|
export class UIText extends UIElement {
|
|
42
|
+
/** Override the variant's color token. Permissive: unknown values are no-ops (variant color wins). Added v0.6.18 (FB-10). */
|
|
43
|
+
color: 'default' | 'subtle' | 'strong' | 'accent' | 'danger' | 'success' | 'warning';
|
|
42
44
|
/** Multi-line clamp count (0 = no clamp) */
|
|
43
45
|
lines: number;
|
|
46
|
+
/** Override the variant's font-size on the body ladder. Maps to --a-body-sm / --a-body-md / --a-body-lg. Permissive: unknown values are no-ops (variant size wins). Added v0.6.18 (FB-10). */
|
|
47
|
+
size: 'sm' | 'md' | 'lg';
|
|
44
48
|
/** 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. */
|
|
45
49
|
strong: boolean;
|
|
46
50
|
/** Display text content. The main payload field for Text components extracted from HTML. */
|
|
@@ -57,4 +61,6 @@ For semantic headings, wrap with native `<h1>`-`<h6>` OR add
|
|
|
57
61
|
labels (eyebrows, kickers, captions, deck), the presentational default
|
|
58
62
|
is correct. The §221k chooser guide in USAGE.md documents picker heuristics. */
|
|
59
63
|
variant: UITextVariant;
|
|
64
|
+
/** Override the variant's font-weight. Maps to --a-weight / --a-weight-medium / --a-weight-semibold / --a-weight-bold. Permissive: unknown values are no-ops (variant weight wins). Added v0.6.18 (FB-10). */
|
|
65
|
+
weight: 'regular' | 'medium' | 'semibold' | 'bold';
|
|
60
66
|
}
|
|
@@ -110,3 +110,93 @@ describe('text-ui §210 — variant enum vs CSS rule completeness', () => {
|
|
|
110
110
|
}
|
|
111
111
|
});
|
|
112
112
|
});
|
|
113
|
+
|
|
114
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
115
|
+
// v0.6.18 (FB-10) — overlay attributes on top of `variant`
|
|
116
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
describe('text-ui v0.6.18 — overlay props (FB-10)', () => {
|
|
119
|
+
beforeEach(() => { document.body.innerHTML = ''; });
|
|
120
|
+
|
|
121
|
+
// ── Attribute reflection: each new prop reflects to the host ──
|
|
122
|
+
it.each([
|
|
123
|
+
['size', 'sm'],
|
|
124
|
+
['size', 'md'],
|
|
125
|
+
['size', 'lg'],
|
|
126
|
+
['color', 'subtle'],
|
|
127
|
+
['color', 'strong'],
|
|
128
|
+
['color', 'accent'],
|
|
129
|
+
['color', 'danger'],
|
|
130
|
+
['color', 'success'],
|
|
131
|
+
['color', 'warning'],
|
|
132
|
+
['color', 'default'],
|
|
133
|
+
['weight', 'regular'],
|
|
134
|
+
['weight', 'medium'],
|
|
135
|
+
['weight', 'semibold'],
|
|
136
|
+
['weight', 'bold'],
|
|
137
|
+
['text-align', 'start'],
|
|
138
|
+
['text-align', 'center'],
|
|
139
|
+
['text-align', 'end'],
|
|
140
|
+
['text-align', 'justify'],
|
|
141
|
+
])('<text-ui %s="%s"> reflects the attribute', async (prop, value) => {
|
|
142
|
+
const el = mount(`<text-ui ${prop}="${value}">x</text-ui>`);
|
|
143
|
+
await tick();
|
|
144
|
+
expect(el.getAttribute(prop)).toBe(value);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// ── CSS-side: every documented value has a :scope[attr="value"] rule ──
|
|
148
|
+
const sizes = ['sm', 'md', 'lg'];
|
|
149
|
+
const colors = ['default', 'subtle', 'strong', 'accent', 'danger', 'success', 'warning'];
|
|
150
|
+
const weights = ['regular', 'medium', 'semibold', 'bold'];
|
|
151
|
+
const aligns = ['start', 'center', 'end', 'justify'];
|
|
152
|
+
|
|
153
|
+
it.each(sizes)('text.css ships :scope[size="%s"] rule', (s) => {
|
|
154
|
+
expect(TEXT_CSS).toMatch(new RegExp(`:scope\\[size="${s}"\\]`));
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it.each(colors)('text.css ships :scope[color="%s"] rule', (c) => {
|
|
158
|
+
expect(TEXT_CSS).toMatch(new RegExp(`:scope\\[color="${c}"\\]`));
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it.each(weights)('text.css ships :scope[weight="%s"] rule', (w) => {
|
|
162
|
+
expect(TEXT_CSS).toMatch(new RegExp(`:scope\\[weight="${w}"\\]`));
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it.each(aligns)('text.css ships :scope[text-align="%s"] rule', (a) => {
|
|
166
|
+
expect(TEXT_CSS).toMatch(new RegExp(`:scope\\[text-align="${a}"\\]`));
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// ── yaml-vs-impl consistency: every prop in the a2ui enum has a CSS rule ──
|
|
170
|
+
it('a2ui.json color enum matches CSS rules 1:1', () => {
|
|
171
|
+
const colorEnum = TEXT_A2UI.properties.color?.enum ?? [];
|
|
172
|
+
expect(colorEnum.sort()).toEqual([...colors].sort());
|
|
173
|
+
for (const c of colorEnum) {
|
|
174
|
+
expect(TEXT_CSS).toMatch(new RegExp(`:scope\\[color="${c}"\\]`));
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('a2ui.json size enum matches CSS rules 1:1', () => {
|
|
179
|
+
const sizeEnum = TEXT_A2UI.properties.size?.enum ?? [];
|
|
180
|
+
expect(sizeEnum.sort()).toEqual([...sizes].sort());
|
|
181
|
+
for (const s of sizeEnum) {
|
|
182
|
+
expect(TEXT_CSS).toMatch(new RegExp(`:scope\\[size="${s}"\\]`));
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('a2ui.json weight enum matches CSS rules 1:1', () => {
|
|
187
|
+
const weightEnum = TEXT_A2UI.properties.weight?.enum ?? [];
|
|
188
|
+
expect(weightEnum.sort()).toEqual([...weights].sort());
|
|
189
|
+
for (const w of weightEnum) {
|
|
190
|
+
expect(TEXT_CSS).toMatch(new RegExp(`:scope\\[weight="${w}"\\]`));
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// ── Permissive fallback: unknown values are no-ops (no JS error) ──
|
|
195
|
+
it('unknown color value renders without throwing', async () => {
|
|
196
|
+
const el = mount('<text-ui color="banana">x</text-ui>');
|
|
197
|
+
await tick();
|
|
198
|
+
expect(el.getAttribute('color')).toBe('banana');
|
|
199
|
+
// The variant default wins; no CSS rule matches "banana". Test the
|
|
200
|
+
// shape: no thrown error during mount, no console.error.
|
|
201
|
+
});
|
|
202
|
+
});
|
|
@@ -8,20 +8,56 @@ category: display
|
|
|
8
8
|
version: 1
|
|
9
9
|
description: Typography wrapper that applies role tokens. Supports truncation and line clamping.
|
|
10
10
|
props:
|
|
11
|
+
color:
|
|
12
|
+
description: >-
|
|
13
|
+
Override the variant's color token. Permissive: unknown values are
|
|
14
|
+
no-ops (variant color wins). Added v0.6.18 (FB-10).
|
|
15
|
+
type: string
|
|
16
|
+
enum: ["default", "subtle", "strong", "accent", "danger", "success", "warning"]
|
|
17
|
+
default: ""
|
|
18
|
+
reflect: true
|
|
11
19
|
lines:
|
|
12
20
|
description: Multi-line clamp count (0 = no clamp)
|
|
13
21
|
type: number
|
|
14
22
|
default: 0
|
|
23
|
+
size:
|
|
24
|
+
description: >-
|
|
25
|
+
Override the variant's font-size on the body ladder. Maps to
|
|
26
|
+
--a-body-sm / --a-body-md / --a-body-lg. Permissive: unknown values
|
|
27
|
+
are no-ops (variant size wins). Added v0.6.18 (FB-10).
|
|
28
|
+
type: string
|
|
29
|
+
enum: ["sm", "md", "lg"]
|
|
30
|
+
default: ""
|
|
31
|
+
reflect: true
|
|
15
32
|
strong:
|
|
16
33
|
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
34
|
type: boolean
|
|
18
35
|
default: false
|
|
19
36
|
reflect: true
|
|
37
|
+
text-align:
|
|
38
|
+
description: >-
|
|
39
|
+
Override text alignment. Note: text-ui defaults to display:inline,
|
|
40
|
+
so this only takes effect when text-ui is block-like (wrapping or
|
|
41
|
+
parent display:block/grid). Added v0.6.18 (FB-10).
|
|
42
|
+
type: string
|
|
43
|
+
enum: ["start", "center", "end", "justify"]
|
|
44
|
+
default: ""
|
|
45
|
+
reflect: true
|
|
20
46
|
truncate:
|
|
21
47
|
description: Single-line truncation with ellipsis. Ignored when `lines` is set.
|
|
22
48
|
type: boolean
|
|
23
49
|
default: false
|
|
24
50
|
reflect: true
|
|
51
|
+
weight:
|
|
52
|
+
description: >-
|
|
53
|
+
Override the variant's font-weight. Maps to --a-weight /
|
|
54
|
+
--a-weight-medium / --a-weight-semibold / --a-weight-bold.
|
|
55
|
+
Permissive: unknown values are no-ops (variant weight wins). Added
|
|
56
|
+
v0.6.18 (FB-10).
|
|
57
|
+
type: string
|
|
58
|
+
enum: ["regular", "medium", "semibold", "bold"]
|
|
59
|
+
default: ""
|
|
60
|
+
reflect: true
|
|
25
61
|
textContent:
|
|
26
62
|
description: Display text content. The main payload field for Text components extracted from HTML.
|
|
27
63
|
type: string
|
|
@@ -13,9 +13,24 @@
|
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"properties": {
|
|
16
|
+
"required": {
|
|
17
|
+
"description": "Marks the field as required for form validation. Sets aria-required. Inherited from UIFormElement.",
|
|
18
|
+
"type": "boolean",
|
|
19
|
+
"default": false
|
|
20
|
+
},
|
|
16
21
|
"component": {
|
|
17
22
|
"const": "Textarea"
|
|
18
23
|
},
|
|
24
|
+
"disabled": {
|
|
25
|
+
"description": "Disables interaction, removes contenteditable, and dims the control. Inherited from UIFormElement.",
|
|
26
|
+
"type": "boolean",
|
|
27
|
+
"default": false
|
|
28
|
+
},
|
|
29
|
+
"error": {
|
|
30
|
+
"description": "Validation error message. Set by constraint validation or manually via setInvalid(). Inherited from UIFormElement.",
|
|
31
|
+
"type": "string",
|
|
32
|
+
"default": ""
|
|
33
|
+
},
|
|
19
34
|
"hint": {
|
|
20
35
|
"description": "Help text displayed below the textarea. Hidden when error is set.",
|
|
21
36
|
"type": "string",
|
|
@@ -36,6 +51,11 @@
|
|
|
36
51
|
"type": "string",
|
|
37
52
|
"default": ""
|
|
38
53
|
},
|
|
54
|
+
"readonly": {
|
|
55
|
+
"description": "Prevents editing while keeping the surface focusable. Sets contenteditable=false. Inherited from UIFormElement.",
|
|
56
|
+
"type": "boolean",
|
|
57
|
+
"default": false
|
|
58
|
+
},
|
|
39
59
|
"resize": {
|
|
40
60
|
"description": "Resize behavior of the textarea.",
|
|
41
61
|
"type": "string",
|
|
@@ -56,6 +76,11 @@
|
|
|
56
76
|
"description": "§220 (v0.5.9, FEEDBACK-14 §3). Trailing-debounce on the `input`\nevent in milliseconds. When > 0, value mutates immediately + the UI\nstays responsive, but `input` dispatch is collapsed so only the\nfinal value in the throttle window emits. Useful for expensive\n`input`-driven computation (autosave preview, server-side\nautocomplete, large-doc reflow). `change` fires unthrottled on blur\n/ Enter; any pending `input` flushes before `change` so consumers\nsee input→input→…→input→change ordering. Default 0 preserves\nsynchronous emission.",
|
|
57
77
|
"type": "number",
|
|
58
78
|
"default": 0
|
|
79
|
+
},
|
|
80
|
+
"value": {
|
|
81
|
+
"description": "Current textarea value, synced with the contenteditable text surface. Inherited from UIFormElement.",
|
|
82
|
+
"type": "string",
|
|
83
|
+
"default": ""
|
|
59
84
|
}
|
|
60
85
|
},
|
|
61
86
|
"required": [
|
|
@@ -8,6 +8,15 @@ category: layout
|
|
|
8
8
|
version: 1
|
|
9
9
|
description: Multiline text input. The host IS the interactive surface.
|
|
10
10
|
props:
|
|
11
|
+
disabled:
|
|
12
|
+
description: Disables interaction, removes contenteditable, and dims the control. Inherited from UIFormElement.
|
|
13
|
+
type: boolean
|
|
14
|
+
default: false
|
|
15
|
+
reflect: true
|
|
16
|
+
error:
|
|
17
|
+
description: Validation error message. Set by constraint validation or manually via setInvalid(). Inherited from UIFormElement.
|
|
18
|
+
type: string
|
|
19
|
+
default: ""
|
|
11
20
|
hint:
|
|
12
21
|
description: Help text displayed below the textarea. Hidden when error is set.
|
|
13
22
|
type: string
|
|
@@ -24,6 +33,16 @@ props:
|
|
|
24
33
|
description: Placeholder text shown when textarea is empty.
|
|
25
34
|
type: string
|
|
26
35
|
default: ""
|
|
36
|
+
readonly:
|
|
37
|
+
description: Prevents editing while keeping the surface focusable. Sets contenteditable=false. Inherited from UIFormElement.
|
|
38
|
+
type: boolean
|
|
39
|
+
default: false
|
|
40
|
+
reflect: true
|
|
41
|
+
required:
|
|
42
|
+
description: Marks the field as required for form validation. Sets aria-required. Inherited from UIFormElement.
|
|
43
|
+
type: boolean
|
|
44
|
+
default: false
|
|
45
|
+
reflect: true
|
|
27
46
|
resize:
|
|
28
47
|
description: Resize behavior of the textarea.
|
|
29
48
|
type: string
|
|
@@ -51,6 +70,10 @@ props:
|
|
|
51
70
|
type: number
|
|
52
71
|
default: 0
|
|
53
72
|
reflect: true
|
|
73
|
+
value:
|
|
74
|
+
description: Current textarea value, synced with the contenteditable text surface. Inherited from UIFormElement.
|
|
75
|
+
type: string
|
|
76
|
+
default: ""
|
|
54
77
|
events:
|
|
55
78
|
change:
|
|
56
79
|
description: Fired when the textarea loses focus after a value change.
|
|
@@ -272,11 +272,17 @@ export class UIToggleScheme extends UIElement {
|
|
|
272
272
|
#writeTarget(scheme) {
|
|
273
273
|
const t = this.#resolveTarget();
|
|
274
274
|
t.style.setProperty('color-scheme', scheme);
|
|
275
|
+
// FEEDBACK-14: also write the [data-scheme] attribute. styles/themes.css
|
|
276
|
+
// selects on [data-scheme="dark"] etc., so consumer CSS patterned after
|
|
277
|
+
// themes.css needs the attribute — the inline color-scheme style alone
|
|
278
|
+
// satisfies AdiaUI's light-dark() tokens but not [data-scheme]-scoped CSS.
|
|
279
|
+
t.setAttribute('data-scheme', scheme);
|
|
275
280
|
}
|
|
276
281
|
|
|
277
282
|
#clearTargetOverride() {
|
|
278
283
|
const t = this.#resolveTarget();
|
|
279
284
|
t.style.removeProperty('color-scheme');
|
|
285
|
+
t.removeAttribute('data-scheme'); // FEEDBACK-14 — paired with #writeTarget
|
|
280
286
|
if (this.persist) {
|
|
281
287
|
try { localStorage.removeItem(`${this.storagePrefix}scheme`); } catch {}
|
|
282
288
|
}
|
|
@@ -149,7 +149,13 @@ tokens:
|
|
|
149
149
|
--toggle-scheme-icon-transition:
|
|
150
150
|
description: Duration + easing for icon-color transition when scheme flips.
|
|
151
151
|
a2ui:
|
|
152
|
-
rules:
|
|
152
|
+
rules:
|
|
153
|
+
- >-
|
|
154
|
+
Place toggle-scheme-ui in the shell topbar's trailing action cluster
|
|
155
|
+
— slot="action" inside <admin-topbar slot="header"> of
|
|
156
|
+
<admin-content>. It is a persistent, app-wide preference control;
|
|
157
|
+
never put it in a sidebar footer / <admin-statusbar>, which hosts
|
|
158
|
+
user-account items only.
|
|
153
159
|
anti_patterns: []
|
|
154
160
|
examples:
|
|
155
161
|
- name: header-action
|
package/core/element.js
CHANGED
|
@@ -262,6 +262,18 @@ export class UIElement extends HTMLElement {
|
|
|
262
262
|
|
|
263
263
|
signal(v) { const s = signal(v); this.#as.push(s); return s; }
|
|
264
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Get-or-create a structural part by slot name. Returns the existing
|
|
267
|
+
* `[slot="X"]` child when present, otherwise clones the part blueprint
|
|
268
|
+
* (`static parts`) and appends it. Re-stamped parts carry `_uiPart = true`
|
|
269
|
+
* so a part wiped by a host `innerHTML` mutation is detectable downstream.
|
|
270
|
+
*
|
|
271
|
+
* INVARIANT (FEEDBACK-31) — call `ensure()` from `render()`; never cache
|
|
272
|
+
* its result once in `connected()`. A consumer that replaces the host's
|
|
273
|
+
* children (`el.innerHTML = …`) wipes stamped parts; `render()` re-stamps
|
|
274
|
+
* them, but a reference captured once in `connected()` is left pointing at
|
|
275
|
+
* detached DOM. Part identity does not survive a host child-list wipe.
|
|
276
|
+
*/
|
|
265
277
|
ensure(slot) {
|
|
266
278
|
for (const ch of this.children) {
|
|
267
279
|
if (ch.getAttribute('slot') === slot) return ch;
|
|
@@ -272,6 +284,7 @@ export class UIElement extends HTMLElement {
|
|
|
272
284
|
const blueprint = this.constructor._pp?.[slot];
|
|
273
285
|
if (!blueprint) return null;
|
|
274
286
|
const el = blueprint.cloneNode(true);
|
|
287
|
+
el._uiPart = true;
|
|
275
288
|
this.appendChild(el);
|
|
276
289
|
return el;
|
|
277
290
|
}
|
package/css-module.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Ambient declaration so TypeScript (moduleResolution: bundler / node16)
|
|
2
|
+
// can resolve CSS side-effect subpath imports — e.g.
|
|
3
|
+
// import '@adia-ai/web-components/css';
|
|
4
|
+
// without a TS2882 "no type declarations for side-effect import" error.
|
|
5
|
+
// See FEEDBACK-26.
|
|
6
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/web-components",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.19",
|
|
4
4
|
"description": "AdiaUI web components \u2014 vanilla custom elements. A2UI runtime (renderer, registry, streams, wiring) lives in @adia-ai/a2ui-runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
"import": "./index.js",
|
|
14
14
|
"default": "./index.js"
|
|
15
15
|
},
|
|
16
|
-
"./css":
|
|
16
|
+
"./css": {
|
|
17
|
+
"types": "./css-module.d.ts",
|
|
18
|
+
"default": "./index.css"
|
|
19
|
+
},
|
|
17
20
|
"./core": {
|
|
18
21
|
"types": "./core/index.d.ts",
|
|
19
22
|
"import": "./core/index.js",
|
|
@@ -39,9 +42,18 @@
|
|
|
39
42
|
"import": "./components/*/class.js",
|
|
40
43
|
"default": "./components/*/class.js"
|
|
41
44
|
},
|
|
42
|
-
"./components/*.css":
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
"./components/*.css": {
|
|
46
|
+
"types": "./css-module.d.ts",
|
|
47
|
+
"default": "./components/*/*.css"
|
|
48
|
+
},
|
|
49
|
+
"./components/*/*.css": {
|
|
50
|
+
"types": "./css-module.d.ts",
|
|
51
|
+
"default": "./components/*/*.css"
|
|
52
|
+
},
|
|
53
|
+
"./components/*/css/*.css": {
|
|
54
|
+
"types": "./css-module.d.ts",
|
|
55
|
+
"default": "./components/*/css/*.css"
|
|
56
|
+
},
|
|
45
57
|
"./styles/*": "./styles/*",
|
|
46
58
|
"./traits": {
|
|
47
59
|
"types": "./traits.d.ts",
|
|
@@ -77,6 +89,7 @@
|
|
|
77
89
|
"index.js",
|
|
78
90
|
"index.css",
|
|
79
91
|
"index.d.ts",
|
|
92
|
+
"css-module.d.ts",
|
|
80
93
|
"bin/",
|
|
81
94
|
"custom-elements.json",
|
|
82
95
|
"USAGE.md",
|