@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
package/src/charts/legend.svelte
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
// =========================
|
|
3
|
-
// IMPORTS
|
|
4
|
-
// =========================
|
|
5
|
-
import "./legend.css";
|
|
6
|
-
import { cn } from "@heyramzi/utils";
|
|
7
|
-
|
|
8
|
-
// =========================
|
|
9
|
-
// TYPES
|
|
10
|
-
// =========================
|
|
11
|
-
type LegendItem = {
|
|
12
|
-
label: string;
|
|
13
|
-
value: number;
|
|
14
|
-
/** Required when `showProgress` or `showPercentage` is set. */
|
|
15
|
-
maxValue?: number;
|
|
16
|
-
color: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
type Props = {
|
|
20
|
-
items: LegendItem[];
|
|
21
|
-
title?: string;
|
|
22
|
-
/** Stacked rows vs inline wrap. */
|
|
23
|
-
layout?: "vertical" | "horizontal";
|
|
24
|
-
/** Render a progress bar under each row (needs maxValue). */
|
|
25
|
-
showProgress?: boolean;
|
|
26
|
-
/** Show the value beside each label. */
|
|
27
|
-
showValue?: boolean;
|
|
28
|
-
/** Append a percentage (needs maxValue). */
|
|
29
|
-
showPercentage?: boolean;
|
|
30
|
-
formatValue?: (v: number) => string;
|
|
31
|
-
formatPercentage?: (p: number) => string;
|
|
32
|
-
/** Hovered index, bindable for chart hover-sync. */
|
|
33
|
-
hoveredIndex?: number | null;
|
|
34
|
-
onHoverChange?: (index: number | null) => void;
|
|
35
|
-
class?: string;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// =========================
|
|
39
|
-
// PROPS
|
|
40
|
-
// =========================
|
|
41
|
-
let {
|
|
42
|
-
items,
|
|
43
|
-
title,
|
|
44
|
-
layout = "vertical",
|
|
45
|
-
showProgress = false,
|
|
46
|
-
showValue = true,
|
|
47
|
-
showPercentage = false,
|
|
48
|
-
formatValue = (v) => v.toLocaleString(),
|
|
49
|
-
formatPercentage = (p) => `${p.toFixed(0)}%`,
|
|
50
|
-
hoveredIndex = $bindable(null),
|
|
51
|
-
onHoverChange,
|
|
52
|
-
class: className,
|
|
53
|
-
}: Props = $props();
|
|
54
|
-
|
|
55
|
-
// =========================
|
|
56
|
-
// FUNCTIONS
|
|
57
|
-
// =========================
|
|
58
|
-
function pct(item: LegendItem): number {
|
|
59
|
-
if (!item.maxValue || item.maxValue <= 0) return 0;
|
|
60
|
-
return Math.max(0, Math.min(100, (item.value / item.maxValue) * 100));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function setHover(index: number | null) {
|
|
64
|
-
hoveredIndex = index;
|
|
65
|
-
onHoverChange?.(index);
|
|
66
|
-
}
|
|
67
|
-
</script>
|
|
68
|
-
|
|
69
|
-
<!-- =========================== -->
|
|
70
|
-
<!-- MARKUP -->
|
|
71
|
-
<!-- =========================== -->
|
|
72
|
-
<div class={cn("hr-legend", className)} class:horizontal={layout === "horizontal"}>
|
|
73
|
-
{#if title}
|
|
74
|
-
<p class="hr-legend-title">{title}</p>
|
|
75
|
-
{/if}
|
|
76
|
-
<ul class="hr-legend-items">
|
|
77
|
-
{#each items as item, i (item.label + i)}
|
|
78
|
-
{@const dimmed = hoveredIndex !== null && hoveredIndex !== i}
|
|
79
|
-
<li>
|
|
80
|
-
<button
|
|
81
|
-
type="button"
|
|
82
|
-
class="hr-legend-item"
|
|
83
|
-
class:dimmed
|
|
84
|
-
onmouseenter={() => setHover(i)}
|
|
85
|
-
onmouseleave={() => setHover(null)}
|
|
86
|
-
onfocus={() => setHover(i)}
|
|
87
|
-
onblur={() => setHover(null)}
|
|
88
|
-
>
|
|
89
|
-
<span class="hr-legend-marker" style:background={item.color}></span>
|
|
90
|
-
<span class="hr-legend-label">{item.label}</span>
|
|
91
|
-
{#if showValue}
|
|
92
|
-
<span class="hr-legend-value">
|
|
93
|
-
{formatValue(item.value)}{#if showPercentage && item.maxValue}<span
|
|
94
|
-
class="hr-legend-pct">{formatPercentage(pct(item))}</span
|
|
95
|
-
>{/if}
|
|
96
|
-
</span>
|
|
97
|
-
{/if}
|
|
98
|
-
{#if showProgress && item.maxValue}
|
|
99
|
-
<span class="hr-legend-track">
|
|
100
|
-
<span
|
|
101
|
-
class="hr-legend-bar"
|
|
102
|
-
style:--hr-bar-scale={pct(item) / 100}
|
|
103
|
-
style:background={item.color}
|
|
104
|
-
style:animation-delay="{160 + i * 120}ms"
|
|
105
|
-
></span>
|
|
106
|
-
</span>
|
|
107
|
-
{/if}
|
|
108
|
-
</button>
|
|
109
|
-
</li>
|
|
110
|
-
{/each}
|
|
111
|
-
</ul>
|
|
112
|
-
</div>
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/* Styles for LineChart. Plain stylesheet (see area-chart.css for why). Selectors
|
|
2
|
-
are namespaced under `.hr-line-chart`. */
|
|
3
|
-
|
|
4
|
-
.hr-line-chart {
|
|
5
|
-
width: 100%;
|
|
6
|
-
display: flex;
|
|
7
|
-
flex-direction: column;
|
|
8
|
-
gap: 0.5rem;
|
|
9
|
-
}
|
|
10
|
-
.hr-line-chart .hr-chart-body {
|
|
11
|
-
width: 100%;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.hr-line-chart .empty {
|
|
15
|
-
display: flex;
|
|
16
|
-
align-items: center;
|
|
17
|
-
justify-content: center;
|
|
18
|
-
height: 100%;
|
|
19
|
-
border: 1px dashed var(--chart-grid, oklch(0.5 0.01 286 / 0.2));
|
|
20
|
-
border-radius: 0.5rem;
|
|
21
|
-
}
|
|
22
|
-
.hr-line-chart .empty p {
|
|
23
|
-
font-size: 0.8125rem;
|
|
24
|
-
color: var(--chart-label, oklch(0.5 0.01 286));
|
|
25
|
-
margin: 0;
|
|
26
|
-
}
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
-
// =========================
|
|
3
|
-
// IMPORTS
|
|
4
|
-
// =========================
|
|
5
|
-
import "./line-chart.css";
|
|
6
|
-
import {
|
|
7
|
-
Area,
|
|
8
|
-
Axis,
|
|
9
|
-
Chart,
|
|
10
|
-
Highlight,
|
|
11
|
-
LinearGradient,
|
|
12
|
-
Points,
|
|
13
|
-
Spline,
|
|
14
|
-
Svg,
|
|
15
|
-
Tooltip,
|
|
16
|
-
} from "layerchart";
|
|
17
|
-
import { curveMonotoneX } from "d3-shape";
|
|
18
|
-
import Crosshair from "./crosshair.svelte";
|
|
19
|
-
import EdgeFade from "./edge-fade.svelte";
|
|
20
|
-
import { resolveEdgeFade } from "./edge-fade.js";
|
|
21
|
-
import Figure from "./figure.svelte";
|
|
22
|
-
import HoverFocus from "./hover-focus.svelte";
|
|
23
|
-
import { DOMAIN_MOTION, TOOLTIP_GAP, TOOLTIP_TOP } from "./motion.js";
|
|
24
|
-
import Reveal from "./reveal.svelte";
|
|
25
|
-
|
|
26
|
-
// =========================
|
|
27
|
-
// TYPES
|
|
28
|
-
// =========================
|
|
29
|
-
type Series = {
|
|
30
|
-
key: keyof TData & string;
|
|
31
|
-
label?: string;
|
|
32
|
-
color?: string;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
type Props = {
|
|
36
|
-
data: TData[];
|
|
37
|
-
xKey: keyof TData & string;
|
|
38
|
-
yKey?: keyof TData & string;
|
|
39
|
-
series?: Series[];
|
|
40
|
-
color?: string;
|
|
41
|
-
height?: number;
|
|
42
|
-
smooth?: boolean;
|
|
43
|
-
/**
|
|
44
|
-
* Softens the left and right ends of the gradient fill instead of cutting them off at the plot edge.
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
/*
|
|
48
|
-
* `true` fades 8% of the width per side, a number sets the fraction (0-0.45), `false` keeps the hard edges.
|
|
49
|
-
*/
|
|
50
|
-
edgeFade?: boolean | number;
|
|
51
|
-
/** Draw a ring marker at every data point. */
|
|
52
|
-
showMarkers?: boolean;
|
|
53
|
-
/** Inclusive index where a dashed "in progress" tail begins (e.g. the latest, still-open period). */
|
|
54
|
-
dashFromIndex?: number;
|
|
55
|
-
/** Dash pattern for the tail segment. */
|
|
56
|
-
dashArray?: string;
|
|
57
|
-
formatValue?: (v: number) => string;
|
|
58
|
-
formatX?: (v: unknown) => string;
|
|
59
|
-
class?: string;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
// =========================
|
|
63
|
-
// PROPS
|
|
64
|
-
// =========================
|
|
65
|
-
let {
|
|
66
|
-
data,
|
|
67
|
-
xKey,
|
|
68
|
-
yKey,
|
|
69
|
-
series: seriesInput,
|
|
70
|
-
color = "var(--chart-1)",
|
|
71
|
-
height = 240,
|
|
72
|
-
smooth = true,
|
|
73
|
-
edgeFade = true,
|
|
74
|
-
showMarkers = false,
|
|
75
|
-
dashFromIndex,
|
|
76
|
-
dashArray = "5 4",
|
|
77
|
-
formatValue = (v) => v.toLocaleString(),
|
|
78
|
-
formatX = (v) => String(v),
|
|
79
|
-
class: className,
|
|
80
|
-
}: Props = $props();
|
|
81
|
-
|
|
82
|
-
// =========================
|
|
83
|
-
// STATE
|
|
84
|
-
// =========================
|
|
85
|
-
let active = $state<TData | null>(null);
|
|
86
|
-
|
|
87
|
-
// ========================= FUNCTIONS ========================= WHY: called from the tooltip header's value expression so it re-runs on every active-point change; an unread {@const} side effect only evaluates once.
|
|
88
|
-
|
|
89
|
-
// The microtask defers the state write out of template evaluation.
|
|
90
|
-
function trackActive(d: TData): string {
|
|
91
|
-
queueMicrotask(() => {
|
|
92
|
-
active = d;
|
|
93
|
-
});
|
|
94
|
-
return formatX(d[xKey]);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// =========================
|
|
98
|
-
// DERIVED
|
|
99
|
-
// =========================
|
|
100
|
-
const uid = `hr-line-${Math.random().toString(36).slice(2, 8)}`;
|
|
101
|
-
const series = $derived(
|
|
102
|
-
seriesInput && seriesInput.length > 0
|
|
103
|
-
? seriesInput.map((s, i) => ({
|
|
104
|
-
key: s.key,
|
|
105
|
-
label: s.label ?? s.key,
|
|
106
|
-
color: s.color ?? `var(--chart-${(i % 5) + 1})`,
|
|
107
|
-
}))
|
|
108
|
-
: yKey
|
|
109
|
-
? [{ key: yKey, label: yKey, color }]
|
|
110
|
-
: [],
|
|
111
|
-
);
|
|
112
|
-
const yMax = $derived(
|
|
113
|
-
Math.max(0, ...data.flatMap((d) => series.map((s) => Number(d[s.key] ?? 0)))),
|
|
114
|
-
);
|
|
115
|
-
const curve = $derived(smooth ? curveMonotoneX : undefined);
|
|
116
|
-
const fade = $derived(resolveEdgeFade(edgeFade));
|
|
117
|
-
const fadeMask = $derived(fade > 0 ? `url(#${uid}-fade)` : undefined);
|
|
118
|
-
const fallback = $derived(data.length > 0 ? data[data.length - 1] : null);
|
|
119
|
-
const display = $derived(active ?? fallback);
|
|
120
|
-
// WHY: a dashed tail is two splines sharing the boundary point so the solid
|
|
121
|
-
// and dashed segments meet without a gap.
|
|
122
|
-
const hasTail = $derived(
|
|
123
|
-
dashFromIndex != null && dashFromIndex >= 0 && dashFromIndex < data.length - 1,
|
|
124
|
-
);
|
|
125
|
-
const solidData = $derived(hasTail ? data.slice(0, (dashFromIndex as number) + 1) : data);
|
|
126
|
-
const tailData = $derived(hasTail ? data.slice(dashFromIndex as number) : []);
|
|
127
|
-
const figureRows = $derived(
|
|
128
|
-
display
|
|
129
|
-
? series.map((s) => ({ value: Number(display[s.key]), label: s.label, color: s.color }))
|
|
130
|
-
: null,
|
|
131
|
-
);
|
|
132
|
-
</script>
|
|
133
|
-
|
|
134
|
-
<!-- =========================== -->
|
|
135
|
-
<!-- LINE CHART -->
|
|
136
|
-
<!-- =========================== -->
|
|
137
|
-
<div
|
|
138
|
-
class="hr-line-chart {className ?? ''}"
|
|
139
|
-
role="img"
|
|
140
|
-
aria-label="Line chart"
|
|
141
|
-
onpointerleave={() => (active = null)}
|
|
142
|
-
>
|
|
143
|
-
{#if figureRows && display}
|
|
144
|
-
<Figure series={figureRows} eyebrow={formatX(display[xKey])} format={formatValue} size="md" />
|
|
145
|
-
{:else}
|
|
146
|
-
<Figure value="—" eyebrow="Latest" size="md" />
|
|
147
|
-
{/if}
|
|
148
|
-
|
|
149
|
-
<div class="hr-chart-body" style:height="{height}px">
|
|
150
|
-
{#snippet strokes(s: (typeof series)[number])}
|
|
151
|
-
{#if hasTail}
|
|
152
|
-
<Spline
|
|
153
|
-
data={solidData}
|
|
154
|
-
y={s.key}
|
|
155
|
-
{curve}
|
|
156
|
-
style="stroke: {s.color}; fill: none"
|
|
157
|
-
stroke-width="2"
|
|
158
|
-
stroke-linecap="round"
|
|
159
|
-
/>
|
|
160
|
-
<Spline
|
|
161
|
-
data={tailData}
|
|
162
|
-
y={s.key}
|
|
163
|
-
{curve}
|
|
164
|
-
style="stroke: {s.color}; fill: none"
|
|
165
|
-
stroke-width="2"
|
|
166
|
-
stroke-dasharray={dashArray}
|
|
167
|
-
/>
|
|
168
|
-
{:else}
|
|
169
|
-
<Spline
|
|
170
|
-
y={s.key}
|
|
171
|
-
{curve}
|
|
172
|
-
style="stroke: {s.color}; fill: none"
|
|
173
|
-
stroke-width="2"
|
|
174
|
-
stroke-linecap="round"
|
|
175
|
-
/>
|
|
176
|
-
{/if}
|
|
177
|
-
{/snippet}
|
|
178
|
-
{#if data.length === 0}
|
|
179
|
-
<div class="empty"><p>No data</p></div>
|
|
180
|
-
{:else}
|
|
181
|
-
<Chart
|
|
182
|
-
{data}
|
|
183
|
-
x={xKey}
|
|
184
|
-
y={series[0]?.key}
|
|
185
|
-
yDomain={[0, yMax || 1]}
|
|
186
|
-
yNice
|
|
187
|
-
padding={{ left: 48, bottom: 28, top: 8, right: 12 }}
|
|
188
|
-
tooltipContext={{ mode: "bisect-x" }}
|
|
189
|
-
motion={DOMAIN_MOTION}
|
|
190
|
-
>
|
|
191
|
-
<Svg>
|
|
192
|
-
<Axis placement="left" format={(v) => formatValue(Number(v))} ticks={4} />
|
|
193
|
-
<Axis placement="bottom" format={(v) => formatX(v)} />
|
|
194
|
-
<g class="hr-line-grid">
|
|
195
|
-
<Axis placement="left" grid rule={false} ticks={4} format={() => ""} />
|
|
196
|
-
</g>
|
|
197
|
-
{#if fade > 0}
|
|
198
|
-
<EdgeFade id="{uid}-fade" amount={fade} />
|
|
199
|
-
{/if}
|
|
200
|
-
<Crosshair id="{uid}-cross" />
|
|
201
|
-
<HoverFocus>
|
|
202
|
-
<Reveal>
|
|
203
|
-
{#each series as s, i (s.key)}
|
|
204
|
-
<LinearGradient id="{uid}-{i}" vertical>
|
|
205
|
-
{#snippet stopsContent()}
|
|
206
|
-
<stop offset="0%" stop-color={s.color} stop-opacity="0.22" />
|
|
207
|
-
<stop offset="100%" stop-color={s.color} stop-opacity="0.01" />
|
|
208
|
-
{/snippet}
|
|
209
|
-
</LinearGradient>
|
|
210
|
-
<Area
|
|
211
|
-
y1={s.key}
|
|
212
|
-
{curve}
|
|
213
|
-
fill="url(#{uid}-{i})"
|
|
214
|
-
mask={fadeMask}
|
|
215
|
-
line={false}
|
|
216
|
-
class="hr-line-area"
|
|
217
|
-
/>
|
|
218
|
-
{@render strokes(s)}
|
|
219
|
-
{#if showMarkers}
|
|
220
|
-
<Points
|
|
221
|
-
y={s.key}
|
|
222
|
-
r={3}
|
|
223
|
-
fill="var(--background, white)"
|
|
224
|
-
stroke={s.color}
|
|
225
|
-
stroke-width={2}
|
|
226
|
-
class="hr-line-marker"
|
|
227
|
-
/>
|
|
228
|
-
{/if}
|
|
229
|
-
{/each}
|
|
230
|
-
</Reveal>
|
|
231
|
-
{#snippet segment()}
|
|
232
|
-
{#each series as s (s.key)}
|
|
233
|
-
{@render strokes(s)}
|
|
234
|
-
{/each}
|
|
235
|
-
{/snippet}
|
|
236
|
-
</HoverFocus>
|
|
237
|
-
<Highlight points lines={{ style: `stroke: url(#${uid}-cross)` }} />
|
|
238
|
-
</Svg>
|
|
239
|
-
<Tooltip.Root x="data" y={TOOLTIP_TOP} xOffset={TOOLTIP_GAP}>
|
|
240
|
-
{#snippet children({ data: d })}
|
|
241
|
-
<Tooltip.Header value={trackActive(d as TData)} />
|
|
242
|
-
<Tooltip.List>
|
|
243
|
-
{#each series as s (s.key)}
|
|
244
|
-
<Tooltip.Item
|
|
245
|
-
label={s.label}
|
|
246
|
-
value={formatValue(Number(d[s.key]))}
|
|
247
|
-
color={s.color}
|
|
248
|
-
/>
|
|
249
|
-
{/each}
|
|
250
|
-
</Tooltip.List>
|
|
251
|
-
{/snippet}
|
|
252
|
-
</Tooltip.Root>
|
|
253
|
-
</Chart>
|
|
254
|
-
{/if}
|
|
255
|
-
</div>
|
|
256
|
-
</div>
|
package/src/charts/motion.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { cubicInOut } from "svelte/easing";
|
|
2
|
-
|
|
3
|
-
/** Mirrors `--chart-motion-reveal` in charts.css, for when no element is mounted to read it from. */
|
|
4
|
-
export const REVEAL_MS = 1100;
|
|
5
|
-
|
|
6
|
-
/** Rescales the axes when the data changes; the first render never animates. */
|
|
7
|
-
export const DOMAIN_MOTION = { type: "tween", duration: 500, easing: cubicInOut } as const;
|
|
8
|
-
|
|
9
|
-
/** The tooltip sits beside the hovered point at the top of the plot, so it never chases the cursor. */
|
|
10
|
-
export const TOOLTIP_TOP = 8;
|
|
11
|
-
export const TOOLTIP_GAP = 16;
|
|
12
|
-
|
|
13
|
-
/** A chart duration token in ms, read off a mounted element; both `ms` and `s` parse. */
|
|
14
|
-
export function tokenMs(el: Element, name: string, fallback: number): number {
|
|
15
|
-
const raw = getComputedStyle(el).getPropertyValue(name).trim();
|
|
16
|
-
const n = Number.parseFloat(raw);
|
|
17
|
-
if (Number.isNaN(n)) return fallback;
|
|
18
|
-
return raw.endsWith("ms") ? n : n * 1000;
|
|
19
|
-
}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
/* Styles for NumberChart. Plain stylesheet (see area-chart.css for why). All
|
|
2
|
-
selectors are already namespaced under `.hr-number-chart`. */
|
|
3
|
-
|
|
4
|
-
.hr-number-chart {
|
|
5
|
-
display: flex;
|
|
6
|
-
flex-direction: column;
|
|
7
|
-
gap: 0.375rem;
|
|
8
|
-
min-width: 0;
|
|
9
|
-
padding: 1rem 1.25rem;
|
|
10
|
-
border: 1px solid var(--border, oklch(0.92 0.004 286));
|
|
11
|
-
border-radius: 0.75rem;
|
|
12
|
-
background: var(--card, white);
|
|
13
|
-
box-shadow: var(--chart-card-shadow);
|
|
14
|
-
transition: border-color var(--chart-motion, 250ms) var(--chart-ease-out, ease);
|
|
15
|
-
}
|
|
16
|
-
.hr-number-chart:hover {
|
|
17
|
-
border-color: color-mix(in srgb, var(--ring, var(--chart-1)) 28%, var(--border, transparent));
|
|
18
|
-
}
|
|
19
|
-
/* WHY a bare mode and not a second component: a band is one panel with
|
|
20
|
-
hairlines through it, so a figure inside it must bring no edge of its own.
|
|
21
|
-
Same object, one less border. */
|
|
22
|
-
.hr-number-chart[data-bare] {
|
|
23
|
-
padding: 1rem;
|
|
24
|
-
border: 0;
|
|
25
|
-
border-radius: 0;
|
|
26
|
-
box-shadow: none;
|
|
27
|
-
}
|
|
28
|
-
.hr-number-chart[data-bare]:hover {
|
|
29
|
-
border-color: transparent;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.hr-number-label {
|
|
33
|
-
display: flex;
|
|
34
|
-
align-items: center;
|
|
35
|
-
gap: 0.375rem;
|
|
36
|
-
margin: 0;
|
|
37
|
-
font-size: 0.75rem;
|
|
38
|
-
font-weight: 500;
|
|
39
|
-
line-height: 1.4;
|
|
40
|
-
color: var(--muted-foreground, oklch(0.5 0.01 286));
|
|
41
|
-
}
|
|
42
|
-
.hr-number-label-text {
|
|
43
|
-
min-width: 0;
|
|
44
|
-
overflow: hidden;
|
|
45
|
-
text-overflow: ellipsis;
|
|
46
|
-
white-space: nowrap;
|
|
47
|
-
}
|
|
48
|
-
.hr-number-icon {
|
|
49
|
-
display: inline-flex;
|
|
50
|
-
align-items: center;
|
|
51
|
-
flex: none;
|
|
52
|
-
}
|
|
53
|
-
.hr-number-trailing {
|
|
54
|
-
margin-left: auto;
|
|
55
|
-
flex: none;
|
|
56
|
-
font-size: 0.625rem;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/* WHY the row is baseline-aligned and top-anchored: a band mixes figures that
|
|
60
|
-
carry a caption with figures that do not, and every value in the row has to
|
|
61
|
-
sit on one line. The slack falls to the bottom, where nothing reads it. */
|
|
62
|
-
.hr-number-row {
|
|
63
|
-
display: flex;
|
|
64
|
-
align-items: baseline;
|
|
65
|
-
justify-content: space-between;
|
|
66
|
-
gap: 0.5rem;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/* WHY the heading family and not the body one: a figure is structure, not
|
|
70
|
-
prose, and tabular digits are what makes a column of them scannable. */
|
|
71
|
-
.hr-number-value {
|
|
72
|
-
font-family: var(--font-heading, inherit);
|
|
73
|
-
font-weight: 600;
|
|
74
|
-
font-variant-numeric: tabular-nums;
|
|
75
|
-
font-feature-settings: "tnum";
|
|
76
|
-
line-height: 1.15;
|
|
77
|
-
letter-spacing: -0.015em;
|
|
78
|
-
color: var(--foreground, oklch(0.2 0.01 286));
|
|
79
|
-
min-width: 0;
|
|
80
|
-
}
|
|
81
|
-
.hr-number-chart[data-size="md"] .hr-number-value {
|
|
82
|
-
font-size: 1.25rem;
|
|
83
|
-
}
|
|
84
|
-
/* WHY the lead figure is size and not colour: the accent is spent on actions,
|
|
85
|
-
active states, marks and links. A number is none of those. */
|
|
86
|
-
.hr-number-chart[data-size="lg"] .hr-number-value {
|
|
87
|
-
font-size: 1.5rem;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.hr-number-delta {
|
|
91
|
-
display: inline-flex;
|
|
92
|
-
align-items: center;
|
|
93
|
-
gap: 0.125rem;
|
|
94
|
-
flex: none;
|
|
95
|
-
font-size: 0.75rem;
|
|
96
|
-
font-weight: 500;
|
|
97
|
-
line-height: 1.2;
|
|
98
|
-
color: var(--muted-foreground, oklch(0.5 0.01 286));
|
|
99
|
-
}
|
|
100
|
-
.hr-number-delta-text {
|
|
101
|
-
font-variant-numeric: tabular-nums;
|
|
102
|
-
}
|
|
103
|
-
/* The readable form of a trend colour: a hue picked to read as a mark measures
|
|
104
|
-
about 3.5:1 as 12px text, so it is mixed toward the page foreground. One rule
|
|
105
|
-
serves both themes and the package needs to know nothing about which is on. */
|
|
106
|
-
.hr-number-delta[data-tone="up"] {
|
|
107
|
-
color: color-mix(
|
|
108
|
-
in oklab,
|
|
109
|
-
var(--stat-up, var(--success, oklch(0.6 0.13 163))) 72%,
|
|
110
|
-
var(--foreground, oklch(0.2 0.01 286))
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
.hr-number-delta[data-tone="down"] {
|
|
114
|
-
color: color-mix(
|
|
115
|
-
in oklab,
|
|
116
|
-
var(--stat-down, var(--destructive, oklch(0.58 0.22 25))) 72%,
|
|
117
|
-
var(--foreground, oklch(0.2 0.01 286))
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
.hr-number-delta[data-tone="none"] {
|
|
121
|
-
color: color-mix(in srgb, var(--muted-foreground, oklch(0.5 0.01 286)) 40%, transparent);
|
|
122
|
-
}
|
|
123
|
-
.hr-number-chart .hr-number-arrow {
|
|
124
|
-
width: 0.875rem;
|
|
125
|
-
height: 0.875rem;
|
|
126
|
-
flex: none;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
.hr-number-track {
|
|
130
|
-
height: 0.25rem;
|
|
131
|
-
border-radius: 999px;
|
|
132
|
-
overflow: hidden;
|
|
133
|
-
background: color-mix(in srgb, var(--border, oklch(0.92 0.004 286)) 80%, transparent);
|
|
134
|
-
}
|
|
135
|
-
.hr-number-fill {
|
|
136
|
-
display: block;
|
|
137
|
-
height: 100%;
|
|
138
|
-
border-radius: inherit;
|
|
139
|
-
transform-origin: left center;
|
|
140
|
-
animation: hr-number-fill-in var(--chart-motion-slow, 800ms) var(--chart-ease-out, ease) both;
|
|
141
|
-
transition: width var(--chart-motion, 250ms) var(--chart-ease-out, ease);
|
|
142
|
-
}
|
|
143
|
-
@keyframes hr-number-fill-in {
|
|
144
|
-
from {
|
|
145
|
-
transform: scaleX(0);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
.hr-number-caption {
|
|
150
|
-
margin: 0;
|
|
151
|
-
font-size: 0.75rem;
|
|
152
|
-
line-height: 1.4;
|
|
153
|
-
color: var(--muted-foreground, oklch(0.5 0.01 286));
|
|
154
|
-
overflow: hidden;
|
|
155
|
-
text-overflow: ellipsis;
|
|
156
|
-
white-space: nowrap;
|
|
157
|
-
}
|
|
158
|
-
.hr-number-share {
|
|
159
|
-
font-variant-numeric: tabular-nums;
|
|
160
|
-
font-weight: 600;
|
|
161
|
-
color: var(--foreground, oklch(0.2 0.01 286));
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
@media (prefers-reduced-motion: reduce) {
|
|
165
|
-
.hr-number-fill {
|
|
166
|
-
animation: none;
|
|
167
|
-
}
|
|
168
|
-
}
|