@adia-ai/web-components 0.6.37 → 0.6.39

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 (73) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/components/accordion/accordion-item.a2ui.json +3 -0
  3. package/components/accordion/accordion-item.yaml +5 -0
  4. package/components/action-list/action-item.a2ui.json +5 -1
  5. package/components/action-list/action-item.yaml +7 -0
  6. package/components/card/card.a2ui.json +17 -1
  7. package/components/card/card.yaml +24 -1
  8. package/components/date-range-picker/date-range-picker.css +4 -4
  9. package/components/datetime-picker/datetime-picker.css +3 -3
  10. package/components/demo-toggle/demo-toggle.css +11 -11
  11. package/components/empty-state/empty-state.a2ui.json +9 -0
  12. package/components/empty-state/empty-state.yaml +15 -0
  13. package/components/feed/feed-item.a2ui.json +5 -0
  14. package/components/feed/feed-item.yaml +10 -0
  15. package/components/feed/feed.css +2 -2
  16. package/components/field/field.a2ui.json +6 -0
  17. package/components/field/field.css +18 -18
  18. package/components/field/field.yaml +10 -0
  19. package/components/heatmap/heatmap.css +1 -1
  20. package/components/index.js +3 -0
  21. package/components/inline-edit/inline-edit.a2ui.json +159 -0
  22. package/components/inline-edit/inline-edit.class.js +184 -0
  23. package/components/inline-edit/inline-edit.css +62 -0
  24. package/components/inline-edit/inline-edit.d.ts +52 -0
  25. package/components/inline-edit/inline-edit.js +12 -0
  26. package/components/inline-edit/inline-edit.yaml +125 -0
  27. package/components/inline-message/inline-message.css +1 -1
  28. package/components/list/list-item.a2ui.json +11 -1
  29. package/components/list/list-item.yaml +19 -0
  30. package/components/list/list.css +36 -6
  31. package/components/list-window/list-window.css +4 -4
  32. package/components/mark/mark.a2ui.json +109 -0
  33. package/components/mark/mark.class.js +22 -0
  34. package/components/mark/mark.css +39 -0
  35. package/components/mark/mark.d.ts +27 -0
  36. package/components/mark/mark.js +12 -0
  37. package/components/mark/mark.yaml +87 -0
  38. package/components/modal/modal.a2ui.json +9 -0
  39. package/components/modal/modal.css +8 -8
  40. package/components/modal/modal.yaml +14 -0
  41. package/components/nav-group/nav-group.a2ui.json +3 -0
  42. package/components/nav-group/nav-group.yaml +5 -0
  43. package/components/nav-item/nav-item.a2ui.json +3 -0
  44. package/components/nav-item/nav-item.yaml +5 -0
  45. package/components/option-card/option-card.css +9 -9
  46. package/components/segmented/segmented.class.js +10 -2
  47. package/components/select/select.a2ui.json +3 -0
  48. package/components/select/select.css +5 -5
  49. package/components/select/select.yaml +5 -0
  50. package/components/slider/slider.a2ui.json +6 -0
  51. package/components/slider/slider.yaml +10 -0
  52. package/components/stat/stat.css +18 -14
  53. package/components/stepper/stepper-item.a2ui.json +3 -0
  54. package/components/stepper/stepper-item.yaml +5 -0
  55. package/components/timeline/timeline-item.a2ui.json +8 -1
  56. package/components/timeline/timeline-item.yaml +12 -0
  57. package/components/timeline/timeline.css +19 -19
  58. package/components/tour/tour-step.a2ui.json +92 -0
  59. package/components/tour/tour-step.yaml +84 -0
  60. package/components/tour/tour.a2ui.json +172 -0
  61. package/components/tour/tour.class.js +309 -0
  62. package/components/tour/tour.css +135 -0
  63. package/components/tour/tour.d.ts +78 -0
  64. package/components/tour/tour.js +13 -0
  65. package/components/tour/tour.yaml +161 -0
  66. package/components/tree/tree-item.a2ui.json +5 -1
  67. package/components/tree/tree-item.yaml +7 -0
  68. package/components/tree/tree.a2ui.json +3 -0
  69. package/components/tree/tree.yaml +5 -0
  70. package/dist/web-components.min.css +1 -1
  71. package/dist/web-components.min.js +88 -74
  72. package/package.json +1 -1
  73. package/styles/components.css +3 -0
