@heyramzi/ui 6.0.1 → 7.0.0
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/COMPONENTS.md +7 -26
- package/README.md +12 -5
- package/package.json +14 -16
- package/scripts/sync-shadcn.mjs +12 -3
- package/src/agents/agent-avatar.svelte +639 -0
- package/src/agents/agent-cast.svelte +173 -0
- package/src/agents/demo.svelte +78 -0
- package/src/agents/index.ts +11 -0
- package/src/agents/types.ts +72 -0
- package/{LICENSE → src/agents/vendor/LICENSE} +1 -1
- package/src/agents/vendor/color.ts +155 -0
- package/src/agents/vendor/draw.ts +840 -0
- package/src/agents/vendor/engine.ts +845 -0
- package/src/agents/vendor/mesh.ts +838 -0
- package/src/agents/vendor/plastic.ts +4958 -0
- package/src/agents/vendor/presets.ts +103 -0
- package/src/agents/vendor/shapes.ts +41 -0
- package/src/agents/vendor/ticker.ts +67 -0
- package/src/agents/vendor/types.ts +261 -0
- package/src/agents/vendor/wear.ts +1699 -0
- package/src/ai/index.ts +0 -18
- package/src/animations/README.md +3 -3
- package/src/lib/sliding-pill.ts +68 -0
- package/src/lib/theme-transition.ts +4 -2
- package/src/shadcn/code-block/code-block-actions.svelte +23 -0
- package/src/shadcn/code-block/code-block-content.svelte +55 -0
- package/src/shadcn/code-block/code-block-copy-button.svelte +59 -0
- package/src/shadcn/code-block/code-block-footer.svelte +20 -0
- package/src/shadcn/code-block/code-block-header.svelte +23 -0
- package/src/shadcn/code-block/code-block-line.svelte +71 -0
- package/src/shadcn/code-block/code-block-title.svelte +23 -0
- package/src/shadcn/code-block/code-block.svelte +47 -0
- package/src/shadcn/code-block/index.ts +42 -0
- package/src/shadcn/hooks/highlighter.ts +132 -0
- package/src/shadcn/hooks/use-highlighted-code.svelte.ts +98 -0
- package/src/shadcn/kbd/index.ts +10 -0
- package/src/shadcn/kbd/kbd-group.svelte +20 -0
- package/src/shadcn/kbd/kbd.svelte +23 -0
- package/src/shadcn/message-scroller/index.ts +28 -0
- package/src/shadcn/message-scroller/message-scroller-button.svelte +52 -0
- package/src/shadcn/message-scroller/message-scroller-content.svelte +17 -0
- package/src/shadcn/message-scroller/message-scroller-item.svelte +22 -0
- package/src/shadcn/message-scroller/message-scroller-provider.svelte +7 -0
- package/src/shadcn/message-scroller/message-scroller-viewport.svelte +20 -0
- package/src/shadcn/message-scroller/message-scroller.svelte +20 -0
- package/src/shadcn/tabs/tabs-list.svelte +13 -2
- package/src/shadcn/tabs/tabs-trigger.svelte +1 -1
- package/src/shadcn/trace/index.ts +29 -0
- package/src/shadcn/trace/trace-collapsible-content.svelte +29 -0
- package/src/shadcn/trace/trace-collapsible-trigger.svelte +29 -0
- package/src/shadcn/trace/trace-collapsible.svelte +20 -0
- package/src/shadcn/trace/trace-description.svelte +20 -0
- package/src/shadcn/trace/trace-icon.svelte +24 -0
- package/src/shadcn/trace/trace-line.svelte +31 -0
- package/src/shadcn/trace/trace-title.svelte +20 -0
- package/src/shadcn/trace/trace.svelte +23 -0
- package/src/showcase/AiSection.svelte +0 -7
- package/src/showcase/demos/shadcn/code-block.svelte +80 -0
- package/src/showcase/demos/shadcn/index.ts +24 -0
- package/src/showcase/demos/shadcn/message-scroller.svelte +44 -0
- package/src/showcase/demos/shadcn/trace.svelte +51 -0
- package/src/showcase/kit.ts +1 -2
- package/src/ai/conversation/Conversation.svelte +0 -28
- package/src/ai/conversation/ConversationContent.svelte +0 -35
- package/src/ai/conversation/ConversationEmptyState.svelte +0 -46
- package/src/ai/conversation/ConversationScrollButton.svelte +0 -51
- package/src/ai/conversation/index.ts +0 -33
- package/src/ai/conversation/stick-to-bottom-context.svelte.ts +0 -131
- package/src/charts/animated-value.css +0 -7
- package/src/charts/animated-value.svelte +0 -110
- package/src/charts/area-chart.css +0 -29
- package/src/charts/area-chart.svelte +0 -195
- package/src/charts/bar-chart.css +0 -119
- package/src/charts/bar-chart.svelte +0 -269
- package/src/charts/charts.css +0 -201
- package/src/charts/crosshair.svelte +0 -35
- package/src/charts/donut-chart.css +0 -56
- package/src/charts/donut-chart.svelte +0 -158
- package/src/charts/edge-fade.svelte +0 -43
- package/src/charts/edge-fade.ts +0 -16
- package/src/charts/figure.css +0 -100
- package/src/charts/figure.svelte +0 -122
- package/src/charts/gauge-chart.css +0 -94
- package/src/charts/gauge-chart.svelte +0 -303
- package/src/charts/hover-band.test.ts +0 -30
- package/src/charts/hover-band.ts +0 -21
- package/src/charts/hover-focus.svelte +0 -85
- package/src/charts/index.ts +0 -30
- package/src/charts/legend.css +0 -131
- package/src/charts/legend.svelte +0 -112
- package/src/charts/line-chart.css +0 -26
- package/src/charts/line-chart.svelte +0 -256
- package/src/charts/motion.ts +0 -19
- package/src/charts/number-chart.css +0 -168
- package/src/charts/number-chart.svelte +0 -177
- package/src/charts/primitives/chart-container.svelte +0 -57
- package/src/charts/primitives/chart-style.svelte +0 -36
- package/src/charts/primitives/chart-tooltip.svelte +0 -161
- package/src/charts/primitives/chart-utils.ts +0 -54
- package/src/charts/primitives/index.ts +0 -11
- package/src/charts/reveal.svelte +0 -61
- package/src/charts/ring-chart.css +0 -96
- package/src/charts/ring-chart.svelte +0 -158
- package/src/charts/sparkline.css +0 -45
- package/src/charts/sparkline.svelte +0 -140
- package/src/charts/stat-card.css +0 -103
- package/src/charts/stat-card.svelte +0 -267
- package/src/charts/time-series-chart.css +0 -28
- package/src/charts/time-series-chart.svelte +0 -179
- package/src/charts/trend-pill.css +0 -38
- package/src/charts/trend-pill.svelte +0 -48
- package/src/lib/hooks/is-mobile.svelte.ts +0 -11
- package/src/showcase/ChartsSection.svelte +0 -458
- package/src/showcase/demos/ai/conversation.svelte +0 -59
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
-
// =========================
|
|
3
|
-
// IMPORTS
|
|
4
|
-
// =========================
|
|
5
|
-
import "./bar-chart.css";
|
|
6
|
-
import { Axis, Bars, Chart, Highlight, Svg, Tooltip } from "layerchart";
|
|
7
|
-
import { scaleBand } from "d3-scale";
|
|
8
|
-
import Figure from "./figure.svelte";
|
|
9
|
-
import { TOOLTIP_GAP, TOOLTIP_TOP } from "./motion.js";
|
|
10
|
-
|
|
11
|
-
// =========================
|
|
12
|
-
// TYPES
|
|
13
|
-
// =========================
|
|
14
|
-
type Series = { key: keyof TData & string; label: string; color: string };
|
|
15
|
-
|
|
16
|
-
type Props = {
|
|
17
|
-
data: TData[];
|
|
18
|
-
xKey: keyof TData & string;
|
|
19
|
-
/** The bar's value. Required unless `series` is set. */
|
|
20
|
-
yKey?: keyof TData & string;
|
|
21
|
-
/** Stacks these keys into one bar per row; the bar's value is their sum. */
|
|
22
|
-
series?: Series[];
|
|
23
|
-
color?: string;
|
|
24
|
-
/** A fill per bar, for bands whose meaning changes along the axis. */
|
|
25
|
-
colorOf?: (d: TData) => string;
|
|
26
|
-
/** Body height in px, or "fill" to grow to the parent's height (parent must
|
|
27
|
-
* be a flex column that gives the chart a determinate height). Default 240. */
|
|
28
|
-
height?: number | "fill";
|
|
29
|
-
orientation?: "vertical" | "horizontal";
|
|
30
|
-
/** Left padding for horizontal charts (label space). Default 80. */
|
|
31
|
-
leftPadding?: number;
|
|
32
|
-
formatValue?: (v: number) => string;
|
|
33
|
-
formatX?: (v: unknown) => string;
|
|
34
|
-
/** Axis tick label. Return "" to skip a tick. Defaults to formatX. */
|
|
35
|
-
formatTick?: (v: unknown) => string;
|
|
36
|
-
/** Screen-reader summary; also renders an sr-only data table when set. */
|
|
37
|
-
label?: string;
|
|
38
|
-
/** Column header for the x values in the sr-only table. */
|
|
39
|
-
xLabel?: string;
|
|
40
|
-
/** Column header for the y values in the sr-only table, and the tooltip's label. */
|
|
41
|
-
yLabel?: string;
|
|
42
|
-
/** Show the value/label figure above the chart. */
|
|
43
|
-
showFigure?: boolean;
|
|
44
|
-
class?: string;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// =========================
|
|
48
|
-
// PROPS
|
|
49
|
-
// =========================
|
|
50
|
-
let {
|
|
51
|
-
data,
|
|
52
|
-
xKey,
|
|
53
|
-
yKey,
|
|
54
|
-
series,
|
|
55
|
-
color = "var(--chart-1)",
|
|
56
|
-
colorOf,
|
|
57
|
-
height = 240,
|
|
58
|
-
orientation = "vertical",
|
|
59
|
-
leftPadding = 80,
|
|
60
|
-
formatValue = (v) => v.toLocaleString(),
|
|
61
|
-
formatX = (v) => String(v),
|
|
62
|
-
formatTick,
|
|
63
|
-
label,
|
|
64
|
-
xLabel,
|
|
65
|
-
yLabel,
|
|
66
|
-
showFigure = true,
|
|
67
|
-
class: className,
|
|
68
|
-
}: Props = $props();
|
|
69
|
-
|
|
70
|
-
// =========================
|
|
71
|
-
// STATE
|
|
72
|
-
// =========================
|
|
73
|
-
let active = $state<TData | null>(null);
|
|
74
|
-
|
|
75
|
-
// ========================= FUNCTIONS ========================= WHY: called from the tooltip header's value expression so it re-runs on every active-band change; an unread {@const} side effect only evaluates once.
|
|
76
|
-
|
|
77
|
-
// The microtask defers the state write out of template evaluation.
|
|
78
|
-
function trackActive(d: TData): string {
|
|
79
|
-
queueMicrotask(() => {
|
|
80
|
-
active = d;
|
|
81
|
-
});
|
|
82
|
-
return formatX(d[xKey]);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function valueOf(d: TData): number {
|
|
86
|
-
if (series) return series.reduce((sum, s) => sum + Number(d[s.key] ?? 0), 0);
|
|
87
|
-
return Number(yKey ? (d[yKey] ?? 0) : 0);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/** Where one series' segment starts and ends inside its stacked bar. */
|
|
91
|
-
function span(d: TData, key: string): [number, number] {
|
|
92
|
-
let at = 0;
|
|
93
|
-
for (const s of series ?? []) {
|
|
94
|
-
const next = at + Number(d[s.key] ?? 0);
|
|
95
|
-
if (s.key === key) return [at, next];
|
|
96
|
-
at = next;
|
|
97
|
-
}
|
|
98
|
-
return [0, 0];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// =========================
|
|
102
|
-
// DERIVED
|
|
103
|
-
// =========================
|
|
104
|
-
const yMax = $derived(Math.max(0, ...data.map(valueOf)));
|
|
105
|
-
const total = $derived(data.reduce((sum, d) => sum + valueOf(d), 0));
|
|
106
|
-
const valueLabel = $derived(yLabel ?? String(yKey ?? "value"));
|
|
107
|
-
const fill = $derived(height === "fill");
|
|
108
|
-
const horizontal = $derived(orientation === "horizontal");
|
|
109
|
-
const radius = $derived(horizontal ? "right" : "top");
|
|
110
|
-
// One Bars layer per fill: a stacked series, a colorOf group, or the single color.
|
|
111
|
-
const layers = $derived.by(() => {
|
|
112
|
-
if (series) {
|
|
113
|
-
return series.map((s) => ({
|
|
114
|
-
key: s.key,
|
|
115
|
-
color: s.color,
|
|
116
|
-
rows: data,
|
|
117
|
-
at: (d: TData) => span(d, s.key),
|
|
118
|
-
}));
|
|
119
|
-
}
|
|
120
|
-
const groups = new Map<string, TData[]>();
|
|
121
|
-
for (const d of data) {
|
|
122
|
-
const c = colorOf?.(d) ?? color;
|
|
123
|
-
groups.set(c, [...(groups.get(c) ?? []), d]);
|
|
124
|
-
}
|
|
125
|
-
return [...groups].map(([c, rows]) => ({ key: c, color: c, rows, at: undefined }));
|
|
126
|
-
});
|
|
127
|
-
const activeColor = $derived(active && colorOf ? colorOf(active) : color);
|
|
128
|
-
</script>
|
|
129
|
-
|
|
130
|
-
<!-- =========================== -->
|
|
131
|
-
<!-- BAR CHART -->
|
|
132
|
-
<!-- =========================== -->
|
|
133
|
-
<div
|
|
134
|
-
class="hr-bar-chart {className ?? ''}"
|
|
135
|
-
class:hr-bar-horizontal={horizontal}
|
|
136
|
-
class:hr-bar-fill={fill}
|
|
137
|
-
class:hr-bar-has-active={active !== null && !series}
|
|
138
|
-
role="img"
|
|
139
|
-
aria-label={label ?? "Bar chart"}
|
|
140
|
-
onpointerleave={() => (active = null)}
|
|
141
|
-
>
|
|
142
|
-
{#if showFigure}
|
|
143
|
-
<Figure
|
|
144
|
-
value={active ? valueOf(active) : total}
|
|
145
|
-
color="var(--chart-1)"
|
|
146
|
-
eyebrow={active ? formatX(active[xKey]) : "Total"}
|
|
147
|
-
format={formatValue}
|
|
148
|
-
size="md"
|
|
149
|
-
/>
|
|
150
|
-
{/if}
|
|
151
|
-
|
|
152
|
-
<div class="hr-chart-body" style:height={fill ? null : `${height}px`}>
|
|
153
|
-
{#if data.length === 0}
|
|
154
|
-
<div class="empty"><p>No data</p></div>
|
|
155
|
-
{:else}
|
|
156
|
-
<Chart
|
|
157
|
-
{data}
|
|
158
|
-
x={horizontal ? valueOf : xKey}
|
|
159
|
-
y={horizontal ? xKey : valueOf}
|
|
160
|
-
xScale={horizontal ? undefined : scaleBand().padding(0.3)}
|
|
161
|
-
yScale={horizontal ? scaleBand().padding(0.3) : undefined}
|
|
162
|
-
xDomain={horizontal ? [0, yMax || 1] : undefined}
|
|
163
|
-
yDomain={horizontal ? undefined : [0, yMax || 1]}
|
|
164
|
-
xNice={horizontal}
|
|
165
|
-
yNice={!horizontal}
|
|
166
|
-
padding={{ left: horizontal ? leftPadding : 48, bottom: 28, top: 8, right: 12 }}
|
|
167
|
-
tooltipContext={{ mode: "band" }}
|
|
168
|
-
>
|
|
169
|
-
<Svg>
|
|
170
|
-
{#if horizontal}
|
|
171
|
-
<Axis placement="left" format={(v) => (formatTick ?? formatX)(v)} />
|
|
172
|
-
<Axis placement="bottom" format={(v) => formatValue(Number(v))} ticks={4} />
|
|
173
|
-
<g class="hr-bar-grid">
|
|
174
|
-
<Axis placement="bottom" grid rule={false} ticks={4} format={() => ""} />
|
|
175
|
-
</g>
|
|
176
|
-
{:else}
|
|
177
|
-
<Axis placement="left" format={(v) => formatValue(Number(v))} ticks={4} />
|
|
178
|
-
<Axis placement="bottom" format={(v) => (formatTick ?? formatX)(v)} />
|
|
179
|
-
<g class="hr-bar-grid">
|
|
180
|
-
<Axis placement="left" grid rule={false} ticks={4} format={() => ""} />
|
|
181
|
-
</g>
|
|
182
|
-
{/if}
|
|
183
|
-
{#each layers as layer (layer.key)}
|
|
184
|
-
{#if layer.at && horizontal}
|
|
185
|
-
<Bars x={layer.at} style="fill: {layer.color}" class="hr-bar-bars" />
|
|
186
|
-
{:else if layer.at}
|
|
187
|
-
<Bars y={layer.at} style="fill: {layer.color}" class="hr-bar-bars" />
|
|
188
|
-
{:else}
|
|
189
|
-
<Bars
|
|
190
|
-
data={layer.rows}
|
|
191
|
-
rounded={radius}
|
|
192
|
-
radius={4}
|
|
193
|
-
style="fill: {layer.color}"
|
|
194
|
-
class="hr-bar-bars"
|
|
195
|
-
/>
|
|
196
|
-
{/if}
|
|
197
|
-
{/each}
|
|
198
|
-
<!-- WHY: the band tooltip layer eats pointer events, so bar :hover never
|
|
199
|
-
fires. The active bar is a Highlight copy; motion "none" keeps it from
|
|
200
|
-
sliding between bands. -->
|
|
201
|
-
{#if !series}
|
|
202
|
-
<Highlight
|
|
203
|
-
motion="none"
|
|
204
|
-
bar={{ rounded: radius, radius: 4, fill: activeColor, class: "hr-bar-active" }}
|
|
205
|
-
/>
|
|
206
|
-
{/if}
|
|
207
|
-
</Svg>
|
|
208
|
-
<Tooltip.Root
|
|
209
|
-
x={horizontal ? "pointer" : "data"}
|
|
210
|
-
y={horizontal ? "data" : TOOLTIP_TOP}
|
|
211
|
-
xOffset={TOOLTIP_GAP}
|
|
212
|
-
>
|
|
213
|
-
{#snippet children({ data: d })}
|
|
214
|
-
<Tooltip.Header value={trackActive(d as TData)} />
|
|
215
|
-
<Tooltip.List>
|
|
216
|
-
{#if series}
|
|
217
|
-
{#each series as s (s.key)}
|
|
218
|
-
<Tooltip.Item
|
|
219
|
-
label={s.label}
|
|
220
|
-
value={formatValue(Number(d[s.key] ?? 0))}
|
|
221
|
-
color={s.color}
|
|
222
|
-
/>
|
|
223
|
-
{/each}
|
|
224
|
-
{:else}
|
|
225
|
-
<Tooltip.Item
|
|
226
|
-
label={valueLabel}
|
|
227
|
-
value={formatValue(valueOf(d as TData))}
|
|
228
|
-
color={colorOf ? colorOf(d as TData) : color}
|
|
229
|
-
/>
|
|
230
|
-
{/if}
|
|
231
|
-
</Tooltip.List>
|
|
232
|
-
{/snippet}
|
|
233
|
-
</Tooltip.Root>
|
|
234
|
-
</Chart>
|
|
235
|
-
{/if}
|
|
236
|
-
</div>
|
|
237
|
-
|
|
238
|
-
{#if label && data.length > 0}
|
|
239
|
-
<table class="hr-sr-only">
|
|
240
|
-
<caption>{label}</caption>
|
|
241
|
-
<thead>
|
|
242
|
-
<tr>
|
|
243
|
-
<th scope="col">{xLabel}</th>
|
|
244
|
-
{#if series}
|
|
245
|
-
{#each series as s (s.key)}
|
|
246
|
-
<th scope="col">{s.label}</th>
|
|
247
|
-
{/each}
|
|
248
|
-
{:else}
|
|
249
|
-
<th scope="col">{yLabel}</th>
|
|
250
|
-
{/if}
|
|
251
|
-
</tr>
|
|
252
|
-
</thead>
|
|
253
|
-
<tbody>
|
|
254
|
-
{#each data as d, i (i)}
|
|
255
|
-
<tr>
|
|
256
|
-
<th scope="row">{formatX(d[xKey])}</th>
|
|
257
|
-
{#if series}
|
|
258
|
-
{#each series as s (s.key)}
|
|
259
|
-
<td>{formatValue(Number(d[s.key] ?? 0))}</td>
|
|
260
|
-
{/each}
|
|
261
|
-
{:else}
|
|
262
|
-
<td>{formatValue(valueOf(d))}</td>
|
|
263
|
-
{/if}
|
|
264
|
-
</tr>
|
|
265
|
-
{/each}
|
|
266
|
-
</tbody>
|
|
267
|
-
</table>
|
|
268
|
-
{/if}
|
|
269
|
-
</div>
|
package/src/charts/charts.css
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/* Global theming for layerchart-rendered chrome shared by every chart in this
|
|
2
|
-
package (tooltip surface, header, rows). Ships with `@heyramzi/ui/charts`, so
|
|
3
|
-
any consumer that defines the shadcn token set gets a legible tooltip in both
|
|
4
|
-
themes for free.
|
|
5
|
-
|
|
6
|
-
WHY: layerchart's built-in `default` tooltip paints itself with
|
|
7
|
-
`light-dark(var(--color-surface-100, white), var(--color-surface-300, black))`
|
|
8
|
-
and a `backdrop-filter` blur. Apps that don't define `--color-surface-*` (and
|
|
9
|
-
don't set `color-scheme`) fall back to a translucent white card, which is
|
|
10
|
-
unreadable on a dark page. These rules repaint it with `--popover` /
|
|
11
|
-
`--border` / `--muted-foreground`, which already flip per theme. The selectors
|
|
12
|
-
stay unlayered so they beat layerchart's `@layer component` defaults
|
|
13
|
-
regardless of specificity. */
|
|
14
|
-
|
|
15
|
-
.lc-tooltip-container[data-variant="default"] {
|
|
16
|
-
color: var(--popover-foreground, var(--foreground));
|
|
17
|
-
background-color: var(--popover, #fff);
|
|
18
|
-
border: 1px solid var(--border, transparent);
|
|
19
|
-
border-radius: 0.5rem;
|
|
20
|
-
padding: 0.625rem 0.75rem;
|
|
21
|
-
min-width: 8.75rem;
|
|
22
|
-
backdrop-filter: none;
|
|
23
|
-
box-shadow:
|
|
24
|
-
0 1px 2px -1px oklch(0 0 0 / 0.2),
|
|
25
|
-
0 10px 28px -10px oklch(0 0 0 / 0.32);
|
|
26
|
-
/* WHY: opacity only; the container's transform is inline positioning, so
|
|
27
|
-
animating transform here would fight it and make the tooltip jump. */
|
|
28
|
-
transform-origin: top left;
|
|
29
|
-
animation: hr-tooltip-in var(--duration-fast, 250ms) var(--ease-smooth-out) both;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/* WHY `scale` and `translate`, not `transform`: the container's inline transform is
|
|
33
|
-
its position, and the individual properties compose with it instead of fighting. */
|
|
34
|
-
@keyframes hr-tooltip-in {
|
|
35
|
-
from {
|
|
36
|
-
opacity: 0;
|
|
37
|
-
scale: var(--scale-large, 0.96);
|
|
38
|
-
translate: calc(var(--distance-small, 6px) * -1) 0;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@media (prefers-reduced-motion: reduce) {
|
|
43
|
-
.lc-tooltip-container[data-variant="default"] {
|
|
44
|
-
animation: none;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/* bklit-ui's panel: a small title with no rule under it, and a dot on every row. */
|
|
49
|
-
.lc-tooltip-header {
|
|
50
|
-
color: var(--popover-foreground, var(--foreground));
|
|
51
|
-
font-size: 0.75rem;
|
|
52
|
-
font-weight: 500;
|
|
53
|
-
border-bottom: none;
|
|
54
|
-
margin-bottom: 0.5rem;
|
|
55
|
-
padding-bottom: 0;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.lc-tooltip-list {
|
|
59
|
-
gap: 0.375rem 1rem;
|
|
60
|
-
font-size: 0.8125rem;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.lc-tooltip-item-color {
|
|
64
|
-
width: 0.625rem;
|
|
65
|
-
height: 0.625rem;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.lc-tooltip-item-label,
|
|
69
|
-
.lc-tooltip-container .label {
|
|
70
|
-
color: var(--muted-foreground);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.lc-tooltip-item-value,
|
|
74
|
-
.lc-tooltip-container .value {
|
|
75
|
-
color: var(--popover-foreground, var(--foreground));
|
|
76
|
-
font-weight: 500;
|
|
77
|
-
font-variant-numeric: tabular-nums;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/* Shared chart tokens, held at zero specificity by `:where()`. The reveal pair
|
|
81
|
-
is the entrance every chart shares; motion.ts mirrors its duration. */
|
|
82
|
-
:where(
|
|
83
|
-
.hr-area-chart,
|
|
84
|
-
.hr-bar-chart,
|
|
85
|
-
.hr-line-chart,
|
|
86
|
-
.hr-sparkline,
|
|
87
|
-
.hr-number-chart,
|
|
88
|
-
.hr-stat-card,
|
|
89
|
-
.hr-legend,
|
|
90
|
-
.hr-ts-chart,
|
|
91
|
-
.hr-donut-chart,
|
|
92
|
-
.hr-ring,
|
|
93
|
-
.hr-gauge
|
|
94
|
-
) {
|
|
95
|
-
--chart-label: var(--muted-foreground, oklch(0.5 0.01 286));
|
|
96
|
-
--chart-grid: color-mix(in srgb, var(--border, oklch(0.5 0.01 286)) 65%, transparent);
|
|
97
|
-
--chart-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
|
|
98
|
-
--chart-motion-fast: 150ms;
|
|
99
|
-
--chart-motion: 250ms;
|
|
100
|
-
--chart-motion-slow: 800ms;
|
|
101
|
-
--chart-motion-reveal: 1100ms;
|
|
102
|
-
--chart-ease-reveal: cubic-bezier(0.85, 0, 0.15, 1);
|
|
103
|
-
--chart-stagger: 30ms;
|
|
104
|
-
--chart-crosshair: color-mix(
|
|
105
|
-
in srgb,
|
|
106
|
-
var(--muted-foreground, oklch(0.5 0.01 286)) 60%,
|
|
107
|
-
transparent
|
|
108
|
-
);
|
|
109
|
-
--chart-card-shadow: 0 1px 2px 0 oklch(0 0 0 / 0.04), 0 1px 3px 0 oklch(0 0 0 / 0.06);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/* Shared layerchart chrome: axis labels, grid rules, and hover highlights were
|
|
113
|
-
duplicated identically across every chart's scoped <style>. Centralize them
|
|
114
|
-
here, scoped to the chart roots, so the look is defined once. `:where()` keeps
|
|
115
|
-
specificity at 0 so a component can still override locally if it must. */
|
|
116
|
-
:where(
|
|
117
|
-
.hr-area-chart,
|
|
118
|
-
.hr-bar-chart,
|
|
119
|
-
.hr-line-chart,
|
|
120
|
-
.hr-scatter-chart,
|
|
121
|
-
.hr-live-line-chart,
|
|
122
|
-
.hr-sparkline,
|
|
123
|
-
.hr-stat-card,
|
|
124
|
-
.hr-donut-chart
|
|
125
|
-
)
|
|
126
|
-
.lc-axis-tick-label {
|
|
127
|
-
fill: var(--chart-label);
|
|
128
|
-
font-size: 11px;
|
|
129
|
-
}
|
|
130
|
-
:where(
|
|
131
|
-
.hr-area-chart,
|
|
132
|
-
.hr-bar-chart,
|
|
133
|
-
.hr-line-chart,
|
|
134
|
-
.hr-scatter-chart,
|
|
135
|
-
.hr-live-line-chart,
|
|
136
|
-
.hr-sparkline,
|
|
137
|
-
.hr-stat-card,
|
|
138
|
-
.hr-donut-chart
|
|
139
|
-
)
|
|
140
|
-
.lc-axis-tick {
|
|
141
|
-
stroke: transparent;
|
|
142
|
-
}
|
|
143
|
-
:where(
|
|
144
|
-
.hr-area-chart,
|
|
145
|
-
.hr-bar-chart,
|
|
146
|
-
.hr-line-chart,
|
|
147
|
-
.hr-scatter-chart,
|
|
148
|
-
.hr-live-line-chart,
|
|
149
|
-
.hr-sparkline,
|
|
150
|
-
.hr-stat-card,
|
|
151
|
-
.hr-donut-chart
|
|
152
|
-
)
|
|
153
|
-
:is(.lc-grid-x-rule, .lc-grid-y-rule) {
|
|
154
|
-
stroke: var(--chart-grid);
|
|
155
|
-
stroke-dasharray: 4 4;
|
|
156
|
-
}
|
|
157
|
-
:where(
|
|
158
|
-
.hr-area-chart,
|
|
159
|
-
.hr-bar-chart,
|
|
160
|
-
.hr-line-chart,
|
|
161
|
-
.hr-scatter-chart,
|
|
162
|
-
.hr-live-line-chart,
|
|
163
|
-
.hr-sparkline,
|
|
164
|
-
.hr-stat-card,
|
|
165
|
-
.hr-donut-chart
|
|
166
|
-
)
|
|
167
|
-
.lc-highlight-point {
|
|
168
|
-
stroke: var(--background, white);
|
|
169
|
-
stroke-width: 2;
|
|
170
|
-
}
|
|
171
|
-
:where(
|
|
172
|
-
.hr-area-chart,
|
|
173
|
-
.hr-bar-chart,
|
|
174
|
-
.hr-line-chart,
|
|
175
|
-
.hr-scatter-chart,
|
|
176
|
-
.hr-live-line-chart,
|
|
177
|
-
.hr-sparkline,
|
|
178
|
-
.hr-stat-card,
|
|
179
|
-
.hr-donut-chart
|
|
180
|
-
)
|
|
181
|
-
.lc-highlight-line {
|
|
182
|
-
stroke: var(--chart-grid);
|
|
183
|
-
stroke-width: 1;
|
|
184
|
-
stroke-dasharray: none;
|
|
185
|
-
}
|
|
186
|
-
/* bklit-ui's hover: the series drops to 0.3 and hover-focus.svelte redraws the
|
|
187
|
-
stretch around the point at full strength. */
|
|
188
|
-
.hr-hover-dim {
|
|
189
|
-
transition: opacity 400ms ease-in-out;
|
|
190
|
-
}
|
|
191
|
-
.hr-hover-dim.hr-hover-dimmed {
|
|
192
|
-
opacity: 0.3;
|
|
193
|
-
}
|
|
194
|
-
@media (prefers-reduced-motion: reduce) {
|
|
195
|
-
.hr-hover-dim {
|
|
196
|
-
transition: none;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
.hr-crosshair-stop {
|
|
200
|
-
stop-color: var(--chart-crosshair);
|
|
201
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
// =========================
|
|
3
|
-
// IMPORTS
|
|
4
|
-
// =========================
|
|
5
|
-
import { getChartContext } from "layerchart";
|
|
6
|
-
|
|
7
|
-
// =========================
|
|
8
|
-
// TYPES
|
|
9
|
-
// =========================
|
|
10
|
-
type Props = {
|
|
11
|
-
/** Gradient id. Paint the highlight line with `stroke: url(#id)`. */
|
|
12
|
-
id: string;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
// =========================
|
|
16
|
-
// PROPS
|
|
17
|
-
// =========================
|
|
18
|
-
let { id }: Props = $props();
|
|
19
|
-
|
|
20
|
-
const ctx = getChartContext();
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
<!-- =========================== -->
|
|
24
|
-
<!-- CROSSHAIR -->
|
|
25
|
-
<!-- =========================== -->
|
|
26
|
-
<!-- WHY userSpaceOnUse: a vertical line has a zero-width bounding box, so an
|
|
27
|
-
objectBoundingBox gradient on it paints nothing. -->
|
|
28
|
-
<defs>
|
|
29
|
-
<linearGradient {id} gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2={ctx.height}>
|
|
30
|
-
<stop offset="0" class="hr-crosshair-stop" stop-opacity="0" />
|
|
31
|
-
<stop offset="0.12" class="hr-crosshair-stop" />
|
|
32
|
-
<stop offset="0.88" class="hr-crosshair-stop" />
|
|
33
|
-
<stop offset="1" class="hr-crosshair-stop" stop-opacity="0" />
|
|
34
|
-
</linearGradient>
|
|
35
|
-
</defs>
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/* Styles for DonutChart. Plain stylesheet (see area-chart.css for why).
|
|
2
|
-
Selectors are namespaced under `.hr-donut-chart`. */
|
|
3
|
-
|
|
4
|
-
.hr-donut-chart {
|
|
5
|
-
width: 100%;
|
|
6
|
-
display: flex;
|
|
7
|
-
justify-content: center;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.hr-donut-chart .empty {
|
|
11
|
-
display: flex;
|
|
12
|
-
align-items: center;
|
|
13
|
-
justify-content: center;
|
|
14
|
-
width: 100%;
|
|
15
|
-
border: 1px dashed var(--chart-grid, oklch(0.5 0.01 286 / 0.2));
|
|
16
|
-
border-radius: 0.5rem;
|
|
17
|
-
}
|
|
18
|
-
.hr-donut-chart .empty p {
|
|
19
|
-
font-size: 0.8125rem;
|
|
20
|
-
color: var(--chart-label, oklch(0.5 0.01 286));
|
|
21
|
-
margin: 0;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/* The slice slides out a little slower than it slides back: a close is always the quicker. */
|
|
25
|
-
.hr-donut-chart .hr-donut-arc {
|
|
26
|
-
cursor: pointer;
|
|
27
|
-
transition:
|
|
28
|
-
opacity var(--chart-motion-fast, 150ms) ease,
|
|
29
|
-
translate var(--duration-quick, 150ms) var(--ease-smooth-out, ease-out);
|
|
30
|
-
}
|
|
31
|
-
.hr-donut-chart .hr-donut-arc[data-hovered] {
|
|
32
|
-
transition:
|
|
33
|
-
opacity var(--chart-motion-fast, 150ms) ease,
|
|
34
|
-
translate var(--duration-fast, 250ms) var(--ease-smooth-out);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.hr-donut-chart .hr-donut-center-value {
|
|
38
|
-
fill: var(--foreground, oklch(0.18 0.02 240));
|
|
39
|
-
font-size: 16px;
|
|
40
|
-
font-weight: 600;
|
|
41
|
-
font-feature-settings: "tnum";
|
|
42
|
-
transition: opacity 180ms ease;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.hr-donut-chart .hr-donut-center-label {
|
|
46
|
-
fill: var(--chart-label, oklch(0.5 0.01 286));
|
|
47
|
-
font-size: 11px;
|
|
48
|
-
transition: opacity 180ms ease;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@media (prefers-reduced-motion: reduce) {
|
|
52
|
-
.hr-donut-chart .hr-donut-arc,
|
|
53
|
-
.hr-donut-chart .hr-donut-arc[data-hovered] {
|
|
54
|
-
transition: opacity 120ms ease;
|
|
55
|
-
}
|
|
56
|
-
}
|