@adia-ai/web-components 0.8.33 → 0.8.35
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 +33 -0
- package/components/agent-questions/agent-questions.class.js +0 -1
- package/components/agent-reasoning/agent-reasoning.a2ui.json +1 -1
- package/components/agent-reasoning/agent-reasoning.yaml +3 -3
- package/components/badge/badge.css +33 -7
- package/components/badge/badge.examples.md +4 -4
- package/components/button/button.css +12 -0
- package/components/card/card.css +44 -1
- package/components/check/check.a2ui.json +25 -11
- package/components/check/check.class.js +5 -0
- package/components/check/check.css +21 -0
- package/components/check/check.d.ts +2 -0
- package/components/check/check.examples.md +4 -4
- package/components/check/check.yaml +26 -7
- package/components/combobox/combobox.a2ui.json +1 -1
- package/components/combobox/combobox.yaml +3 -0
- package/components/command/command.a2ui.json +4 -0
- package/components/command/command.class.js +54 -4
- package/components/command/command.d.ts +2 -0
- package/components/command/command.yaml +25 -3
- package/components/date-range-picker/date-range-picker.a2ui.json +1 -1
- package/components/date-range-picker/date-range-picker.class.js +42 -43
- package/components/date-range-picker/date-range-picker.css +11 -0
- package/components/date-range-picker/date-range-picker.yaml +6 -3
- package/components/demo-toggle/demo-toggle.css +4 -0
- package/components/demo-toggle/demo-toggle.examples.md +4 -4
- package/components/description-list/description-list.css +16 -4
- package/components/feed/feed-item.a2ui.json +3 -2
- package/components/feed/feed-item.yaml +7 -1
- package/components/feed/feed.css +28 -5
- package/components/field/field.examples.md +4 -4
- package/components/image/image.class.js +8 -0
- package/components/modal/modal.class.js +43 -2
- package/components/modal/modal.css +23 -0
- package/components/nav-group/nav-group.css +27 -5
- package/components/nav-item/nav-item.css +11 -3
- package/components/option-card/option-card.a2ui.json +10 -10
- package/components/option-card/option-card.css +32 -16
- package/components/option-card/option-card.yaml +19 -15
- package/components/radio/radio.examples.md +4 -4
- package/components/range/range.css +8 -4
- package/components/richtext/richtext.css +5 -1
- package/components/segment/segment.css +10 -0
- package/components/slider/slider.a2ui.json +6 -3
- package/components/slider/slider.css +28 -12
- package/components/slider/slider.yaml +11 -3
- package/components/stat/stat.examples.md +4 -4
- package/components/step-progress/step-progress.css +16 -3
- package/components/swatch/swatch.css +14 -6
- package/components/switch/switch.examples.md +4 -4
- package/components/table/cell-types.js +8 -0
- package/components/table/table.a2ui.json +1 -1
- package/components/table/table.class.js +11 -0
- package/components/table/table.css +9 -0
- package/components/table/table.d.ts +1 -1
- package/components/table/table.yaml +1 -1
- package/components/table-toolbar/table-toolbar.css +10 -1
- package/components/tabs/tabs.css +13 -5
- package/components/tag/tag.class.js +14 -1
- package/components/tag/tag.css +70 -9
- package/components/text/text.examples.md +4 -4
- package/components/timeline/timeline-item.a2ui.json +2 -2
- package/components/timeline/timeline-item.yaml +2 -2
- package/components/timeline/timeline.css +33 -5
- package/components/timeline/timeline.d.ts +2 -2
- package/components/toast/toast.css +28 -5
- package/core/element.js +31 -0
- package/core/signals.js +3 -1
- package/custom-elements.json +469 -46
- package/dist/theme-provider.min.js +2 -2
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +41 -41
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
- package/patterns/access-requests/access-requests.examples.html +3 -3
- package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +3 -3
- package/patterns/admin-shell/admin-shell.examples.html +3 -4
- package/patterns/agent-cost/agent-cost.examples.html +3 -3
- package/patterns/agent-memory/agent-memory.examples.html +3 -3
- package/patterns/agent-prompt-library/agent-prompt-library.examples.html +3 -3
- package/patterns/agent-tool-call/agent-tool-call.examples.html +3 -3
- package/patterns/alert-dialog/alert-dialog.examples.html +3 -3
- package/patterns/app-nav/app-nav.examples.html +4 -4
- package/patterns/approvals/approvals.examples.html +3 -3
- package/patterns/audit-log/audit-log.examples.html +3 -3
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +19 -9
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.js +2 -2
- package/patterns/changelog-feed/changelog-feed.examples.html +3 -3
- package/patterns/chart-in-card/chart-in-card.examples.html +37 -3
- package/patterns/chart-in-card/chart-in-card.examples.js +12 -0
- package/patterns/chart-in-card/chart-in-card.html +6 -0
- package/patterns/chat-shell/chat-shell.examples.html +3 -4
- package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +3 -3
- package/patterns/conversion-funnel/conversion-funnel.examples.html +3 -3
- package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +3 -3
- package/patterns/diff-review/diff-review.examples.html +3 -3
- package/patterns/editor-shell/editor-shell.examples.html +3 -4
- package/patterns/export-flow/export-flow.examples.html +3 -3
- package/patterns/filter-bar/filter-bar.examples.html +3 -3
- package/patterns/form-drawer/form-drawer.examples.html +3 -3
- package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.examples.html +3 -3
- package/patterns/inline-dialog/inline-dialog.examples.html +3 -3
- package/patterns/kanban-board/kanban-board.examples.html +3 -3
- package/patterns/layout/layout.examples.html +4 -7
- package/patterns/marketing-engagement/marketing-engagement.examples.html +3 -3
- package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +3 -3
- package/patterns/permissions-matrix/permissions-matrix.examples.html +3 -3
- package/patterns/permissions-role-picker/permissions-role-picker.examples.html +3 -3
- package/patterns/permissions-sharing/permissions-sharing.examples.html +3 -3
- package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +3 -3
- package/patterns/record-detail-drawer/record-detail-drawer.examples.html +3 -3
- package/patterns/responsive-shell-sidebar/responsive-shell-sidebar.examples.html +135 -147
- package/patterns/retention-cohort/retention-cohort.examples.html +3 -3
- package/patterns/search-discovery/search-discovery.examples.html +3 -3
- package/patterns/system-banners/system-banners.examples.html +3 -3
- package/patterns/timezone-selector/timezone-selector.examples.html +3 -3
- package/patterns/wizard-drawer/wizard-drawer.examples.html +3 -3
- package/styles/colors/semantics/core.css +22 -2
package/components/tabs/tabs.css
CHANGED
|
@@ -4,8 +4,13 @@
|
|
|
4
4
|
--tabs-border: transparent;
|
|
5
5
|
--tabs-bg: transparent;
|
|
6
6
|
--tabs-radius: var(--a-radius-md);
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/* One quarter-rem taller than the shared control height (operator
|
|
8
|
+
ruling 2026-08-12) — tab labels sit at --a-ui-lg since gh#965 and
|
|
9
|
+
needed the extra breathing room. */
|
|
10
|
+
--tabs-button-height: calc(var(--a-size) + 0.25rem);
|
|
11
|
+
/* One rung UP the --a-ui-* scale (gh#965): tab labels are primary
|
|
12
|
+
navigation, not control chrome. */
|
|
13
|
+
--tabs-font-size: var(--a-ui-lg);
|
|
9
14
|
--tabs-font-family: var(--a-font-family-ui);
|
|
10
15
|
/* Strip owns the button-to-button spacing — 4px base gap + one
|
|
11
16
|
padding unit (8px) folded in, since tab-button carries no
|
|
@@ -13,9 +18,12 @@
|
|
|
13
18
|
--tabs-gap: var(--a-space-3);
|
|
14
19
|
--tabs-indicator-color: var(--md-sys-color-primary);
|
|
15
20
|
--tabs-indicator-height: 2px;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
/* State fg follows nav-item-ui's convention (gh#968 ruling, gh#1088):
|
|
22
|
+
idle neutral-high · hover/selected the shared --a-ui-text-* aliases —
|
|
23
|
+
one color language across horizontal (tabs) and vertical (nav) selection. */
|
|
24
|
+
--tabs-fg: var(--md-sys-color-neutral-high);
|
|
25
|
+
--tabs-fg-hover: var(--a-ui-text-hover);
|
|
26
|
+
--tabs-fg-active: var(--a-ui-text-selected);
|
|
19
27
|
--tabs-fg-disabled: var(--a-ui-text-disabled);
|
|
20
28
|
|
|
21
29
|
/* ── Spacing ── */
|
|
@@ -57,7 +57,20 @@ export class UITag extends UIElement {
|
|
|
57
57
|
static parts = {
|
|
58
58
|
// button-ui, not a native <button> (gh issue 276) — the icon slots in
|
|
59
59
|
// explicitly to keep its bold weight (the icon= prop stamps regular).
|
|
60
|
-
|
|
60
|
+
// gh#1084: the icon carries its own explicit free-form `size` (routes
|
|
61
|
+
// through icon.class.js's inline-style path, --icon-size) rather than
|
|
62
|
+
// relying on tag.css's `[slot="dismiss"] { --a-icon-size: … }` token
|
|
63
|
+
// override — that CSS-custom-property override is DEAD on this button:
|
|
64
|
+
// the button also carries `size="sm"`, and the universal
|
|
65
|
+
// `[size="sm"] { --a-icon-size: 0.875rem; … }` rule (styles/api/
|
|
66
|
+
// sizing.css) lives in the `utilities` layer, which the cascade-layer
|
|
67
|
+
// order (`@layer reset, tokens, elements, components, utilities, …` —
|
|
68
|
+
// styles/index.css) ranks ABOVE the `components` layer tag.css's own
|
|
69
|
+
// rule lives in — so the universal rule always wins on this element
|
|
70
|
+
// regardless of specificity, and any --a-icon-size value tag.css sets
|
|
71
|
+
// there is inert. An icon-level `size="…"` attribute sets an inline
|
|
72
|
+
// style directly (icon.class.js), which outranks every layer.
|
|
73
|
+
dismiss: '<button-ui slot="dismiss" variant="ghost" size="sm" aria-label="Remove"><icon-ui slot="icon" name="x" weight="bold" size="0.75rem"></icon-ui></button-ui>',
|
|
61
74
|
};
|
|
62
75
|
|
|
63
76
|
static template = () => null;
|
package/components/tag/tag.css
CHANGED
|
@@ -28,9 +28,29 @@ tag-ui[removable]:not([disabled]):hover {
|
|
|
28
28
|
--tag-border: transparent;
|
|
29
29
|
--tag-radius: var(--a-radius-full);
|
|
30
30
|
--tag-px: var(--a-space-1-5);
|
|
31
|
-
|
|
31
|
+
/* gh#1084: block padding flattened toward 1px per tier — the
|
|
32
|
+
--tag-min-h floor (below) now owns the chip's vertical size, so
|
|
33
|
+
py no longer has to carry it. Was --a-space-0-5 (2px); the extra
|
|
34
|
+
space min-height used to need from padding is now supplied by
|
|
35
|
+
align-items:center centering the content inside the floored box. */
|
|
36
|
+
--tag-py: var(--a-space-px);
|
|
32
37
|
--tag-gap: var(--a-space-1);
|
|
33
|
-
|
|
38
|
+
/* gh#1084 — min-height floor, decoupled from padding (mirrors
|
|
39
|
+
tags-input-ui's --tags-input-min-h). Component-owned fixed rem
|
|
40
|
+
constants (not density-scaled, matching --tag-dismiss-size's own
|
|
41
|
+
precedent below) calibrated to the CURRENT rendered height of a
|
|
42
|
+
plain (non-removable) tag at each tier — measured 14/17/22px
|
|
43
|
+
sm/md/lg before this change — so the dominant, non-removable case
|
|
44
|
+
has zero visual regression. Removable tags (previously inflated
|
|
45
|
+
by the oversized dismiss button, see --tag-dismiss-size) now
|
|
46
|
+
settle at or above this same floor instead of exceeding it. */
|
|
47
|
+
--tag-min-h: 1.0625rem; /* 17px @ d=1 — md */
|
|
48
|
+
--tag-min-h-sm: 0.875rem; /* 14px @ d=1 */
|
|
49
|
+
--tag-min-h-lg: 1.375rem; /* 22px @ d=1 */
|
|
50
|
+
/* One rung down the --a-ui-* scale (gh#965): tags read as metadata
|
|
51
|
+
chrome, not body copy. Whole tier ladder shifts with it (sm=2xs,
|
|
52
|
+
lg=sm) so the tiers stay one rung apart. */
|
|
53
|
+
--tag-font: var(--a-ui-xs);
|
|
34
54
|
|
|
35
55
|
/* ── Size tiers (gh#779) — md (above) is the pixel-identical default;
|
|
36
56
|
[size="sm"|"lg"] below re-point the active tokens. Component-owned
|
|
@@ -43,12 +63,34 @@ tag-ui[removable]:not([disabled]):hover {
|
|
|
43
63
|
same rung spacing the space/type scales already use. */
|
|
44
64
|
--tag-px-sm: var(--a-space-1);
|
|
45
65
|
--tag-px-lg: var(--a-space-2);
|
|
66
|
+
/* gh#1084: py flattened toward 1px/tier now that --tag-min-h floors
|
|
67
|
+
the box — was --a-space-px/--a-space-1 (1px/4px), a 4x spread;
|
|
68
|
+
the height job moved to the floor, so the ladder can compress. */
|
|
46
69
|
--tag-py-sm: var(--a-space-px);
|
|
47
|
-
--tag-py-lg: var(--a-space-
|
|
48
|
-
--tag-font-sm: var(--a-ui-
|
|
49
|
-
--tag-font-lg: var(--a-ui-
|
|
70
|
+
--tag-py-lg: var(--a-space-0-5);
|
|
71
|
+
--tag-font-sm: var(--a-ui-2xs);
|
|
72
|
+
--tag-font-lg: var(--a-ui-sm);
|
|
50
73
|
--tag-font-family: var(--a-font-family-ui);
|
|
51
|
-
--
|
|
74
|
+
/* gh#1084: was 1rem (16px). NOTE: --button-height (button.css) is a
|
|
75
|
+
MIN-height on the dismiss <button-ui>, but an icon-only button
|
|
76
|
+
also gets an explicit fixed `width: var(--button-height)`
|
|
77
|
+
([data-icon-only], button.css) — so shrinking this token alone
|
|
78
|
+
(leaving the glyph at its old 14px) would be a no-op on height
|
|
79
|
+
(border(2px, top+bottom) + icon(14px) = 16px content already
|
|
80
|
+
exceeded the old 16px floor exactly, so content — not the
|
|
81
|
+
floor — was driving height) and would CLIP the width (a smaller
|
|
82
|
+
fixed width vs. the still-16px icon+border content). The real
|
|
83
|
+
fix is shrinking the glyph itself — see tag.class.js's dismiss
|
|
84
|
+
template, which now gives the icon its own `size="0.75rem"`
|
|
85
|
+
(12px) instead of leaning on a `--a-icon-size` CSS override here
|
|
86
|
+
(that override is dead — see the [slot="dismiss"] rule below) —
|
|
87
|
+
and re-deriving this token to match: new icon (12px) + the
|
|
88
|
+
button's own 1px top/bottom border (2px) = 14px, so width and
|
|
89
|
+
the min-height floor both land exactly on the new content size —
|
|
90
|
+
no floor/content mismatch, no clipping. Net: the dismiss button
|
|
91
|
+
(and its glyph) really is ~2px smaller in both dimensions, at
|
|
92
|
+
every [size] tier (this token isn't tiered). */
|
|
93
|
+
--tag-dismiss-size: 0.875rem;
|
|
52
94
|
--tag-bg-hover: var(--a-bg-hover);
|
|
53
95
|
--tag-bg-disabled: var(--a-ui-bg-disabled);
|
|
54
96
|
--tag-fg-disabled: var(--a-ui-text-disabled);
|
|
@@ -98,6 +140,11 @@ tag-ui[removable]:not([disabled]):hover {
|
|
|
98
140
|
label still centers instead of reading left-aligned in an oversized
|
|
99
141
|
pill. */
|
|
100
142
|
width: fit-content;
|
|
143
|
+
/* gh#1084: floor, not a fixed size — mirrors tags-input-ui's own
|
|
144
|
+
min-height (tags-input.css). Decouples the chip's vertical size
|
|
145
|
+
from --tag-py so padding can stay minimal; content taller than
|
|
146
|
+
the floor (e.g. a slotted leading icon) still grows the box. */
|
|
147
|
+
min-height: var(--tag-min-h);
|
|
101
148
|
justify-content: center;
|
|
102
149
|
gap: var(--tag-gap);
|
|
103
150
|
padding: var(--tag-py) var(--tag-px);
|
|
@@ -288,16 +335,19 @@ tag-ui[removable]:not([disabled]):hover {
|
|
|
288
335
|
--tag-px: var(--tag-px-sm);
|
|
289
336
|
--tag-py: var(--tag-py-sm);
|
|
290
337
|
--tag-font: var(--tag-font-sm);
|
|
338
|
+
--tag-min-h: var(--tag-min-h-sm);
|
|
291
339
|
}
|
|
292
340
|
:scope[size="md"] {
|
|
293
341
|
--tag-px: var(--a-space-1-5);
|
|
294
|
-
--tag-py: var(--a-space-
|
|
295
|
-
--tag-font: var(--a-ui-
|
|
342
|
+
--tag-py: var(--a-space-px);
|
|
343
|
+
--tag-font: var(--a-ui-xs);
|
|
344
|
+
--tag-min-h: 1.0625rem; /* 17px @ d=1 — matches the :where(:scope) default */
|
|
296
345
|
}
|
|
297
346
|
:scope[size="lg"] {
|
|
298
347
|
--tag-px: var(--tag-px-lg);
|
|
299
348
|
--tag-py: var(--tag-py-lg);
|
|
300
349
|
--tag-font: var(--tag-font-lg);
|
|
350
|
+
--tag-min-h: var(--tag-min-h-lg);
|
|
301
351
|
}
|
|
302
352
|
|
|
303
353
|
/* hover rule moved outside @scope — see Safari 17.x bug note at top. */
|
|
@@ -342,7 +392,18 @@ tag-ui[removable]:not([disabled]):hover {
|
|
|
342
392
|
--button-fg: var(--tag-dismiss-fg);
|
|
343
393
|
--button-bg-ghost-hover: var(--tag-dismiss-bg-hover);
|
|
344
394
|
--button-fg-ghost-hover: var(--tag-dismiss-fg);
|
|
345
|
-
|
|
395
|
+
/* gh#1084: NO `--a-icon-size` override here — it doesn't work. This
|
|
396
|
+
button also carries `size="sm"` (tag.class.js), and the universal
|
|
397
|
+
`[size="sm"] { --a-icon-size: 0.875rem; }` rule (styles/api/
|
|
398
|
+
sizing.css) lives in the `utilities` cascade layer, which
|
|
399
|
+
`@layer reset, tokens, elements, components, utilities, …`
|
|
400
|
+
(styles/index.css) ranks ABOVE `components` — so it always wins
|
|
401
|
+
over anything this file sets on the same element, regardless of
|
|
402
|
+
selector specificity. The icon's rendered size is set directly
|
|
403
|
+
on the icon itself instead (tag.class.js's dismiss template gives
|
|
404
|
+
`<icon-ui size="0.75rem">` — a free-form size, which icon.class.js
|
|
405
|
+
applies as an inline style, outranking every layer). See
|
|
406
|
+
--tag-dismiss-size above — it's kept in sync with that 0.75rem. */
|
|
346
407
|
|
|
347
408
|
opacity: var(--tag-dismiss-opacity);
|
|
348
409
|
order: 1; /* push dismiss to end so layout reads [text] [×] */
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
```html
|
|
12
12
|
<row-ui gap="6" align="start" wrap>
|
|
13
13
|
<col-ui gap="2">
|
|
14
|
-
<text-ui variant="caption" color="muted">
|
|
15
|
-
<div
|
|
14
|
+
<text-ui variant="caption" color="muted">scale="ui-sm"</text-ui>
|
|
15
|
+
<div scale="ui-sm" style="max-width:240px">
|
|
16
16
|
<col-ui gap="2">
|
|
17
17
|
<text-ui variant="heading">Heading</text-ui>
|
|
18
18
|
<text-ui variant="body">Body copy showing how this register sizes running text and the leading between lines.</text-ui>
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
</div>
|
|
32
32
|
</col-ui>
|
|
33
33
|
<col-ui gap="2">
|
|
34
|
-
<text-ui variant="caption" color="muted">
|
|
35
|
-
<div
|
|
34
|
+
<text-ui variant="caption" color="muted">scale="content-md"</text-ui>
|
|
35
|
+
<div scale="content-md" style="max-width:240px">
|
|
36
36
|
<col-ui gap="2">
|
|
37
37
|
<text-ui variant="heading">Heading</text-ui>
|
|
38
38
|
<text-ui variant="body">Body copy showing how this register sizes running text and the leading between lines.</text-ui>
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"type": "string"
|
|
30
30
|
},
|
|
31
31
|
"spinner": {
|
|
32
|
-
"description": "Show a spinner instead of the icon while status
|
|
32
|
+
"description": "Show a spinner instead of the dot/icon while status=\"active\".",
|
|
33
33
|
"type": "boolean",
|
|
34
34
|
"default": false
|
|
35
35
|
},
|
|
36
36
|
"status": {
|
|
37
|
-
"description": "Lifecycle state (idle |
|
|
37
|
+
"description": "Lifecycle state (idle | active | completed | error). Pairs with `spinner` on \"active\" for an in-progress step.",
|
|
38
38
|
"type": "string",
|
|
39
39
|
"default": "idle"
|
|
40
40
|
},
|
|
@@ -39,11 +39,11 @@ props:
|
|
|
39
39
|
type: string
|
|
40
40
|
default: 'default'
|
|
41
41
|
status:
|
|
42
|
-
description: Lifecycle state (idle |
|
|
42
|
+
description: Lifecycle state (idle | active | completed | error). Pairs with `spinner` on "active" for an in-progress step.
|
|
43
43
|
type: string
|
|
44
44
|
default: 'idle'
|
|
45
45
|
spinner:
|
|
46
|
-
description: Show a spinner instead of the icon while status=
|
|
46
|
+
description: Show a spinner instead of the dot/icon while status="active".
|
|
47
47
|
type: boolean
|
|
48
48
|
default: false
|
|
49
49
|
|
|
@@ -176,6 +176,17 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
|
|
|
176
176
|
--timeline-item-toggle-px: var(--a-space-0-5);
|
|
177
177
|
--timeline-item-toggle-time-margin: 1.5rem;
|
|
178
178
|
--timeline-item-outcome-indent: 0.75rem;
|
|
179
|
+
|
|
180
|
+
/* Row-1's rendered height — [slot="label"]'s own line-height (1.4,
|
|
181
|
+
set at var(--timeline-item-label-size), timeline.css below). Marker
|
|
182
|
+
centering (dot/line/icon/caret) must measure against THIS, not a
|
|
183
|
+
bare `1.4em`: `em` on the marker's own box resolves against
|
|
184
|
+
timeline-item-ui's ambient/inherited font-size, which is NOT
|
|
185
|
+
guaranteed to equal --timeline-item-label-size (it doesn't, by
|
|
186
|
+
default — nothing sets font-size on timeline-item-ui itself), so a
|
|
187
|
+
literal `1.4em` silently drifted off the label's real line-height
|
|
188
|
+
and threw every marker's vertical center off by that gap (gh#1090). */
|
|
189
|
+
--timeline-item-row-h: calc(var(--timeline-item-label-size) * 1.4);
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
:scope {
|
|
@@ -200,7 +211,7 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
|
|
|
200
211
|
content: '';
|
|
201
212
|
position: absolute;
|
|
202
213
|
left: calc((var(--timeline-item-marker-w) - var(--timeline-item-dot-size)) / 2);
|
|
203
|
-
top: calc((
|
|
214
|
+
top: calc((var(--timeline-item-row-h) - var(--timeline-item-dot-size)) / 2 + 1px);
|
|
204
215
|
width: var(--timeline-item-dot-size);
|
|
205
216
|
height: var(--timeline-item-dot-size);
|
|
206
217
|
border-radius: 50%;
|
|
@@ -235,7 +246,7 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
|
|
|
235
246
|
content: '';
|
|
236
247
|
position: absolute;
|
|
237
248
|
left: calc((var(--timeline-item-marker-w) - var(--timeline-item-line-size)) / 2);
|
|
238
|
-
top: calc((
|
|
249
|
+
top: calc((var(--timeline-item-row-h) + var(--timeline-item-dot-size)) / 2 + 2px);
|
|
239
250
|
bottom: calc(-1 * var(--timeline-item-gap-row));
|
|
240
251
|
width: var(--timeline-item-line-size);
|
|
241
252
|
background: var(--timeline-item-line-fg);
|
|
@@ -252,8 +263,17 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
|
|
|
252
263
|
grid-column: marker;
|
|
253
264
|
grid-row: 1;
|
|
254
265
|
justify-self: center;
|
|
255
|
-
|
|
256
|
-
|
|
266
|
+
/* `baseline` anchors a baseline-less box (icon-ui has no text) by its
|
|
267
|
+
synthesized baseline — the bottom margin edge (CSS Box Alignment) —
|
|
268
|
+
to the row's shared text baseline. That pins the icon's BOTTOM to
|
|
269
|
+
near the bottom of the label's glyphs and makes the margin-top
|
|
270
|
+
centering below a no-op (the alignment step repositions the box
|
|
271
|
+
after margin is applied, so no margin-top value moves the rendered
|
|
272
|
+
circle). `start` anchors the row's block-start instead, so
|
|
273
|
+
margin-top's `(row-h - icon-size)/2` genuinely centers the icon
|
|
274
|
+
against the label's line-height (gh#1090). */
|
|
275
|
+
align-self: start;
|
|
276
|
+
margin-top: calc((var(--timeline-item-row-h) - var(--timeline-item-icon-size)) / 2);
|
|
257
277
|
width: var(--timeline-item-icon-size);
|
|
258
278
|
height: var(--timeline-item-icon-size);
|
|
259
279
|
border-radius: 50%;
|
|
@@ -278,7 +298,7 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
|
|
|
278
298
|
|
|
279
299
|
/* Push connector line past the icon circle */
|
|
280
300
|
:scope:has([slot="icon"])::after {
|
|
281
|
-
top: calc((
|
|
301
|
+
top: calc((var(--timeline-item-row-h) + var(--timeline-item-icon-size)) / 2 + 2px);
|
|
282
302
|
}
|
|
283
303
|
|
|
284
304
|
/* ═══════ Content slots ═══════ */
|
|
@@ -400,6 +420,14 @@ timeline-ui[size="sm"] > timeline-item-ui[status="active"][spinner]::before {
|
|
|
400
420
|
timeline-ui[orientation="horizontal"] > timeline-item-ui {
|
|
401
421
|
display: flex;
|
|
402
422
|
flex-direction: column;
|
|
423
|
+
/* Reset the vertical-mode grid's `align-items: baseline` (timeline.css
|
|
424
|
+
above) — baseline is incompatible with cross-axis stretch, so without
|
|
425
|
+
this reset [slot="label"]/[slot="description"]/[slot="time"] (plain
|
|
426
|
+
<span>s) shrink-to-fit their own text instead of spanning the item's
|
|
427
|
+
full width, leaving `text-align: center` below with no extra width to
|
|
428
|
+
center within (labels rendered flush against the item's left edge —
|
|
429
|
+
gh#1090). */
|
|
430
|
+
align-items: stretch;
|
|
403
431
|
flex: 1 1 0;
|
|
404
432
|
min-width: 0;
|
|
405
433
|
padding-top: calc(var(--timeline-dot-size) + var(--timeline-gap-col));
|
|
@@ -40,9 +40,9 @@ export class UITimelineItem extends UIElement {
|
|
|
40
40
|
duration: string;
|
|
41
41
|
/** Optional leading icon name (Phosphor). */
|
|
42
42
|
icon: string;
|
|
43
|
-
/** Show a spinner instead of the icon while status=
|
|
43
|
+
/** Show a spinner instead of the dot/icon while status="active". */
|
|
44
44
|
spinner: boolean;
|
|
45
|
-
/** Lifecycle state (idle |
|
|
45
|
+
/** Lifecycle state (idle | active | completed | error). Pairs with `spinner` on "active" for an in-progress step. */
|
|
46
46
|
status: string;
|
|
47
47
|
/** Primary step label. */
|
|
48
48
|
text: string;
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
TOAST-N — Notification popup with auto-dismiss.
|
|
3
3
|
═══════════════════════════════════════════════════════════════ */
|
|
4
4
|
|
|
5
|
+
/* DEAD-CODE NOTICE (gh#1104, ties to Phase 4 of
|
|
6
|
+
.claude/docs/specs/feed-channel.md / SPEC-FEED-CHANNEL-001):
|
|
7
|
+
<toast-ui> is a self-removing facade — toast.class.js's
|
|
8
|
+
`connected()` posts into <feed-ui>/UIFeed then `queueMicrotask`s
|
|
9
|
+
`this.remove()`, so this element never survives to a paint. Every
|
|
10
|
+
rule below (including the `primary` variant) is unreachable at
|
|
11
|
+
runtime. The real paint site is feed.css's `@scope (feed-item-ui)`
|
|
12
|
+
block — edit THAT file to change what a posted toast looks like.
|
|
13
|
+
Kept here (not deleted) as the documented visual contract + the
|
|
14
|
+
reference the feed-item-ui `primary` variant was ported from. */
|
|
15
|
+
|
|
5
16
|
/* Safari 17.x bug: `:scope[data-open]` and `:scope[data-closing]`
|
|
6
17
|
(Flavor B — attribute-removal restyle) don't reliably restyle on
|
|
7
18
|
attribute toggling inside `@scope`. Selectors moved out as plain
|
|
@@ -73,6 +84,10 @@ toast-ui[data-closing][position="top-left"] {
|
|
|
73
84
|
box-shadow: var(--toast-shadow);
|
|
74
85
|
opacity: 0;
|
|
75
86
|
pointer-events: auto;
|
|
87
|
+
/* Elevated-surface separation over busy page content (gh#1091) —
|
|
88
|
+
mirrors loading-overlay.css's [variant="blur"] treatment. */
|
|
89
|
+
backdrop-filter: blur(4px);
|
|
90
|
+
-webkit-backdrop-filter: blur(4px);
|
|
76
91
|
}
|
|
77
92
|
|
|
78
93
|
/* ── Position variants ── */
|
|
@@ -112,26 +127,34 @@ toast-ui[data-closing][position="top-left"] {
|
|
|
112
127
|
light-dark scheme-aware token), NOT `--a-{variant}-text-strong`
|
|
113
128
|
(the latter is locked dark for warning + light for the others —
|
|
114
129
|
designed for solid `--variant-strong` fills, where the bg never
|
|
115
|
-
flips). Mirrors alert.css's variant wiring.
|
|
130
|
+
flips). Mirrors alert.css's variant wiring.
|
|
131
|
+
|
|
132
|
+
`--toast-bg` rides `-container-high` (NOT the plain `-container`
|
|
133
|
+
alert.css uses) — a floating overlay over arbitrary page content
|
|
134
|
+
needs a stronger tonal step than an inline, already-boxed alert to
|
|
135
|
+
read as separated (gh#1091). `-container-high` is a real generated
|
|
136
|
+
role per family in colors/material-static.css (the same tier
|
|
137
|
+
`--a-{family}-subtle` aliases to per component-token-contract.md's
|
|
138
|
+
`-strong` semantics note) — not a hand-authored addition. */
|
|
116
139
|
|
|
117
140
|
:where(:scope),
|
|
118
141
|
:where(:scope[variant="info"]) {
|
|
119
|
-
--toast-bg: var(--md-sys-color-info-container);
|
|
142
|
+
--toast-bg: var(--md-sys-color-info-container-high);
|
|
120
143
|
--toast-fg: var(--md-sys-color-info-on-surface);
|
|
121
144
|
--toast-border: var(--md-sys-color-info-outline-variant);
|
|
122
145
|
}
|
|
123
146
|
:where(:scope[variant="success"]) {
|
|
124
|
-
--toast-bg: var(--md-sys-color-success-container);
|
|
147
|
+
--toast-bg: var(--md-sys-color-success-container-high);
|
|
125
148
|
--toast-fg: var(--md-sys-color-success-on-surface);
|
|
126
149
|
--toast-border: var(--md-sys-color-success-outline-variant);
|
|
127
150
|
}
|
|
128
151
|
:where(:scope[variant="warning"]) {
|
|
129
|
-
--toast-bg: var(--md-sys-color-warning-container);
|
|
152
|
+
--toast-bg: var(--md-sys-color-warning-container-high);
|
|
130
153
|
--toast-fg: var(--md-sys-color-warning-on-surface);
|
|
131
154
|
--toast-border: var(--md-sys-color-warning-outline-variant);
|
|
132
155
|
}
|
|
133
156
|
:where(:scope[variant="danger"]) {
|
|
134
|
-
--toast-bg: var(--md-sys-color-danger-container);
|
|
157
|
+
--toast-bg: var(--md-sys-color-danger-container-high);
|
|
135
158
|
--toast-fg: var(--md-sys-color-danger-on-surface);
|
|
136
159
|
--toast-border: var(--md-sys-color-danger-outline-variant);
|
|
137
160
|
}
|
package/core/element.js
CHANGED
|
@@ -176,12 +176,43 @@ export class UIElement extends HTMLElement {
|
|
|
176
176
|
// compliant environments: the value already matches (the property
|
|
177
177
|
// setter's Object.is check short-circuits), so this never causes an
|
|
178
178
|
// extra render pass on browsers/environments that already got it right.
|
|
179
|
+
// The whole pre-sync loop runs UNTRACKED: connectedCallback commonly
|
|
180
|
+
// fires synchronously inside a PARENT's render effect (template-created
|
|
181
|
+
// children connect during stamp()), and the gh#961 branch below READS
|
|
182
|
+
// `this[key]` — a tracked read there subscribes the parent's effect to
|
|
183
|
+
// this child's signals, so any later child-prop write (a `.checked`
|
|
184
|
+
// template apply) re-dirties the parent, which re-stamps fresh
|
|
185
|
+
// children, whose own mount-reads re-subscribe: the unbounded
|
|
186
|
+
// parent↔child oscillation the signals drain-loop guard traps (the
|
|
187
|
+
// admin-settings/switch-ui/button-ui loop on gh#961). Same rationale
|
|
188
|
+
// as the untracked(connected()) wrapper below.
|
|
189
|
+
untracked(() => {
|
|
179
190
|
for (const [key, cfg] of Object.entries(ctor.properties)) {
|
|
180
191
|
const attr = cfg.attribute ?? key.toLowerCase();
|
|
181
192
|
if (this.hasAttribute(attr)) {
|
|
182
193
|
this[key] = parseAttr(this.getAttribute(attr), cfg.type ?? String);
|
|
194
|
+
} else if (cfg.reflect && cfg.type === Boolean && this[key] === true) {
|
|
195
|
+
// gh#961 — stamp the initial attribute for a TRUE-default reflected
|
|
196
|
+
// boolean. installProps seeds the signal with the default but can't
|
|
197
|
+
// touch attributes (constructor restriction), and the property
|
|
198
|
+
// setter's Object.is short-circuit means a later same-value set
|
|
199
|
+
// (e.g. chat-thread's #syncEmptyFromChildren recomputing `empty:
|
|
200
|
+
// true` on first connect) never reflects either — so CSS gates like
|
|
201
|
+
// `chat-thread:not([empty]) > chat-empty` and
|
|
202
|
+
// `editor-canvas:not([empty]) > editor-canvas-empty` read the
|
|
203
|
+
// wrong state forever. Deliberately scoped to Boolean-true ONLY:
|
|
204
|
+
// reflecting string/number defaults here stamps `text=""`-shaped
|
|
205
|
+
// attributes framework-wide, flipping `[attr]` CSS gates and
|
|
206
|
+
// cascading re-renders into the signals drain-loop guard (the
|
|
207
|
+
// full-reflect attempt documented on gh#961). A false default is
|
|
208
|
+
// already a DOM no-op (removeAttribute on an absent attribute).
|
|
209
|
+
// The setAttribute replays attributeChangedCallback → parseAttr →
|
|
210
|
+
// same value → Object.is short-circuit: no signal write, no
|
|
211
|
+
// render pass.
|
|
212
|
+
this.setAttribute(attr, '');
|
|
183
213
|
}
|
|
184
214
|
}
|
|
215
|
+
});
|
|
185
216
|
// connected() commonly reads this element's reactive properties via
|
|
186
217
|
// template-literal interpolation (`${this.label}` etc.) to stamp its
|
|
187
218
|
// inner DOM. If the outer call path is inside another effect (e.g.
|
package/core/signals.js
CHANGED
|
@@ -32,7 +32,9 @@ function flushSigs() {
|
|
|
32
32
|
while ((q = pending)) {
|
|
33
33
|
if (++loops > 100) {
|
|
34
34
|
pending = null;
|
|
35
|
-
|
|
35
|
+
// Name the still-dirty effect hosts — a bare count is undiagnosable
|
|
36
|
+
// (gh#961's oscillation took host attribution to even locate).
|
|
37
|
+
console.error(`signals: drain loop exceeded 100 iterations`, JSON.stringify([...q].map(s => s.host || '?')));
|
|
36
38
|
break;
|
|
37
39
|
}
|
|
38
40
|
pending = null;
|