@adia-ai/web-components 0.0.18 → 0.0.20

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.
Files changed (90) hide show
  1. package/components/accordion/accordion.css +101 -102
  2. package/components/agent-feedback-bar/agent-feedback-bar.js +8 -8
  3. package/components/agent-questions/agent-questions.css +2 -1
  4. package/components/agent-questions/agent-questions.js +6 -6
  5. package/components/agent-reasoning/agent-reasoning.js +20 -5
  6. package/components/agent-trace/agent-trace.a2ui.json +5 -5
  7. package/components/agent-trace/agent-trace.js +7 -5
  8. package/components/agent-trace/agent-trace.yaml +2 -2
  9. package/components/alert/alert.a2ui.json +1 -2
  10. package/components/alert/alert.css +4 -4
  11. package/components/alert/alert.yaml +1 -2
  12. package/components/avatar/avatar.a2ui.json +3 -3
  13. package/components/avatar/avatar.js +10 -0
  14. package/components/avatar/avatar.yaml +6 -6
  15. package/components/button/button.a2ui.json +14 -2
  16. package/components/button/button.css +19 -2
  17. package/components/button/button.js +1 -0
  18. package/components/button/button.yaml +20 -2
  19. package/components/calendar-picker/calendar-picker.css +2 -1
  20. package/components/calendar-picker/calendar-picker.js +12 -1
  21. package/components/chart/chart.css +11 -11
  22. package/components/chart/chart.js +26 -18
  23. package/components/chart-legend/chart-legend.a2ui.json +2 -2
  24. package/components/chart-legend/chart-legend.js +4 -1
  25. package/components/chart-legend/chart-legend.yaml +2 -2
  26. package/components/chat/chat-input.js +13 -5
  27. package/components/chat/chat.a2ui.json +2 -2
  28. package/components/chat/chat.js +14 -3
  29. package/components/chat/chat.yaml +2 -2
  30. package/components/code/code.css +16 -6
  31. package/components/command/command.js +9 -1
  32. package/components/field/field.a2ui.json +0 -5
  33. package/components/field/field.css +2 -2
  34. package/components/field/field.js +53 -5
  35. package/components/field/field.yaml +5 -8
  36. package/components/heatmap/heatmap.css +32 -23
  37. package/components/input/input.js +30 -1
  38. package/components/kbd/kbd.a2ui.json +5 -1
  39. package/components/kbd/kbd.yaml +5 -1
  40. package/components/menu/menu.css +20 -8
  41. package/components/menu/menu.js +9 -1
  42. package/components/modal/modal.css +101 -108
  43. package/components/noodles/noodles.js +25 -8
  44. package/components/pipeline-status/pipeline-status.css +4 -4
  45. package/components/pipeline-status/pipeline-status.js +6 -4
  46. package/components/popover/popover.js +4 -0
  47. package/components/progress-row/progress-row.a2ui.json +3 -2
  48. package/components/progress-row/progress-row.yaml +2 -1
  49. package/components/range/range.js +7 -0
  50. package/components/richtext/richtext.css +2 -2
  51. package/components/richtext/richtext.js +4 -1
  52. package/components/segment/segment.css +1 -1
  53. package/components/segmented/segmented.js +7 -1
  54. package/components/select/select.css +7 -4
  55. package/components/slider/slider.js +15 -8
  56. package/components/stepper/stepper.css +181 -144
  57. package/components/stepper/stepper.js +5 -2
  58. package/components/swiper/swiper.a2ui.json +3 -3
  59. package/components/swiper/swiper.css +11 -77
  60. package/components/swiper/swiper.js +6 -5
  61. package/components/swiper/swiper.yaml +3 -3
  62. package/components/switch/switch.a2ui.json +8 -1
  63. package/components/switch/switch.yaml +8 -1
  64. package/components/table/table.js +9 -1
  65. package/components/table-toolbar/table-toolbar.a2ui.json +21 -21
  66. package/components/table-toolbar/table-toolbar.css +32 -91
  67. package/components/table-toolbar/table-toolbar.js +219 -86
  68. package/components/table-toolbar/table-toolbar.yaml +21 -12
  69. package/components/tabs/tabs.css +3 -2
  70. package/components/tabs/tabs.js +7 -1
  71. package/components/tag/tag.a2ui.json +2 -2
  72. package/components/tag/tag.yaml +2 -2
  73. package/components/timeline/timeline.css +244 -204
  74. package/components/timeline/timeline.js +1 -3
  75. package/components/toast/toast.a2ui.json +2 -3
  76. package/components/toast/toast.yaml +5 -3
  77. package/components/toolbar/toolbar.css +6 -1
  78. package/components/toolbar/toolbar.js +10 -2
  79. package/components/tooltip/tooltip.css +8 -2
  80. package/components/tooltip/tooltip.js +12 -14
  81. package/components/tree/tree.css +21 -0
  82. package/core/icons.js +14 -0
  83. package/core/polyfills.js +17 -7
  84. package/package.json +1 -1
  85. package/patterns/a2ui-root/a2ui-root.js +21 -14
  86. package/patterns/app-shell/css/app-shell.main.css +30 -1
  87. package/patterns/app-shell/css/app-shell.tokens.css +1 -0
  88. package/patterns/gen-ui/gen-ui.js +1 -1
  89. package/styles/colors/semantics.css +59 -2
  90. package/styles/tokens.css +16 -12