@@ -160,9 +160,9 @@
160
160
  }
161
161
 
162
162
  /* Caret color is held against button-ui's stronger cascade by chaining
163
- :scope > [slot="trigger"] > [slot="caret"] — matches at the same
163
+ :scope [slot="trigger"] [slot="caret"] — matches at the same
164
164
  specificity as button-ui's own slot rules without !important. */
165
- :scope > [slot="trigger"] > [slot="caret"] {
165
+ :scope [slot="trigger"] [slot="caret"] {
166
166
  color: var(--select-caret-fg, var(--select-caret-fg-default));
167
167
  flex-shrink: 0;
168
168
  }
@@ -179,7 +179,7 @@
179
179
  background: var(--select-ghost-bg-hover, var(--select-ghost-bg-hover-default));
180
180
  color: var(--select-fg, var(--select-fg-default));
181
181
  }
182
- :scope[variant="ghost"] > [slot="trigger"]:hover > [slot="caret"] {
182
+ :scope[variant="ghost"] [slot="trigger"]:hover [slot="caret"] {
183
183
  color: var(--select-fg-subtle, var(--select-fg-subtle-default));
184
184
  }
185
185
 
@@ -188,7 +188,7 @@
188
188
  active. Layout switches from inline-text trigger to wrap-flex chip row.
189
189
  Tag-ui chips inside [data-chips] inherit the host's tag-ui token set;
190
190
  the +more pill is a CSS-only button styled to match. */
191
- :scope[data-multi-chips] > [slot="trigger"] {
191
+ :scope[data-multi-chips] [slot="trigger"] {
192
192
  flex-wrap: wrap;
193
193
  align-items: center;
194
194
  gap: var(--a-space-1);
@@ -381,7 +381,7 @@ select-ui[divider] [role="group"] + [role="group"] {
381
381
 
382
382
  /* ── Hint (§184, v0.5.5, FEEDBACK-08 §7) ──
383
383
  Caption beneath the trigger; wired to aria-describedby on the host. */
384
- select-ui > [slot="hint"] {
384
+ select-ui [slot="hint"] {
385
385
  display: block;
386
386
  margin-top: var(--select-hint-mt, var(--a-space-1));
387
387
  font-size: var(--select-hint-size, var(--a-ui-xs));
@@ -220,6 +220,11 @@ slots:
220
220
  description: Popover container for options (role=listbox)
221
221
  trigger:
222
222
  description: Button that opens the listbox
223
+ hint:
224
+ description: >-
225
+ Override slot for hint markup richer than the plain [hint] attribute
226
+ string (inline links, code spans). Renders beneath the trigger at
227
+ body-subtle typography. Mutually exclusive with [hint].
223
228
  states:
224
229
  - name: idle
225
230
  description: Default, ready for interaction.
@@ -133,6 +133,12 @@
133
133
  "embed"
134
134
  ],
135
135
  "slots": {
136
+ "header": {
137
+ "description": "Wholesale override of the stamped label + value-readout header row. Use only when full custom-header markup is needed; otherwise prefer the granular `label` / `value` slots and the [label] attribute."
138
+ },
139
+ "hint": {
140
+ "description": "Override slot for hint markup richer than the plain [hint] attribute string (inline links, code spans). Renders beneath the slider at body-subtle typography. Mutually exclusive with [hint]."
141
+ },
136
142
  "input": {
137
143
  "description": "Native range input element"
138
144
  },
@@ -96,6 +96,16 @@ slots:
96
96
  description: Label element above the slider
97
97
  value:
98
98
  description: Current value display
99
+ header:
100
+ description: >-
101
+ Wholesale override of the stamped label + value-readout header row.
102
+ Use only when full custom-header markup is needed; otherwise prefer
103
+ the granular `label` / `value` slots and the [label] attribute.
104
+ hint:
105
+ description: >-
106
+ Override slot for hint markup richer than the plain [hint] attribute
107
+ string (inline links, code spans). Renders beneath the slider at
108
+ body-subtle typography. Mutually exclusive with [hint].
99
109
  states:
100
110
  - name: idle
101
111
  description: Default, ready for interaction.
@@ -38,34 +38,38 @@
38
38
 
39
39
  /* ── Chart slot (inline sparkline) ──
40
40
  When an author adds <chart-ui slot="chart"> (or any sparkline-shape
41
- child), the grid reflows so the chart occupies the right column
42
- across the value + change rows, fixed to the stat's right edge.
43
- Hero number and chart read as a single visual unit. */
41
+ child), the grid reflows so the chart sits in the value row and
42
+ ends at the value's baseline hero number and chart read as one
43
+ visual unit, the chart "resting on" the value text. */
44
44
  :scope:has([slot="chart"]) {
45
45
  grid-template-columns: minmax(0, 1fr) minmax(5rem, 40%);
46
46
  grid-template-areas:
47
47
  "label icon"
48
48
  "value chart"
49
- "change chart";
49
+ "change .";
50
50
  align-items: end;
51
51
  }
52
52
 
53
- /* Cap the chart slot at a sparkline-appropriate size otherwise the
54
- chart's default aspect ratio stretches the row heights and bloats
55
- the whole card. Consumers who want a taller inline chart can
56
- override --stat-chart-max-height on the host. Uses `chart-ui[slot]`
57
- compound selector to beat chart-ui's own `:scope { max-height: 28rem }`
58
- (specificity 0,1,1 beats 0,0,1). `[slot="chart"]` alone is (0,1,0)
59
- — enough on paper but empirically losing to chart-ui's own scope in
60
- practice; the type selector makes it explicit. */
53
+ /* Chart cell bottom-aligned to the value row's baseline; aspect
54
+ ratio 4:3 (width:height) keeps it readable as a small inline chart
55
+ rather than a thin sparkline rail. Consumers override via
56
+ --stat-chart-aspect. */
61
57
  [slot="chart"] {
62
58
  grid-area: chart;
63
- align-self: center;
59
+ align-self: end;
64
60
  min-width: 0;
65
61
  width: 100%;
62
+ aspect-ratio: var(--stat-chart-aspect, 4 / 3);
66
63
  }
67
64
  chart-ui[slot="chart"] {
68
- max-height: var(--stat-chart-max-height, 3rem);
65
+ height: 100%;
66
+ }
67
+
68
+ /* When chart is present, value must NOT span into the chart column
69
+ (its default `grid-column: 1 / -1` would overlap the chart cell and
70
+ misalign both). Confine it to col 1. */
71
+ :scope:has([slot="chart"]) [slot="value"] {
72
+ grid-column: 1;
69
73
  }
70
74
 
71
75
  /* ── Label (eyebrow) ── */
@@ -70,6 +70,9 @@
70
70
  "description": {
71
71
  "description": "Custom description content; falls through to `[description]` prop if not slotted."
72
72
  },
73
+ "icon": {
74
+ "description": "Override the step-status glyph with a custom slotted element. By default the step renders a numeral / check / x indicator based on [status]; slot an `<icon-ui>` or image to customize."
75
+ },
73
76
  "label": {
74
77
  "description": "Custom label content; falls through to `[text]` prop if not slotted."
75
78
  }
@@ -44,6 +44,11 @@ slots:
44
44
  description: Custom label content; falls through to `[text]` prop if not slotted.
45
45
  description:
46
46
  description: Custom description content; falls through to `[description]` prop if not slotted.
47
+ icon:
48
+ description: >-
49
+ Override the step-status glyph with a custom slotted element. By default
50
+ the step renders a numeral / check / x indicator based on [status];
51
+ slot an `<icon-ui>` or image to customize.
47
52
 
48
53
  keywords:
49
54
  - stepper-item
@@ -75,7 +75,14 @@
75
75
  "FeedItem",
76
76
  "Stepper"
77
77
  ],
78
- "slots": {},
78
+ "slots": {
79
+ "description": {
80
+ "description": "Override slot for rich description markup (inline links, code spans, embedded badges). Renders beneath the primary text at body-subtle typography."
81
+ },
82
+ "icon": {
83
+ "description": "Override the [icon] glyph with a custom slotted element. Use for branded icons, avatars, or non-Phosphor sources. Mutually exclusive with the [icon] attribute."
84
+ }
85
+ },
79
86
  "states": [],
80
87
  "status": "stable",
81
88
  "synonyms": {
@@ -47,6 +47,18 @@ props:
47
47
  type: boolean
48
48
  default: false
49
49
 
50
+ slots:
51
+ icon:
52
+ description: >-
53
+ Override the [icon] glyph with a custom slotted element. Use for
54
+ branded icons, avatars, or non-Phosphor sources. Mutually exclusive
55
+ with the [icon] attribute.
56
+ description:
57
+ description: >-
58
+ Override slot for rich description markup (inline links, code spans,
59
+ embedded badges). Renders beneath the primary text at body-subtle
60
+ typography.
61
+
50
62
  keywords:
51
63
  - timeline-item
52
64
  - timeline-row
@@ -232,9 +232,9 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
232
232
 
233
233
  /* ═══════ Icon mode — icon-ui in [slot="icon"] replaces the dot ═══════ */
234
234
 
235
- :scope:has(> [slot="icon"])::before { display: none; }
235
+ :scope:has([slot="icon"])::before { display: none; }
236
236
 
237
- :scope > [slot="icon"] {
237
+ :scope [slot="icon"] {
238
238
  grid-column: marker;
239
239
  grid-row: 1;
240
240
  justify-self: center;
@@ -253,19 +253,19 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
253
253
  box-sizing: border-box;
254
254
  }
255
255
 
256
- :scope[variant="success"] > [slot="icon"] { background: var(--timeline-item-icon-bg-success); color: var(--timeline-item-icon-fg-success); }
257
- :scope[variant="accent"] > [slot="icon"] { background: var(--timeline-item-icon-bg-accent); color: var(--timeline-item-icon-fg-accent); }
258
- :scope[variant="warning"] > [slot="icon"] { background: var(--timeline-item-icon-bg-warning); color: var(--timeline-item-icon-fg-warning); }
259
- :scope[variant="danger"] > [slot="icon"] { background: var(--timeline-item-icon-bg-danger); color: var(--timeline-item-icon-fg-danger); }
256
+ :scope[variant="success"] [slot="icon"] { background: var(--timeline-item-icon-bg-success); color: var(--timeline-item-icon-fg-success); }
257
+ :scope[variant="accent"] [slot="icon"] { background: var(--timeline-item-icon-bg-accent); color: var(--timeline-item-icon-fg-accent); }
258
+ :scope[variant="warning"] [slot="icon"] { background: var(--timeline-item-icon-bg-warning); color: var(--timeline-item-icon-fg-warning); }
259
+ :scope[variant="danger"] [slot="icon"] { background: var(--timeline-item-icon-bg-danger); color: var(--timeline-item-icon-fg-danger); }
260
260
 
261
261
  /* Push connector line past the icon circle */
262
- :scope:has(> [slot="icon"])::after {
262
+ :scope:has([slot="icon"])::after {
263
263
  top: calc((1.4em + var(--timeline-item-icon-size)) / 2 + 2px);
264
264
  }
265
265
 
266
266
  /* ═══════ Content slots ═══════ */
267
267
 
268
- :scope > [slot="label"] {
268
+ :scope [slot="label"] {
269
269
  grid-column: content;
270
270
  grid-row: 1;
271
271
  font-weight: var(--timeline-item-label-weight);
@@ -276,11 +276,11 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
276
276
  min-width: 0;
277
277
  }
278
278
 
279
- :scope[status="completed"] > [slot="label"] {
279
+ :scope[status="completed"] [slot="label"] {
280
280
  color: var(--timeline-item-label-fg-muted);
281
281
  }
282
282
 
283
- :scope > [slot="description"] {
283
+ :scope [slot="description"] {
284
284
  grid-column: content / -1;
285
285
  grid-row: 2;
286
286
  color: var(--timeline-item-desc-fg);
@@ -289,7 +289,7 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
289
289
  margin-top: var(--a-space-0-5);
290
290
  }
291
291
 
292
- :scope > [slot="time"] {
292
+ :scope [slot="time"] {
293
293
  grid-column: aside;
294
294
  grid-row: 1;
295
295
  color: var(--timeline-item-time-fg);
@@ -307,7 +307,7 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
307
307
 
308
308
  /* ═══════ Outcomes — nested sub-rows ═══════ */
309
309
 
310
- :scope > [slot="outcomes"] {
310
+ :scope [slot="outcomes"] {
311
311
  grid-column: content / -1;
312
312
  grid-row: 3;
313
313
  margin: var(--a-space-1) 0 0 0;
@@ -322,16 +322,16 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
322
322
  animation: tl-fade var(--timeline-item-duration) var(--timeline-item-easing);
323
323
  }
324
324
 
325
- :scope > [slot="outcomes"][hidden] { display: none; }
325
+ :scope [slot="outcomes"][hidden] { display: none; }
326
326
 
327
- :scope > [slot="outcomes"] > li {
327
+ :scope [slot="outcomes"] > li {
328
328
  position: relative;
329
329
  padding-left: var(--timeline-item-outcome-indent);
330
330
  overflow-wrap: break-word;
331
331
  min-width: 0;
332
332
  }
333
333
 
334
- :scope > [slot="outcomes"] > li::before {
334
+ :scope [slot="outcomes"] > li::before {
335
335
  content: '';
336
336
  position: absolute;
337
337
  left: calc((var(--timeline-item-outcome-indent) - var(--timeline-item-subdot-size)) / 2);
@@ -373,7 +373,7 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
373
373
  }
374
374
 
375
375
  /* Reserve room so the time isn't overlapped by the chevron */
376
- :scope:has(> [data-timeline-toggle]) > [slot="time"] {
376
+ :scope:has(> [data-timeline-toggle]) [slot="time"] {
377
377
  margin-inline-end: var(--timeline-item-toggle-time-margin);
378
378
  }
379
379
 
@@ -416,9 +416,9 @@ timeline-ui[orientation="horizontal"] > timeline-item-ui::after {
416
416
  height: var(--timeline-line-size, var(--timeline-line-size-default));
417
417
  }
418
418
 
419
- timeline-ui[orientation="horizontal"] > timeline-item-ui > [slot="label"],
420
- timeline-ui[orientation="horizontal"] > timeline-item-ui > [slot="description"],
421
- timeline-ui[orientation="horizontal"] > timeline-item-ui > [slot="time"] {
419
+ timeline-ui[orientation="horizontal"] > timeline-item-ui [slot="label"],
420
+ timeline-ui[orientation="horizontal"] > timeline-item-ui [slot="description"],
421
+ timeline-ui[orientation="horizontal"] > timeline-item-ui [slot="time"] {
422
422
  grid-column: auto;
423
423
  grid-row: auto;
424
424
  margin-top: var(--a-space-1);
@@ -0,0 +1,92 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/TourStep.json",
4
+ "title": "TourStep",
5
+ "description": "Single step inside a `<tour-ui>` walkthrough. Declares a target\nelement (via CSS selector), a title, and body content. The host\n`<tour-ui>` reads these declaratively and renders them in the\npopover as the user advances through the tour.\n\n`<tour-step>` itself renders nothing — it's a data carrier (light\nDOM source of truth). The tour-ui orchestrator clones the body\ncontent into the spotlight popover when the step becomes active.\n",
6
+ "type": "object",
7
+ "allOf": [
8
+ {
9
+ "$ref": "common_types.json#/$defs/ComponentCommon"
10
+ },
11
+ {
12
+ "$ref": "common_types.json#/$defs/CatalogComponentCommon"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "title": {
17
+ "description": "Step heading rendered in the popover.",
18
+ "type": "string",
19
+ "default": ""
20
+ },
21
+ "component": {
22
+ "const": "TourStep"
23
+ },
24
+ "placement": {
25
+ "description": "Preferred popover placement relative to the target. Same vocabulary\nas `core/anchor.js` (`top`, `bottom`, `left`, `right`,\n`bottom-start`, `bottom-end`, etc.). Auto-flips on viewport overflow\nvia position-try-fallbacks.\n",
26
+ "type": "string",
27
+ "enum": [
28
+ "top",
29
+ "bottom",
30
+ "left",
31
+ "right",
32
+ "top-start",
33
+ "top-end",
34
+ "bottom-start",
35
+ "bottom-end",
36
+ "left-start",
37
+ "left-end",
38
+ "right-start",
39
+ "right-end"
40
+ ],
41
+ "default": "bottom"
42
+ },
43
+ "target": {
44
+ "description": "CSS selector for the element to spotlight when this step is\nactive. Resolved via `document.querySelector(target)` at step\nactivation time. If the selector matches nothing, the spotlight\nfalls back to viewport-center and the popover anchors to the\npage (no halo cutout).\n",
45
+ "type": "string",
46
+ "default": ""
47
+ }
48
+ },
49
+ "required": [
50
+ "component"
51
+ ],
52
+ "unevaluatedProperties": false,
53
+ "x-adiaui": {
54
+ "anti_patterns": [
55
+ {
56
+ "fix": "<tour-step target=\"#dashboard\">",
57
+ "why": "target is a CSS selector — bare \"dashboard\" doesn't match.",
58
+ "wrong": "<tour-step target=\"dashboard\">"
59
+ }
60
+ ],
61
+ "category": "feedback",
62
+ "composes": [],
63
+ "events": {},
64
+ "examples": [],
65
+ "keywords": [
66
+ "tour-step",
67
+ "walkthrough-step",
68
+ "guided-step"
69
+ ],
70
+ "name": "UITourStep",
71
+ "related": [
72
+ "tour"
73
+ ],
74
+ "slots": {
75
+ "default": {
76
+ "description": "Body content rendered inside the step popover (plain text or inline HTML)."
77
+ }
78
+ },
79
+ "states": [],
80
+ "status": "stable",
81
+ "synonyms": {
82
+ "step": [
83
+ "tour-step",
84
+ "walkthrough-step"
85
+ ]
86
+ },
87
+ "tag": "tour-step-ui",
88
+ "tokens": {},
89
+ "traits": [],
90
+ "version": 1
91
+ }
92
+ }
@@ -0,0 +1,84 @@
1
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
2
+ name: UITourStep
3
+ tag: tour-step-ui
4
+ status: stable
5
+ component: TourStep
6
+ category: feedback
7
+ version: 1
8
+ description: |
9
+ Single step inside a `<tour-ui>` walkthrough. Declares a target
10
+ element (via CSS selector), a title, and body content. The host
11
+ `<tour-ui>` reads these declaratively and renders them in the
12
+ popover as the user advances through the tour.
13
+
14
+ `<tour-step>` itself renders nothing — it's a data carrier (light
15
+ DOM source of truth). The tour-ui orchestrator clones the body
16
+ content into the spotlight popover when the step becomes active.
17
+ props:
18
+ target:
19
+ description: |
20
+ CSS selector for the element to spotlight when this step is
21
+ active. Resolved via `document.querySelector(target)` at step
22
+ activation time. If the selector matches nothing, the spotlight
23
+ falls back to viewport-center and the popover anchors to the
24
+ page (no halo cutout).
25
+ type: string
26
+ default: ''
27
+ reflect: true
28
+ title:
29
+ description: Step heading rendered in the popover.
30
+ type: string
31
+ default: ''
32
+ reflect: true
33
+ placement:
34
+ description: |
35
+ Preferred popover placement relative to the target. Same vocabulary
36
+ as `core/anchor.js` (`top`, `bottom`, `left`, `right`,
37
+ `bottom-start`, `bottom-end`, etc.). Auto-flips on viewport overflow
38
+ via position-try-fallbacks.
39
+ type: string
40
+ default: bottom
41
+ enum:
42
+ - top
43
+ - bottom
44
+ - left
45
+ - right
46
+ - top-start
47
+ - top-end
48
+ - bottom-start
49
+ - bottom-end
50
+ - left-start
51
+ - left-end
52
+ - right-start
53
+ - right-end
54
+ reflect: true
55
+ events: {}
56
+ slots:
57
+ default:
58
+ description: 'Body content rendered inside the step popover (plain text or inline HTML).'
59
+ states: []
60
+ traits: []
61
+ tokens: {}
62
+ a2ui:
63
+ rules:
64
+ - rule: 'Single step inside <tour-ui>. Declares target (CSS selector) + title + body content.'
65
+ reason: 'Data carrier for tour-ui.'
66
+ - rule: 'target is a CSS selector (e.g. "#dashboard", ".filters button"), NOT a bare ID. Use the # prefix.'
67
+ reason: 'Selector contract.'
68
+ - rule: 'Renders nothing on its own — tour-ui orchestrates the popover stamping when the step becomes active.'
69
+ reason: 'Stamp-nothing wrapper.'
70
+ anti_patterns:
71
+ - wrong: '<tour-step target="dashboard">'
72
+ why: 'target is a CSS selector — bare "dashboard" doesn''t match.'
73
+ fix: '<tour-step target="#dashboard">'
74
+ examples: []
75
+ keywords:
76
+ - tour-step
77
+ - walkthrough-step
78
+ - guided-step
79
+ synonyms:
80
+ step:
81
+ - tour-step
82
+ - walkthrough-step
83
+ related:
84
+ - tour
@@ -0,0 +1,172 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/Tour.json",
4
+ "title": "Tour",
5
+ "description": "Spotlight-driven product tour / guided walkthrough. Hosts a sequence\nof `<tour-step>` children, each targeting an element via CSS selector.\nWhen active, dims the page with a scrim, cuts a \"hole\" around the\ncurrent step's target, and renders a popover next to it with step\ncontent + Skip / Previous / Next navigation.\n\nUse for first-run onboarding tours, feature introductions after a\nrelease, and inline walkthroughs the user opts into (\"Take the tour\").\nDistinct from `<onboarding-checklist-ui>` (persistent todo-list of\nsetup steps the user works through at their own pace) and from\n`<tooltip-ui>` (single hover hint with no orchestration).\n\nArchitecture: tour-ui is a behavioral wrapper (`display: contents`)\nthat reads target / title / content from `<tour-step>` children. On\nstart, mounts a spotlight + popover surface into `document.body`\n(top-layer via Popover API). The spotlight is a transparent\nposition:fixed element with a huge box-shadow that produces the\ndimmed scrim outside its bounds (single-element backdrop, no clip-path\nor SVG mask needed). The popover is anchored to the target via the\nsame `core/anchor.js` pattern used by menu-ui / context-menu-ui /\npopover-ui.\n",
6
+ "type": "object",
7
+ "allOf": [
8
+ {
9
+ "$ref": "common_types.json#/$defs/ComponentCommon"
10
+ },
11
+ {
12
+ "$ref": "common_types.json#/$defs/CatalogComponentCommon"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "active": {
17
+ "description": "Whether the tour is currently running. Setting to `true` mounts\nthe spotlight + popover; setting to `false` tears down.\n",
18
+ "type": "boolean",
19
+ "default": false
20
+ },
21
+ "auto-start": {
22
+ "description": "Start the tour automatically when the element connects. Useful for\nfirst-run flows gated by a storage flag on the consumer side.\n",
23
+ "type": "boolean",
24
+ "default": false
25
+ },
26
+ "component": {
27
+ "const": "Tour"
28
+ },
29
+ "step": {
30
+ "description": "Current step index (0-based). Setting this property advances the\ntour to that step (updating spotlight + popover position).\n",
31
+ "type": "number",
32
+ "default": 0
33
+ },
34
+ "storage-key": {
35
+ "description": "Optional localStorage key. When set, the tour records its\ncompletion state (`\"done\"`) to that key on finish/skip — and\nrefuses to auto-start on subsequent loads if the key is \"done\".\nUseful for \"show this tour once per user\" flows.\n",
36
+ "type": "string",
37
+ "default": ""
38
+ }
39
+ },
40
+ "required": [
41
+ "component"
42
+ ],
43
+ "unevaluatedProperties": false,
44
+ "x-adiaui": {
45
+ "anti_patterns": [
46
+ {
47
+ "fix": "<tour-ui><tour-step target=\"#dashboard\" title=\"Dashboard\">Tour the dashboard…</tour-step>…</tour-ui>",
48
+ "why": "Bare divs have no target / title — tour-ui can't position the spotlight.",
49
+ "wrong": "<tour-ui><div>step 1 content</div><div>step 2 content</div></tour-ui>"
50
+ },
51
+ {
52
+ "fix": "<tour-step target=\"#dashboard\">",
53
+ "why": "target is a CSS selector — bare \"dashboard\" matches a <dashboard> element, NOT an id; use the # prefix.",
54
+ "wrong": "<tour-step target=\"dashboard\">"
55
+ }
56
+ ],
57
+ "category": "feedback",
58
+ "composes": [
59
+ "button-ui",
60
+ "tour-step-ui"
61
+ ],
62
+ "events": {
63
+ "tour-finish": {
64
+ "description": "Fired when the user completes the last step. detail = { totalSteps }. Bubbles."
65
+ },
66
+ "tour-skip": {
67
+ "description": "Fired when the user skips the tour mid-way. detail = { step, totalSteps }. Bubbles."
68
+ },
69
+ "tour-start": {
70
+ "description": "Fired when the tour starts (after spotlight + popover mount). detail = { step }. Bubbles."
71
+ },
72
+ "tour-step-change": {
73
+ "description": "Fired when the active step changes. detail = { from, to, totalSteps }. Bubbles."
74
+ }
75
+ },
76
+ "examples": [
77
+ {
78
+ "description": "A 3-step product tour anchored to selector-resolved elements.",
79
+ "a2ui": "[\n { \"id\": \"tour\", \"component\": \"Tour\", \"auto-start\": true, \"children\": [\"s1\", \"s2\", \"s3\"] },\n { \"id\": \"s1\", \"component\": \"TourStep\", \"target\": \"#dashboard\", \"title\": \"Your dashboard\", \"textContent\": \"Here's where you'll see your latest activity.\" },\n { \"id\": \"s2\", \"component\": \"TourStep\", \"target\": \"#filters\", \"title\": \"Filters\", \"textContent\": \"Narrow results by status, owner, or date.\" },\n { \"id\": \"s3\", \"component\": \"TourStep\", \"target\": \"#export\", \"title\": \"Export\", \"textContent\": \"Download a CSV of the current view.\" }\n]\n",
80
+ "name": "basic-tour"
81
+ }
82
+ ],
83
+ "keywords": [
84
+ "tour",
85
+ "product-tour",
86
+ "walkthrough",
87
+ "guided-tour",
88
+ "spotlight",
89
+ "coachmark",
90
+ "feature-introduction"
91
+ ],
92
+ "name": "UITour",
93
+ "related": [
94
+ "tooltip",
95
+ "popover",
96
+ "onboarding-checklist"
97
+ ],
98
+ "slots": {
99
+ "default": {
100
+ "description": "<tour-step> children — each declares target + title + body content."
101
+ }
102
+ },
103
+ "states": [
104
+ {
105
+ "description": "Tour is dormant; no scrim / popover rendered.",
106
+ "name": "idle"
107
+ },
108
+ {
109
+ "description": "Tour is running; scrim dims the page, current target is spotlighted.",
110
+ "name": "active"
111
+ },
112
+ {
113
+ "description": "Last step reached (Done is shown instead of Next).",
114
+ "name": "complete"
115
+ }
116
+ ],
117
+ "status": "stable",
118
+ "synonyms": {
119
+ "spotlight": [
120
+ "coachmark",
121
+ "feature-highlight"
122
+ ],
123
+ "tour": [
124
+ "product-tour",
125
+ "guided-tour",
126
+ "walkthrough",
127
+ "feature-intro"
128
+ ]
129
+ },
130
+ "tag": "tour-ui",
131
+ "tokens": {
132
+ "--tour-popover-bg": {
133
+ "description": "Background of the step-content popover.",
134
+ "default": "var(--a-bg-subtle)"
135
+ },
136
+ "--tour-popover-border": {
137
+ "description": "Border color of the popover.",
138
+ "default": "var(--a-border-subtle)"
139
+ },
140
+ "--tour-popover-max-width": {
141
+ "description": "Maximum width of the popover.",
142
+ "default": "22rem"
143
+ },
144
+ "--tour-popover-min-width": {
145
+ "description": "Minimum width of the popover (so step text wraps reasonably).",
146
+ "default": "18rem"
147
+ },
148
+ "--tour-popover-radius": {
149
+ "description": "Border-radius of the popover.",
150
+ "default": "var(--a-radius-lg)"
151
+ },
152
+ "--tour-popover-shadow": {
153
+ "description": "Shadow of the popover.",
154
+ "default": "var(--a-shadow-lg)"
155
+ },
156
+ "--tour-scrim": {
157
+ "description": "Backdrop scrim color (everything outside the spotlight).",
158
+ "default": "var(--a-scrim-dialog)"
159
+ },
160
+ "--tour-spotlight-padding": {
161
+ "description": "Padding around the target bounding box (the spotlight's \"halo\").",
162
+ "default": "var(--a-space-2)"
163
+ },
164
+ "--tour-spotlight-radius": {
165
+ "description": "Border radius of the spotlight cutout.",
166
+ "default": "var(--a-radius-md)"
167
+ }
168
+ },
169
+ "traits": [],
170
+ "version": 1
171
+ }
172
+ }