@adia-ai/web-components 0.6.23 → 0.6.24
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 +10 -0
- package/README.md +1 -1
- package/components/slider/class.js +15 -0
- package/components/slider/slider.test.js +39 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog — @adia-ai/web-components
|
|
2
2
|
|
|
3
|
+
## [0.6.24] — 2026-05-22
|
|
4
|
+
|
|
5
|
+
### Fixed — `slider-ui` label and suffix template snapshot trap (FB-45)
|
|
6
|
+
|
|
7
|
+
- **`[slot="label"]` and `[slot="suffix"]` now re-sync in `render()`**, resolving the snapshot trap where `label=${expr}` via the template engine rendered the literal `{{p:N}}` placeholder instead of the resolved value. Both spans are updated on every reactive cycle; a missing label span is also created if absent at connection time. File: `components/slider/class.js`.
|
|
8
|
+
|
|
9
|
+
### Fixed — `toast-ui` demo shell missing `feed.css` import
|
|
10
|
+
|
|
11
|
+
- **`toast.html` now imports `feed/feed.css` + `feed/feed.js`.** `<toast-ui>` renders via `<feed-ui>` — the demo shell was not loading feed's stylesheet, so feed items rendered without background, typography, or spacing. Files: `components/toast/toast.html`.
|
|
12
|
+
|
|
3
13
|
## [0.6.23] — 2026-05-22
|
|
4
14
|
|
|
5
15
|
### Added — `row-ui` `wrap-at="bp"` responsive wrap (`components/row/`)
|
package/README.md
CHANGED
|
@@ -215,7 +215,7 @@ class MyPanel extends UIElement {
|
|
|
215
215
|
The `el` parameter is the element instance — every signal-backed property is reactively read.
|
|
216
216
|
|
|
217
217
|
Full authoring contract: [`docs/specs/component-token-contract.md`](../../docs/specs/component-token-contract.md).
|
|
218
|
-
The `adia-ui-
|
|
218
|
+
The `adia-ui-authoring` skill encodes the 20 non-negotiable rules.
|
|
219
219
|
|
|
220
220
|
## Card-n / drawer-ui composition parity
|
|
221
221
|
|
|
@@ -149,6 +149,21 @@ export class UISlider extends UIFormElement {
|
|
|
149
149
|
const valueEl = this.querySelector('[slot="value"]');
|
|
150
150
|
if (valueEl) valueEl.textContent = this.#format(this.value);
|
|
151
151
|
|
|
152
|
+
// §FB-45: label and suffix are read in connected() but may be set later
|
|
153
|
+
// by the template engine (which first writes {{p:N}} then resolves).
|
|
154
|
+
// Re-sync both slots on every render so reactive bindings work.
|
|
155
|
+
const labelEl = this.querySelector('[slot="label"]');
|
|
156
|
+
if (labelEl) {
|
|
157
|
+
labelEl.textContent = this.label;
|
|
158
|
+
} else if (this.label) {
|
|
159
|
+
const header = this.querySelector('[slot="header"]');
|
|
160
|
+
if (header) { const s = document.createElement('span'); s.slot = 'label'; s.textContent = this.label; header.prepend(s); }
|
|
161
|
+
}
|
|
162
|
+
if (this.label) this.setAttribute('aria-label', this.label);
|
|
163
|
+
|
|
164
|
+
const suffixEl = this.querySelector('[slot="suffix"]');
|
|
165
|
+
if (suffixEl) suffixEl.textContent = this.suffix;
|
|
166
|
+
|
|
152
167
|
this.setAttribute('aria-valuenow', this.value);
|
|
153
168
|
this.setAttribute('aria-valuetext', `${this.#format(this.value)}${this.suffix ? ' ' + this.suffix : ''}`);
|
|
154
169
|
this.syncValue(String(this.value));
|
|
@@ -105,4 +105,43 @@ describe('slider-ui', () => {
|
|
|
105
105
|
await tick();
|
|
106
106
|
expect(s.getAttribute('aria-valuenow')).toBe('80');
|
|
107
107
|
});
|
|
108
|
+
|
|
109
|
+
// §FB-45 (color-app, 2026-05-22) — template engine snapshot trap.
|
|
110
|
+
// connected() stamped label/suffix once; render() didn't re-sync them.
|
|
111
|
+
// Template engine writes {{p:N}} first, then resolves to the real value —
|
|
112
|
+
// simulated here by setAttribute('label', placeholder) then setting the
|
|
113
|
+
// real value. Both spans must reflect the final value, not the placeholder.
|
|
114
|
+
it('re-syncs [slot="label"] when label attribute changes after connection', async () => {
|
|
115
|
+
const s = mount('<slider-ui value="50" min="0" max="100"></slider-ui>');
|
|
116
|
+
await tick();
|
|
117
|
+
// No label initially — span absent
|
|
118
|
+
expect(s.querySelector('[slot="label"]')).toBeNull();
|
|
119
|
+
|
|
120
|
+
// Simulate template engine writing placeholder then real value
|
|
121
|
+
s.setAttribute('label', '{{p:7}}');
|
|
122
|
+
await tick();
|
|
123
|
+
s.setAttribute('label', 'Volume');
|
|
124
|
+
await tick();
|
|
125
|
+
|
|
126
|
+
const labelEl = s.querySelector('[slot="label"]');
|
|
127
|
+
expect(labelEl).not.toBeNull();
|
|
128
|
+
expect(labelEl.textContent).toBe('Volume');
|
|
129
|
+
expect(s.getAttribute('aria-label')).toBe('Volume');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('re-syncs [slot="suffix"] when suffix attribute changes after connection', async () => {
|
|
133
|
+
const s = mount('<slider-ui value="50" min="0" max="100" label="Volume" suffix="%"></slider-ui>');
|
|
134
|
+
await tick();
|
|
135
|
+
const suffixEl = s.querySelector('[slot="suffix"]');
|
|
136
|
+
expect(suffixEl).not.toBeNull();
|
|
137
|
+
expect(suffixEl.textContent).toBe('%');
|
|
138
|
+
|
|
139
|
+
// Simulate placeholder → resolved suffix
|
|
140
|
+
s.setAttribute('suffix', '{{p:8}}');
|
|
141
|
+
await tick();
|
|
142
|
+
s.setAttribute('suffix', 'rem');
|
|
143
|
+
await tick();
|
|
144
|
+
|
|
145
|
+
expect(s.querySelector('[slot="suffix"]').textContent).toBe('rem');
|
|
146
|
+
});
|
|
108
147
|
});
|
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.24",
|
|
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",
|