@arcfusionz/arc-analytic-ui 0.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/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/components/AnomalyCard/AnomalyCard.chart.d.ts +64 -0
- package/dist/components/AnomalyCard/AnomalyCard.chart.js +341 -0
- package/dist/components/AnomalyCard/AnomalyCard.d.ts +169 -0
- package/dist/components/AnomalyCard/AnomalyCard.js +1019 -0
- package/dist/components/AnomalyCard/AnomalyCard.model.d.ts +508 -0
- package/dist/components/AnomalyCard/AnomalyCard.model.js +553 -0
- package/dist/components/AnomalyCard/index.d.ts +4 -0
- package/dist/components/AnomalyCard/index.js +4 -0
- package/dist/components/ChartCard/ChartCard.chart.d.ts +72 -0
- package/dist/components/ChartCard/ChartCard.chart.js +1333 -0
- package/dist/components/ChartCard/ChartCard.d.ts +206 -0
- package/dist/components/ChartCard/ChartCard.js +718 -0
- package/dist/components/ChartCard/ChartCard.model.d.ts +452 -0
- package/dist/components/ChartCard/ChartCard.model.js +1223 -0
- package/dist/components/ChartCard/index.d.ts +4 -0
- package/dist/components/ChartCard/index.js +4 -0
- package/dist/components/ComparisonCard/ComparisonCard.chart.d.ts +80 -0
- package/dist/components/ComparisonCard/ComparisonCard.chart.js +337 -0
- package/dist/components/ComparisonCard/ComparisonCard.d.ts +200 -0
- package/dist/components/ComparisonCard/ComparisonCard.js +1325 -0
- package/dist/components/ComparisonCard/ComparisonCard.model.d.ts +309 -0
- package/dist/components/ComparisonCard/ComparisonCard.model.js +263 -0
- package/dist/components/ComparisonCard/index.d.ts +4 -0
- package/dist/components/ComparisonCard/index.js +4 -0
- package/dist/components/ForecastCard/ForecastCard.chart.d.ts +82 -0
- package/dist/components/ForecastCard/ForecastCard.chart.js +416 -0
- package/dist/components/ForecastCard/ForecastCard.d.ts +148 -0
- package/dist/components/ForecastCard/ForecastCard.js +1029 -0
- package/dist/components/ForecastCard/ForecastCard.model.d.ts +497 -0
- package/dist/components/ForecastCard/ForecastCard.model.js +554 -0
- package/dist/components/ForecastCard/index.d.ts +4 -0
- package/dist/components/ForecastCard/index.js +4 -0
- package/dist/components/HighlightCard/HighlightCard.chart.d.ts +122 -0
- package/dist/components/HighlightCard/HighlightCard.chart.js +660 -0
- package/dist/components/HighlightCard/HighlightCard.d.ts +202 -0
- package/dist/components/HighlightCard/HighlightCard.js +1286 -0
- package/dist/components/HighlightCard/HighlightCard.model.d.ts +692 -0
- package/dist/components/HighlightCard/HighlightCard.model.js +875 -0
- package/dist/components/HighlightCard/index.d.ts +4 -0
- package/dist/components/HighlightCard/index.js +4 -0
- package/dist/components/InsightCard/InsightCard.chart.d.ts +91 -0
- package/dist/components/InsightCard/InsightCard.chart.js +471 -0
- package/dist/components/InsightCard/InsightCard.d.ts +161 -0
- package/dist/components/InsightCard/InsightCard.js +961 -0
- package/dist/components/InsightCard/InsightCard.model.d.ts +405 -0
- package/dist/components/InsightCard/InsightCard.model.js +421 -0
- package/dist/components/InsightCard/index.d.ts +4 -0
- package/dist/components/InsightCard/index.js +4 -0
- package/dist/components/MetricCard/MetricCard.chart.d.ts +79 -0
- package/dist/components/MetricCard/MetricCard.chart.js +435 -0
- package/dist/components/MetricCard/MetricCard.d.ts +227 -0
- package/dist/components/MetricCard/MetricCard.js +1293 -0
- package/dist/components/MetricCard/MetricCard.model.d.ts +521 -0
- package/dist/components/MetricCard/MetricCard.model.js +627 -0
- package/dist/components/MetricCard/index.d.ts +4 -0
- package/dist/components/MetricCard/index.js +4 -0
- package/dist/components/ProfileCard/ProfileCard.chart.d.ts +64 -0
- package/dist/components/ProfileCard/ProfileCard.chart.js +427 -0
- package/dist/components/ProfileCard/ProfileCard.d.ts +140 -0
- package/dist/components/ProfileCard/ProfileCard.js +735 -0
- package/dist/components/ProfileCard/ProfileCard.model.d.ts +279 -0
- package/dist/components/ProfileCard/ProfileCard.model.js +244 -0
- package/dist/components/ProfileCard/index.d.ts +4 -0
- package/dist/components/ProfileCard/index.js +4 -0
- package/dist/components/ProgressCard/ProgressCard.chart.d.ts +73 -0
- package/dist/components/ProgressCard/ProgressCard.chart.js +373 -0
- package/dist/components/ProgressCard/ProgressCard.d.ts +137 -0
- package/dist/components/ProgressCard/ProgressCard.js +908 -0
- package/dist/components/ProgressCard/ProgressCard.model.d.ts +385 -0
- package/dist/components/ProgressCard/ProgressCard.model.js +389 -0
- package/dist/components/ProgressCard/index.d.ts +4 -0
- package/dist/components/ProgressCard/index.js +4 -0
- package/dist/components/ReportCard/ReportCard.chart.d.ts +45 -0
- package/dist/components/ReportCard/ReportCard.chart.js +231 -0
- package/dist/components/ReportCard/ReportCard.d.ts +153 -0
- package/dist/components/ReportCard/ReportCard.js +1118 -0
- package/dist/components/ReportCard/ReportCard.model.d.ts +392 -0
- package/dist/components/ReportCard/ReportCard.model.js +399 -0
- package/dist/components/ReportCard/index.d.ts +4 -0
- package/dist/components/ReportCard/index.js +4 -0
- package/dist/components/SankeyCard/SankeyCard.chart.d.ts +75 -0
- package/dist/components/SankeyCard/SankeyCard.chart.js +249 -0
- package/dist/components/SankeyCard/SankeyCard.d.ts +185 -0
- package/dist/components/SankeyCard/SankeyCard.js +788 -0
- package/dist/components/SankeyCard/SankeyCard.model.d.ts +501 -0
- package/dist/components/SankeyCard/SankeyCard.model.js +789 -0
- package/dist/components/SankeyCard/index.d.ts +4 -0
- package/dist/components/SankeyCard/index.js +4 -0
- package/dist/components/StatusCard/StatusCard.chart.d.ts +60 -0
- package/dist/components/StatusCard/StatusCard.chart.js +188 -0
- package/dist/components/StatusCard/StatusCard.d.ts +176 -0
- package/dist/components/StatusCard/StatusCard.js +989 -0
- package/dist/components/StatusCard/StatusCard.model.d.ts +555 -0
- package/dist/components/StatusCard/StatusCard.model.js +776 -0
- package/dist/components/StatusCard/index.d.ts +4 -0
- package/dist/components/StatusCard/index.js +4 -0
- package/dist/components/TableCard/TableCard.chart.d.ts +53 -0
- package/dist/components/TableCard/TableCard.chart.js +192 -0
- package/dist/components/TableCard/TableCard.d.ts +140 -0
- package/dist/components/TableCard/TableCard.js +811 -0
- package/dist/components/TableCard/TableCard.model.d.ts +381 -0
- package/dist/components/TableCard/TableCard.model.js +475 -0
- package/dist/components/TableCard/index.d.ts +4 -0
- package/dist/components/TableCard/index.js +4 -0
- package/dist/components/TargetCard/TargetCard.chart.d.ts +52 -0
- package/dist/components/TargetCard/TargetCard.chart.js +273 -0
- package/dist/components/TargetCard/TargetCard.d.ts +143 -0
- package/dist/components/TargetCard/TargetCard.js +910 -0
- package/dist/components/TargetCard/TargetCard.model.d.ts +468 -0
- package/dist/components/TargetCard/TargetCard.model.js +581 -0
- package/dist/components/TargetCard/index.d.ts +4 -0
- package/dist/components/TargetCard/index.js +4 -0
- package/dist/components/TreeCard/TreeCard.chart.d.ts +80 -0
- package/dist/components/TreeCard/TreeCard.chart.js +178 -0
- package/dist/components/TreeCard/TreeCard.d.ts +182 -0
- package/dist/components/TreeCard/TreeCard.js +1187 -0
- package/dist/components/TreeCard/TreeCard.model.d.ts +330 -0
- package/dist/components/TreeCard/TreeCard.model.js +401 -0
- package/dist/components/TreeCard/index.d.ts +4 -0
- package/dist/components/TreeCard/index.js +4 -0
- package/dist/components/TrendCard/TrendCard.chart.d.ts +75 -0
- package/dist/components/TrendCard/TrendCard.chart.js +393 -0
- package/dist/components/TrendCard/TrendCard.d.ts +224 -0
- package/dist/components/TrendCard/TrendCard.js +1053 -0
- package/dist/components/TrendCard/TrendCard.model.d.ts +545 -0
- package/dist/components/TrendCard/TrendCard.model.js +623 -0
- package/dist/components/TrendCard/index.d.ts +4 -0
- package/dist/components/TrendCard/index.js +4 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.js +57 -0
- package/dist/lib/vega/ArcVegaChart.d.ts +24 -0
- package/dist/lib/vega/ArcVegaChart.js +42 -0
- package/dist/lib/vega/ArcVegaSurface.d.ts +13 -0
- package/dist/lib/vega/ArcVegaSurface.js +38 -0
- package/dist/lib/vega/axisTicks.js +156 -0
- package/dist/lib/vega/config.d.ts +29 -0
- package/dist/lib/vega/config.js +113 -0
- package/dist/lib/vega/embed.d.ts +29 -0
- package/dist/lib/vega/embed.js +29 -0
- package/dist/lib/vega/engine.d.ts +10 -0
- package/dist/lib/vega/engine.js +6 -0
- package/dist/lib/vega/formatters.d.ts +125 -0
- package/dist/lib/vega/formatters.js +277 -0
- package/dist/lib/vega/index.d.ts +11 -0
- package/dist/lib/vega/load.d.ts +13 -0
- package/dist/lib/vega/load.js +21 -0
- package/dist/lib/vega/time.d.ts +45 -0
- package/dist/lib/vega/time.js +105 -0
- package/dist/lib/vega/tokens.d.ts +73 -0
- package/dist/lib/vega/tokens.js +137 -0
- package/dist/lib/vega/tooltip.d.ts +45 -0
- package/dist/lib/vega/tooltip.js +124 -0
- package/dist/lib/vega/useArcVega.d.ts +43 -0
- package/dist/lib/vega/useArcVega.js +121 -0
- package/package.json +60 -0
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
import { formatDate, formatDateRange, formatDelta, formatNumber, parseArcNumberFormat } from "../../lib/vega/formatters.js";
|
|
2
|
+
//#region src/components/MetricCard/MetricCard.model.ts
|
|
3
|
+
const DEFAULT_METRIC_LABELS = {
|
|
4
|
+
previousPeriod: "vs previous period",
|
|
5
|
+
increase: "Up",
|
|
6
|
+
decrease: "Down",
|
|
7
|
+
unchanged: "No change",
|
|
8
|
+
ofTarget: "of target",
|
|
9
|
+
vsTarget: "vs target",
|
|
10
|
+
percentagePoints: " pp",
|
|
11
|
+
noData: "No data",
|
|
12
|
+
noMatch: "No matching data",
|
|
13
|
+
clearFilters: "Clear filters",
|
|
14
|
+
error: "Couldn't load this metric",
|
|
15
|
+
retry: "Try again",
|
|
16
|
+
insufficientTrend: "Not enough data for a trend",
|
|
17
|
+
stale: "Stale",
|
|
18
|
+
asOf: "As of",
|
|
19
|
+
tablePeriod: "Period",
|
|
20
|
+
tableValue: "Value",
|
|
21
|
+
target: "Target",
|
|
22
|
+
highlightStart: "Start",
|
|
23
|
+
highlightEnd: "End",
|
|
24
|
+
highlightChange: "Change",
|
|
25
|
+
highlightChangePercent: "Change %",
|
|
26
|
+
highlightRange: "Period",
|
|
27
|
+
highlighted: "highlighted",
|
|
28
|
+
versus: (baseline) => `vs ${baseline}`,
|
|
29
|
+
chooseComparison: (name) => `Choose what ${name} is compared with`,
|
|
30
|
+
compareWith: "Compare with",
|
|
31
|
+
previous: "Previous",
|
|
32
|
+
changePercent: "Change %",
|
|
33
|
+
changeAmount: "Change",
|
|
34
|
+
highlightDetails: (name) => `Details of the ${name} highlight`,
|
|
35
|
+
highlightReadings: (name) => `Readings of ${name} inside the highlighted period`,
|
|
36
|
+
highlightBefore: "Before",
|
|
37
|
+
highlightSince: "Since",
|
|
38
|
+
highlightLatest: "Latest",
|
|
39
|
+
markNames: {
|
|
40
|
+
line: "Line",
|
|
41
|
+
area: "Area",
|
|
42
|
+
bar: "Bar"
|
|
43
|
+
},
|
|
44
|
+
showTable: (name) => `Show the data behind ${name}`,
|
|
45
|
+
hideTable: (name) => `Hide the data behind ${name}`,
|
|
46
|
+
about: (name) => `About ${name}`,
|
|
47
|
+
loading: (name) => `Loading ${name}`,
|
|
48
|
+
tableCaption: (name) => `Data behind the ${name} trend`,
|
|
49
|
+
targetProgress: (name) => `${name} progress to target`,
|
|
50
|
+
targetExplanation: ({ percentText, progressAmountText, targetText, varianceText, direction }) => [
|
|
51
|
+
["Progress toward target", percentText],
|
|
52
|
+
[`Amount at ${percentText}`, progressAmountText],
|
|
53
|
+
["Target", targetText],
|
|
54
|
+
[direction === "down" ? "Below target" : direction === "up" ? "Above target" : "On target", varianceText]
|
|
55
|
+
],
|
|
56
|
+
deltaComparison: (name) => `${name} comparison`,
|
|
57
|
+
deltaExplanation: ({ kind, previousText, previousLabel, currentText, changeText, secondaryText, renderedMode, direction, comparisonText, periodText }) => {
|
|
58
|
+
const rows = [];
|
|
59
|
+
if (kind === "window" && periodText && periodText !== comparisonText) rows.push(["Period", periodText]);
|
|
60
|
+
rows.push([kind === "window" ? "Start" : previousLabel ?? "Previous", previousText], [kind === "window" ? "End" : "Current", currentText], [direction === "up" ? "Increase" : direction === "down" ? "Decrease" : "No change", changeText]);
|
|
61
|
+
if (secondaryText) rows.push([renderedMode === "percent" ? "Change" : "Change %", secondaryText]);
|
|
62
|
+
return rows;
|
|
63
|
+
},
|
|
64
|
+
trendSummary: (count, first, last, min, max) => `Trend of ${count} points from ${first} to ${last}, ranging ${min} to ${max}.`,
|
|
65
|
+
chartDescription: ({ mark, name, count, first, last, min, max, latest, target }) => `${mark} sparkline of ${name}: ${count} points from ${first} to ${last}, ranging ${min} to ${max}, latest ${latest}.` + (target ? ` Reference line at the ${target} target.` : ""),
|
|
66
|
+
highlightSentence: ({ word, primary, secondary, range, label, from, to }) => {
|
|
67
|
+
const period = label ? `${label} (${range})` : range;
|
|
68
|
+
return primary ? `${word} ${primary}${secondary ? ` (${secondary})` : ""} over ${period}, from ${from} to ${to}.` : `${word} over ${period} (${from}).`;
|
|
69
|
+
},
|
|
70
|
+
highlightDescription: ({ range, label, from, to, direction, primary }) => {
|
|
71
|
+
return `Highlighted ${label ? `${label}, ${range}` : range}: ${from} to ${to}, ${direction === "flat" ? "unchanged" : `${direction === "up" ? "up" : "down"} ${primary}`}.`;
|
|
72
|
+
},
|
|
73
|
+
insightMark: "Insight",
|
|
74
|
+
highlightInsight: ({ name, direction, from, to, change, secondary, range }) => {
|
|
75
|
+
if (direction === "flat") return [
|
|
76
|
+
`${name} held at `,
|
|
77
|
+
{ value: from },
|
|
78
|
+
` over ${range}.`
|
|
79
|
+
];
|
|
80
|
+
const segments = [
|
|
81
|
+
`${name} ${direction === "up" ? "rose" : "fell"} from `,
|
|
82
|
+
{ value: from },
|
|
83
|
+
" to ",
|
|
84
|
+
{ value: to },
|
|
85
|
+
` over ${range}, a ${direction === "up" ? "rise" : "drop"} of `,
|
|
86
|
+
{ value: change }
|
|
87
|
+
];
|
|
88
|
+
if (secondary) segments.push(" (", { value: secondary }, ")");
|
|
89
|
+
segments.push(".");
|
|
90
|
+
return segments;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
function resolveMetricLabels(overrides) {
|
|
94
|
+
return overrides ? {
|
|
95
|
+
...DEFAULT_METRIC_LABELS,
|
|
96
|
+
...overrides
|
|
97
|
+
} : DEFAULT_METRIC_LABELS;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The state machine. Error wins; loading over existing data is a refresh (the
|
|
101
|
+
* previous render stays under the veil); a missing value is `no-match` when
|
|
102
|
+
* the consumer's filter caused it and `empty` otherwise.
|
|
103
|
+
*/
|
|
104
|
+
function deriveMetricState({ status, hasValue, hasData, filtered }) {
|
|
105
|
+
if (status === "error") return "error";
|
|
106
|
+
if (status === "loading") return hasData ? "refreshing" : "loading";
|
|
107
|
+
if (hasValue) return "ready";
|
|
108
|
+
return filtered ? "no-match" : "empty";
|
|
109
|
+
}
|
|
110
|
+
const isFinite = (value) => typeof value === "number" && Number.isFinite(value);
|
|
111
|
+
const DAY_MS = 864e5;
|
|
112
|
+
const ISO_DATE = /^\d{4}-\d{2}(-\d{2})?([T ].*)?$/;
|
|
113
|
+
function inferXType(points) {
|
|
114
|
+
const sample = points.find((point) => point.x != null);
|
|
115
|
+
if (!sample) return "ordinal";
|
|
116
|
+
const { x } = sample;
|
|
117
|
+
if (x instanceof Date) return "temporal";
|
|
118
|
+
if (typeof x === "number") return "quantitative";
|
|
119
|
+
return ISO_DATE.test(x) ? "temporal" : "ordinal";
|
|
120
|
+
}
|
|
121
|
+
function inferGranularity(rows) {
|
|
122
|
+
const xs = rows.map((row) => row.x).filter((x) => typeof x === "number");
|
|
123
|
+
if (xs.length < 2) return "day";
|
|
124
|
+
const gaps = [];
|
|
125
|
+
for (let index = 1; index < xs.length; index += 1) gaps.push(Math.abs(xs[index] - xs[index - 1]));
|
|
126
|
+
gaps.sort((a, b) => a - b);
|
|
127
|
+
const median = gaps[Math.floor(gaps.length / 2)];
|
|
128
|
+
if (median < DAY_MS) return "time";
|
|
129
|
+
if (median >= 360 * DAY_MS) return "year";
|
|
130
|
+
if (median >= 27 * DAY_MS) return "month";
|
|
131
|
+
return "day";
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Normalises `trend` for Vega and the table: temporal `x` becomes epoch
|
|
135
|
+
* milliseconds (numbers are treated as quantitative; pass a `Date` or an ISO
|
|
136
|
+
* string for time), invalid dates are dropped, `null` readings are kept as
|
|
137
|
+
* gaps, and the range and the latest reading are summarised for the text
|
|
138
|
+
* equivalents. Returns `null` when there is no trend at all.
|
|
139
|
+
*/
|
|
140
|
+
function normalizeTrend(points, granularity) {
|
|
141
|
+
if (!points) return null;
|
|
142
|
+
const xType = inferXType(points);
|
|
143
|
+
const rows = [];
|
|
144
|
+
for (const point of points) {
|
|
145
|
+
const y = isFinite(point.y) ? point.y : null;
|
|
146
|
+
if (xType === "temporal") {
|
|
147
|
+
const time = point.x instanceof Date ? point.x.getTime() : new Date(point.x).getTime();
|
|
148
|
+
if (Number.isNaN(time)) continue;
|
|
149
|
+
rows.push({
|
|
150
|
+
x: time,
|
|
151
|
+
y
|
|
152
|
+
});
|
|
153
|
+
} else if (xType === "quantitative") {
|
|
154
|
+
if (!isFinite(point.x)) continue;
|
|
155
|
+
rows.push({
|
|
156
|
+
x: point.x,
|
|
157
|
+
y
|
|
158
|
+
});
|
|
159
|
+
} else rows.push({
|
|
160
|
+
x: String(point.x),
|
|
161
|
+
y
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
const valid = rows.filter((row) => row.y != null);
|
|
165
|
+
let latest = null;
|
|
166
|
+
if (valid.length > 0) latest = xType === "ordinal" ? valid[valid.length - 1] : valid.reduce((best, row) => row.x >= best.x ? row : best);
|
|
167
|
+
const values = valid.map((row) => row.y);
|
|
168
|
+
return {
|
|
169
|
+
rows,
|
|
170
|
+
xType,
|
|
171
|
+
count: valid.length,
|
|
172
|
+
first: rows[0] ?? null,
|
|
173
|
+
last: rows[rows.length - 1] ?? null,
|
|
174
|
+
latest,
|
|
175
|
+
min: values.length > 0 ? Math.min(...values) : null,
|
|
176
|
+
max: values.length > 0 ? Math.max(...values) : null,
|
|
177
|
+
granularity: granularity ?? (xType === "temporal" ? inferGranularity(rows) : "day")
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/** The comparison against the previous reading, with polarity resolved through `goodDirection`. */
|
|
181
|
+
function deriveDelta(value, previousValue, { deltaMode, goodDirection, format, locale, percentagePoints }) {
|
|
182
|
+
if (!isFinite(value) || !isFinite(previousValue)) return null;
|
|
183
|
+
const delta = formatDelta(value, previousValue, {
|
|
184
|
+
mode: deltaMode,
|
|
185
|
+
format,
|
|
186
|
+
locale,
|
|
187
|
+
pointsSuffix: percentagePoints
|
|
188
|
+
});
|
|
189
|
+
const other = formatDelta(value, previousValue, {
|
|
190
|
+
mode: delta.renderedMode === "percent" ? "absolute" : "percent",
|
|
191
|
+
format,
|
|
192
|
+
locale,
|
|
193
|
+
pointsSuffix: percentagePoints
|
|
194
|
+
});
|
|
195
|
+
let polarity = "neutral";
|
|
196
|
+
if (delta.direction !== "flat" && goodDirection !== "none") polarity = delta.direction === "up" === (goodDirection === "up") ? "positive" : "negative";
|
|
197
|
+
return {
|
|
198
|
+
direction: delta.direction,
|
|
199
|
+
polarity,
|
|
200
|
+
text: delta.text,
|
|
201
|
+
renderedMode: delta.renderedMode,
|
|
202
|
+
secondaryText: other.renderedMode === delta.renderedMode ? null : other.text
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/** Progress against the target. `null` without a usable target (a zero target has no ratio). */
|
|
206
|
+
function deriveTarget(value, target, { goodDirection, format, locale, formatValue }) {
|
|
207
|
+
if (!isFinite(value) || !isFinite(target) || target === 0) return null;
|
|
208
|
+
const ratio = value / target;
|
|
209
|
+
const displayedRatio = Math.sign(ratio) * Math.round(Math.abs(ratio) * 100) / 100;
|
|
210
|
+
const progressAmount = displayedRatio * target;
|
|
211
|
+
const amountFormat = parseArcNumberFormat(format);
|
|
212
|
+
const amountPrecision = amountFormat.kind === "compact" || amountFormat.compact ? { maximumFractionDigits: Math.max(2, amountFormat.digits ?? 1) } : void 0;
|
|
213
|
+
const met = goodDirection === "down" ? value <= target : value >= target;
|
|
214
|
+
const variant = goodDirection === "none" ? "primary" : met ? "success" : goodDirection === "down" ? "destructive" : "primary";
|
|
215
|
+
const variance = formatDelta(value, target, {
|
|
216
|
+
mode: "percent",
|
|
217
|
+
format,
|
|
218
|
+
locale
|
|
219
|
+
});
|
|
220
|
+
return {
|
|
221
|
+
ratio,
|
|
222
|
+
met,
|
|
223
|
+
variant,
|
|
224
|
+
percentText: formatNumber(displayedRatio, "percent:0", locale),
|
|
225
|
+
progressAmountText: formatValue ? formatValue(progressAmount) : formatNumber(progressAmount, format, locale, amountPrecision),
|
|
226
|
+
targetText: formatValue ? formatValue(target) : formatNumber(target, format, locale),
|
|
227
|
+
varianceText: variance.text,
|
|
228
|
+
direction: variance.direction
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* The granularity an x axis labels its ticks at: the tooltip and table keep
|
|
233
|
+
* the full form (`Sep 8, 2026`); a 250px axis has room for `Sep 8`.
|
|
234
|
+
*/
|
|
235
|
+
function axisGranularity(granularity) {
|
|
236
|
+
switch (granularity) {
|
|
237
|
+
case "day": return "day-short";
|
|
238
|
+
case "month": return "month-short";
|
|
239
|
+
case "datetime": return "time";
|
|
240
|
+
default: return granularity;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/** The two formatters every text surface shares — headline, delta, table, tooltip, descriptions. */
|
|
244
|
+
function createMetricFormatters({ format, locale, timeZone, formatValue, xType, granularity }) {
|
|
245
|
+
const formatX = (x) => {
|
|
246
|
+
if (xType === "temporal" && typeof x === "number") return formatDate(x, {
|
|
247
|
+
granularity,
|
|
248
|
+
locale,
|
|
249
|
+
timeZone
|
|
250
|
+
});
|
|
251
|
+
if (xType === "quantitative" && typeof x === "number") return formatNumber(x, "number", locale);
|
|
252
|
+
return String(x);
|
|
253
|
+
};
|
|
254
|
+
return {
|
|
255
|
+
formatY: (value) => isFinite(value) ? formatValue ? formatValue(value) : formatNumber(value, format, locale) : "—",
|
|
256
|
+
formatX,
|
|
257
|
+
formatXRange: (start, end) => xType === "temporal" && typeof start === "number" && typeof end === "number" ? formatDateRange(start, end, {
|
|
258
|
+
granularity,
|
|
259
|
+
locale,
|
|
260
|
+
timeZone
|
|
261
|
+
}) : `${formatX(start)} – ${formatX(end)}`
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function normalizeHighlightBound(value, xType) {
|
|
265
|
+
if (xType === "temporal") {
|
|
266
|
+
const time = value instanceof Date ? value.getTime() : new Date(value).getTime();
|
|
267
|
+
return Number.isNaN(time) ? null : time;
|
|
268
|
+
}
|
|
269
|
+
if (xType === "quantitative") {
|
|
270
|
+
const numeric = typeof value === "number" ? value : Number(value);
|
|
271
|
+
return Number.isFinite(numeric) ? numeric : null;
|
|
272
|
+
}
|
|
273
|
+
return String(value);
|
|
274
|
+
}
|
|
275
|
+
const stripSign = (text) => text.replace(/^[+\-−]/, "");
|
|
276
|
+
/**
|
|
277
|
+
* Snaps a highlight window onto the trend and measures it. Each bound moves
|
|
278
|
+
* inward to the nearest finite reading (a temporal or quantitative bound need
|
|
279
|
+
* not hit a point exactly; an ordinal bound is a category label), the bounds
|
|
280
|
+
* may come in either order, and the result is `null` when the window does not
|
|
281
|
+
* hold two distinct finite readings — the card then draws the plain sparkline
|
|
282
|
+
* and stamps `data-highlight="unresolved"` rather than inventing a change.
|
|
283
|
+
*/
|
|
284
|
+
function resolveHighlight(summary, range, { deltaMode, goodDirection, format, locale, percentagePoints, formatters }) {
|
|
285
|
+
if (!summary || !range) return null;
|
|
286
|
+
const { rows, xType } = summary;
|
|
287
|
+
const lo = normalizeHighlightBound(range.start, xType);
|
|
288
|
+
const hi = normalizeHighlightBound(range.end, xType);
|
|
289
|
+
if (lo == null || hi == null) return null;
|
|
290
|
+
let startIndex = -1;
|
|
291
|
+
let endIndex = -1;
|
|
292
|
+
if (xType === "ordinal") {
|
|
293
|
+
let first = rows.findIndex((row) => row.x === lo);
|
|
294
|
+
let last = -1;
|
|
295
|
+
for (let index = rows.length - 1; index >= 0; index -= 1) if (rows[index].x === hi) {
|
|
296
|
+
last = index;
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
if (first < 0 || last < 0) return null;
|
|
300
|
+
if (first > last) [first, last] = [last, first];
|
|
301
|
+
while (first <= last && rows[first].y == null) first += 1;
|
|
302
|
+
while (last >= first && rows[last].y == null) last -= 1;
|
|
303
|
+
if (first >= last) return null;
|
|
304
|
+
startIndex = first;
|
|
305
|
+
endIndex = last;
|
|
306
|
+
} else {
|
|
307
|
+
const [min, max] = lo <= hi ? [lo, hi] : [hi, lo];
|
|
308
|
+
rows.forEach((row, index) => {
|
|
309
|
+
if (row.y == null || typeof row.x !== "number" || row.x < min || row.x > max) return;
|
|
310
|
+
if (startIndex < 0 || row.x < rows[startIndex].x) startIndex = index;
|
|
311
|
+
if (endIndex < 0 || row.x > rows[endIndex].x) endIndex = index;
|
|
312
|
+
});
|
|
313
|
+
if (startIndex < 0 || endIndex < 0 || rows[startIndex].x === rows[endIndex].x) return null;
|
|
314
|
+
}
|
|
315
|
+
const start = {
|
|
316
|
+
x: rows[startIndex].x,
|
|
317
|
+
y: rows[startIndex].y,
|
|
318
|
+
index: startIndex
|
|
319
|
+
};
|
|
320
|
+
const end = {
|
|
321
|
+
x: rows[endIndex].x,
|
|
322
|
+
y: rows[endIndex].y,
|
|
323
|
+
index: endIndex
|
|
324
|
+
};
|
|
325
|
+
const delta = deriveDelta(end.y, start.y, {
|
|
326
|
+
deltaMode,
|
|
327
|
+
goodDirection,
|
|
328
|
+
format,
|
|
329
|
+
locale,
|
|
330
|
+
percentagePoints
|
|
331
|
+
});
|
|
332
|
+
if (!delta) return null;
|
|
333
|
+
const absolute = formatDelta(end.y, start.y, {
|
|
334
|
+
mode: "absolute",
|
|
335
|
+
format,
|
|
336
|
+
locale,
|
|
337
|
+
pointsSuffix: percentagePoints
|
|
338
|
+
});
|
|
339
|
+
const percent = formatDelta(end.y, start.y, {
|
|
340
|
+
mode: "percent",
|
|
341
|
+
format,
|
|
342
|
+
locale
|
|
343
|
+
});
|
|
344
|
+
return {
|
|
345
|
+
start,
|
|
346
|
+
end,
|
|
347
|
+
label: range.label,
|
|
348
|
+
rangeText: formatters.formatXRange(start.x, end.x),
|
|
349
|
+
delta,
|
|
350
|
+
absoluteText: absolute.text,
|
|
351
|
+
percentText: percent.percent == null ? "—" : percent.text
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* The highlight variant's default insight sentence — what the card shows
|
|
356
|
+
* beside the AI mark when the consumer passes no `insight`. The window's start
|
|
357
|
+
* and end readings and its change (in the badge's form, with the other form
|
|
358
|
+
* in brackets) come back as `{ value }` segments so the card can set them in
|
|
359
|
+
* bold; the words come from `labels.highlightInsight`.
|
|
360
|
+
*/
|
|
361
|
+
function buildHighlightInsight({ name, highlight, formatters, labels }) {
|
|
362
|
+
const flat = highlight.delta.direction === "flat";
|
|
363
|
+
const secondary = highlight.delta.renderedMode === "percent" ? highlight.absoluteText : highlight.percentText;
|
|
364
|
+
return labels.highlightInsight({
|
|
365
|
+
name,
|
|
366
|
+
direction: highlight.delta.direction,
|
|
367
|
+
from: formatters.formatY(highlight.start.y),
|
|
368
|
+
to: formatters.formatY(highlight.end.y),
|
|
369
|
+
change: flat ? "" : stripSign(highlight.delta.text),
|
|
370
|
+
secondary: flat || secondary === "—" ? null : stripSign(secondary),
|
|
371
|
+
range: highlight.rangeText,
|
|
372
|
+
label: highlight.label
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
/** The plain-text reading of insight segments — for descriptions and tests. */
|
|
376
|
+
function insightSegmentsToText(segments) {
|
|
377
|
+
return segments.map((segment) => typeof segment === "string" ? segment : segment.value).join("");
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* The datasets the highlight sparkline reads, derived once per trend or window
|
|
381
|
+
* change: every row flagged with `hl` (bars colour themselves from it, the
|
|
382
|
+
* hover dot too), the context readings split into a `before` and an `after`
|
|
383
|
+
* run so the gray line stops at the window's edges, the window's own readings
|
|
384
|
+
* for the coloured segment, its two endpoint dots, and the one-row band. A
|
|
385
|
+
* continuous axis decides membership by `x`, an ordinal one by position.
|
|
386
|
+
*/
|
|
387
|
+
function buildHighlightDatasets(summary, info) {
|
|
388
|
+
const { rows, xType } = summary;
|
|
389
|
+
const tone = info.delta.polarity;
|
|
390
|
+
const at = (row, index) => xType === "ordinal" ? index : row.x;
|
|
391
|
+
const startAt = at(rows[info.start.index], info.start.index);
|
|
392
|
+
const endAt = at(rows[info.end.index], info.end.index);
|
|
393
|
+
const table = [];
|
|
394
|
+
const context = [];
|
|
395
|
+
const highlightRows = [];
|
|
396
|
+
rows.forEach((row, index) => {
|
|
397
|
+
const position = at(row, index);
|
|
398
|
+
const inside = position >= startAt && position <= endAt;
|
|
399
|
+
table.push({
|
|
400
|
+
...row,
|
|
401
|
+
hl: inside,
|
|
402
|
+
tone: inside ? tone : null
|
|
403
|
+
});
|
|
404
|
+
if (inside) highlightRows.push({
|
|
405
|
+
...row,
|
|
406
|
+
hl: true,
|
|
407
|
+
tone
|
|
408
|
+
});
|
|
409
|
+
if (position <= startAt) context.push({
|
|
410
|
+
...row,
|
|
411
|
+
seg: "before"
|
|
412
|
+
});
|
|
413
|
+
if (position >= endAt) context.push({
|
|
414
|
+
...row,
|
|
415
|
+
seg: "after"
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
return {
|
|
419
|
+
table,
|
|
420
|
+
context,
|
|
421
|
+
highlightRows,
|
|
422
|
+
highlightPoints: [{
|
|
423
|
+
x: info.start.x,
|
|
424
|
+
y: info.start.y,
|
|
425
|
+
role: "start",
|
|
426
|
+
tone
|
|
427
|
+
}, {
|
|
428
|
+
x: info.end.x,
|
|
429
|
+
y: info.end.y,
|
|
430
|
+
role: "end",
|
|
431
|
+
tone
|
|
432
|
+
}],
|
|
433
|
+
highlight: [{
|
|
434
|
+
start: info.start.x,
|
|
435
|
+
end: info.end.x,
|
|
436
|
+
startY: info.start.y,
|
|
437
|
+
endY: info.end.y,
|
|
438
|
+
tone
|
|
439
|
+
}]
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
/** The key of the one baseline a tile builds from `previousValue` for its compare-with menu. Never collides with a consumer's key. */
|
|
443
|
+
const METRIC_PREVIOUS_KEY = "__previous__";
|
|
444
|
+
/**
|
|
445
|
+
* Normalises the baselines a metric tile offers: keys default to labels (a
|
|
446
|
+
* repeated key is suffixed so two options never collide), non-finite values
|
|
447
|
+
* become `null`. The consumer's order is kept — it is the menu's order.
|
|
448
|
+
*/
|
|
449
|
+
function normalizeComparisons(items) {
|
|
450
|
+
if (!items) return [];
|
|
451
|
+
const seen = /* @__PURE__ */ new Map();
|
|
452
|
+
return items.map((item) => {
|
|
453
|
+
const base = item.key ?? item.label;
|
|
454
|
+
const repeats = seen.get(base) ?? 0;
|
|
455
|
+
seen.set(base, repeats + 1);
|
|
456
|
+
return {
|
|
457
|
+
key: repeats === 0 ? base : `${base}·${repeats + 1}`,
|
|
458
|
+
label: item.label,
|
|
459
|
+
value: isFinite(item.value) ? item.value : null
|
|
460
|
+
};
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* The selected baseline. `null` designates none; a key names one — an absent
|
|
465
|
+
* key selects none rather than a substitute, so the card never compares
|
|
466
|
+
* against something the app did not ask for; `undefined` takes the first
|
|
467
|
+
* baseline with a value, else the first baseline.
|
|
468
|
+
*/
|
|
469
|
+
function resolveComparison(rows, key) {
|
|
470
|
+
if (key === null) return null;
|
|
471
|
+
if (key !== void 0) return rows.find((row) => row.key === key) ?? null;
|
|
472
|
+
return rows.find((row) => row.value != null) ?? rows[0] ?? null;
|
|
473
|
+
}
|
|
474
|
+
/** The compare-with menu's table: every baseline with the change the headline would show against it, in percent and in the value's units. */
|
|
475
|
+
function describeComparisons(rows, value, { formatters, ...options }) {
|
|
476
|
+
return rows.map((row) => {
|
|
477
|
+
const delta = deriveDelta(value, row.value, options);
|
|
478
|
+
const percentText = delta ? delta.renderedMode === "percent" ? delta.text : delta.secondaryText : null;
|
|
479
|
+
const amountText = delta ? delta.renderedMode === "absolute" ? delta.text : delta.secondaryText : null;
|
|
480
|
+
return {
|
|
481
|
+
row,
|
|
482
|
+
delta,
|
|
483
|
+
polarity: delta?.polarity ?? "neutral",
|
|
484
|
+
valueText: formatters.formatY(row.value),
|
|
485
|
+
percentText: percentText ?? "—",
|
|
486
|
+
amountText: amountText ?? "—"
|
|
487
|
+
};
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* The detail behind a resolved window — what the sparkline cannot show at
|
|
492
|
+
* tile scale: the readings inside the window one by one, each with its step
|
|
493
|
+
* from the previous finite reading, and the trend's movement before the
|
|
494
|
+
* window and since it, so the reader can tell a step change from a slide and
|
|
495
|
+
* a recovery from a plateau. A continuous axis decides membership by `x`, an
|
|
496
|
+
* ordinal one by position.
|
|
497
|
+
*/
|
|
498
|
+
function buildHighlightDetails(summary, info, { deltaMode, goodDirection, format, locale, percentagePoints, formatters }) {
|
|
499
|
+
const { rows, xType } = summary;
|
|
500
|
+
const deltaOptions = {
|
|
501
|
+
deltaMode,
|
|
502
|
+
goodDirection,
|
|
503
|
+
format,
|
|
504
|
+
locale,
|
|
505
|
+
percentagePoints
|
|
506
|
+
};
|
|
507
|
+
const at = (row, index) => xType === "ordinal" ? index : row.x;
|
|
508
|
+
const startAt = at(rows[info.start.index], info.start.index);
|
|
509
|
+
const endAt = at(rows[info.end.index], info.end.index);
|
|
510
|
+
const reading = (row) => ({
|
|
511
|
+
x: row.x,
|
|
512
|
+
xText: formatters.formatX(row.x),
|
|
513
|
+
yText: formatters.formatY(row.y)
|
|
514
|
+
});
|
|
515
|
+
const inside = [];
|
|
516
|
+
let first = null;
|
|
517
|
+
let firstAt = Number.POSITIVE_INFINITY;
|
|
518
|
+
let latest = null;
|
|
519
|
+
let latestAt = Number.NEGATIVE_INFINITY;
|
|
520
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
521
|
+
const row = rows[index];
|
|
522
|
+
const position = at(row, index);
|
|
523
|
+
if (position >= startAt && position <= endAt) inside.push({
|
|
524
|
+
row,
|
|
525
|
+
index,
|
|
526
|
+
position
|
|
527
|
+
});
|
|
528
|
+
if (row.y == null) continue;
|
|
529
|
+
if (position < startAt && position < firstAt) {
|
|
530
|
+
first = row;
|
|
531
|
+
firstAt = position;
|
|
532
|
+
}
|
|
533
|
+
if (position > endAt && position > latestAt) {
|
|
534
|
+
latest = row;
|
|
535
|
+
latestAt = position;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
inside.sort((a, b) => a.position - b.position);
|
|
539
|
+
let previous = null;
|
|
540
|
+
const steps = inside.map(({ row, index }) => {
|
|
541
|
+
const delta = row.y != null && previous != null ? deriveDelta(row.y, previous, deltaOptions) : null;
|
|
542
|
+
if (row.y != null) previous = row.y;
|
|
543
|
+
return {
|
|
544
|
+
...reading(row),
|
|
545
|
+
changeText: delta?.text ?? null,
|
|
546
|
+
polarity: delta?.polarity ?? "neutral",
|
|
547
|
+
role: index === info.start.index ? "start" : index === info.end.index ? "end" : "inside"
|
|
548
|
+
};
|
|
549
|
+
});
|
|
550
|
+
const stretch = (from, to) => {
|
|
551
|
+
const delta = deriveDelta(to.y, from.y, deltaOptions);
|
|
552
|
+
if (!delta) return null;
|
|
553
|
+
return {
|
|
554
|
+
from: reading(from),
|
|
555
|
+
to: reading(to),
|
|
556
|
+
rangeText: formatters.formatXRange(from.x, to.x),
|
|
557
|
+
changeText: delta.text,
|
|
558
|
+
secondaryText: delta.secondaryText,
|
|
559
|
+
direction: delta.direction,
|
|
560
|
+
polarity: delta.polarity
|
|
561
|
+
};
|
|
562
|
+
};
|
|
563
|
+
return {
|
|
564
|
+
steps,
|
|
565
|
+
before: first ? stretch(first, rows[info.start.index]) : null,
|
|
566
|
+
since: latest ? stretch(rows[info.end.index], latest) : null
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* The card's text equivalent (Amy Cesal's alt-text formula: what it is, what
|
|
571
|
+
* it shows, why it is here, when it was true) — the figure's accessible
|
|
572
|
+
* description, and the summary a screen reader gets before the parts.
|
|
573
|
+
*/
|
|
574
|
+
function buildMetricDescription({ name, state, valueText, unit, delta, comparisonText, target, trend, formatters, asOfText, labels, highlight }) {
|
|
575
|
+
if (state === "loading") return `${labels.loading(name)}.`;
|
|
576
|
+
if (state === "error") return `${name}: ${labels.error}.`;
|
|
577
|
+
if (state === "empty") return `${name}: ${labels.noData}.`;
|
|
578
|
+
if (state === "no-match") return `${name}: ${labels.noMatch}.`;
|
|
579
|
+
const directionWord = (direction) => direction === "up" ? labels.increase : direction === "down" ? labels.decrease : labels.unchanged;
|
|
580
|
+
const sentences = [`${name}: ${valueText}${unit ? ` ${unit}` : ""}.`];
|
|
581
|
+
if (highlight) {
|
|
582
|
+
const flat = highlight.delta.direction === "flat";
|
|
583
|
+
const secondary = highlight.delta.renderedMode === "percent" ? highlight.absoluteText : highlight.percentText;
|
|
584
|
+
sentences.push(labels.highlightSentence({
|
|
585
|
+
word: directionWord(highlight.delta.direction),
|
|
586
|
+
primary: flat ? "" : stripSign(highlight.delta.text),
|
|
587
|
+
secondary: flat || secondary === "—" ? null : stripSign(secondary),
|
|
588
|
+
range: highlight.rangeText,
|
|
589
|
+
label: highlight.label,
|
|
590
|
+
from: formatters.formatY(highlight.start.y),
|
|
591
|
+
to: formatters.formatY(highlight.end.y)
|
|
592
|
+
}));
|
|
593
|
+
} else if (delta) {
|
|
594
|
+
const word = directionWord(delta.direction);
|
|
595
|
+
const magnitude = stripSign(delta.text);
|
|
596
|
+
sentences.push(delta.direction === "flat" ? `${word} ${comparisonText}.` : `${word} ${magnitude} ${comparisonText}.`);
|
|
597
|
+
}
|
|
598
|
+
if (target) sentences.push(`${target.percentText} ${labels.ofTarget} (${target.targetText}).`);
|
|
599
|
+
if (trend && trend.count >= 2 && trend.first && trend.last) sentences.push(labels.trendSummary(trend.count, formatters.formatX(trend.first.x), formatters.formatX(trend.last.x), formatters.formatY(trend.min), formatters.formatY(trend.max)));
|
|
600
|
+
if (asOfText) sentences.push(`${labels.asOf} ${asOfText}.`);
|
|
601
|
+
return sentences.join(" ");
|
|
602
|
+
}
|
|
603
|
+
/** The sparkline's own `description` — the `aria-label` Vega stamps on the `graphics-document`. */
|
|
604
|
+
function buildMetricChartDescription({ name, mark, trend, target, formatters, labels, highlight }) {
|
|
605
|
+
const base = labels.chartDescription({
|
|
606
|
+
mark: labels.markNames[mark],
|
|
607
|
+
name,
|
|
608
|
+
count: trend.count,
|
|
609
|
+
first: trend.first ? formatters.formatX(trend.first.x) : "—",
|
|
610
|
+
last: trend.last ? formatters.formatX(trend.last.x) : "—",
|
|
611
|
+
min: formatters.formatY(trend.min),
|
|
612
|
+
max: formatters.formatY(trend.max),
|
|
613
|
+
latest: trend.latest ? formatters.formatY(trend.latest.y) : "—",
|
|
614
|
+
target: target ? target.targetText : null
|
|
615
|
+
});
|
|
616
|
+
if (!highlight) return base;
|
|
617
|
+
return `${base} ${labels.highlightDescription({
|
|
618
|
+
range: highlight.rangeText,
|
|
619
|
+
label: highlight.label,
|
|
620
|
+
from: formatters.formatY(highlight.start.y),
|
|
621
|
+
to: formatters.formatY(highlight.end.y),
|
|
622
|
+
direction: highlight.delta.direction,
|
|
623
|
+
primary: stripSign(highlight.delta.text)
|
|
624
|
+
})}`;
|
|
625
|
+
}
|
|
626
|
+
//#endregion
|
|
627
|
+
export { DEFAULT_METRIC_LABELS, METRIC_PREVIOUS_KEY, axisGranularity, buildHighlightDatasets, buildHighlightDetails, buildHighlightInsight, buildMetricChartDescription, buildMetricDescription, createMetricFormatters, deriveDelta, deriveMetricState, deriveTarget, describeComparisons, insightSegmentsToText, normalizeComparisons, normalizeTrend, resolveComparison, resolveHighlight, resolveMetricLabels };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { DEFAULT_METRIC_LABELS, DescribeComparisonsOptions, METRIC_PREVIOUS_KEY, MetricCardLabels, MetricCardSize, MetricCardState, MetricCardStatus, MetricCardVariant, MetricComparison, MetricComparisonCandidate, MetricComparisonRow, MetricDelta, MetricDeltaExplanation, MetricDeltaMode, MetricGoodDirection, MetricHighlightBand, MetricHighlightContextRow, MetricHighlightDatasets, MetricHighlightDetails, MetricHighlightInfo, MetricHighlightPoint, MetricHighlightRange, MetricHighlightReading, MetricHighlightReadingText, MetricHighlightStep, MetricHighlightStretch, MetricHighlightTrendRow, MetricInsightSegment, MetricPolarity, MetricTargetInfo, MetricTextFormatters, MetricTrendAxes, MetricTrendMark, MetricTrendPoint, MetricTrendRow, MetricTrendScale, MetricTrendSummary, MetricTrendXType, ResolveHighlightOptions, axisGranularity, buildHighlightDatasets, buildHighlightDetails, buildHighlightInsight, buildMetricChartDescription, buildMetricDescription, createMetricFormatters, deriveDelta, deriveMetricState, deriveTarget, describeComparisons, insightSegmentsToText, normalizeComparisons, normalizeTrend, resolveComparison, resolveHighlight, resolveMetricLabels } from "./MetricCard.model.js";
|
|
2
|
+
import { MetricCard, MetricCardBaseProps, MetricCardComparisonProps, MetricCardProps, MetricCardVariantProps } from "./MetricCard.js";
|
|
3
|
+
import { METRIC_CONTEXT_DATASET, METRIC_HIGHLIGHT_DATASET, METRIC_HIGHLIGHT_END_PARAM, METRIC_HIGHLIGHT_POINTS_DATASET, METRIC_HIGHLIGHT_ROWS_DATASET, METRIC_HIGHLIGHT_START_PARAM, METRIC_HOVER_PARAM, METRIC_LATEST_DATASET, METRIC_REFERENCE_DATASET, METRIC_TREND_DATASET, METRIC_X_TICKS_PARAM, MetricTrendSpecOptions, buildMetricTrendSpec } from "./MetricCard.chart.js";
|
|
4
|
+
export { DEFAULT_METRIC_LABELS, type DescribeComparisonsOptions, METRIC_CONTEXT_DATASET, METRIC_HIGHLIGHT_DATASET, METRIC_HIGHLIGHT_END_PARAM, METRIC_HIGHLIGHT_POINTS_DATASET, METRIC_HIGHLIGHT_ROWS_DATASET, METRIC_HIGHLIGHT_START_PARAM, METRIC_HOVER_PARAM, METRIC_LATEST_DATASET, METRIC_PREVIOUS_KEY, METRIC_REFERENCE_DATASET, METRIC_TREND_DATASET, METRIC_X_TICKS_PARAM, MetricCard, type MetricCardBaseProps, type MetricCardComparisonProps, type MetricCardLabels, type MetricCardProps, type MetricCardSize, type MetricCardState, type MetricCardStatus, type MetricCardVariant, type MetricCardVariantProps, type MetricComparison, type MetricComparisonCandidate, type MetricComparisonRow, type MetricDelta, type MetricDeltaExplanation, type MetricDeltaMode, type MetricGoodDirection, type MetricHighlightBand, type MetricHighlightContextRow, type MetricHighlightDatasets, type MetricHighlightDetails, type MetricHighlightInfo, type MetricHighlightPoint, type MetricHighlightRange, type MetricHighlightReading, type MetricHighlightReadingText, type MetricHighlightStep, type MetricHighlightStretch, type MetricHighlightTrendRow, type MetricInsightSegment, type MetricPolarity, type MetricTargetInfo, type MetricTextFormatters, type MetricTrendAxes, type MetricTrendMark, type MetricTrendPoint, type MetricTrendRow, type MetricTrendScale, type MetricTrendSpecOptions, type MetricTrendSummary, type MetricTrendXType, type ResolveHighlightOptions, axisGranularity, buildHighlightDatasets, buildHighlightDetails, buildHighlightInsight, buildMetricChartDescription, buildMetricDescription, buildMetricTrendSpec, createMetricFormatters, deriveDelta, deriveMetricState, deriveTarget, describeComparisons, insightSegmentsToText, normalizeComparisons, normalizeTrend, resolveComparison, resolveHighlight, resolveMetricLabels };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { METRIC_CONTEXT_DATASET, METRIC_HIGHLIGHT_DATASET, METRIC_HIGHLIGHT_END_PARAM, METRIC_HIGHLIGHT_POINTS_DATASET, METRIC_HIGHLIGHT_ROWS_DATASET, METRIC_HIGHLIGHT_START_PARAM, METRIC_HOVER_PARAM, METRIC_LATEST_DATASET, METRIC_REFERENCE_DATASET, METRIC_TREND_DATASET, METRIC_X_TICKS_PARAM, buildMetricTrendSpec } from "./MetricCard.chart.js";
|
|
2
|
+
import { DEFAULT_METRIC_LABELS, METRIC_PREVIOUS_KEY, axisGranularity, buildHighlightDatasets, buildHighlightDetails, buildHighlightInsight, buildMetricChartDescription, buildMetricDescription, createMetricFormatters, deriveDelta, deriveMetricState, deriveTarget, describeComparisons, insightSegmentsToText, normalizeComparisons, normalizeTrend, resolveComparison, resolveHighlight, resolveMetricLabels } from "./MetricCard.model.js";
|
|
3
|
+
import { MetricCard } from "./MetricCard.js";
|
|
4
|
+
export { DEFAULT_METRIC_LABELS, METRIC_CONTEXT_DATASET, METRIC_HIGHLIGHT_DATASET, METRIC_HIGHLIGHT_END_PARAM, METRIC_HIGHLIGHT_POINTS_DATASET, METRIC_HIGHLIGHT_ROWS_DATASET, METRIC_HIGHLIGHT_START_PARAM, METRIC_HOVER_PARAM, METRIC_LATEST_DATASET, METRIC_PREVIOUS_KEY, METRIC_REFERENCE_DATASET, METRIC_TREND_DATASET, METRIC_X_TICKS_PARAM, MetricCard, axisGranularity, buildHighlightDatasets, buildHighlightDetails, buildHighlightInsight, buildMetricChartDescription, buildMetricDescription, buildMetricTrendSpec, createMetricFormatters, deriveDelta, deriveMetricState, deriveTarget, describeComparisons, insightSegmentsToText, normalizeComparisons, normalizeTrend, resolveComparison, resolveHighlight, resolveMetricLabels };
|