@adia-ai/web-components 0.8.26 → 0.8.27
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 +9 -0
- package/components/menu/menu-item.a2ui.json +12 -1
- package/components/menu/menu-item.yaml +9 -1
- package/components/menu/menu.class.js +33 -1
- package/components/menu/menu.css +43 -0
- package/components/menu/menu.d.ts +2 -0
- package/dist/theme-provider.min.js +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +1 -1
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog — @adia-ai/web-components
|
|
2
2
|
|
|
3
|
+
## [0.8.27] — 2026-08-05
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **`menu-item-ui` gains `subtitle` (+ a trailing slot)** — menu rows can carry a secondary line, unblocking composite menu rows without native `<button>` stamps (gh#616, PR #623).
|
|
7
|
+
|
|
8
|
+
### Maintenance
|
|
9
|
+
- **`components/` touched in this release window** (5 file(s), e.g. `menu/menu-item.a2ui.json`) — carried by the entries above.
|
|
10
|
+
- **`dist/` bundles rebuilt** in this cut's window (4 file(s)) — regenerated from the source changes described above, not independent edits.
|
|
11
|
+
|
|
3
12
|
## [0.8.26] — 2026-08-05
|
|
4
13
|
|
|
5
14
|
### Fixed
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://adiaui.dev/a2ui/v0_9/components/MenuItem.json",
|
|
4
4
|
"title": "MenuItem",
|
|
5
|
-
"description": "Child of `<menu-ui>`. One actionable row inside a menu, with optional leading icon + label + value.",
|
|
5
|
+
"description": "Child of `<menu-ui>`. One actionable row inside a menu, with optional leading icon + label + subtitle + value.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"allOf": [
|
|
8
8
|
{
|
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
"type": "string",
|
|
27
27
|
"default": ""
|
|
28
28
|
},
|
|
29
|
+
"subtitle": {
|
|
30
|
+
"description": "Optional secondary description line rendered under the label.",
|
|
31
|
+
"type": "string",
|
|
32
|
+
"default": ""
|
|
33
|
+
},
|
|
29
34
|
"text": {
|
|
30
35
|
"description": "Item label text.",
|
|
31
36
|
"type": "string",
|
|
@@ -73,8 +78,14 @@
|
|
|
73
78
|
"icon": {
|
|
74
79
|
"description": "Custom leading element override; falls through to `[icon]` prop if not slotted."
|
|
75
80
|
},
|
|
81
|
+
"subtitle": {
|
|
82
|
+
"description": "Custom secondary-line content override; falls through to `[subtitle]` prop if not slotted."
|
|
83
|
+
},
|
|
76
84
|
"text": {
|
|
77
85
|
"description": "Custom label content; falls through to `[text]` prop if not slotted."
|
|
86
|
+
},
|
|
87
|
+
"trailing": {
|
|
88
|
+
"description": "Trailing element pinned to the far edge (shortcut hint, check mark)."
|
|
78
89
|
}
|
|
79
90
|
},
|
|
80
91
|
"states": [],
|
|
@@ -13,7 +13,7 @@ component: MenuItem
|
|
|
13
13
|
category: navigation
|
|
14
14
|
version: 1
|
|
15
15
|
description: |-
|
|
16
|
-
Child of `<menu-ui>`. One actionable row inside a menu, with optional leading icon + label + value.
|
|
16
|
+
Child of `<menu-ui>`. One actionable row inside a menu, with optional leading icon + label + subtitle + value.
|
|
17
17
|
|
|
18
18
|
props:
|
|
19
19
|
icon:
|
|
@@ -24,6 +24,10 @@ props:
|
|
|
24
24
|
description: Item label text.
|
|
25
25
|
type: string
|
|
26
26
|
default: ""
|
|
27
|
+
subtitle:
|
|
28
|
+
description: Optional secondary description line rendered under the label.
|
|
29
|
+
type: string
|
|
30
|
+
default: ""
|
|
27
31
|
value:
|
|
28
32
|
description: Stable identifier emitted via the parent menu's `select` event.
|
|
29
33
|
type: string
|
|
@@ -44,6 +48,10 @@ slots:
|
|
|
44
48
|
description: Custom leading element override; falls through to `[icon]` prop if not slotted.
|
|
45
49
|
text:
|
|
46
50
|
description: Custom label content; falls through to `[text]` prop if not slotted.
|
|
51
|
+
subtitle:
|
|
52
|
+
description: Custom secondary-line content override; falls through to `[subtitle]` prop if not slotted.
|
|
53
|
+
trailing:
|
|
54
|
+
description: Trailing element pinned to the far edge (shortcut hint, check mark).
|
|
47
55
|
|
|
48
56
|
a2ui:
|
|
49
57
|
rules:
|
|
@@ -258,6 +258,7 @@ export class UIMenuItem extends UIElement {
|
|
|
258
258
|
static properties = {
|
|
259
259
|
icon: { type: String, default: '', reflect: true },
|
|
260
260
|
text: { type: String, default: '', reflect: true },
|
|
261
|
+
subtitle: { type: String, default: '', reflect: true },
|
|
261
262
|
value: { type: String, default: '', reflect: true },
|
|
262
263
|
variant: { type: String, default: 'default', reflect: true },
|
|
263
264
|
disabled: { type: Boolean, default: false, reflect: true },
|
|
@@ -265,6 +266,11 @@ export class UIMenuItem extends UIElement {
|
|
|
265
266
|
|
|
266
267
|
static template = () => null;
|
|
267
268
|
|
|
269
|
+
// Set when connected() stamped role="menuitem" itself; a consumer-provided
|
|
270
|
+
// role (e.g. admin-roster's role="menuitemradio", gh#616) is never touched
|
|
271
|
+
// — that consumer also owns tabindex and any checked-state aria.
|
|
272
|
+
#roleStamped = false;
|
|
273
|
+
|
|
268
274
|
connected() {
|
|
269
275
|
// role="menuitem" ONLY when actually inside a menu container. A menu-ui
|
|
270
276
|
// closes by moving its items back into its own light DOM (see #hide()),
|
|
@@ -273,12 +279,16 @@ export class UIMenuItem extends UIElement {
|
|
|
273
279
|
// open popover (role="menu") adopts items via appendChild, which re-fires
|
|
274
280
|
// connected(), so the role re-applies when the menu opens and is dropped
|
|
275
281
|
// again on close.
|
|
276
|
-
if (this.
|
|
282
|
+
if (this.hasAttribute('role') && !this.#roleStamped) {
|
|
283
|
+
// Consumer-owned role — leave role/tabindex alone.
|
|
284
|
+
} else if (this.closest('[role="menu"], [role="menubar"]')) {
|
|
277
285
|
this.setAttribute('role', 'menuitem');
|
|
286
|
+
this.#roleStamped = true;
|
|
278
287
|
if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', '-1');
|
|
279
288
|
} else {
|
|
280
289
|
this.removeAttribute('role');
|
|
281
290
|
this.removeAttribute('tabindex');
|
|
291
|
+
this.#roleStamped = false;
|
|
282
292
|
}
|
|
283
293
|
this.#stamp();
|
|
284
294
|
this.#syncAria();
|
|
@@ -313,6 +323,13 @@ export class UIMenuItem extends UIElement {
|
|
|
313
323
|
span.textContent = this.text;
|
|
314
324
|
this.appendChild(span);
|
|
315
325
|
}
|
|
326
|
+
|
|
327
|
+
if (this.subtitle && !this.#ownChild('[slot="subtitle"]')) {
|
|
328
|
+
const sub = this.#stampMark(document.createElement('span'));
|
|
329
|
+
sub.setAttribute('slot', 'subtitle');
|
|
330
|
+
sub.textContent = this.subtitle;
|
|
331
|
+
this.appendChild(sub);
|
|
332
|
+
}
|
|
316
333
|
}
|
|
317
334
|
|
|
318
335
|
#syncAria() {
|
|
@@ -340,6 +357,21 @@ export class UIMenuItem extends UIElement {
|
|
|
340
357
|
const textEl = this.#ownChild('[slot="text"]');
|
|
341
358
|
if (this.#wasStamped(textEl)) textEl.textContent = this.text;
|
|
342
359
|
|
|
360
|
+
// Sync subtitle — only touch elements we stamped.
|
|
361
|
+
const subEl = this.#ownChild('[slot="subtitle"]');
|
|
362
|
+
if (this.subtitle) {
|
|
363
|
+
if (subEl) {
|
|
364
|
+
if (this.#wasStamped(subEl)) subEl.textContent = this.subtitle;
|
|
365
|
+
} else {
|
|
366
|
+
const el = this.#stampMark(document.createElement('span'));
|
|
367
|
+
el.setAttribute('slot', 'subtitle');
|
|
368
|
+
el.textContent = this.subtitle;
|
|
369
|
+
this.appendChild(el);
|
|
370
|
+
}
|
|
371
|
+
} else if (this.#wasStamped(subEl)) {
|
|
372
|
+
subEl.remove();
|
|
373
|
+
}
|
|
374
|
+
|
|
343
375
|
this.#syncAria();
|
|
344
376
|
}
|
|
345
377
|
}
|
package/components/menu/menu.css
CHANGED
|
@@ -136,6 +136,8 @@ menu-item-ui[variant="danger"]:hover [slot="icon"] {
|
|
|
136
136
|
|
|
137
137
|
/* ── Typography ── */
|
|
138
138
|
--menu-item-font-size: var(--a-ui-size);
|
|
139
|
+
--menu-item-subtitle-size: var(--a-ui-sm);
|
|
140
|
+
--menu-item-subtitle-fg: var(--a-fg-muted);
|
|
139
141
|
|
|
140
142
|
/* ── Transition ── */
|
|
141
143
|
--menu-item-duration: var(--a-duration-fast);
|
|
@@ -178,6 +180,47 @@ menu-item-ui[variant="danger"]:hover [slot="icon"] {
|
|
|
178
180
|
white-space: nowrap;
|
|
179
181
|
}
|
|
180
182
|
|
|
183
|
+
/* Trailing (shortcut hint, check mark) — pinned to the far edge */
|
|
184
|
+
[slot="trailing"] {
|
|
185
|
+
flex-shrink: 0;
|
|
186
|
+
margin-left: auto;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* ── Subtitle — two-line anatomy ──
|
|
190
|
+
Content-driven: a present [slot="subtitle"] switches the row to a
|
|
191
|
+
grid so the subtitle sits under the label while icon and trailing
|
|
192
|
+
content span both lines. */
|
|
193
|
+
:scope:has(> [slot="subtitle"]) {
|
|
194
|
+
display: grid;
|
|
195
|
+
grid-template-columns: auto 1fr auto;
|
|
196
|
+
align-items: center;
|
|
197
|
+
column-gap: var(--menu-item-gap);
|
|
198
|
+
row-gap: 0;
|
|
199
|
+
}
|
|
200
|
+
:scope:has(> [slot="subtitle"]) > [slot="icon"] {
|
|
201
|
+
grid-column: 1;
|
|
202
|
+
grid-row: 1 / span 2;
|
|
203
|
+
}
|
|
204
|
+
:scope:has(> [slot="subtitle"]) > [slot="text"] {
|
|
205
|
+
grid-column: 2;
|
|
206
|
+
grid-row: 1;
|
|
207
|
+
}
|
|
208
|
+
:scope:has(> [slot="subtitle"]) > [slot="trailing"] {
|
|
209
|
+
grid-column: 3;
|
|
210
|
+
grid-row: 1 / span 2;
|
|
211
|
+
margin-left: 0;
|
|
212
|
+
}
|
|
213
|
+
:scope > [slot="subtitle"] {
|
|
214
|
+
grid-column: 2;
|
|
215
|
+
grid-row: 2;
|
|
216
|
+
min-width: 0;
|
|
217
|
+
font-size: var(--menu-item-subtitle-size);
|
|
218
|
+
color: var(--menu-item-subtitle-fg);
|
|
219
|
+
white-space: nowrap;
|
|
220
|
+
overflow: hidden;
|
|
221
|
+
text-overflow: ellipsis;
|
|
222
|
+
}
|
|
223
|
+
|
|
181
224
|
/* ── Variant: danger ── */
|
|
182
225
|
:scope[variant="danger"] {
|
|
183
226
|
--menu-item-fg: var(--a-danger-bg);
|
|
@@ -45,6 +45,8 @@ export class UIMenuItem extends UIElement {
|
|
|
45
45
|
disabled: boolean;
|
|
46
46
|
/** Optional leading Phosphor icon name. */
|
|
47
47
|
icon: string;
|
|
48
|
+
/** Optional secondary description line rendered under the label. */
|
|
49
|
+
subtitle: string;
|
|
48
50
|
/** Item label text. */
|
|
49
51
|
text: string;
|
|
50
52
|
/** Stable identifier emitted via the parent menu's `select` event. */
|