@adia-ai/web-components 0.6.42 → 0.6.44
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 +26 -0
- package/components/alert/alert.css +7 -1
- package/components/button/button.a2ui.json +5 -0
- package/components/button/button.class.js +13 -1
- package/components/button/button.css +13 -1
- package/components/button/button.yaml +4 -0
- package/components/canvas/canvas.js +69 -9
- package/components/card/card.css +36 -7
- package/components/list/list.a2ui.json +5 -0
- package/components/list/list.d.ts +7 -0
- package/components/list/list.yaml +9 -0
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +106 -106
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog — @adia-ai/web-components
|
|
2
2
|
|
|
3
|
+
## [0.6.44] — 2026-05-28
|
|
4
|
+
|
|
5
|
+
### Fixed — `<canvas-ui>` no longer hard-requires `@adia-ai/web-modules` at build time (FEEDBACK-81)
|
|
6
|
+
|
|
7
|
+
- **`components/canvas/canvas.js`** — the A2UI renderer `<a2ui-root>` (which lives in `@adia-ai/web-modules`) was a top-level *static* import. Because `@adia-ai/web-components` declares no dependency on `@adia-ai/web-modules`, the default barrel `import '@adia-ai/web-components'` (which registers `<canvas-ui>`) failed to build for primitives-only consumers who omitted `web-modules` — a hard Vite/rolldown `UNRESOLVED_IMPORT … web-modules/runtime/a2ui-root`. The import is now lazy + guarded: `#ensureRenderer()` runs a `/* @vite-ignore */` dynamic import on `connected()`, and a missing `web-modules` degrades to a one-time console warning instead of breaking the build. Consumers that have `web-modules` keep the prior synchronous render path (fast-path when `<a2ui-root>` is already defined); `process` / `processAll` / `reset` / version-restore buffer until the renderer is ready, preserving call order. The primitives barrel is now self-contained.
|
|
8
|
+
|
|
9
|
+
### Maintenance
|
|
10
|
+
|
|
11
|
+
- **`dist/web-components.min.js` + `dist/icons-manifest.js`** — bundle rebuild reflecting the `components/canvas/canvas.js` decouple above.
|
|
12
|
+
|
|
13
|
+
## [0.6.43] — 2026-05-27
|
|
14
|
+
|
|
15
|
+
### Added — `<list-ui>` `[contained]` prop declared in yaml
|
|
16
|
+
|
|
17
|
+
- **`list/list.yaml` + `list.d.ts` + `list.a2ui.json`** — declares the `[contained]` attribute (already implemented in CSS) as a first-class prop so the gen-UI corpus + A2UI sidecar can emit `<list-ui contained>` deterministically. Closes gen-review cycle-18 task #63.
|
|
18
|
+
|
|
19
|
+
### Fixed — Cycle-18 Ralph Loop substrate fixes (button + card + alert)
|
|
20
|
+
|
|
21
|
+
- **`button/button.yaml` + `button.class.js` + `button.css` + `button.a2ui.json`** — Ralph-Loop sweep absorbing cycle-18 RL findings (6 visual bugs fixed at SoT).
|
|
22
|
+
- **`card/card.css`** — preserves transpiled `text-ui` slot grammar; matches header-slot patterns from RL2.
|
|
23
|
+
- **`alert/alert.css`** — header-slot polish from cycle-18 RL2 (10 visual bugs across header slot, leaf children, calendar widget).
|
|
24
|
+
|
|
25
|
+
### Maintenance
|
|
26
|
+
|
|
27
|
+
- **`dist/web-components.min.{js,css}` + `dist/icons-manifest.js`** — bundle rebuild reflecting the `components/` substrate fixes above.
|
|
28
|
+
|
|
3
29
|
## [0.6.42] — 2026-05-26
|
|
4
30
|
|
|
5
31
|
### Changed — yaml/sidecar polish absorbing gen-review cycle 8-17 findings
|
|
@@ -116,10 +116,16 @@
|
|
|
116
116
|
/* Close button is a `<button-ui icon="x" variant="ghost" size="sm">`
|
|
117
117
|
stamped by alert.js — it brings its own focus ring, hover state,
|
|
118
118
|
and transitions. Box height matches the leading slot so X and icon
|
|
119
|
-
sit on the same first-line baseline.
|
|
119
|
+
sit on the same first-line baseline.
|
|
120
|
+
The X color tracks the alert's variant text color (e.g. success-text
|
|
121
|
+
on success, danger-text on danger) instead of the default ghost
|
|
122
|
+
subtle/muted — so the dismiss icon reads as part of the alert chrome
|
|
123
|
+
rather than disconnected grey. */
|
|
120
124
|
:scope [slot="close"] {
|
|
121
125
|
flex-shrink: 0;
|
|
122
126
|
min-height: calc(var(--alert-font, var(--alert-font-default)) * var(--alert-line-height, var(--alert-line-height-default)));
|
|
127
|
+
--button-fg-ghost: var(--alert-fg, var(--alert-fg-default));
|
|
128
|
+
--button-fg-ghost-hover: var(--alert-icon-fg, var(--alert-icon-fg-default));
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
/* ──────────────────────────────────────────────────────────────
|
|
@@ -49,6 +49,11 @@
|
|
|
49
49
|
"type": "string",
|
|
50
50
|
"default": ""
|
|
51
51
|
},
|
|
52
|
+
"icon-trailing": {
|
|
53
|
+
"description": "Trailing Phosphor icon name (rendered after text). Use for forward affordances like \"Next →\" / wizards / pagination / product tours where the caret points away from the label.",
|
|
54
|
+
"type": "string",
|
|
55
|
+
"default": ""
|
|
56
|
+
},
|
|
52
57
|
"size": {
|
|
53
58
|
"description": "Sizing scale (xs/sm/md/lg/xl).",
|
|
54
59
|
"type": "string",
|
|
@@ -43,6 +43,7 @@ export class UIButton extends UIElement {
|
|
|
43
43
|
disabled: { type: Boolean, default: false, reflect: true },
|
|
44
44
|
stretch: { type: Boolean, default: false, reflect: true },
|
|
45
45
|
icon: { type: String, default: '', reflect: true },
|
|
46
|
+
iconTrailing: { type: String, default: '', reflect: true, attribute: 'icon-trailing' },
|
|
46
47
|
type: { type: String, default: 'button', reflect: true },
|
|
47
48
|
};
|
|
48
49
|
|
|
@@ -61,7 +62,7 @@ export class UIButton extends UIElement {
|
|
|
61
62
|
// Only auto-set when we have meaningful text to put there.
|
|
62
63
|
if (this.text) this.setAttribute('aria-label', this.text);
|
|
63
64
|
if (this.icon) {
|
|
64
|
-
const existing = this.querySelector('icon-ui');
|
|
65
|
+
const existing = this.querySelector(':scope > icon-ui:not([slot])');
|
|
65
66
|
if (!existing || existing.name !== this.icon) {
|
|
66
67
|
if (existing) existing.remove();
|
|
67
68
|
const iconEl = document.createElement('icon-ui');
|
|
@@ -70,6 +71,17 @@ export class UIButton extends UIElement {
|
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
if (this.iconTrailing) {
|
|
75
|
+
const existing = this.querySelector(':scope > icon-ui[slot="icon-trailing"]');
|
|
76
|
+
if (!existing || existing.name !== this.iconTrailing) {
|
|
77
|
+
if (existing) existing.remove();
|
|
78
|
+
const iconEl = document.createElement('icon-ui');
|
|
79
|
+
iconEl.setAttribute('name', this.iconTrailing);
|
|
80
|
+
iconEl.setAttribute('slot', 'icon-trailing');
|
|
81
|
+
this.appendChild(iconEl);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
73
85
|
// FEEDBACK-15: warn when text= begins with a symbol that icon= already
|
|
74
86
|
// renders (e.g. text="+ New Claim" icon="plus" → a doubled "+"). One-shot
|
|
75
87
|
// per element via WeakSet; warning-only — the button still renders. The
|
|
@@ -113,7 +113,19 @@ button-ui[color="danger"]:not([disabled]):hover {
|
|
|
113
113
|
min-width: 0;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
/* Trailing slot
|
|
116
|
+
/* Trailing icon slot — for forward-affordance carets ("Next →"), distinct
|
|
117
|
+
from `[slot="trailing"]` which is styled as a kbd-pill for shortcut
|
|
118
|
+
indicators. Auto-stamped when `[icon-trailing]` is set. */
|
|
119
|
+
[slot="icon-trailing"] {
|
|
120
|
+
order: 99;
|
|
121
|
+
margin-inline-start: var(--a-space-1);
|
|
122
|
+
display: flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
flex-shrink: 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Trailing slot — kbd-pill style for `<kbd-ui slot="trailing">⌘K</kbd-ui>`.
|
|
128
|
+
Use `[icon-trailing="<name>"]` (above) for trailing icons instead. */
|
|
117
129
|
[slot="trailing"] {
|
|
118
130
|
order: 99;
|
|
119
131
|
margin-inline-start: auto;
|
|
@@ -36,6 +36,10 @@ props:
|
|
|
36
36
|
description: Leading Phosphor icon name (rendered before text).
|
|
37
37
|
type: string
|
|
38
38
|
default: ""
|
|
39
|
+
icon-trailing:
|
|
40
|
+
description: Trailing Phosphor icon name (rendered after text). Use for forward affordances like "Next →" / wizards / pagination / product tours where the caret points away from the label.
|
|
41
|
+
type: string
|
|
42
|
+
default: ""
|
|
39
43
|
size:
|
|
40
44
|
description: "Sizing scale (xs/sm/md/lg/xl)."
|
|
41
45
|
type: string
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { UIElement } from '../../core/element.js';
|
|
2
|
-
|
|
2
|
+
// NOTE: the A2UI renderer (<a2ui-root>) lives in @adia-ai/web-modules and is
|
|
3
|
+
// loaded lazily + guarded inside #ensureRenderer() (kicked off from connected()).
|
|
4
|
+
// It is deliberately NOT a static import: @adia-ai/web-components declares no
|
|
5
|
+
// dependency on @adia-ai/web-modules, so a static cross-package import hard-fails
|
|
6
|
+
// the build for primitives-only consumers who never use <canvas-ui> (FEEDBACK-81).
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* <canvas-ui> — A2UI rendering surface.
|
|
@@ -25,6 +29,10 @@ export class UICanvas extends UIElement {
|
|
|
25
29
|
#historyIndex = -1;
|
|
26
30
|
static MAX_HISTORY = 10;
|
|
27
31
|
|
|
32
|
+
// FB-81: lazy/guarded <a2ui-root> loader state.
|
|
33
|
+
#rendererReady = null; // Promise<boolean> | null
|
|
34
|
+
static #warnedMissingRenderer = false;
|
|
35
|
+
|
|
28
36
|
#onKeydown = (e) => {
|
|
29
37
|
if (e.target.closest('input, textarea, [contenteditable]')) return;
|
|
30
38
|
if (!this.contains(document.activeElement) && document.activeElement !== document.body) return;
|
|
@@ -66,6 +74,8 @@ export class UICanvas extends UIElement {
|
|
|
66
74
|
this.addEventListener('input', this.#onInput);
|
|
67
75
|
// Forward a2ui-retry from wired error cards so consumers can retry generation
|
|
68
76
|
this.addEventListener('a2ui-retry', this.#onRetry);
|
|
77
|
+
// Kick off the lazy renderer load now that a canvas is in the DOM.
|
|
78
|
+
this.#ensureRenderer();
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
disconnected() {
|
|
@@ -79,6 +89,53 @@ export class UICanvas extends UIElement {
|
|
|
79
89
|
this.#bound = false;
|
|
80
90
|
}
|
|
81
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Lazily load the A2UI renderer (<a2ui-root>) from @adia-ai/web-modules.
|
|
94
|
+
* Resolves true once the element is defined, false if web-modules is not
|
|
95
|
+
* installed (primitives-only consumers). Idempotent — the import runs once.
|
|
96
|
+
* Guarded so a missing sibling package degrades to a one-time warning
|
|
97
|
+
* instead of a hard build/runtime failure (FEEDBACK-81).
|
|
98
|
+
*/
|
|
99
|
+
#ensureRenderer() {
|
|
100
|
+
if (this.#rendererReady) return this.#rendererReady;
|
|
101
|
+
if (customElements.get('a2ui-root')) {
|
|
102
|
+
this.#rendererReady = Promise.resolve(true);
|
|
103
|
+
return this.#rendererReady;
|
|
104
|
+
}
|
|
105
|
+
this.#rendererReady = import(/* @vite-ignore */ '../../../web-modules/runtime/a2ui-root/a2ui-root.js')
|
|
106
|
+
.then(() => customElements.whenDefined('a2ui-root'))
|
|
107
|
+
.then(() => true)
|
|
108
|
+
.catch((err) => {
|
|
109
|
+
if (!UICanvas.#warnedMissingRenderer) {
|
|
110
|
+
UICanvas.#warnedMissingRenderer = true;
|
|
111
|
+
console.warn(
|
|
112
|
+
'[canvas-ui] A2UI renderer <a2ui-root> could not be loaded — install ' +
|
|
113
|
+
'@adia-ai/web-modules to render generated UI in <canvas-ui>. Apps that ' +
|
|
114
|
+
'use only primitives (and never <canvas-ui>) can ignore this.',
|
|
115
|
+
err,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
});
|
|
120
|
+
return this.#rendererReady;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Run `fn(rootEl)` against the <a2ui-root> once it is available. Synchronous
|
|
125
|
+
* fast-path when the renderer is already upgraded (preserves prior timing for
|
|
126
|
+
* consumers that have @adia-ai/web-modules); otherwise defers until the lazy
|
|
127
|
+
* import resolves, preserving call order. No-op when web-modules is absent.
|
|
128
|
+
*/
|
|
129
|
+
#whenRoot(fn) {
|
|
130
|
+
if (this.#rootEl && typeof this.#rootEl.process === 'function') {
|
|
131
|
+
fn(this.#rootEl);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
this.#ensureRenderer().then((ok) => {
|
|
135
|
+
if (ok && this.#rootEl && typeof this.#rootEl.process === 'function') fn(this.#rootEl);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
82
139
|
render() {
|
|
83
140
|
if (this.#bound) return;
|
|
84
141
|
this.#bound = true;
|
|
@@ -104,18 +161,19 @@ export class UICanvas extends UIElement {
|
|
|
104
161
|
|
|
105
162
|
/** Process a single A2UI message. */
|
|
106
163
|
process(message) {
|
|
107
|
-
this.#
|
|
164
|
+
this.#whenRoot((root) => root.process(message));
|
|
108
165
|
}
|
|
109
166
|
|
|
110
167
|
/** Process an array of A2UI messages. */
|
|
111
168
|
processAll(messages) {
|
|
112
|
-
|
|
113
|
-
|
|
169
|
+
this.#whenRoot((root) => {
|
|
170
|
+
for (const msg of messages) root.process(msg);
|
|
171
|
+
});
|
|
114
172
|
}
|
|
115
173
|
|
|
116
174
|
/** Reset the canvas. */
|
|
117
175
|
reset() {
|
|
118
|
-
this.#
|
|
176
|
+
this.#whenRoot((root) => root.reset());
|
|
119
177
|
}
|
|
120
178
|
|
|
121
179
|
/** Return formatted innerHTML of the a2ui-root. */
|
|
@@ -155,10 +213,12 @@ export class UICanvas extends UIElement {
|
|
|
155
213
|
|
|
156
214
|
#restoreVersion() {
|
|
157
215
|
const messages = this.#history[this.#historyIndex];
|
|
158
|
-
this.#
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
216
|
+
this.#whenRoot((root) => {
|
|
217
|
+
root.reset();
|
|
218
|
+
if (messages) {
|
|
219
|
+
for (const msg of messages) root.process(msg);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
162
222
|
}
|
|
163
223
|
|
|
164
224
|
// ── Private ──
|
package/components/card/card.css
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
|
|
152
152
|
& > header {
|
|
153
153
|
display: block;
|
|
154
|
+
width: stretch;
|
|
154
155
|
margin: var(--card-inset, var(--card-inset-default));
|
|
155
156
|
}
|
|
156
157
|
|
|
@@ -194,8 +195,20 @@
|
|
|
194
195
|
/* Unslotted children (zettel fragment injection, etc.) — each on its own row,
|
|
195
196
|
spanning the full width, stacked ABOVE the heading/description/action grid.
|
|
196
197
|
This lets compositions inject logos, banners, etc. into a header without
|
|
197
|
-
having to know the slot vocabulary.
|
|
198
|
-
|
|
198
|
+
having to know the slot vocabulary.
|
|
199
|
+
|
|
200
|
+
Guarded by `:has(> [slot])` so it ONLY fires when the header is in grid
|
|
201
|
+
mode. Modern browsers honor `justify-self` on block-level in-flow elements,
|
|
202
|
+
so without this guard, an unslotted `<row-ui>` direct child of header
|
|
203
|
+
would be centered even when no slot grammar is in use — causing the
|
|
204
|
+
role-management center-align bug seen in cycle-18 follow-up.
|
|
205
|
+
|
|
206
|
+
A2UI transpilation note: the corpus harvester transpiles <h1>..<h6>/<p>/<small>
|
|
207
|
+
to <text-ui variant="display|title|heading|subsection|body|caption">. The
|
|
208
|
+
heading/description rules below match those variants so transpiled chunks
|
|
209
|
+
get the same grid placement as hand-authored native heading/paragraph
|
|
210
|
+
elements. text-ui is excluded here to avoid the centered-fallback. */
|
|
211
|
+
& > header:has(> [slot]) > *:not([slot]):not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(p):not(small):not(text-ui) {
|
|
199
212
|
grid-column: 1 / -1;
|
|
200
213
|
justify-self: center;
|
|
201
214
|
}
|
|
@@ -213,13 +226,19 @@
|
|
|
213
226
|
justify-content: center;
|
|
214
227
|
}
|
|
215
228
|
|
|
216
|
-
& > header:has(> :is([slot="description"], p, small)) > [slot="icon"] {
|
|
229
|
+
& > header:has(> :is([slot="description"], p, small, text-ui[variant="body"], text-ui[variant="caption"])) > [slot="icon"] {
|
|
217
230
|
grid-row: 1 / span 2;
|
|
218
231
|
align-self: start;
|
|
219
232
|
}
|
|
220
233
|
|
|
221
|
-
/* Heading — row 1
|
|
234
|
+
/* Heading — row 1.
|
|
235
|
+
Matches native h1-h6 AND the text-ui variants the A2UI transpiler emits
|
|
236
|
+
for them (display|title|heading|subsection — see HTML_TAG_MAP in
|
|
237
|
+
packages/a2ui/compose/transpiler/transpiler-maps.js).
|
|
238
|
+
The text-ui variants are matched only when UNSLOTTED so an explicit
|
|
239
|
+
`slot="heading"` / `slot="description"` / `slot="action"` always wins. */
|
|
222
240
|
& > header > :is([slot="heading"], h1, h2, h3, h4, h5, h6),
|
|
241
|
+
& > header > :is(text-ui[variant="display"], text-ui[variant="title"], text-ui[variant="heading"], text-ui[variant="subsection"]):not([slot]),
|
|
223
242
|
& > header > [slot="heading"] :is(h1, h2, h3, h4, h5, h6) {
|
|
224
243
|
grid-row: 1;
|
|
225
244
|
line-height: 1.3;
|
|
@@ -232,16 +251,24 @@
|
|
|
232
251
|
gap: var(--card-header-gap, var(--card-header-gap-default));
|
|
233
252
|
}
|
|
234
253
|
& > header:has(> [slot="icon"]) > :is([slot="heading"], h1, h2, h3, h4, h5, h6) { grid-column: 2; }
|
|
254
|
+
& > header:has(> [slot="icon"]) > :is(text-ui[variant="display"], text-ui[variant="title"], text-ui[variant="heading"], text-ui[variant="subsection"]):not([slot]) { grid-column: 2; }
|
|
235
255
|
& > header:not(:has(> [slot="icon"])) > :is([slot="heading"], h1, h2, h3, h4, h5, h6) { grid-column: 1; }
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
256
|
+
& > header:not(:has(> [slot="icon"])) > :is(text-ui[variant="display"], text-ui[variant="title"], text-ui[variant="heading"], text-ui[variant="subsection"]):not([slot]) { grid-column: 1; }
|
|
257
|
+
|
|
258
|
+
/* Description — row 2.
|
|
259
|
+
Matches native p/small (with or without slot=description) AND the
|
|
260
|
+
text-ui variants the transpiler emits for them (body|caption) ONLY
|
|
261
|
+
when unslotted — so a `slot="heading"` text-ui doesn't get treated
|
|
262
|
+
as description. */
|
|
263
|
+
& > header > :is([slot="description"], p, small),
|
|
264
|
+
& > header > :is(text-ui[variant="body"], text-ui[variant="caption"]):not([slot]) {
|
|
239
265
|
grid-row: 2;
|
|
240
266
|
grid-column: 1 / -1;
|
|
241
267
|
line-height: 1.4;
|
|
242
268
|
margin: 0;
|
|
243
269
|
}
|
|
244
270
|
& > header:has(> [slot="icon"]) > :is([slot="description"], p, small) { grid-column: 2 / -1; }
|
|
271
|
+
& > header:has(> [slot="icon"]) > :is(text-ui[variant="body"], text-ui[variant="caption"]):not([slot]) { grid-column: 2 / -1; }
|
|
245
272
|
|
|
246
273
|
/* Action — row 1, last column.
|
|
247
274
|
Flex container so it can hold badge + button + anything inline. */
|
|
@@ -262,6 +289,7 @@
|
|
|
262
289
|
[bleed] removes all spacing for edge-to-edge content. */
|
|
263
290
|
|
|
264
291
|
& > section {
|
|
292
|
+
width: stretch;
|
|
265
293
|
margin: var(--card-inset, var(--card-inset-default));
|
|
266
294
|
}
|
|
267
295
|
|
|
@@ -299,6 +327,7 @@
|
|
|
299
327
|
|
|
300
328
|
& > footer {
|
|
301
329
|
display: block;
|
|
330
|
+
width: stretch;
|
|
302
331
|
margin: var(--card-inset, var(--card-inset-default));
|
|
303
332
|
}
|
|
304
333
|
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
"component": {
|
|
17
17
|
"const": "List"
|
|
18
18
|
},
|
|
19
|
+
"contained": {
|
|
20
|
+
"description": "Add inline padding to list items so content aligns with surrounding\ncard/section insets. Pairs with [divider] — combining `[divider]\n[contained]` gives full-width borders between items but inset\ncontent. Without contained, [divider] items have `padding-inline: 0`\nso content sits at the list-ui edges (canonical edge-to-edge style).\n",
|
|
21
|
+
"type": "boolean",
|
|
22
|
+
"default": false
|
|
23
|
+
},
|
|
19
24
|
"divider": {
|
|
20
25
|
"description": "Show dividers between items",
|
|
21
26
|
"type": "boolean",
|
|
@@ -30,6 +30,13 @@ export interface ListSelectionChangeEventDetail {
|
|
|
30
30
|
export type ListSelectionChangeEvent = CustomEvent<ListSelectionChangeEventDetail>;
|
|
31
31
|
|
|
32
32
|
export class UIList extends UIElement {
|
|
33
|
+
/** Add inline padding to list items so content aligns with surrounding
|
|
34
|
+
card/section insets. Pairs with [divider] — combining `[divider]
|
|
35
|
+
[contained]` gives full-width borders between items but inset
|
|
36
|
+
content. Without contained, [divider] items have `padding-inline: 0`
|
|
37
|
+
so content sits at the list-ui edges (canonical edge-to-edge style).
|
|
38
|
+
*/
|
|
39
|
+
contained: boolean;
|
|
33
40
|
/** Show dividers between items */
|
|
34
41
|
divider: boolean;
|
|
35
42
|
/** Enable selection on child listitems (roving tabindex + aria-selected). */
|
|
@@ -25,6 +25,15 @@ props:
|
|
|
25
25
|
description: Show dividers between items
|
|
26
26
|
type: boolean
|
|
27
27
|
default: false
|
|
28
|
+
contained:
|
|
29
|
+
description: |
|
|
30
|
+
Add inline padding to list items so content aligns with surrounding
|
|
31
|
+
card/section insets. Pairs with [divider] — combining `[divider]
|
|
32
|
+
[contained]` gives full-width borders between items but inset
|
|
33
|
+
content. Without contained, [divider] items have `padding-inline: 0`
|
|
34
|
+
so content sits at the list-ui edges (canonical edge-to-edge style).
|
|
35
|
+
type: boolean
|
|
36
|
+
default: false
|
|
28
37
|
selectable:
|
|
29
38
|
description: Enable selection on child listitems (roving tabindex + aria-selected).
|
|
30
39
|
type: boolean
|