@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.
Files changed (156) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +13 -0
  2. package/dist/components/AnomalyCard/AnomalyCard.chart.d.ts +64 -0
  3. package/dist/components/AnomalyCard/AnomalyCard.chart.js +341 -0
  4. package/dist/components/AnomalyCard/AnomalyCard.d.ts +169 -0
  5. package/dist/components/AnomalyCard/AnomalyCard.js +1019 -0
  6. package/dist/components/AnomalyCard/AnomalyCard.model.d.ts +508 -0
  7. package/dist/components/AnomalyCard/AnomalyCard.model.js +553 -0
  8. package/dist/components/AnomalyCard/index.d.ts +4 -0
  9. package/dist/components/AnomalyCard/index.js +4 -0
  10. package/dist/components/ChartCard/ChartCard.chart.d.ts +72 -0
  11. package/dist/components/ChartCard/ChartCard.chart.js +1333 -0
  12. package/dist/components/ChartCard/ChartCard.d.ts +206 -0
  13. package/dist/components/ChartCard/ChartCard.js +718 -0
  14. package/dist/components/ChartCard/ChartCard.model.d.ts +452 -0
  15. package/dist/components/ChartCard/ChartCard.model.js +1223 -0
  16. package/dist/components/ChartCard/index.d.ts +4 -0
  17. package/dist/components/ChartCard/index.js +4 -0
  18. package/dist/components/ComparisonCard/ComparisonCard.chart.d.ts +80 -0
  19. package/dist/components/ComparisonCard/ComparisonCard.chart.js +337 -0
  20. package/dist/components/ComparisonCard/ComparisonCard.d.ts +200 -0
  21. package/dist/components/ComparisonCard/ComparisonCard.js +1325 -0
  22. package/dist/components/ComparisonCard/ComparisonCard.model.d.ts +309 -0
  23. package/dist/components/ComparisonCard/ComparisonCard.model.js +263 -0
  24. package/dist/components/ComparisonCard/index.d.ts +4 -0
  25. package/dist/components/ComparisonCard/index.js +4 -0
  26. package/dist/components/ForecastCard/ForecastCard.chart.d.ts +82 -0
  27. package/dist/components/ForecastCard/ForecastCard.chart.js +416 -0
  28. package/dist/components/ForecastCard/ForecastCard.d.ts +148 -0
  29. package/dist/components/ForecastCard/ForecastCard.js +1029 -0
  30. package/dist/components/ForecastCard/ForecastCard.model.d.ts +497 -0
  31. package/dist/components/ForecastCard/ForecastCard.model.js +554 -0
  32. package/dist/components/ForecastCard/index.d.ts +4 -0
  33. package/dist/components/ForecastCard/index.js +4 -0
  34. package/dist/components/HighlightCard/HighlightCard.chart.d.ts +122 -0
  35. package/dist/components/HighlightCard/HighlightCard.chart.js +660 -0
  36. package/dist/components/HighlightCard/HighlightCard.d.ts +202 -0
  37. package/dist/components/HighlightCard/HighlightCard.js +1286 -0
  38. package/dist/components/HighlightCard/HighlightCard.model.d.ts +692 -0
  39. package/dist/components/HighlightCard/HighlightCard.model.js +875 -0
  40. package/dist/components/HighlightCard/index.d.ts +4 -0
  41. package/dist/components/HighlightCard/index.js +4 -0
  42. package/dist/components/InsightCard/InsightCard.chart.d.ts +91 -0
  43. package/dist/components/InsightCard/InsightCard.chart.js +471 -0
  44. package/dist/components/InsightCard/InsightCard.d.ts +161 -0
  45. package/dist/components/InsightCard/InsightCard.js +961 -0
  46. package/dist/components/InsightCard/InsightCard.model.d.ts +405 -0
  47. package/dist/components/InsightCard/InsightCard.model.js +421 -0
  48. package/dist/components/InsightCard/index.d.ts +4 -0
  49. package/dist/components/InsightCard/index.js +4 -0
  50. package/dist/components/MetricCard/MetricCard.chart.d.ts +79 -0
  51. package/dist/components/MetricCard/MetricCard.chart.js +435 -0
  52. package/dist/components/MetricCard/MetricCard.d.ts +227 -0
  53. package/dist/components/MetricCard/MetricCard.js +1293 -0
  54. package/dist/components/MetricCard/MetricCard.model.d.ts +521 -0
  55. package/dist/components/MetricCard/MetricCard.model.js +627 -0
  56. package/dist/components/MetricCard/index.d.ts +4 -0
  57. package/dist/components/MetricCard/index.js +4 -0
  58. package/dist/components/ProfileCard/ProfileCard.chart.d.ts +64 -0
  59. package/dist/components/ProfileCard/ProfileCard.chart.js +427 -0
  60. package/dist/components/ProfileCard/ProfileCard.d.ts +140 -0
  61. package/dist/components/ProfileCard/ProfileCard.js +735 -0
  62. package/dist/components/ProfileCard/ProfileCard.model.d.ts +279 -0
  63. package/dist/components/ProfileCard/ProfileCard.model.js +244 -0
  64. package/dist/components/ProfileCard/index.d.ts +4 -0
  65. package/dist/components/ProfileCard/index.js +4 -0
  66. package/dist/components/ProgressCard/ProgressCard.chart.d.ts +73 -0
  67. package/dist/components/ProgressCard/ProgressCard.chart.js +373 -0
  68. package/dist/components/ProgressCard/ProgressCard.d.ts +137 -0
  69. package/dist/components/ProgressCard/ProgressCard.js +908 -0
  70. package/dist/components/ProgressCard/ProgressCard.model.d.ts +385 -0
  71. package/dist/components/ProgressCard/ProgressCard.model.js +389 -0
  72. package/dist/components/ProgressCard/index.d.ts +4 -0
  73. package/dist/components/ProgressCard/index.js +4 -0
  74. package/dist/components/ReportCard/ReportCard.chart.d.ts +45 -0
  75. package/dist/components/ReportCard/ReportCard.chart.js +231 -0
  76. package/dist/components/ReportCard/ReportCard.d.ts +153 -0
  77. package/dist/components/ReportCard/ReportCard.js +1118 -0
  78. package/dist/components/ReportCard/ReportCard.model.d.ts +392 -0
  79. package/dist/components/ReportCard/ReportCard.model.js +399 -0
  80. package/dist/components/ReportCard/index.d.ts +4 -0
  81. package/dist/components/ReportCard/index.js +4 -0
  82. package/dist/components/SankeyCard/SankeyCard.chart.d.ts +75 -0
  83. package/dist/components/SankeyCard/SankeyCard.chart.js +249 -0
  84. package/dist/components/SankeyCard/SankeyCard.d.ts +185 -0
  85. package/dist/components/SankeyCard/SankeyCard.js +788 -0
  86. package/dist/components/SankeyCard/SankeyCard.model.d.ts +501 -0
  87. package/dist/components/SankeyCard/SankeyCard.model.js +789 -0
  88. package/dist/components/SankeyCard/index.d.ts +4 -0
  89. package/dist/components/SankeyCard/index.js +4 -0
  90. package/dist/components/StatusCard/StatusCard.chart.d.ts +60 -0
  91. package/dist/components/StatusCard/StatusCard.chart.js +188 -0
  92. package/dist/components/StatusCard/StatusCard.d.ts +176 -0
  93. package/dist/components/StatusCard/StatusCard.js +989 -0
  94. package/dist/components/StatusCard/StatusCard.model.d.ts +555 -0
  95. package/dist/components/StatusCard/StatusCard.model.js +776 -0
  96. package/dist/components/StatusCard/index.d.ts +4 -0
  97. package/dist/components/StatusCard/index.js +4 -0
  98. package/dist/components/TableCard/TableCard.chart.d.ts +53 -0
  99. package/dist/components/TableCard/TableCard.chart.js +192 -0
  100. package/dist/components/TableCard/TableCard.d.ts +140 -0
  101. package/dist/components/TableCard/TableCard.js +811 -0
  102. package/dist/components/TableCard/TableCard.model.d.ts +381 -0
  103. package/dist/components/TableCard/TableCard.model.js +475 -0
  104. package/dist/components/TableCard/index.d.ts +4 -0
  105. package/dist/components/TableCard/index.js +4 -0
  106. package/dist/components/TargetCard/TargetCard.chart.d.ts +52 -0
  107. package/dist/components/TargetCard/TargetCard.chart.js +273 -0
  108. package/dist/components/TargetCard/TargetCard.d.ts +143 -0
  109. package/dist/components/TargetCard/TargetCard.js +910 -0
  110. package/dist/components/TargetCard/TargetCard.model.d.ts +468 -0
  111. package/dist/components/TargetCard/TargetCard.model.js +581 -0
  112. package/dist/components/TargetCard/index.d.ts +4 -0
  113. package/dist/components/TargetCard/index.js +4 -0
  114. package/dist/components/TreeCard/TreeCard.chart.d.ts +80 -0
  115. package/dist/components/TreeCard/TreeCard.chart.js +178 -0
  116. package/dist/components/TreeCard/TreeCard.d.ts +182 -0
  117. package/dist/components/TreeCard/TreeCard.js +1187 -0
  118. package/dist/components/TreeCard/TreeCard.model.d.ts +330 -0
  119. package/dist/components/TreeCard/TreeCard.model.js +401 -0
  120. package/dist/components/TreeCard/index.d.ts +4 -0
  121. package/dist/components/TreeCard/index.js +4 -0
  122. package/dist/components/TrendCard/TrendCard.chart.d.ts +75 -0
  123. package/dist/components/TrendCard/TrendCard.chart.js +393 -0
  124. package/dist/components/TrendCard/TrendCard.d.ts +224 -0
  125. package/dist/components/TrendCard/TrendCard.js +1053 -0
  126. package/dist/components/TrendCard/TrendCard.model.d.ts +545 -0
  127. package/dist/components/TrendCard/TrendCard.model.js +623 -0
  128. package/dist/components/TrendCard/index.d.ts +4 -0
  129. package/dist/components/TrendCard/index.js +4 -0
  130. package/dist/index.d.ts +76 -0
  131. package/dist/index.js +57 -0
  132. package/dist/lib/vega/ArcVegaChart.d.ts +24 -0
  133. package/dist/lib/vega/ArcVegaChart.js +42 -0
  134. package/dist/lib/vega/ArcVegaSurface.d.ts +13 -0
  135. package/dist/lib/vega/ArcVegaSurface.js +38 -0
  136. package/dist/lib/vega/axisTicks.js +156 -0
  137. package/dist/lib/vega/config.d.ts +29 -0
  138. package/dist/lib/vega/config.js +113 -0
  139. package/dist/lib/vega/embed.d.ts +29 -0
  140. package/dist/lib/vega/embed.js +29 -0
  141. package/dist/lib/vega/engine.d.ts +10 -0
  142. package/dist/lib/vega/engine.js +6 -0
  143. package/dist/lib/vega/formatters.d.ts +125 -0
  144. package/dist/lib/vega/formatters.js +277 -0
  145. package/dist/lib/vega/index.d.ts +11 -0
  146. package/dist/lib/vega/load.d.ts +13 -0
  147. package/dist/lib/vega/load.js +21 -0
  148. package/dist/lib/vega/time.d.ts +45 -0
  149. package/dist/lib/vega/time.js +105 -0
  150. package/dist/lib/vega/tokens.d.ts +73 -0
  151. package/dist/lib/vega/tokens.js +137 -0
  152. package/dist/lib/vega/tooltip.d.ts +45 -0
  153. package/dist/lib/vega/tooltip.js +124 -0
  154. package/dist/lib/vega/useArcVega.d.ts +43 -0
  155. package/dist/lib/vega/useArcVega.js +121 -0
  156. package/package.json +60 -0
