@adia-ai/web-components 0.5.19 → 0.5.21
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/USAGE.md +30 -2
- package/components/index.d.ts +4 -0
- package/components/pane/pane.css +6 -4
- package/components/stat/stat.a2ui.json +3 -1
- package/components/stat/stat.d.ts +26 -0
- package/components/stat/stat.yaml +2 -0
- package/components/tabs/tabs.css +5 -4
- package/package.json +22 -12
- package/styles/components.css +1 -1
- package/components/stat/stat-ui.d.ts +0 -38
- /package/components/stat/{stat-ui.css → stat.css} +0 -0
- /package/components/stat/{stat-ui.js → stat.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,23 @@ runtime ships in the sibling `@adia-ai/a2ui-runtime` package
|
|
|
11
11
|
|
|
12
12
|
_No pending changes._
|
|
13
13
|
|
|
14
|
+
## [0.5.21] - 2026-05-18
|
|
15
|
+
|
|
16
|
+
_Lockstep ride-along (no source change in this package; companion to web-components v0.5.21 — see root CHANGELOG)._
|
|
17
|
+
|
|
18
|
+
## [0.5.20] - 2026-05-18
|
|
19
|
+
|
|
20
|
+
### Added — §353 (v0.5.20) — `<pane-ui>` + `<tabs-ui>` bar-rule alignment
|
|
21
|
+
|
|
22
|
+
Both primitives' header/tablist bars converted from `border-bottom` to `box-shadow: inset 0 -1px 0`. Header height fixed at `--pane-bar-height` / `--tabs-button-height` (was `min-height` + the border added a pixel). Pane header gains `box-sizing: border-box` + `justify-content: flex-start`. Collapsed pane header drops the box-shadow. Visually identical to consumers; measurable change in computed height (1px shorter than border-bearing version). Brings these two primitives in line with the rest of the catalog using box-shadow for bar rules.
|
|
23
|
+
|
|
24
|
+
### Docs
|
|
25
|
+
- §351 (FB-53 #2) — USAGE.md `§349 Event handling inside reactive lists` section gains a `CSS child-combinator caveat` paragraph. Calls out that `display:contents` wrapper-spans ARE in the DOM tree, so the CSS child combinator (`>`) walks past them: `.parent > .my-item` will NOT match items inside `repeat()` because the wrapper-span sits between. Recommends descendant combinator (single space) instead. Same caveat extended to `:nth-child` / positional pseudo-classes. Closes the post-Lane-AA1 migration docs gap surfaced by Tokens Studio.
|
|
26
|
+
- §352 (FB-53 #3) — USAGE.md `§345 .map() vs repeat() for reactive lists` section gains a `Sizing heuristic` paragraph. Two cases where `repeat()` pays for itself: (a) ≥20 items re-rendering on every signal change, OR (b) any-size list whose items host custom elements with internal state (chrome slots, focus, scroll). Discourages reflexive `.map()` → `repeat()` migration when neither threshold applies.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- §-headers (v0.5.20) — USAGE.md headers for `§345` and `§349` renumbered from `§-TBD (v0.5.19)` to `§345 (v0.5.19)` / `§349 (v0.5.19)` — peer-agent's v0.5.19 pre-cut docs sweep renumbered the CHANGELOG but missed the USAGE.md section headers. Sync restored so the section anchors match between CHANGELOG and USAGE.md.
|
|
30
|
+
|
|
14
31
|
## [0.5.19] - 2026-05-17
|
|
15
32
|
|
|
16
33
|
### Added
|
package/USAGE.md
CHANGED
|
@@ -1086,7 +1086,7 @@ Why AdiaUI doesn't implement `?attr=`: custom elements declare their reflective
|
|
|
1086
1086
|
- HTML comments containing quoted attributes (`<!-- attr="value" -->`) — same fix (v0.5.3 §155).
|
|
1087
1087
|
- Backticks inside HTML comments — see §221i above (JS-spec footgun; not a parser bug).
|
|
1088
1088
|
|
|
1089
|
-
###
|
|
1089
|
+
### §345 (v0.5.19) — `.map()` vs `repeat()` for reactive lists (FB-47)
|
|
1090
1090
|
|
|
1091
1091
|
Use **`repeat(items, keyFn, tplFn)`** for any list whose items are signal-driven and should preserve identity across re-renders. Plain `.map()` returns an `Array` of template results, which the template engine materializes via `container.replaceChildren()` on every parent update — correct, but per-item DOM is re-created from scratch.
|
|
1092
1092
|
|
|
@@ -1118,7 +1118,9 @@ html`
|
|
|
1118
1118
|
|
|
1119
1119
|
**Key selection:** pick a stable consumer-supplied identifier (database id, slot.key, etc.), NOT array index. Array indices are unstable under insert/remove and defeat the keyed-reuse contract.
|
|
1120
1120
|
|
|
1121
|
-
|
|
1121
|
+
**Sizing heuristic (FB-53 #3):** `.map()` is fine for static lists of ≤10 items that don't re-render or only re-render at navigation boundaries. `repeat()` adds per-render bookkeeping (Map lookups, key comparison, DOM reuse) that pays for itself in two cases: (a) lists of ≥20 items that re-render on every signal change (e.g. a palette grid with 66 swatches updating on every slider drag), or (b) any-size list whose items host custom elements with internal state (chrome slots, focus position, scroll offset). Don't migrate every `.map()` reflexively — migrate when one of those two thresholds applies.
|
|
1122
|
+
|
|
1123
|
+
### §349 (v0.5.19) — Event handling inside reactive lists (FB-49)
|
|
1122
1124
|
|
|
1123
1125
|
Custom-element children rendered inside `repeat()` (or as an `${array}` interpolation) are each wrapped in a `<span style="display:contents">` by the template engine. These wrapper spans generate no boxes (`display:contents`) and cannot be click targets, but they ARE in the DOM tree.
|
|
1124
1126
|
|
|
@@ -1154,6 +1156,32 @@ host.addEventListener('click', (e) => {
|
|
|
1154
1156
|
|
|
1155
1157
|
**Don't reach for `composedPath()` reflexively** — it rebuilds the full path on every call and is slower than `closest()`. Default to `closest()` for direct bubble-phase handlers; use `composedPath()` only when one of the three cases above applies.
|
|
1156
1158
|
|
|
1159
|
+
**CSS child-combinator caveat (FB-53 #2):** `display:contents` wrapper-spans ARE in the DOM tree even though they generate no boxes. The CSS child combinator (`>`) walks the DOM tree (not the box tree), so consumer rules of the shape `.parent > .my-item` **will not match** items inside a `repeat()` because the wrapper-span sits between `.parent` and the items:
|
|
1160
|
+
|
|
1161
|
+
```html
|
|
1162
|
+
<!-- Actual DOM produced by repeat(): -->
|
|
1163
|
+
<div class="parent">
|
|
1164
|
+
<span style="display:contents"> <!-- ← repeat() per-item wrapper -->
|
|
1165
|
+
<my-item class="my-item">…</my-item>
|
|
1166
|
+
</span>
|
|
1167
|
+
</div>
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
Use the descendant combinator (a single space) instead, which traverses any depth:
|
|
1171
|
+
|
|
1172
|
+
```css
|
|
1173
|
+
/* ❌ Won't match — wrapper-span sits between .parent and .my-item */
|
|
1174
|
+
.parent > .my-item { … }
|
|
1175
|
+
|
|
1176
|
+
/* ✅ Descendant combinator pierces through the wrapper-spans */
|
|
1177
|
+
.parent .my-item { … }
|
|
1178
|
+
|
|
1179
|
+
/* ✅ Or use :scope/has() if you need precision: */
|
|
1180
|
+
.parent > :is(.my-item, span > .my-item) { … }
|
|
1181
|
+
```
|
|
1182
|
+
|
|
1183
|
+
Same caveat applies to `:nth-child()` / `:nth-of-type()` / `:first-child` / `:last-child` against the parent — those count actual children (the wrapper-spans), not the items inside. If you need nth-item styling, key it via a data attribute on the item itself rather than relying on positional pseudo-classes against the wrapper layer.
|
|
1184
|
+
|
|
1157
1185
|
### §221j — Typography token cheatsheet
|
|
1158
1186
|
|
|
1159
1187
|
Quick-reference for component-CSS authoring. Cross-reference [`styles/typography.css`](./styles/typography.css):
|
package/components/pane/pane.css
CHANGED
|
@@ -82,17 +82,19 @@
|
|
|
82
82
|
|
|
83
83
|
/* ── Pane header ── */
|
|
84
84
|
> header {
|
|
85
|
+
box-sizing: border-box;
|
|
85
86
|
display: flex;
|
|
86
87
|
align-items: center;
|
|
88
|
+
justify-content: flex-start;
|
|
87
89
|
gap: var(--pane-gap-sm);
|
|
88
|
-
|
|
89
|
-
padding:
|
|
90
|
+
height: var(--pane-bar-height);
|
|
91
|
+
padding: 0 var(--pane-header-px);
|
|
90
92
|
font-size: var(--pane-header-size);
|
|
91
93
|
font-weight: var(--pane-header-weight);
|
|
92
94
|
color: var(--pane-header-fg);
|
|
93
95
|
cursor: pointer;
|
|
94
96
|
user-select: none;
|
|
95
|
-
|
|
97
|
+
box-shadow: inset 0 -1px 0 var(--pane-border);
|
|
96
98
|
transition: background var(--pane-duration) var(--pane-easing);
|
|
97
99
|
}
|
|
98
100
|
|
|
@@ -178,7 +180,7 @@
|
|
|
178
180
|
}
|
|
179
181
|
|
|
180
182
|
:scope[collapsed] > header {
|
|
181
|
-
|
|
183
|
+
box-shadow: none;
|
|
182
184
|
}
|
|
183
185
|
|
|
184
186
|
/* ── Resize handle ──
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<stat-ui>` — Metric/KPI display — value + label + optional change indicator and trend.
|
|
3
|
+
*
|
|
4
|
+
* @see https://ui-kit.exe.xyz/site/components/stat
|
|
5
|
+
*
|
|
6
|
+
* Type declarations generated by scripts/build/dts-codegen.mjs from
|
|
7
|
+
* the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
|
|
8
|
+
* run `npm run build:components`, then `npm run codegen:dts` to
|
|
9
|
+
* regenerate; or hand-author this file fully if rich event types are
|
|
10
|
+
* needed beyond what the yaml `events:` block can express.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { UIElement } from '../../core/element.js';
|
|
14
|
+
|
|
15
|
+
export class UIStat extends UIElement {
|
|
16
|
+
/** Change indicator text (e.g. '+12%', '-3%') */
|
|
17
|
+
change: string;
|
|
18
|
+
/** Icon name displayed in the icon slot */
|
|
19
|
+
icon: string;
|
|
20
|
+
/** Eyebrow label describing the metric */
|
|
21
|
+
label: string;
|
|
22
|
+
/** Trend direction or narrative subtitle. Canonical values color the change badge (up=success, down=danger, neutral/flat=muted); any other string renders as caption-style text under the primary value. */
|
|
23
|
+
trend: string;
|
|
24
|
+
/** The primary metric value to display */
|
|
25
|
+
value: string;
|
|
26
|
+
}
|
package/components/tabs/tabs.css
CHANGED
|
@@ -61,15 +61,16 @@
|
|
|
61
61
|
box-sizing: border-box;
|
|
62
62
|
display: flex;
|
|
63
63
|
gap: var(--tabs-gap);
|
|
64
|
-
|
|
64
|
+
height: var(--tabs-button-height);
|
|
65
|
+
box-shadow: inset 0 -1px 0 var(--tabs-border);
|
|
65
66
|
position: relative;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
:scope[orientation="vertical"] > [slot="strip"] {
|
|
69
70
|
flex-direction: column;
|
|
70
71
|
align-items: stretch;
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
height: auto;
|
|
73
|
+
box-shadow: inset 1px 0 0 var(--tabs-border);
|
|
73
74
|
flex-shrink: 0;
|
|
74
75
|
min-width: var(--tabs-vertical-strip-min-width);
|
|
75
76
|
}
|
|
@@ -77,7 +78,7 @@
|
|
|
77
78
|
/* ── Sliding indicator ── */
|
|
78
79
|
[slot="indicator"] {
|
|
79
80
|
position: absolute;
|
|
80
|
-
bottom:
|
|
81
|
+
bottom: 0;
|
|
81
82
|
left: 0;
|
|
82
83
|
height: var(--tabs-indicator-height);
|
|
83
84
|
background: var(--tabs-indicator-color);
|
package/package.json
CHANGED
|
@@ -1,48 +1,58 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/web-components",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.21",
|
|
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
|
"types": "./index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
9
|
"types": "./index.d.ts",
|
|
10
|
+
"import": "./index.js",
|
|
10
11
|
"default": "./index.js"
|
|
11
12
|
},
|
|
12
13
|
"./css": "./index.css",
|
|
13
14
|
"./core": {
|
|
14
15
|
"types": "./core/index.d.ts",
|
|
16
|
+
"import": "./core/index.js",
|
|
15
17
|
"default": "./core/index.js"
|
|
16
18
|
},
|
|
17
19
|
"./core/*": {
|
|
18
20
|
"types": "./core/*.d.ts",
|
|
21
|
+
"import": "./core/*.js",
|
|
19
22
|
"default": "./core/*.js"
|
|
20
23
|
},
|
|
21
|
-
"./components":
|
|
24
|
+
"./components": {
|
|
25
|
+
"types": "./components/index.d.ts",
|
|
26
|
+
"import": "./components/index.js",
|
|
27
|
+
"default": "./components/index.js"
|
|
28
|
+
},
|
|
22
29
|
"./components/*": {
|
|
23
30
|
"types": "./components/*/*.d.ts",
|
|
31
|
+
"import": "./components/*/*.js",
|
|
24
32
|
"default": "./components/*/*.js"
|
|
25
33
|
},
|
|
26
|
-
"./components/stat": {
|
|
27
|
-
"types": "./components/stat/stat-ui.d.ts",
|
|
28
|
-
"default": "./components/stat/stat-ui.js"
|
|
29
|
-
},
|
|
30
|
-
"./components/stat/stat-ui.js": {
|
|
31
|
-
"types": "./components/stat/stat-ui.d.ts",
|
|
32
|
-
"default": "./components/stat/stat-ui.js"
|
|
33
|
-
},
|
|
34
34
|
"./components/*/class": {
|
|
35
35
|
"types": "./components/*/*.d.ts",
|
|
36
|
+
"import": "./components/*/class.js",
|
|
36
37
|
"default": "./components/*/class.js"
|
|
37
38
|
},
|
|
38
39
|
"./components/*.css": "./components/*/*.css",
|
|
39
40
|
"./components/*/*.css": "./components/*/*.css",
|
|
40
41
|
"./components/*/css/*.css": "./components/*/css/*.css",
|
|
41
42
|
"./styles/*": "./styles/*",
|
|
42
|
-
"./traits":
|
|
43
|
-
|
|
43
|
+
"./traits": {
|
|
44
|
+
"types": "./traits.d.ts",
|
|
45
|
+
"import": "./traits/index.js",
|
|
46
|
+
"default": "./traits/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./traits/*": {
|
|
49
|
+
"types": "./traits.d.ts",
|
|
50
|
+
"import": "./traits/*.js",
|
|
51
|
+
"default": "./traits/*.js"
|
|
52
|
+
},
|
|
44
53
|
"./color": {
|
|
45
54
|
"types": "./color/index.d.ts",
|
|
55
|
+
"import": "./color/index.js",
|
|
46
56
|
"default": "./color/index.js"
|
|
47
57
|
},
|
|
48
58
|
"./package.json": "./package.json"
|
package/styles/components.css
CHANGED
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
@import "../components/otp-input/otp-input.css";
|
|
78
78
|
@import "../components/image/image.css";
|
|
79
79
|
@import "../components/search/search.css";
|
|
80
|
-
@import "../components/stat/stat
|
|
80
|
+
@import "../components/stat/stat.css";
|
|
81
81
|
@import "../components/progress-row/progress-row.css";
|
|
82
82
|
@import "../components/action-list/action-list.css";
|
|
83
83
|
@import "../components/empty-state/empty-state.css";
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `<stat-ui>` — Metric/KPI display. Value + label + optional change indicator and trend.
|
|
3
|
-
*
|
|
4
|
-
* @see https://ui-kit.exe.xyz/site/components/stat
|
|
5
|
-
*
|
|
6
|
-
* HAND-AUTHORED (v0.5.12 §253 FB-30 close-out). The codegen pipeline's
|
|
7
|
-
* `isCssOnly()` check at `scripts/build/dts-codegen.mjs:186-194` looks for
|
|
8
|
-
* `${dirname}.js` — but stat ships `stat-ui.js` (irregular filename; the
|
|
9
|
-
* v0.6.0 §303 rename will normalize to `stat.js`). Pre-§303 the codegen
|
|
10
|
-
* false-positives `isCssOnly` and skips this directory entirely. Hand-author
|
|
11
|
-
* this file matching `stat.yaml` props until §303 lands.
|
|
12
|
-
*
|
|
13
|
-
* Filename mirrors the JS file (`stat-ui.js` → `stat-ui.d.ts`) so TypeScript
|
|
14
|
-
* resolves the side-effect import `import '@adia-ai/web-components/components/stat/stat-ui.js'`
|
|
15
|
-
* to a typed module. Post-§303, both files rename to `stat.{js,d.ts}` and
|
|
16
|
-
* codegen takes over.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import { UIElement } from '../../core/element.js';
|
|
20
|
-
|
|
21
|
-
export class UIStat extends UIElement {
|
|
22
|
-
/** Eyebrow label describing the metric. */
|
|
23
|
-
label: string;
|
|
24
|
-
/** Primary metric value (large display number / string). */
|
|
25
|
-
value: string;
|
|
26
|
-
/** Change indicator text (e.g. "+12%", "-3%"). Slotted as a badge next to value. */
|
|
27
|
-
change: string;
|
|
28
|
-
/**
|
|
29
|
-
* Trend direction or narrative subtitle. Canonical values color the change
|
|
30
|
-
* badge: `up` = success (green), `down` = danger (red), `flat`/`neutral` =
|
|
31
|
-
* muted. Any other string renders as caption-style text under the primary
|
|
32
|
-
* value (not enum-validated; yaml documents the canonical set but the type
|
|
33
|
-
* stays `string` for narrative subtitles).
|
|
34
|
-
*/
|
|
35
|
-
trend: string;
|
|
36
|
-
/** Icon name displayed in the icon slot (Phosphor icon registry). */
|
|
37
|
-
icon: string;
|
|
38
|
-
}
|
|
File without changes
|
|
File without changes
|