@adia-ai/web-components 0.0.13 → 0.0.15
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/README.md +45 -3
- package/components/card/card.css +29 -0
- package/components/chart/chart.a2ui.json +43 -6
- package/components/chart/chart.css +224 -0
- package/components/chart/chart.js +1056 -31
- package/components/chart/chart.yaml +62 -6
- package/components/chart-legend/chart-legend.a2ui.json +139 -0
- package/components/chart-legend/chart-legend.css +124 -0
- package/components/chart-legend/chart-legend.js +185 -0
- package/components/chart-legend/chart-legend.yaml +133 -0
- package/components/code/code-editor.js +58 -0
- package/components/code/code.a2ui.json +59 -0
- package/components/code/code.css +78 -2
- package/components/code/code.js +146 -8
- package/components/code/code.yaml +42 -0
- package/components/heatmap/heatmap.js +62 -13
- package/components/index.js +7 -0
- package/components/input/input.css +2 -0
- package/components/stat/stat.a2ui.json +3 -0
- package/components/stat/stat.css +32 -0
- package/components/stat/stat.yaml +6 -0
- package/components/textarea/textarea.css +2 -0
- package/components/tooltip/tooltip.a2ui.json +29 -4
- package/components/tooltip/tooltip.css +111 -0
- package/components/tooltip/tooltip.js +207 -12
- package/components/tooltip/tooltip.yaml +38 -4
- package/core/data-stream.js +465 -0
- package/core/icons.js +35 -1
- package/core/provider.js +1 -1
- package/package.json +1 -1
- package/styles/colors/semantics.css +19 -5
- package/styles/components.css +1 -0
- package/styles/typography.css +6 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ A2UI protocol messages into live DOM.
|
|
|
15
15
|
<link rel="stylesheet" href="node_modules/@adia-ai/web-components/index.css" />
|
|
16
16
|
|
|
17
17
|
<script type="module">
|
|
18
|
-
import '@adia-ai/web-components'; // registers every *-
|
|
18
|
+
import '@adia-ai/web-components'; // registers every *-ui tag
|
|
19
19
|
</script>
|
|
20
20
|
|
|
21
21
|
<card-ui>
|
|
@@ -42,7 +42,9 @@ web-components/
|
|
|
42
42
|
│ ├── provider.js global provider registration + router-ui
|
|
43
43
|
│ ├── anchor.js popover + anchor-positioning
|
|
44
44
|
│ ├── markdown.js lightweight markdown renderer
|
|
45
|
-
│
|
|
45
|
+
│ ├── transport.js SSE / streaming helpers for LLM adapters
|
|
46
|
+
│ └── data-stream.js `data-stream-*` attribute trait (HTTP/SSE/WS,
|
|
47
|
+
│ signal-backed, refcounted shared transports)
|
|
46
48
|
│
|
|
47
49
|
├── components/ — 80 *-ui custom elements
|
|
48
50
|
│ └── <tag>/
|
|
@@ -59,7 +61,7 @@ web-components/
|
|
|
59
61
|
│ │ with @adia-ai/a2ui-utils)
|
|
60
62
|
│ └── index.js — registers all patterns
|
|
61
63
|
│
|
|
62
|
-
├── traits/ —
|
|
64
|
+
├── traits/ — 42 composable behaviors via defineTrait()
|
|
63
65
|
│ (pressable, focusTrap, confetti, resizable, …)
|
|
64
66
|
│
|
|
65
67
|
├── a2ui/ — deprecation shim for one release
|
|
@@ -159,6 +161,46 @@ Accepts the four A2UI message kinds: `updateComponents`,
|
|
|
159
161
|
normalizes LLM-emitted aliases (e.g. `Carousel` → `swiper-ui`) so generated
|
|
160
162
|
output is robust to name drift.
|
|
161
163
|
|
|
164
|
+
## Data streaming via `data-stream-*` attributes
|
|
165
|
+
|
|
166
|
+
Any element with a settable `.data` property — chart-ui, table-ui,
|
|
167
|
+
heatmap-ui, stat-ui, list-ui, etc. — can be fed from a backing
|
|
168
|
+
source via attributes alone. No per-component opt-in:
|
|
169
|
+
|
|
170
|
+
```html
|
|
171
|
+
<!-- HTTP one-shot fetch, JSON -->
|
|
172
|
+
<chart-ui type="area" x="month" y="revenue"
|
|
173
|
+
data-stream-src="/api/revenue?range=3m"
|
|
174
|
+
data-stream-path="data"></chart-ui>
|
|
175
|
+
|
|
176
|
+
<!-- HTTP polling every 5s -->
|
|
177
|
+
<table-ui sortable striped
|
|
178
|
+
data-stream-src="/api/orders"
|
|
179
|
+
data-stream-interval="5000"></table-ui>
|
|
180
|
+
|
|
181
|
+
<!-- Server-Sent Events, append on each message -->
|
|
182
|
+
<heatmap-ui type="matrix" rows="7" cols="52"
|
|
183
|
+
data-stream-src="/sse/activity"
|
|
184
|
+
data-stream-mode="sse"
|
|
185
|
+
data-stream-merge="append"></heatmap-ui>
|
|
186
|
+
|
|
187
|
+
<!-- Spread a multi-property response onto the element -->
|
|
188
|
+
<stat-ui data-stream-src="/api/kpi"
|
|
189
|
+
data-stream-target="*"></stat-ui>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Modes: HTTP (one-shot or polling), `sse` (`EventSource`), `ws`
|
|
193
|
+
(`WebSocket`). Formats: `json` (default), `csv`, `tsv`, `jsonl`,
|
|
194
|
+
`text` — auto-detected from URL extension or content-type. Two
|
|
195
|
+
elements with attribute-identical streams share one transport
|
|
196
|
+
(refcounted, signal-backed); explicit `data-stream-id` lets
|
|
197
|
+
unrelated configs share intentionally. Programmatic access via
|
|
198
|
+
the `streams` registry export from `core/data-stream.js`.
|
|
199
|
+
|
|
200
|
+
Implementation: `core/data-stream.js` (~360 lines). Full
|
|
201
|
+
attribute table + live demos:
|
|
202
|
+
[`/site/components/chart#data-stream`](./site/pages/components/chart/index.html).
|
|
203
|
+
|
|
162
204
|
## Build
|
|
163
205
|
|
|
164
206
|
```bash
|
package/components/card/card.css
CHANGED
|
@@ -323,6 +323,35 @@
|
|
|
323
323
|
margin: 0;
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
+
/* Footer heading — trend-stat line (symmetric with header's [slot="heading"]).
|
|
327
|
+
Used for chart trend-footer patterns like "Trending up by 5.2% this month".
|
|
328
|
+
Paired with [slot="description"] for a "Jan – Mar 2024" period caption. */
|
|
329
|
+
> footer > [slot="heading"] {
|
|
330
|
+
font-size: var(--card-font-size);
|
|
331
|
+
font-weight: var(--a-weight-medium);
|
|
332
|
+
color: var(--card-heading-fg);
|
|
333
|
+
line-height: 1.3;
|
|
334
|
+
margin: 0;
|
|
335
|
+
flex: 0 0 auto;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/* Footer with heading + description = column stack, heading on top. The
|
|
339
|
+
existing flex-row layout becomes a flex-column when a heading is present,
|
|
340
|
+
so the trend line and period caption stack naturally. */
|
|
341
|
+
> footer:has(> [slot="heading"]) {
|
|
342
|
+
flex-direction: column;
|
|
343
|
+
align-items: flex-start;
|
|
344
|
+
gap: var(--a-space-0-5);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
> footer:has(> [slot="heading"])[justify="end"] {
|
|
348
|
+
align-items: flex-end;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
> footer:has(> [slot="heading"])[justify="center"] {
|
|
352
|
+
align-items: center;
|
|
353
|
+
}
|
|
354
|
+
|
|
326
355
|
> footer [slot="action"] {
|
|
327
356
|
margin-inline-start: auto;
|
|
328
357
|
display: flex;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://adiaui.dev/a2ui/v0_9/components/Chart.json",
|
|
4
4
|
"title": "Chart",
|
|
5
|
-
"description": "Declarative SVG chart supporting bar, line, pie, donut, radar, sparkline, stacked-bar, grouped-bar,
|
|
5
|
+
"description": "Declarative SVG chart supporting 18 types: bar, line, pie, donut, radar, sparkline, segments, area, scatter, radial-bar, gauge, stacked-bar, grouped-bar, multi-line, funnel, treemap, sankey, and composed.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"allOf": [
|
|
8
8
|
{
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
],
|
|
15
15
|
"properties": {
|
|
16
16
|
"type": {
|
|
17
|
-
"description": "Chart type.
|
|
17
|
+
"description": "Chart type. All 18 enum values have dedicated render paths in chart.js.",
|
|
18
18
|
"type": "string",
|
|
19
19
|
"enum": [
|
|
20
20
|
"bar",
|
|
@@ -23,14 +23,23 @@
|
|
|
23
23
|
"donut",
|
|
24
24
|
"radar",
|
|
25
25
|
"sparkline",
|
|
26
|
+
"segments",
|
|
27
|
+
"area",
|
|
28
|
+
"scatter",
|
|
29
|
+
"radial-bar",
|
|
30
|
+
"gauge",
|
|
26
31
|
"stacked-bar",
|
|
27
32
|
"grouped-bar",
|
|
28
|
-
"multi-line"
|
|
33
|
+
"multi-line",
|
|
34
|
+
"funnel",
|
|
35
|
+
"treemap",
|
|
36
|
+
"sankey",
|
|
37
|
+
"composed"
|
|
29
38
|
],
|
|
30
39
|
"default": "bar"
|
|
31
40
|
},
|
|
32
41
|
"aspect": {
|
|
33
|
-
"description": "
|
|
42
|
+
"description": "DEPRECATED (OD-CHART-02). Parents should size the chart directly (width/height on the enclosing card or container). Still honored for back-compat; emits a one-shot console.warn per instance when set.",
|
|
34
43
|
"type": "string",
|
|
35
44
|
"enum": [
|
|
36
45
|
"std",
|
|
@@ -55,8 +64,19 @@
|
|
|
55
64
|
"component": {
|
|
56
65
|
"const": "Chart"
|
|
57
66
|
},
|
|
67
|
+
"format": {
|
|
68
|
+
"description": "Number-format mode applied to axis labels + value overlays + donut total + gauge value + treemap value + funnel value + internal tooltip. `abbr` is the legacy 1.2K / 3M format; `decimal` fixes 2 decimals; `currency` prefixes via `--chart-currency-prefix` token (default \"$\"); `percent` multiplies × 100 and adds a % suffix.",
|
|
69
|
+
"type": "string",
|
|
70
|
+
"enum": [
|
|
71
|
+
"abbr",
|
|
72
|
+
"decimal",
|
|
73
|
+
"currency",
|
|
74
|
+
"percent"
|
|
75
|
+
],
|
|
76
|
+
"default": "abbr"
|
|
77
|
+
},
|
|
58
78
|
"heading": {
|
|
59
|
-
"description": "
|
|
79
|
+
"description": "DEPRECATED (OD-CHART-02). Place chart titles in an enclosing card-ui's `<header><span slot=\"heading\">...</span></header>` instead. Still honored for back-compat; emits a one-shot console.warn per instance when set. Used as the chart's `aria-label` when no explicit label is provided.",
|
|
60
80
|
"type": "string",
|
|
61
81
|
"default": ""
|
|
62
82
|
},
|
|
@@ -113,7 +133,17 @@
|
|
|
113
133
|
"x-adiaui": {
|
|
114
134
|
"anti_patterns": [],
|
|
115
135
|
"category": "agent",
|
|
116
|
-
"events": {
|
|
136
|
+
"events": {
|
|
137
|
+
"chart-hover": {
|
|
138
|
+
"description": "Fires when the pointer enters a datum (bar / dot / slice). Detail includes {label, value, pct, series, slot, pointerX, pointerY}. Only re-fires when the hovered datum changes — moving inside the same datum is quiet."
|
|
139
|
+
},
|
|
140
|
+
"chart-leave": {
|
|
141
|
+
"description": "Fires when the pointer leaves the plot area or a previously-hovered datum with no new one entering."
|
|
142
|
+
},
|
|
143
|
+
"chart-select": {
|
|
144
|
+
"description": "Fires on click of a datum with the same detail shape as chart-hover."
|
|
145
|
+
}
|
|
146
|
+
},
|
|
117
147
|
"examples": [
|
|
118
148
|
{
|
|
119
149
|
"description": "Dashboard with KPI stat grid and two chart cards.",
|
|
@@ -158,12 +188,19 @@
|
|
|
158
188
|
},
|
|
159
189
|
"canvas": {
|
|
160
190
|
"description": "Chart rendering area"
|
|
191
|
+
},
|
|
192
|
+
"empty": {
|
|
193
|
+
"description": "Shown in place of the SVG when `.data` is empty or missing. Typically an `<empty-state-ui>` with icon + heading + description + optional action. Visibility is CSS-toggled via `[data-has-data]` on the host — authors don't need to manage it imperatively."
|
|
161
194
|
}
|
|
162
195
|
},
|
|
163
196
|
"states": [
|
|
164
197
|
{
|
|
165
198
|
"description": "Default, ready for interaction.",
|
|
166
199
|
"name": "idle"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"description": "No data — the empty slot (if provided) is rendered; otherwise the chart area renders nothing. Host carries [data-has-data] only when data is present.",
|
|
203
|
+
"name": "empty"
|
|
167
204
|
}
|
|
168
205
|
],
|
|
169
206
|
"synonyms": {
|
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
/* ── Tokens ── */
|
|
4
4
|
--chart-font: var(--a-font-family);
|
|
5
5
|
--chart-font-size: var(--a-ui-sm);
|
|
6
|
+
/* NOTE — `--chart-currency-prefix` is intentionally NOT declared here.
|
|
7
|
+
Declaring a default at `:where(:scope)` would shadow ancestor values
|
|
8
|
+
via the cascade (the child's explicit declaration wins over an
|
|
9
|
+
inherited ancestor value, regardless of specificity). Instead,
|
|
10
|
+
chart.js's `#fmtValue()` falls back to `'$'` when the computed
|
|
11
|
+
value is empty — so ancestors can set `--chart-currency-prefix: "€"`
|
|
12
|
+
and the chart inherits that value naturally. To register the
|
|
13
|
+
default formally (and enable transitions), add an `@property` rule
|
|
14
|
+
at `:root` in a global stylesheet. */
|
|
6
15
|
--chart-fg: var(--a-fg);
|
|
7
16
|
--chart-bar: var(--a-accent);
|
|
8
17
|
--chart-bar-hover: var(--a-accent-bg-hover);
|
|
@@ -69,6 +78,29 @@
|
|
|
69
78
|
position: relative;
|
|
70
79
|
container-type: inline-size;
|
|
71
80
|
container-name: chart;
|
|
81
|
+
/* Suppress default focus ring — we paint our own via [data-a11y-focused]
|
|
82
|
+
below so the ring only shows when the chart has a focused datum
|
|
83
|
+
(keyboard-only indicator, not just "the chart is tabindex=0"). */
|
|
84
|
+
outline: none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* OD-CHART-06 — keyboard a11y focus ring. Painted on the host when a
|
|
88
|
+
datum is focused via keyboard. Uses the canonical --a-focus-ring
|
|
89
|
+
recipe so it matches every other focusable primitive. */
|
|
90
|
+
:scope[data-a11y-focused]:focus-visible {
|
|
91
|
+
box-shadow: var(--a-focus-ring);
|
|
92
|
+
border-radius: var(--a-radius-sm);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Per-datum focus indicator — marks the currently-focused datum
|
|
96
|
+
via a data-a11y-focus attr set by chart.js on keyboard nav.
|
|
97
|
+
SVG paintable elements can't take box-shadow, so use a stroke
|
|
98
|
+
+ drop-shadow filter to approximate a ring. */
|
|
99
|
+
[data-a11y-focus] {
|
|
100
|
+
stroke: var(--a-focus-color);
|
|
101
|
+
stroke-width: 2;
|
|
102
|
+
paint-order: stroke fill;
|
|
103
|
+
filter: drop-shadow(0 0 2px var(--a-focus-color));
|
|
72
104
|
}
|
|
73
105
|
|
|
74
106
|
/* Title + legend are fixed-height siblings; SVG gets the remaining
|
|
@@ -76,6 +108,19 @@
|
|
|
76
108
|
inside the max-height envelope instead of pushing the legend out. */
|
|
77
109
|
[data-chart-heading] { flex: 0 0 auto; }
|
|
78
110
|
[data-legend] { flex: 0 0 auto; }
|
|
111
|
+
|
|
112
|
+
/* Empty-state slot — author places <empty-state-ui slot="empty"> inside
|
|
113
|
+
chart-ui. CSS toggles visibility on [data-has-data] (set by chart.js
|
|
114
|
+
when .data is non-empty). No data ⇒ empty-state visible; data ⇒ hidden. */
|
|
115
|
+
> [slot="empty"] { display: none; }
|
|
116
|
+
:scope:not([data-has-data]) > [slot="empty"] {
|
|
117
|
+
display: flex;
|
|
118
|
+
flex: 1 1 auto;
|
|
119
|
+
align-items: center;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
min-height: 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
79
124
|
:scope > div:not([data-chart-heading]):not([data-legend]) {
|
|
80
125
|
flex: 1 1 auto;
|
|
81
126
|
min-height: 0;
|
|
@@ -354,6 +399,15 @@
|
|
|
354
399
|
font-family: var(--chart-font);
|
|
355
400
|
}
|
|
356
401
|
|
|
402
|
+
/* Container query — the chart element provides `container-type: inline-size`
|
|
403
|
+
+ `container-name: chart` (above). Hide the internal legend at small
|
|
404
|
+
widths where the rows would dominate the chart visual. Consumers who
|
|
405
|
+
want a legend at small sizes should place an external chart-legend-ui
|
|
406
|
+
adjacent in a larger container. */
|
|
407
|
+
@container chart (max-width: 200px) {
|
|
408
|
+
[data-legend] { display: none; }
|
|
409
|
+
}
|
|
410
|
+
|
|
357
411
|
[data-legend-item] {
|
|
358
412
|
display: flex;
|
|
359
413
|
flex-direction: row;
|
|
@@ -379,6 +433,176 @@
|
|
|
379
433
|
[data-legend-dot][data-slice="8"] { background: var(--chart-8); }
|
|
380
434
|
[data-legend-dot][data-slice="9"] { background: var(--chart-9); }
|
|
381
435
|
|
|
436
|
+
/* ── Area chart ──
|
|
437
|
+
Reuses #renderLine() but emphasizes the filled region. Overrides the
|
|
438
|
+
default `[data-area]` opacity of 0.15 (line-chart aesthetic) to 0.35
|
|
439
|
+
so the fill becomes the dominant visual. The `--chart-area-fill-opacity`
|
|
440
|
+
token is the knob for consumers to tune; bump for more presence, dial
|
|
441
|
+
down for subtler. */
|
|
442
|
+
:scope[type="area"] {
|
|
443
|
+
--chart-area-fill-opacity: 0.35;
|
|
444
|
+
}
|
|
445
|
+
:scope[type="area"] [data-area] {
|
|
446
|
+
fill: var(--chart-line);
|
|
447
|
+
opacity: var(--chart-area-fill-opacity);
|
|
448
|
+
stroke: none;
|
|
449
|
+
}
|
|
450
|
+
:scope[type="area"] [data-line] {
|
|
451
|
+
stroke-width: var(--chart-line-width);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/* ── Scatter ──
|
|
455
|
+
Only dots emitted (no line/area paths). Dots are slightly larger than
|
|
456
|
+
line-chart dots by default for readability. */
|
|
457
|
+
:scope[type="scatter"] [data-dot][data-scatter] {
|
|
458
|
+
fill: var(--chart-dot);
|
|
459
|
+
stroke: var(--chart-dot-stroke);
|
|
460
|
+
stroke-width: 1.5;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/* ── Radial bar ──
|
|
464
|
+
Concentric rings — each ring stroked with bandwidth. Track is the
|
|
465
|
+
faint backing, filled arc is accent. Stroke-linecap:round in the path
|
|
466
|
+
gives rounded end-caps on the arcs. */
|
|
467
|
+
[data-radial-track] {
|
|
468
|
+
stroke: var(--a-border-subtle);
|
|
469
|
+
fill: none;
|
|
470
|
+
}
|
|
471
|
+
[data-radial-bar] {
|
|
472
|
+
stroke: var(--chart-bar);
|
|
473
|
+
}
|
|
474
|
+
[data-radial-bar][data-slice="0"] { stroke: var(--chart-0); }
|
|
475
|
+
[data-radial-bar][data-slice="1"] { stroke: var(--chart-1); }
|
|
476
|
+
[data-radial-bar][data-slice="2"] { stroke: var(--chart-2); }
|
|
477
|
+
[data-radial-bar][data-slice="3"] { stroke: var(--chart-3); }
|
|
478
|
+
[data-radial-bar][data-slice="4"] { stroke: var(--chart-4); }
|
|
479
|
+
[data-radial-bar][data-slice="5"] { stroke: var(--chart-5); }
|
|
480
|
+
[data-radial-bar][data-slice="6"] { stroke: var(--chart-6); }
|
|
481
|
+
[data-radial-bar][data-slice="7"] { stroke: var(--chart-7); }
|
|
482
|
+
[data-radial-bar][data-slice="8"] { stroke: var(--chart-8); }
|
|
483
|
+
[data-radial-bar][data-slice="9"] { stroke: var(--chart-9); }
|
|
484
|
+
|
|
485
|
+
/* ── Gauge ──
|
|
486
|
+
Half-donut — track is faint backing, fill reads as primary accent. */
|
|
487
|
+
:scope[type="gauge"] [data-radial-track] {
|
|
488
|
+
fill: var(--a-border-subtle);
|
|
489
|
+
stroke: none;
|
|
490
|
+
}
|
|
491
|
+
:scope[type="gauge"] [data-gauge-fill] {
|
|
492
|
+
fill: var(--chart-bar);
|
|
493
|
+
stroke: none;
|
|
494
|
+
}
|
|
495
|
+
[data-gauge-value] {
|
|
496
|
+
font-weight: var(--a-weight-semibold);
|
|
497
|
+
fill: var(--chart-fg);
|
|
498
|
+
}
|
|
499
|
+
[data-gauge-max] {
|
|
500
|
+
fill: var(--chart-label);
|
|
501
|
+
font-family: var(--chart-font);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/* ── Funnel ──
|
|
505
|
+
Stages stacked top-to-bottom. Trapezoid paths carry data-slice so
|
|
506
|
+
the data palette colors each stage. Labels live outside the
|
|
507
|
+
funnel body — left (stage name) and right (value + drop %). */
|
|
508
|
+
[data-funnel-stage] {
|
|
509
|
+
fill: var(--chart-bar);
|
|
510
|
+
}
|
|
511
|
+
[data-funnel-stage][data-slice="0"] { fill: var(--chart-0); }
|
|
512
|
+
[data-funnel-stage][data-slice="1"] { fill: var(--chart-1); }
|
|
513
|
+
[data-funnel-stage][data-slice="2"] { fill: var(--chart-2); }
|
|
514
|
+
[data-funnel-stage][data-slice="3"] { fill: var(--chart-3); }
|
|
515
|
+
[data-funnel-stage][data-slice="4"] { fill: var(--chart-4); }
|
|
516
|
+
[data-funnel-stage][data-slice="5"] { fill: var(--chart-5); }
|
|
517
|
+
[data-funnel-stage][data-slice="6"] { fill: var(--chart-6); }
|
|
518
|
+
[data-funnel-stage][data-slice="7"] { fill: var(--chart-7); }
|
|
519
|
+
[data-funnel-stage][data-slice="8"] { fill: var(--chart-8); }
|
|
520
|
+
[data-funnel-stage][data-slice="9"] { fill: var(--chart-9); }
|
|
521
|
+
|
|
522
|
+
[data-funnel-label] {
|
|
523
|
+
fill: var(--chart-fg);
|
|
524
|
+
font-weight: var(--a-weight-medium);
|
|
525
|
+
}
|
|
526
|
+
[data-funnel-value] {
|
|
527
|
+
fill: var(--chart-fg);
|
|
528
|
+
font-weight: var(--a-weight-semibold);
|
|
529
|
+
}
|
|
530
|
+
[data-funnel-drop] {
|
|
531
|
+
fill: var(--chart-label);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/* ── Treemap ──
|
|
535
|
+
Flat tiles — each rect filled by the data palette. Labels +
|
|
536
|
+
values appear only on tiles large enough to fit them (size
|
|
537
|
+
check done in JS). Rounded corners pick up the standard
|
|
538
|
+
--a-radius via #resolveRadius(). */
|
|
539
|
+
[data-treemap-tile] {
|
|
540
|
+
stroke: var(--chart-dot-stroke);
|
|
541
|
+
stroke-width: 0;
|
|
542
|
+
}
|
|
543
|
+
[data-treemap-tile][data-slice="0"] { fill: var(--chart-0); }
|
|
544
|
+
[data-treemap-tile][data-slice="1"] { fill: var(--chart-1); }
|
|
545
|
+
[data-treemap-tile][data-slice="2"] { fill: var(--chart-2); }
|
|
546
|
+
[data-treemap-tile][data-slice="3"] { fill: var(--chart-3); }
|
|
547
|
+
[data-treemap-tile][data-slice="4"] { fill: var(--chart-4); }
|
|
548
|
+
[data-treemap-tile][data-slice="5"] { fill: var(--chart-5); }
|
|
549
|
+
[data-treemap-tile][data-slice="6"] { fill: var(--chart-6); }
|
|
550
|
+
[data-treemap-tile][data-slice="7"] { fill: var(--chart-7); }
|
|
551
|
+
[data-treemap-tile][data-slice="8"] { fill: var(--chart-8); }
|
|
552
|
+
[data-treemap-tile][data-slice="9"] { fill: var(--chart-9); }
|
|
553
|
+
|
|
554
|
+
[data-treemap-label] {
|
|
555
|
+
fill: var(--a-canvas-0);
|
|
556
|
+
font-weight: var(--a-weight-semibold);
|
|
557
|
+
}
|
|
558
|
+
[data-treemap-value] {
|
|
559
|
+
fill: var(--a-canvas-0);
|
|
560
|
+
opacity: 0.85;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/* ── Sankey ──
|
|
564
|
+
Left + right column nodes, curved bezier flows between. Flow
|
|
565
|
+
bands render semi-transparent so overlapping routes remain
|
|
566
|
+
distinguishable. Nodes adopt the data palette. */
|
|
567
|
+
[data-sankey-node] {
|
|
568
|
+
fill: var(--chart-bar);
|
|
569
|
+
}
|
|
570
|
+
[data-sankey-node][data-slice="0"] { fill: var(--chart-0); }
|
|
571
|
+
[data-sankey-node][data-slice="1"] { fill: var(--chart-1); }
|
|
572
|
+
[data-sankey-node][data-slice="2"] { fill: var(--chart-2); }
|
|
573
|
+
[data-sankey-node][data-slice="3"] { fill: var(--chart-3); }
|
|
574
|
+
[data-sankey-node][data-slice="4"] { fill: var(--chart-4); }
|
|
575
|
+
[data-sankey-node][data-slice="5"] { fill: var(--chart-5); }
|
|
576
|
+
[data-sankey-node][data-slice="6"] { fill: var(--chart-6); }
|
|
577
|
+
[data-sankey-node][data-slice="7"] { fill: var(--chart-7); }
|
|
578
|
+
[data-sankey-node][data-slice="8"] { fill: var(--chart-8); }
|
|
579
|
+
[data-sankey-node][data-slice="9"] { fill: var(--chart-9); }
|
|
580
|
+
|
|
581
|
+
[data-sankey-link] {
|
|
582
|
+
fill: var(--a-fg-subtle);
|
|
583
|
+
opacity: 0.35;
|
|
584
|
+
}
|
|
585
|
+
[data-sankey-link]:hover {
|
|
586
|
+
opacity: 0.6;
|
|
587
|
+
}
|
|
588
|
+
[data-sankey-label] {
|
|
589
|
+
fill: var(--chart-fg);
|
|
590
|
+
font-weight: var(--a-weight-medium);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/* ── Composed (bar + line overlay) ──
|
|
594
|
+
The bar uses slot 0 + the line uses slot 1 by default via the
|
|
595
|
+
--color-{key} injection in chart.js. CSS here just makes sure
|
|
596
|
+
the line reads over the bar visually — the line's data-line
|
|
597
|
+
element already picks up existing [data-line] styling. */
|
|
598
|
+
:scope[type="composed"] [data-line] {
|
|
599
|
+
stroke-width: calc(var(--chart-line-width) + 1);
|
|
600
|
+
}
|
|
601
|
+
:scope[type="composed"] [data-dot] {
|
|
602
|
+
stroke: var(--chart-dot-stroke);
|
|
603
|
+
stroke-width: 2;
|
|
604
|
+
}
|
|
605
|
+
|
|
382
606
|
/* ── Sparkline container ──
|
|
383
607
|
When host has explicit height, fill it; otherwise give a sensible
|
|
384
608
|
default of 2rem so the sparkline still has room to breathe. */
|