@@ -0,0 +1,421 @@
1
+ import { formatDate, formatDelta, formatNumber, parseArcNumberFormat } from "../../lib/vega/formatters.js";
2
+ //#region src/components/InsightCard/InsightCard.model.ts
3
+ const isFinite = (value) => typeof value === "number" && Number.isFinite(value);
4
+ /** Default severity ladders, per scale. Sigma takes the conventional 2σ / 3σ; a band counts half-widths, so 1 is the edge. */
5
+ const DEFAULT_SEVERITY_THRESHOLDS = {
6
+ sigma: {
7
+ notable: 2,
8
+ critical: 3
9
+ },
10
+ band: {
11
+ notable: 1,
12
+ critical: 2
13
+ },
14
+ relative: {
15
+ notable: .1,
16
+ critical: .25
17
+ }
18
+ };
19
+ /** Confidence at or above these reads as high, then moderate; below, low. */
20
+ const CONFIDENCE_BOUNDS = {
21
+ high: .9,
22
+ moderate: .7
23
+ };
24
+ /** Buckets a 0–1 confidence for the provenance line. `null` for anything outside the range. */
25
+ function insightConfidenceLevel(confidence) {
26
+ if (!isFinite(confidence) || confidence < 0 || confidence > 1) return null;
27
+ if (confidence >= CONFIDENCE_BOUNDS.high) return "high";
28
+ if (confidence >= CONFIDENCE_BOUNDS.moderate) return "moderate";
29
+ return "low";
30
+ }
31
+ /** Guesses the axis kind from the first reading that has an `x`. */
32
+ function inferInsightXType(points) {
33
+ const first = (points ?? []).find((point) => point.x != null);
34
+ if (!first) return "temporal";
35
+ if (first.x instanceof Date) return "temporal";
36
+ if (typeof first.x === "number") return Number.isFinite(first.x) ? "quantitative" : "temporal";
37
+ return Number.isNaN(new Date(first.x).getTime()) ? "ordinal" : "temporal";
38
+ }
39
+ function normalizeX(x, xType) {
40
+ if (xType === "temporal") {
41
+ const time = x instanceof Date ? x.getTime() : new Date(x).getTime();
42
+ return Number.isNaN(time) ? null : time;
43
+ }
44
+ if (xType === "quantitative") return isFinite(x) ? x : null;
45
+ return String(x);
46
+ }
47
+ /** How the deviation is measured, given what the detector actually reported. */
48
+ function resolveStrength(value, expected, lower, upper, sd) {
49
+ if (value == null || expected == null) return {
50
+ strength: null,
51
+ kind: null
52
+ };
53
+ const deviation = Math.abs(value - expected);
54
+ if (isFinite(sd) && sd > 0) return {
55
+ strength: deviation / sd,
56
+ kind: "sigma"
57
+ };
58
+ if (isFinite(lower) && isFinite(upper) && upper > lower) return {
59
+ strength: deviation / ((upper - lower) / 2),
60
+ kind: "band"
61
+ };
62
+ if (expected !== 0) return {
63
+ strength: deviation / Math.abs(expected),
64
+ kind: "relative"
65
+ };
66
+ return {
67
+ strength: null,
68
+ kind: null
69
+ };
70
+ }
71
+ /** The severity the strength supports. Never guesses from a scale the data does not establish. */
72
+ function deriveInsightSeverity(strength, kind, overrides) {
73
+ if (strength == null || kind == null) return "info";
74
+ const base = DEFAULT_SEVERITY_THRESHOLDS[kind];
75
+ const critical = overrides?.critical ?? base.critical;
76
+ const notable = overrides?.notable ?? base.notable;
77
+ if (strength >= critical) return "critical";
78
+ if (strength >= notable) return "notable";
79
+ return "info";
80
+ }
81
+ /** How a deviation reads once the measure's good direction is applied. */
82
+ function deriveInsightPolarity(direction, goodDirection) {
83
+ if (goodDirection === "none" || direction === "flat") return "neutral";
84
+ return direction === (goodDirection === "up" ? "up" : "down") ? "positive" : "negative";
85
+ }
86
+ const STRIP_PADDING = .1;
87
+ /**
88
+ * Resolves the finding: which reading is flagged, what was expected of it,
89
+ * how far off it is and on which scale, how that reads as severity and
90
+ * polarity, which evidence form the data can carry, and the rows each form
91
+ * draws. Returns `null` when there is neither a reading nor a history to
92
+ * speak of.
93
+ */
94
+ function normalizeInsight({ observation, points, xType: xTypeProp, goodDirection = "none", evidence = "auto", severity: severityOverride, severityThresholds, tokens }) {
95
+ const source = points ?? [];
96
+ const xType = xTypeProp ?? inferInsightXType(source);
97
+ const atX = observation?.at != null ? normalizeX(observation.at, xType) : null;
98
+ const rows = [];
99
+ const flags = [];
100
+ source.forEach((point) => {
101
+ const x = normalizeX(point.x, xType);
102
+ if (x == null) return;
103
+ rows.push({
104
+ x,
105
+ y: isFinite(point.y) ? point.y : null,
106
+ e: isFinite(point.expected) ? point.expected : null,
107
+ lo: isFinite(point.lower) ? point.lower : null,
108
+ hi: isFinite(point.upper) ? point.upper : null
109
+ });
110
+ flags.push(point.flagged === true);
111
+ });
112
+ if (xType !== "ordinal") {
113
+ const order = rows.map((_, index) => index).sort((a, b) => rows[a].x - rows[b].x);
114
+ const sortedRows = order.map((index) => rows[index]);
115
+ const sortedFlags = order.map((index) => flags[index]);
116
+ rows.length = 0;
117
+ rows.push(...sortedRows);
118
+ flags.length = 0;
119
+ flags.push(...sortedFlags);
120
+ }
121
+ let flaggedIndex = flags.findIndex(Boolean);
122
+ if (flaggedIndex < 0 && atX != null) flaggedIndex = rows.findIndex((row) => row.x === atX);
123
+ if (flaggedIndex < 0) {
124
+ for (let index = rows.length - 1; index >= 0; index -= 1) if (rows[index].y != null) {
125
+ flaggedIndex = index;
126
+ break;
127
+ }
128
+ }
129
+ const flaggedRow = flaggedIndex >= 0 ? rows[flaggedIndex] : void 0;
130
+ const value = isFinite(observation?.value) ? observation.value : flaggedRow?.y ?? null;
131
+ if (value == null && rows.length === 0) return null;
132
+ const lower = isFinite(observation?.lower) ? observation.lower : flaggedRow?.lo ?? null;
133
+ const upper = isFinite(observation?.upper) ? observation.upper : flaggedRow?.hi ?? null;
134
+ const midpoint = isFinite(lower) && isFinite(upper) ? (lower + upper) / 2 : null;
135
+ const expected = isFinite(observation?.expected) ? observation.expected : flaggedRow?.e ?? midpoint;
136
+ const sd = isFinite(observation?.sd) ? observation.sd : null;
137
+ const deviation = value != null && expected != null ? value - expected : null;
138
+ const relative = deviation != null && expected != null && expected !== 0 ? deviation / Math.abs(expected) : null;
139
+ const outside = value != null && (isFinite(lower) && value < lower || isFinite(upper) && value > upper);
140
+ const direction = deviation == null || deviation === 0 ? "flat" : deviation > 0 ? "up" : "down";
141
+ const polarity = deriveInsightPolarity(direction, goodDirection);
142
+ const { strength, kind } = resolveStrength(value, expected, lower, upper, sd);
143
+ const severity = severityOverride ?? deriveInsightSeverity(strength, kind, severityThresholds);
144
+ const color = polarity === "positive" ? tokens?.positive ?? "" : polarity === "negative" ? tokens?.negative ?? "" : tokens?.emphasis ?? "";
145
+ const finite = rows.filter((row) => row.y != null).length;
146
+ const insufficient = finite < 2;
147
+ const hasBand = rows.filter((row) => row.lo != null && row.hi != null).length >= 2;
148
+ const hasExpectedLine = rows.filter((row) => row.e != null).length >= 2;
149
+ const canSpark = finite >= 2;
150
+ const canRange = value != null && (isFinite(lower) || isFinite(upper) || isFinite(expected));
151
+ const resolvedEvidence = evidence === "none" ? "none" : evidence === "spark" ? canSpark ? "spark" : canRange ? "range" : "none" : evidence === "range" ? canRange ? "range" : "none" : canSpark ? "spark" : canRange ? "range" : "none";
152
+ const pointRows = rows.map((row, index) => ({
153
+ ...row,
154
+ f: index === flaggedIndex,
155
+ c: color
156
+ }));
157
+ const interval = resolvedEvidence === "spark" && !hasBand && flaggedRow && isFinite(lower) && isFinite(upper) ? [{
158
+ x: flaggedRow.x,
159
+ lo: lower,
160
+ hi: upper
161
+ }] : [];
162
+ const strip = [];
163
+ if (resolvedEvidence === "range" && value != null) {
164
+ const marks = [
165
+ value,
166
+ expected,
167
+ lower,
168
+ upper
169
+ ].filter(isFinite);
170
+ let d0 = Math.min(...marks);
171
+ let d1 = Math.max(...marks);
172
+ if (d1 === d0) {
173
+ const pad = Math.max(Math.abs(d0) * STRIP_PADDING, 1);
174
+ d0 -= pad;
175
+ d1 += pad;
176
+ } else {
177
+ const pad = (d1 - d0) * STRIP_PADDING;
178
+ d0 -= pad;
179
+ d1 += pad;
180
+ }
181
+ strip.push({
182
+ lo: lower,
183
+ hi: upper,
184
+ e: expected,
185
+ v: value,
186
+ d0,
187
+ d1,
188
+ c: color
189
+ });
190
+ }
191
+ return {
192
+ value,
193
+ expected,
194
+ lower,
195
+ upper,
196
+ sd,
197
+ deviation,
198
+ relative,
199
+ outside,
200
+ strength,
201
+ strengthKind: kind,
202
+ direction,
203
+ polarity,
204
+ severity,
205
+ color,
206
+ evidence: resolvedEvidence,
207
+ xType,
208
+ points: resolvedEvidence === "spark" ? pointRows : [],
209
+ interval,
210
+ strip,
211
+ flaggedX: flaggedRow?.x ?? null,
212
+ at: observation?.at ?? null,
213
+ count: finite,
214
+ hasBand,
215
+ hasExpectedLine,
216
+ insufficient
217
+ };
218
+ }
219
+ function createInsightFormatters({ format, locale, deltaMode, formatValue, labels }) {
220
+ const value = (input) => isFinite(input) ? formatValue ? formatValue(input) : formatNumber(input, format, locale) : "—";
221
+ return {
222
+ formatValue: value,
223
+ formatRange: (lower, upper) => isFinite(lower) && isFinite(upper) ? labels.rangeText(value(lower), value(upper)) : null,
224
+ formatDeviation: (current, expected) => formatDelta(current, expected, {
225
+ mode: deltaMode,
226
+ format,
227
+ locale
228
+ }).text,
229
+ formatStrength: (strength, kind) => {
230
+ if (strength == null || kind == null) return null;
231
+ if (kind === "sigma") return labels.sigmaText(formatNumber(strength, "number:1", locale));
232
+ if (kind === "band") return labels.bandText(formatNumber(strength, "number:1", locale));
233
+ return labels.relativeText(formatNumber(strength, "percent:0", locale));
234
+ }
235
+ };
236
+ }
237
+ const DEFAULT_INSIGHT_LABELS = {
238
+ noData: "No insight",
239
+ noMatch: "No matching insight",
240
+ clearFilters: "Clear filters",
241
+ error: "Couldn't load this insight",
242
+ retry: "Try again",
243
+ stale: "Stale",
244
+ asOf: "As of",
245
+ observed: "Observed",
246
+ expected: "Expected",
247
+ deviation: "vs expected",
248
+ rangeText: (lower, upper) => `${lower} – ${upper}`,
249
+ outsideRange: (range) => `Outside the expected ${range}.`,
250
+ insideRange: (range) => `Within the expected ${range}.`,
251
+ sigmaText: (value) => `${value}σ from expected`,
252
+ bandText: (value) => `${value}× the expected range`,
253
+ relativeText: (value) => `${value} from expected`,
254
+ detected: (when) => `Detected ${when}`,
255
+ sample: (count) => `${count} readings`,
256
+ confidence: (level, percent) => `${level} confidence (${percent})`,
257
+ confidenceNames: {
258
+ high: "High",
259
+ moderate: "Moderate",
260
+ low: "Low"
261
+ },
262
+ kindNames: {
263
+ anomaly: "Anomaly",
264
+ trend: "Trend",
265
+ threshold: "Threshold",
266
+ outlier: "Outlier",
267
+ correlation: "Correlation",
268
+ forecast: "Forecast",
269
+ milestone: "Milestone",
270
+ note: "Note"
271
+ },
272
+ severityNames: {
273
+ info: "Info",
274
+ notable: "Notable",
275
+ critical: "Critical"
276
+ },
277
+ badge: (severity, kind, key) => key === "info" ? kind : `${severity} ${kind.toLowerCase()}`,
278
+ directionWords: {
279
+ up: "up",
280
+ down: "down",
281
+ flat: "unchanged"
282
+ },
283
+ dismiss: (name) => `Dismiss ${name}`,
284
+ helpful: "Helpful",
285
+ notHelpful: "Not helpful",
286
+ feedbackGroup: (name) => `Was ${name} helpful?`,
287
+ showTable: (name) => `Show the data behind ${name}`,
288
+ hideTable: (name) => `Hide the data behind ${name}`,
289
+ about: (name) => `About ${name}`,
290
+ loading: (name) => `Loading ${name}`,
291
+ tableCaption: (name) => `Data behind ${name}`,
292
+ tablePeriod: "Period",
293
+ tableValue: "Reading",
294
+ tableExpected: "Expected",
295
+ tableRange: "Expected range",
296
+ tableFlagged: "Flagged",
297
+ flagged: "flagged",
298
+ needsHistory: "Not enough history to plot a trend.",
299
+ evidenceNames: {
300
+ spark: "Sparkline",
301
+ range: "Range strip"
302
+ },
303
+ chartDescription: ({ evidence, name, readings, observed, expected, range, at }) => `${evidence} of ${name}${readings > 0 ? `, ${readings} ${readings === 1 ? "reading" : "readings"}` : ""}. Flagged reading ${observed}${at ? ` at ${at}` : ""}.` + (expected ? ` Expected ${expected}.` : "") + (range ? ` Expected range ${range}.` : ""),
304
+ claim: ({ kind, name, observed, expected, deviation }) => `${kind} in ${name}: ${observed}` + (expected ? ` against an expected ${expected}` : "") + (deviation ? ` (${deviation})` : "") + ".",
305
+ insightMark: "Insight"
306
+ };
307
+ function resolveInsightLabels(overrides) {
308
+ return overrides ? {
309
+ ...DEFAULT_INSIGHT_LABELS,
310
+ ...overrides
311
+ } : DEFAULT_INSIGHT_LABELS;
312
+ }
313
+ /**
314
+ * The state machine. Error wins; loading over an existing finding is a
315
+ * refresh (the previous render stays under the veil); a finding with too
316
+ * little history to plot is `insufficient`, not `ready` — the claim still
317
+ * reads, only the time plot degrades; nothing to say is `no-match` when the
318
+ * consumer's filter caused it and `empty` otherwise.
319
+ */
320
+ function deriveInsightState({ status, hasFinding, hasData, insufficient, filtered }) {
321
+ if (status === "error") return "error";
322
+ if (status === "loading") return hasData ? "refreshing" : "loading";
323
+ if (!hasFinding) return filtered ? "no-match" : "empty";
324
+ return insufficient ? "insufficient" : "ready";
325
+ }
326
+ /**
327
+ * The figure's generated description: what kind of finding this is, how much
328
+ * it matters, the claim, the evidence that supports it, where the reading sits
329
+ * against the expected range, and the provenance — because a machine claim
330
+ * without provenance is not honest data.
331
+ */
332
+ function buildInsightDescription({ name, state, statement, kind, severity, summary, formatters, provenance, asOfText, labels }) {
333
+ if (state === "loading") return labels.loading(name);
334
+ if (state === "error") return `${name}: ${labels.error}`;
335
+ if (state === "empty") return `${name}: ${labels.noData}`;
336
+ if (state === "no-match") return `${name}: ${labels.noMatch}`;
337
+ const parts = [`${labels.badge(labels.severityNames[severity], labels.kindNames[kind], severity)}. ${name}.`];
338
+ const observed = summary?.value != null ? formatters.formatValue(summary.value) : null;
339
+ const expected = summary?.expected != null ? formatters.formatValue(summary.expected) : null;
340
+ const deviation = summary?.value != null && summary.expected != null ? formatters.formatDeviation(summary.value, summary.expected) : null;
341
+ if (statement) parts.push(statement.endsWith(".") ? statement : `${statement}.`);
342
+ else if (observed) parts.push(labels.claim({
343
+ kind: labels.kindNames[kind],
344
+ name,
345
+ observed,
346
+ expected,
347
+ deviation
348
+ }));
349
+ const range = summary ? formatters.formatRange(summary.lower, summary.upper) : null;
350
+ if (range) parts.push(summary?.outside ? labels.outsideRange(range) : labels.insideRange(range));
351
+ const strength = summary ? formatters.formatStrength(summary.strength, summary.strengthKind) : null;
352
+ if (strength && !range) parts.push(`${strength}.`);
353
+ if (state === "insufficient") parts.push(labels.needsHistory);
354
+ if (provenance && provenance.length > 0) parts.push(`${provenance.join(" · ")}.`);
355
+ if (asOfText) parts.push(`${labels.asOf} ${asOfText}.`);
356
+ return parts.join(" ");
357
+ }
358
+ /** The plot's own `aria-label` — the form, what is on it, and where the flagged reading sits. */
359
+ function buildInsightChartDescription({ name, summary, formatters, atText, labels }) {
360
+ const evidence = summary.evidence === "none" ? labels.evidenceNames.range : labels.evidenceNames[summary.evidence];
361
+ return labels.chartDescription({
362
+ evidence,
363
+ name,
364
+ readings: summary.evidence === "spark" ? summary.count : 0,
365
+ observed: formatters.formatValue(summary.value),
366
+ expected: summary.expected != null ? formatters.formatValue(summary.expected) : null,
367
+ range: formatters.formatRange(summary.lower, summary.upper),
368
+ at: atText ?? null
369
+ });
370
+ }
371
+ /**
372
+ * The provenance parts, in reading order — method, confidence, sample size,
373
+ * detection time. Empty when the consumer reported none, which is itself
374
+ * worth seeing: an unattributed claim looks unattributed.
375
+ */
376
+ function buildInsightProvenance({ method, confidence, sampleSize, detectedAtText, locale, labels }) {
377
+ const parts = [];
378
+ if (method) parts.push(method);
379
+ const level = insightConfidenceLevel(confidence);
380
+ if (level && confidence != null) parts.push(labels.confidence(labels.confidenceNames[level], formatNumber(confidence, "percent:0", locale)));
381
+ if (isFinite(sampleSize) && sampleSize > 0) parts.push(labels.sample(formatNumber(sampleSize, "integer", locale)));
382
+ if (detectedAtText) parts.push(labels.detected(detectedAtText));
383
+ return parts;
384
+ }
385
+ /** Writes a row's period the way the axis and the tooltip write it, so the table never disagrees with the plot. */
386
+ function formatInsightX(x, { xType, granularity = "day", locale, timeZone }) {
387
+ if (x == null) return "—";
388
+ if (xType === "temporal" && typeof x === "number") return formatDate(x, {
389
+ granularity,
390
+ locale,
391
+ timeZone
392
+ });
393
+ if (xType === "quantitative" && typeof x === "number") return formatNumber(x, "number", locale);
394
+ return String(x);
395
+ }
396
+ /** Whether a measure's own format is a percentage, so an absolute delta is written in points rather than percent. */
397
+ function insightFormatIsPercent(format) {
398
+ return parseArcNumberFormat(format).kind === "percent";
399
+ }
400
+ const DAY_MS = 864e5;
401
+ /**
402
+ * The granularity an axis tick may use, given the one the card reads dates at
403
+ * and how long the plotted window is. An axis label has a pixel budget and
404
+ * ellipsizes past it, so the tooltip's full form is never the axis's form: a
405
+ * date drops its year, a month drops its year, and a datetime drops its clock
406
+ * — except across a window shorter than two days, where a bare date would
407
+ * print the same label at both ends and the hour is the part that separates
408
+ * them. The hour is in the tooltip and the table either way.
409
+ */
410
+ function insightAxisGranularity(granularity, spanMs) {
411
+ switch (granularity) {
412
+ case "day": return "day-short";
413
+ case "month": return "month-short";
414
+ case "datetime":
415
+ case "day-time": return spanMs != null && spanMs < 2 * DAY_MS ? "day-time" : "day-short";
416
+ case "time": return spanMs != null && spanMs >= 2 * DAY_MS ? "day-short" : "time";
417
+ default: return granularity;
418
+ }
419
+ }
420
+ //#endregion
421
+ export { CONFIDENCE_BOUNDS, DEFAULT_INSIGHT_LABELS, DEFAULT_SEVERITY_THRESHOLDS, buildInsightChartDescription, buildInsightDescription, buildInsightProvenance, createInsightFormatters, deriveInsightPolarity, deriveInsightSeverity, deriveInsightState, formatInsightX, inferInsightXType, insightAxisGranularity, insightConfidenceLevel, insightFormatIsPercent, normalizeInsight, resolveInsightLabels };
@@ -0,0 +1,4 @@
1
+ import { BuildInsightDescriptionInput, CONFIDENCE_BOUNDS, DEFAULT_INSIGHT_LABELS, DEFAULT_SEVERITY_THRESHOLDS, DeriveInsightStateInput, InsightCardLabels, InsightCardSize, InsightCardState, InsightCardStatus, InsightConfidenceLevel, InsightDeltaMode, InsightEvidence, InsightFeedback, InsightGoodDirection, InsightIntervalRow, InsightKind, InsightObservation, InsightPoint, InsightPolarity, InsightRow, InsightSeverity, InsightSeverityThresholds, InsightStrengthKind, InsightStripRow, InsightSummary, InsightTextFormatters, InsightXType, NormalizeInsightOptions, buildInsightChartDescription, buildInsightDescription, buildInsightProvenance, createInsightFormatters, deriveInsightPolarity, deriveInsightSeverity, deriveInsightState, formatInsightX, inferInsightXType, insightAxisGranularity, insightConfidenceLevel, insightFormatIsPercent, normalizeInsight, resolveInsightLabels } from "./InsightCard.model.js";
2
+ import { INSIGHT_FLAG_PARAM, INSIGHT_HOVER_PARAM, INSIGHT_INTERVAL_DATASET, INSIGHT_POINTS_DATASET, INSIGHT_STRIP_DATASET, INSIGHT_X_TICKS_PARAM, InsightAxes, InsightSparkSpecOptions, InsightStripSpecOptions, buildInsightSparkSpec, buildInsightStripSpec } from "./InsightCard.chart.js";
3
+ import { InsightCard, InsightCardProps } from "./InsightCard.js";
4
+ export { type BuildInsightDescriptionInput, CONFIDENCE_BOUNDS, DEFAULT_INSIGHT_LABELS, DEFAULT_SEVERITY_THRESHOLDS, type DeriveInsightStateInput, INSIGHT_FLAG_PARAM, INSIGHT_HOVER_PARAM, INSIGHT_INTERVAL_DATASET, INSIGHT_POINTS_DATASET, INSIGHT_STRIP_DATASET, INSIGHT_X_TICKS_PARAM, type InsightAxes, InsightCard, type InsightCardLabels, type InsightCardProps, type InsightCardSize, type InsightCardState, type InsightCardStatus, type InsightConfidenceLevel, type InsightDeltaMode, type InsightEvidence, type InsightFeedback, type InsightGoodDirection, type InsightIntervalRow, type InsightKind, type InsightObservation, type InsightPoint, type InsightPolarity, type InsightRow, type InsightSeverity, type InsightSeverityThresholds, type InsightSparkSpecOptions, type InsightStrengthKind, type InsightStripRow, type InsightStripSpecOptions, type InsightSummary, type InsightTextFormatters, type InsightXType, type NormalizeInsightOptions, buildInsightChartDescription, buildInsightDescription, buildInsightProvenance, buildInsightSparkSpec, buildInsightStripSpec, createInsightFormatters, deriveInsightPolarity, deriveInsightSeverity, deriveInsightState, formatInsightX, inferInsightXType, insightAxisGranularity, insightConfidenceLevel, insightFormatIsPercent, normalizeInsight, resolveInsightLabels };
@@ -0,0 +1,4 @@
1
+ import { INSIGHT_FLAG_PARAM, INSIGHT_HOVER_PARAM, INSIGHT_INTERVAL_DATASET, INSIGHT_POINTS_DATASET, INSIGHT_STRIP_DATASET, INSIGHT_X_TICKS_PARAM, buildInsightSparkSpec, buildInsightStripSpec } from "./InsightCard.chart.js";
2
+ import { CONFIDENCE_BOUNDS, DEFAULT_INSIGHT_LABELS, DEFAULT_SEVERITY_THRESHOLDS, buildInsightChartDescription, buildInsightDescription, buildInsightProvenance, createInsightFormatters, deriveInsightPolarity, deriveInsightSeverity, deriveInsightState, formatInsightX, inferInsightXType, insightAxisGranularity, insightConfidenceLevel, insightFormatIsPercent, normalizeInsight, resolveInsightLabels } from "./InsightCard.model.js";
3
+ import { InsightCard } from "./InsightCard.js";
4
+ export { CONFIDENCE_BOUNDS, DEFAULT_INSIGHT_LABELS, DEFAULT_SEVERITY_THRESHOLDS, INSIGHT_FLAG_PARAM, INSIGHT_HOVER_PARAM, INSIGHT_INTERVAL_DATASET, INSIGHT_POINTS_DATASET, INSIGHT_STRIP_DATASET, INSIGHT_X_TICKS_PARAM, InsightCard, buildInsightChartDescription, buildInsightDescription, buildInsightProvenance, buildInsightSparkSpec, buildInsightStripSpec, createInsightFormatters, deriveInsightPolarity, deriveInsightSeverity, deriveInsightState, formatInsightX, inferInsightXType, insightAxisGranularity, insightConfidenceLevel, insightFormatIsPercent, normalizeInsight, resolveInsightLabels };
@@ -0,0 +1,79 @@
1
+ import { ChartTokens } from "../../lib/vega/tokens.js";
2
+ import { MetricTrendAxes, MetricTrendMark, MetricTrendScale, MetricTrendXType } from "./MetricCard.model.js";
3
+ import { TopLevelSpec } from "vega-lite";
4
+ //#region src/components/MetricCard/MetricCard.chart.d.ts
5
+ /** The trend rows: `{ x, y }` per `MetricTrendRow` (plus `hl` and `tone` in the highlight variant). */
6
+ declare const METRIC_TREND_DATASET = "table";
7
+ /** Zero or one row `{ value }` — the target reference line. */
8
+ declare const METRIC_REFERENCE_DATASET = "reference";
9
+ /** Zero or one row — the latest valid reading, marked with a dot. */
10
+ declare const METRIC_LATEST_DATASET = "latest";
11
+ /** Highlight variant: the readings outside the window with a `seg` of `before` or `after` — the gray context runs. */
12
+ declare const METRIC_CONTEXT_DATASET = "context";
13
+ /** Highlight variant: the readings inside the window — the coloured segment. */
14
+ declare const METRIC_HIGHLIGHT_ROWS_DATASET = "highlightRows";
15
+ /** Highlight variant: the window's start and end readings — the two dots. */
16
+ declare const METRIC_HIGHLIGHT_POINTS_DATASET = "highlightPoints";
17
+ /** Highlight variant: one row `{ start, end, startY, endY, tone }` — the band behind a line and the axis anchors. */
18
+ declare const METRIC_HIGHLIGHT_DATASET = "highlight";
19
+ /** The nearest-point hover selection. */
20
+ declare const METRIC_HOVER_PARAM = "hover";
21
+ /** Responsive x tick values, recomputed by Vega when the domain or width changes. */
22
+ declare const METRIC_X_TICKS_PARAM = "metric_x_ticks";
23
+ /** Highlight variant: the window's snapped bounds, read from the `highlight` dataset — the x axis labels them. */
24
+ declare const METRIC_HIGHLIGHT_START_PARAM = "metric_hl_start";
25
+ declare const METRIC_HIGHLIGHT_END_PARAM = "metric_hl_end";
26
+ interface MetricTrendSpecOptions {
27
+ mark: MetricTrendMark;
28
+ scale: MetricTrendScale;
29
+ xType: MetricTrendXType;
30
+ /** Which axes to draw, default `x`. Axes share the plot's box (`autosize: fit`), so the caller reserves height for the x labels. */
31
+ axes?: MetricTrendAxes;
32
+ height: number;
33
+ /** Draw the target reference rule (the `reference` dataset carries the value). */
34
+ reference: boolean;
35
+ /** Wire the nearest-point hover selection and tooltip channel. */
36
+ tooltip: boolean;
37
+ /**
38
+ * The highlight variant: wash a band behind the window, paint the readings
39
+ * outside it in the context gray and the window in its polarity hue (each
40
+ * row's `tone`), dot its start and end, and label the window's bounds on the
41
+ * x axis. Reads the `context`, `highlightRows`, `highlightPoints` and
42
+ * `highlight` datasets and skips the `latest` dot. Pair it with `tooltip`:
43
+ * the hover layer is what keeps the `table` dataset in the compiled spec for
44
+ * a line or an area.
45
+ */
46
+ highlight?: boolean;
47
+ /** Tooltip titles. */
48
+ xTitle: string;
49
+ yTitle: string;
50
+ /** Localised title for the target reference line's hover value. */
51
+ targetTitle?: string;
52
+ /** `arcNumber` grammar for values (`compact@en-US`). */
53
+ valueFormat: string;
54
+ /** `arcTime` grammar for temporal x in tooltips (`day@en-US@Asia/Bangkok`). */
55
+ timeFormat: string;
56
+ /** `arcTime` grammar for x-axis tick labels — the axis-length form (`day-short@en-US@Asia/Bangkok`). */
57
+ axisTimeFormat: string;
58
+ locale?: string;
59
+ timeZone?: string;
60
+ }
61
+ /**
62
+ * Builds the sparkline: a line (or an area with a crisp line on top, or bars),
63
+ * an optional hairline target rule that joins the y-domain, the latest reading
64
+ * as a dot, a nearest-point hover layer carrying the tooltip, and — when
65
+ * `axes` asks for them — quiet x and/or y axes labelled through the card's own
66
+ * formats. Lines may crop (`scale: "auto"`); areas and bars keep a zero
67
+ * baseline whatever `scale` says — proportional ink is not negotiable. Gaps
68
+ * stay gaps: Vega-Lite's default `invalid` handling breaks the path at a null
69
+ * reading.
70
+ *
71
+ * With `highlight`, the series recedes to the context gray and the window is
72
+ * the subject: a quiet band washes its extent, its readings draw in the
73
+ * polarity hue (bars inside it take the hue), its start and end are dotted,
74
+ * and the x axis labels the window's bounds (flanking the band) before the
75
+ * domain ends.
76
+ */
77
+ declare function buildMetricTrendSpec(options: MetricTrendSpecOptions, tokens: ChartTokens): TopLevelSpec;
78
+ //#endregion
79
+ export { 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 };