@@ -35,7 +35,7 @@
35
35
 
36
36
  --pipeline-status-dot-bg: var(--a-border);
37
37
  --pipeline-status-dot-bg-active: var(--a-accent);
38
- --pipeline-status-dot-bg-complete: var(--a-success);
38
+ --pipeline-status-dot-bg-complete: var(--a-success-strong);
39
39
 
40
40
  --pipeline-status-history-border: var(--a-border-subtle);
41
41
  --pipeline-status-border-thin: 1px;
@@ -48,8 +48,8 @@
48
48
  --pipeline-status-pulse-easing: ease-in-out;
49
49
 
50
50
  /* Variant targets */
51
- --pipeline-status-complete-fg: var(--a-success);
52
- --pipeline-status-complete-border: var(--a-success);
51
+ --pipeline-status-complete-fg: var(--a-success-strong);
52
+ --pipeline-status-complete-border: var(--a-success-strong);
53
53
  }
54
54
 
55
55
  /* ─────────────────────────────────────────────
@@ -110,7 +110,7 @@
110
110
  }
111
111
 
112
112
  /* Complete state — override tokens only */
113
- :scope[complete] {
113
+ :scope[status="completed"] {
114
114
  --pipeline-status-label-fg: var(--pipeline-status-complete-fg);
115
115
  --pipeline-status-history-border: var(--pipeline-status-complete-border);
116
116
  }
@@ -23,9 +23,11 @@ const STAGE_LABELS = {
23
23
 
24
24
  class AdiaPipelineStatus extends AdiaElement {
25
25
  static properties = {
26
- stage: { type: String, default: '', reflect: true },
26
+ stage: { type: String, default: '', reflect: true },
27
27
  message: { type: String, default: '', reflect: true },
28
- complete: { type: Boolean, default: false, reflect: true },
28
+ // `status` is the canonical stage-progress shape (matches timeline-item-ui,
29
+ // stepper-item-ui, agent-reasoning-ui).
30
+ status: { type: String, default: 'idle', reflect: true },
29
31
  };
30
32
 
31
33
  static template = () => null;
@@ -95,7 +97,7 @@ class AdiaPipelineStatus extends AdiaElement {
95
97
  #update() {
96
98
  const { stage, message } = this;
97
99
 
98
- if (this.complete) {
100
+ if (this.status === 'completed') {
99
101
  // Move current to history if not already
100
102
  if (this.#prevStage && this.#prevStage !== this.#history[this.#history.length - 1]?.stage) {
101
103
  this.#pushHistory(this.#prevStage, this.#prevMessage);
@@ -153,7 +155,7 @@ class AdiaPipelineStatus extends AdiaElement {
153
155
  }
154
156
 
155
157
  // Auto-close when complete
156
- if (this.complete) {
158
+ if (this.status === 'completed') {
157
159
  this.#detailsEl.removeAttribute('open');
158
160
  }
159
161
  }
@@ -80,6 +80,10 @@ class AdiaPopover extends AdiaElement {
80
80
  if (!trigger || !content) return;
81
81
 
82
82
  if (!content.matches(':popover-open')) {
83
+ // try/catch covers test envs (happy-dom) without the API. Known iOS
84
+ // Safari quirks at the supported floor (light-dismiss broken on
85
+ // 17.0–18.2, virtual-keyboard-on-input persists past 18.3) are
86
+ // documented in docs/BROWSER-COMPAT.md §3a.
83
87
  try { content.showPopover(); } catch { /* popover API unavailable — anchor positioning still runs */ }
84
88
  }
85
89
 
@@ -35,11 +35,12 @@
35
35
  "description": "Color variant for the progress fill",
36
36
  "type": "string",
37
37
  "enum": [
38
+ "default",
39
+ "accent",
38
40
  "success",
39
41
  "warning",
40
42
  "danger",
41
- "info",
42
- "primary"
43
+ "info"
43
44
  ],
44
45
  "default": "default"
45
46
  }
@@ -26,11 +26,12 @@ props:
26
26
  type: string
27
27
  default: default
28
28
  enum:
29
+ - default
30
+ - accent
29
31
  - success
30
32
  - warning
31
33
  - danger
32
34
  - info
33
- - primary
34
35
  events: {}
35
36
  slots:
36
37
  label:
@@ -14,6 +14,13 @@
14
14
  import { AdiaFormElement } from '../../core/form.js';
15
15
 
16
16
  class AdiaRange extends AdiaFormElement {
17
+ // Opt out of AdiaFormElement's per-control `label` deprecation warning.
18
+ // range-ui's `label` is a first-class API: it renders as the in-track
19
+ // caption next to the value (the entire field is the scrubber surface)
20
+ // and the host gets `aria-label` wired from it for proper screen-reader
21
+ // announcement. Same opt-out rationale as input-ui.
22
+ static labelDeprecated = false;
23
+
17
24
  static properties = {
18
25
  ...AdiaFormElement.properties,
19
26
  /** value: Number — overrides AdiaFormElement.value (String); syncs as string on form submit. */
@@ -5,8 +5,8 @@
5
5
  @scope (richtext-ui) {
6
6
  :where(:scope) {
7
7
  /* ── Layout ── */
8
- /* Optimal reading measure; not on spatial scale */
9
- --richtext-max-width: 720px;
8
+ /* Optimal reading measure; not on spatial scale (45rem ≈ 720px at 1rem=16px). */
9
+ --richtext-max-width: 45rem;
10
10
  --richtext-px: var(--a-space-6);
11
11
  --richtext-py: var(--a-space-8);
12
12
 
@@ -18,7 +18,10 @@ import { renderMarkdown } from '../../core/markdown.js';
18
18
  class AdiaRichText extends AdiaElement {
19
19
  static properties = {
20
20
  src: { type: String, default: '', reflect: true },
21
- markdown: { type: String, default: '' },
21
+ // Markdown bodies can be arbitrarily large; reflecting to the attribute
22
+ // would bloat the DOM (and break parsing on multi-line content with
23
+ // unescaped quotes). The property is the source of truth.
24
+ markdown: { type: String, default: '', reflect: false },
22
25
  };
23
26
 
24
27
  static template = () => null;
@@ -12,7 +12,7 @@
12
12
  /* ── Colors ── */
13
13
  --segment-fg: var(--a-fg-subtle);
14
14
  --segment-fg-hover: var(--a-fg);
15
- --segment-fg-selected: var(--a-neutral-0-shade);
15
+ --segment-fg-selected: var(--a-chrome-dark);
16
16
  --segment-fg-disabled: var(--a-fg-muted);
17
17
 
18
18
  /* ── Transition ── */
@@ -22,6 +22,7 @@ class AdiaSegmented extends AdiaFormElement {
22
22
 
23
23
  #indicator = null;
24
24
  #bound = false;
25
+ #transitionRaf = null;
25
26
 
26
27
  connected() {
27
28
  super.connected();
@@ -42,6 +43,10 @@ class AdiaSegmented extends AdiaFormElement {
42
43
 
43
44
  disconnected() {
44
45
  super.disconnected();
46
+ if (this.#transitionRaf != null) {
47
+ cancelAnimationFrame(this.#transitionRaf);
48
+ this.#transitionRaf = null;
49
+ }
45
50
  this.removeEventListener('click', this.#handleClick);
46
51
  this.removeEventListener('keydown', this.#handleKeydown);
47
52
  this.#indicator = null;
@@ -100,7 +105,8 @@ class AdiaSegmented extends AdiaFormElement {
100
105
  this.#indicator.style.transition = 'none';
101
106
  this.#indicator.style.transform = `translateX(${selectedIdx * 100}%)`;
102
107
  this.setAttribute('data-indicator-ready', '');
103
- requestAnimationFrame(() => {
108
+ this.#transitionRaf = requestAnimationFrame(() => {
109
+ this.#transitionRaf = null;
104
110
  if (this.#indicator) this.#indicator.style.transition = '';
105
111
  });
106
112
  } else {
@@ -154,8 +154,11 @@
154
154
  color: var(--select-placeholder-fg);
155
155
  }
156
156
 
157
- [slot="caret"] {
158
- color: var(--select-caret-fg) !important;
157
+ /* Caret color is held against button-ui's stronger cascade by chaining
158
+ :scope > [slot="trigger"] > [slot="caret"] — matches at the same
159
+ specificity as button-ui's own slot rules without !important. */
160
+ :scope > [slot="trigger"] > [slot="caret"] {
161
+ color: var(--select-caret-fg);
159
162
  flex-shrink: 0;
160
163
  }
161
164
 
@@ -171,8 +174,8 @@
171
174
  background: var(--select-ghost-bg-hover);
172
175
  color: var(--select-fg);
173
176
  }
174
- :scope[variant="ghost"] [slot="trigger"]:hover [slot="caret"] {
175
- color: var(--select-fg-subtle) !important;
177
+ :scope[variant="ghost"] > [slot="trigger"]:hover > [slot="caret"] {
178
+ color: var(--select-fg-subtle);
176
179
  }
177
180
  }
178
181
 
@@ -1,19 +1,25 @@
1
1
  /**
2
- * <field-ui label="Width">
3
- * <slider-ui value="63" min="0" max="200" step="1" suffix="rem"></slider-ui>
4
- * </field-ui>
2
+ * <slider-ui label="Width" value="63" min="0" max="200" step="1" suffix="rem"></slider-ui>
5
3
  *
6
- * Layout inside the field:
7
- * [field label] [value] [suffix]
8
- * [====fill====●─────────────────track──────]
4
+ * Layout:
5
+ * [label] [value] [suffix]
6
+ * [=====fill=====●─────────────────track───────────────────]
9
7
  *
10
- * Bare `<slider-ui label="…">` still works but logs a deprecation warning
11
- * asking you to wrap in <field-ui> for proper label association.
8
+ * The `label` attribute renders as a first-class in-component caption in
9
+ * the slider header and is mirrored to `aria-label` on the host for
10
+ * screen-reader announcement. Wrap in `<field-ui>` only when you need
11
+ * external label-row composition (hint, error, action slot, etc.).
12
12
  */
13
13
 
14
14
  import { AdiaFormElement } from '../../core/form.js';
15
15
 
16
16
  class AdiaSlider extends AdiaFormElement {
17
+ // Opt out of AdiaFormElement's per-control `label` deprecation warning.
18
+ // slider-ui's `label` is a first-class API rendering as the in-header
19
+ // caption next to the value, with `aria-label` wired on the host for
20
+ // a11y. Same opt-out rationale as input-ui and range-ui.
21
+ static labelDeprecated = false;
22
+
17
23
  static properties = {
18
24
  ...AdiaFormElement.properties,
19
25
  /** value: Number — overrides AdiaFormElement.value (String); syncs as string on form submit. */
@@ -47,6 +53,7 @@ class AdiaSlider extends AdiaFormElement {
47
53
  this.setAttribute('tabindex', '0');
48
54
  this.setAttribute('aria-valuemin', this.min);
49
55
  this.setAttribute('aria-valuemax', this.max);
56
+ if (this.label) this.setAttribute('aria-label', this.label);
50
57
 
51
58
  if (!this.querySelector('[slot="track"]')) {
52
59
  this.innerHTML = `
@@ -1,9 +1,12 @@
1
1
  /* ═══════════════════════════════════════════════════════════════
2
- STEPPER-N + STEPPER-ITEM-N
2
+ STEPPER-UI + STEPPER-ITEM-UI
3
3
 
4
- Extracted from the old timeline-ui[mode="steps"]. Wizard-style
5
- numbered circles, auto-checkmark on completed, connector line.
6
- Parent `step` index drives child state.
4
+ Two-element component. Each gets its own @scope block —
5
+ stepper-item-ui is co-located in stepper.js but is a real
6
+ custom element and must follow the two-block @scope pattern.
7
+
8
+ Wizard-style numbered circles, auto-checkmark on completed,
9
+ connector line. Parent `step` index drives child state.
7
10
  ═══════════════════════════════════════════════════════════════ */
8
11
 
9
12
  @scope (stepper-ui) {
@@ -53,168 +56,202 @@
53
56
  }
54
57
  }
55
58
 
56
- /* ── Item tokens + label/description styling ── */
57
- :where(stepper-item-ui) {
58
- --stepper-label-weight: var(--a-weight-medium);
59
- --stepper-label-size: var(--a-ui-size);
60
- --stepper-label-fg: var(--a-fg);
61
- --stepper-pending-fg: var(--a-fg-muted);
62
- --stepper-desc-fg: var(--a-fg-subtle);
63
- --stepper-desc-size: var(--a-ui-sm);
64
- }
59
+ @scope (stepper-item-ui) {
60
+ :where(:scope) {
61
+ /* Inherit parent stepper-ui's circle/line tokens by name —
62
+ co-located item legitimately reads parent tokens (the same
63
+ scope pattern as menu-item-ui inside menu-ui's popover). */
64
+ --stepper-item-size: var(--stepper-size, 2rem);
65
+ --stepper-item-bg: var(--stepper-bg, var(--a-bg));
66
+ --stepper-item-border: var(--stepper-border, var(--a-border));
67
+ --stepper-item-fg: var(--stepper-fg, var(--a-fg-muted));
68
+ --stepper-item-font: var(--stepper-font, var(--a-ui-sm));
69
+ --stepper-item-weight: var(--stepper-weight, var(--a-weight-medium));
70
+ --stepper-item-border-size: var(--stepper-border-size, 2px);
71
+
72
+ --stepper-item-active-bg: var(--stepper-active-bg, var(--a-bg));
73
+ --stepper-item-active-border: var(--stepper-active-border, var(--a-accent));
74
+ --stepper-item-active-fg: var(--stepper-active-fg, var(--a-accent));
75
+
76
+ --stepper-item-done-bg: var(--stepper-done-bg, var(--a-accent));
77
+ --stepper-item-done-border: var(--stepper-done-border, var(--a-accent));
78
+ --stepper-item-done-fg: var(--stepper-done-fg, var(--a-accent-fg));
79
+
80
+ --stepper-item-line: var(--stepper-line, var(--a-border-subtle));
81
+ --stepper-item-line-done: var(--stepper-line-done, var(--a-accent));
82
+ --stepper-item-line-size: var(--stepper-line-size, 2px);
83
+
84
+ --stepper-item-radius-full: var(--a-radius-full);
85
+ --stepper-item-gap-sm: var(--stepper-item-gap-sm, var(--a-space-2));
86
+ --stepper-item-pad-x: var(--stepper-pad-x, var(--a-space-4));
87
+ --stepper-item-pad-y: var(--stepper-pad-y, var(--a-space-6));
88
+ --stepper-item-offset-xs: var(--stepper-offset-xs, var(--a-space-1));
89
+ --stepper-item-min-width: var(--stepper-min-width, 5rem);
90
+
91
+ --stepper-item-label-weight: var(--a-weight-medium);
92
+ --stepper-item-label-size: var(--a-ui-size);
93
+ --stepper-item-label-fg: var(--a-fg);
94
+ --stepper-item-pending-fg: var(--a-fg-muted);
95
+ --stepper-item-desc-fg: var(--a-fg-subtle);
96
+ --stepper-item-desc-size: var(--a-ui-sm);
97
+
98
+ --stepper-item-icon-size: 0.625rem;
99
+ }
65
100
 
66
- stepper-item-ui {
67
- box-sizing: border-box;
68
- position: relative;
69
- display: block;
70
- counter-increment: step;
71
- flex: 1;
72
- min-width: var(--stepper-min-width);
73
- text-align: center;
74
- padding-top: calc(var(--stepper-size) + var(--stepper-item-gap-sm));
75
- padding-left: 0;
76
- padding-bottom: 0;
77
- }
101
+ :scope {
102
+ box-sizing: border-box;
103
+ position: relative;
104
+ display: block;
105
+ counter-increment: step;
106
+ flex: 1;
107
+ min-width: var(--stepper-item-min-width);
108
+ text-align: center;
109
+ padding-top: calc(var(--stepper-item-size) + var(--stepper-item-gap-sm));
110
+ padding-left: 0;
111
+ padding-bottom: 0;
112
+ }
78
113
 
79
- /* Numbered circle */
80
- stepper-item-ui::after {
81
- content: counter(step);
82
- position: absolute;
83
- top: 0;
84
- left: 50%;
85
- transform: translateX(-50%);
86
- width: var(--stepper-size);
87
- height: var(--stepper-size);
88
- border-radius: var(--stepper-radius-full);
89
- border: var(--stepper-border-size) solid var(--stepper-border);
90
- background: var(--stepper-bg);
91
- color: var(--stepper-fg);
92
- font-size: var(--stepper-font);
93
- font-weight: var(--stepper-weight);
94
- display: flex;
95
- align-items: center;
96
- justify-content: center;
97
- box-sizing: border-box;
98
- z-index: 1;
99
- }
114
+ /* Numbered circle */
115
+ :scope::after {
116
+ content: counter(step);
117
+ position: absolute;
118
+ top: 0;
119
+ left: 50%;
120
+ transform: translateX(-50%);
121
+ width: var(--stepper-item-size);
122
+ height: var(--stepper-item-size);
123
+ border-radius: var(--stepper-item-radius-full);
124
+ border: var(--stepper-item-border-size) solid var(--stepper-item-border);
125
+ background: var(--stepper-item-bg);
126
+ color: var(--stepper-item-fg);
127
+ font-size: var(--stepper-item-font);
128
+ font-weight: var(--stepper-item-weight);
129
+ display: flex;
130
+ align-items: center;
131
+ justify-content: center;
132
+ box-sizing: border-box;
133
+ z-index: 1;
134
+ }
100
135
 
101
- /* Connector line */
102
- stepper-item-ui::before {
103
- content: '';
104
- position: absolute;
105
- top: calc(var(--stepper-size) / 2);
106
- left: calc(50% + var(--stepper-size) / 2 + 2px);
107
- right: calc(-50% + var(--stepper-size) / 2 + 2px);
108
- height: var(--stepper-line-size);
109
- background: var(--stepper-line);
110
- }
136
+ /* Connector line */
137
+ :scope::before {
138
+ content: '';
139
+ position: absolute;
140
+ top: calc(var(--stepper-item-size) / 2);
141
+ left: calc(50% + var(--stepper-item-size) / 2 + 2px);
142
+ right: calc(-50% + var(--stepper-item-size) / 2 + 2px);
143
+ height: var(--stepper-item-line-size);
144
+ background: var(--stepper-item-line);
145
+ }
111
146
 
112
- stepper-item-ui[data-last]::before {
113
- display: none;
114
- }
147
+ :scope[data-last]::before {
148
+ display: none;
149
+ }
115
150
 
116
- /* Active state */
117
- stepper-item-ui[active]::after {
118
- border-color: var(--stepper-active-border);
119
- color: var(--stepper-active-fg);
120
- background: var(--stepper-active-bg);
121
- }
151
+ /* Active state */
152
+ :scope[status="active"]::after {
153
+ border-color: var(--stepper-item-active-border);
154
+ color: var(--stepper-item-active-fg);
155
+ background: var(--stepper-item-active-bg);
156
+ }
122
157
 
123
- stepper-item-ui[active] [slot="label"] {
124
- color: var(--stepper-label-fg);
125
- font-weight: var(--stepper-label-weight);
126
- }
158
+ :scope[status="active"] [slot="label"] {
159
+ color: var(--stepper-item-label-fg);
160
+ font-weight: var(--stepper-item-label-weight);
161
+ }
127
162
 
128
- /* Completed state — checkmark replaces number */
129
- stepper-item-ui[completed]::after {
130
- content: '\2713';
131
- background: var(--stepper-done-bg);
132
- border-color: var(--stepper-done-border);
133
- color: var(--stepper-done-fg);
134
- }
163
+ /* Completed state — checkmark replaces number */
164
+ :scope[status="completed"]::after {
165
+ content: '\2713';
166
+ background: var(--stepper-item-done-bg);
167
+ border-color: var(--stepper-item-done-border);
168
+ color: var(--stepper-item-done-fg);
169
+ }
135
170
 
136
- stepper-item-ui[completed]::before {
137
- background: var(--stepper-line-done);
138
- }
171
+ :scope[status="completed"]::before {
172
+ background: var(--stepper-item-line-done);
173
+ }
139
174
 
140
- stepper-item-ui[completed] [slot="label"] {
141
- color: var(--stepper-label-fg);
142
- }
175
+ :scope[status="completed"] [slot="label"] {
176
+ color: var(--stepper-item-label-fg);
177
+ }
143
178
 
144
- /* Pending label */
145
- stepper-item-ui:not([active]):not([completed]) [slot="label"] {
146
- color: var(--stepper-pending-fg);
147
- }
179
+ /* Pending label */
180
+ :scope:not([status="active"]):not([status="completed"]) [slot="label"] {
181
+ color: var(--stepper-item-pending-fg);
182
+ }
148
183
 
149
- /* Icon replaces number */
150
- stepper-item-ui:has([slot="icon"])::after {
151
- content: '';
152
- font-size: 0;
153
- }
184
+ /* Icon replaces number */
185
+ :scope:has([slot="icon"])::after {
186
+ content: '';
187
+ font-size: 0;
188
+ }
154
189
 
155
- stepper-item-ui [slot="icon"] {
156
- position: absolute;
157
- top: 0;
158
- left: 50%;
159
- transform: translateX(-50%);
160
- width: var(--stepper-size);
161
- height: var(--stepper-size);
162
- border-radius: var(--stepper-radius-full);
163
- border: var(--stepper-border-size) solid var(--stepper-border);
164
- background: var(--stepper-bg);
165
- display: flex;
166
- align-items: center;
167
- justify-content: center;
168
- --a-icon-size: 0.625rem;
169
- color: var(--stepper-fg);
170
- z-index: 1;
171
- }
190
+ :scope [slot="icon"] {
191
+ position: absolute;
192
+ top: 0;
193
+ left: 50%;
194
+ transform: translateX(-50%);
195
+ width: var(--stepper-item-size);
196
+ height: var(--stepper-item-size);
197
+ border-radius: var(--stepper-item-radius-full);
198
+ border: var(--stepper-item-border-size) solid var(--stepper-item-border);
199
+ background: var(--stepper-item-bg);
200
+ display: flex;
201
+ align-items: center;
202
+ justify-content: center;
203
+ --a-icon-size: var(--stepper-item-icon-size);
204
+ color: var(--stepper-item-fg);
205
+ z-index: 1;
206
+ }
172
207
 
173
- stepper-item-ui[active] [slot="icon"] {
174
- border-color: var(--stepper-active-border);
175
- color: var(--stepper-active-fg);
176
- background: var(--stepper-active-bg);
177
- }
208
+ :scope[status="active"] [slot="icon"] {
209
+ border-color: var(--stepper-item-active-border);
210
+ color: var(--stepper-item-active-fg);
211
+ background: var(--stepper-item-active-bg);
212
+ }
178
213
 
179
- stepper-item-ui[completed] [slot="icon"] {
180
- background: var(--stepper-done-bg);
181
- border-color: var(--stepper-done-border);
182
- color: var(--stepper-done-fg);
183
- }
214
+ :scope[status="completed"] [slot="icon"] {
215
+ background: var(--stepper-item-done-bg);
216
+ border-color: var(--stepper-item-done-border);
217
+ color: var(--stepper-item-done-fg);
218
+ }
184
219
 
185
- /* ── Content slots ── */
220
+ /* ── Content slots ── */
186
221
 
187
- stepper-item-ui [slot="label"] {
188
- display: block;
189
- font-weight: var(--stepper-label-weight);
190
- font-size: var(--stepper-label-size);
191
- line-height: 1.4;
192
- color: var(--stepper-label-fg);
193
- min-width: 0;
194
- overflow-wrap: break-word;
195
- }
222
+ :scope [slot="label"] {
223
+ display: block;
224
+ font-weight: var(--stepper-item-label-weight);
225
+ font-size: var(--stepper-item-label-size);
226
+ line-height: 1.4;
227
+ color: var(--stepper-item-label-fg);
228
+ min-width: 0;
229
+ overflow-wrap: break-word;
230
+ }
196
231
 
197
- stepper-item-ui [slot="description"] {
198
- display: block;
199
- margin-top: var(--stepper-offset-xs);
200
- color: var(--stepper-desc-fg);
201
- font-size: var(--stepper-desc-size);
202
- line-height: 1.5;
203
- }
232
+ :scope [slot="description"] {
233
+ display: block;
234
+ margin-top: var(--stepper-item-offset-xs);
235
+ color: var(--stepper-item-desc-fg);
236
+ font-size: var(--stepper-item-desc-size);
237
+ line-height: 1.5;
238
+ }
204
239
 
205
- stepper-item-ui [slot]:empty {
206
- display: none;
240
+ :scope [slot]:empty {
241
+ display: none;
242
+ }
207
243
  }
208
244
 
209
- /* ── Vertical orientation ── */
245
+ /* ── Vertical orientation rules — must reach across stepper-ui →
246
+ stepper-item-ui boundary, kept outside @scope. ── */
210
247
 
211
248
  stepper-ui[orientation="vertical"] > stepper-item-ui {
212
249
  flex: none;
213
250
  text-align: left;
214
251
  padding-top: 0;
215
- padding-left: calc(var(--stepper-size) + var(--stepper-pad-x));
216
- padding-bottom: var(--stepper-pad-y);
217
- min-height: var(--stepper-size);
252
+ padding-left: calc(var(--stepper-item-size) + var(--stepper-item-pad-x));
253
+ padding-bottom: var(--stepper-item-pad-y);
254
+ min-height: var(--stepper-item-size);
218
255
  }
219
256
 
220
257
  stepper-ui[orientation="vertical"] > stepper-item-ui::after {
@@ -224,11 +261,11 @@ stepper-ui[orientation="vertical"] > stepper-item-ui::after {
224
261
  }
225
262
 
226
263
  stepper-ui[orientation="vertical"] > stepper-item-ui::before {
227
- left: calc(var(--stepper-size) / 2 - 1px);
264
+ left: calc(var(--stepper-item-size) / 2 - 1px);
228
265
  transform: none;
229
- top: calc(var(--stepper-size) + var(--stepper-offset-xs));
266
+ top: calc(var(--stepper-item-size) + var(--stepper-item-offset-xs));
230
267
  right: auto;
231
- width: var(--stepper-line-size);
268
+ width: var(--stepper-item-line-size);
232
269
  height: auto;
233
270
  bottom: 0;
234
271
  }
@@ -78,8 +78,11 @@ class AdiaStepperItem extends AdiaElement {
78
78
  text: { type: String, default: '', reflect: true },
79
79
  description: { type: String, default: '', reflect: true },
80
80
  icon: { type: String, default: '', reflect: true },
81
- completed: { type: Boolean, default: false, reflect: true },
82
- active: { type: Boolean, default: false, reflect: true },
81
+ // `status` is the canonical stage-progress shape across timeline-item,
82
+ // stepper-item, pipeline-status, agent-reasoning. Mutually exclusive
83
+ // values prevent the `active && completed` footgun the prior multi-
84
+ // Boolean shape allowed.
85
+ status: { type: String, default: 'idle', reflect: true },
83
86
  };
84
87
 
85
88
  static template = () => null;