@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,393 @@
1
+ import { AXIS_LABEL_LIMIT_EXPR } from "../../lib/vega/axisTicks.js";
2
+ import { arcVegaConfig } from "../../lib/vega/config.js";
3
+ //#region src/components/TrendCard/TrendCard.chart.ts
4
+ /** Long-form readings: `{ x, s, y, raw, i, c, n }` per `TrendRow`, for the visible series only. */
5
+ const TREND_TABLE_DATASET = "table";
6
+ /** One row per period, `{ x }` — the crosshair, filtered by the hover selection. */
7
+ const TREND_PERIODS_DATASET = "periods";
8
+ /** Zero or one row `{ value }` — the target reference rule. */
9
+ const TREND_REFERENCE_DATASET = "reference";
10
+ /** Resolved bands `{ start, end, label? }` — the washed period annotations. */
11
+ const TREND_BANDS_DATASET = "bands";
12
+ /** One row per visible series — its last finite reading, for the endpoint labels. */
13
+ const TREND_LATEST_DATASET = "latest";
14
+ /** The shared-x hover selection: projected onto `x`, so every series lights up at the pointed period. */
15
+ const TREND_HOVER_PARAM = "hover";
16
+ /** Responsive x tick values, recomputed by Vega when the domain or the width changes. */
17
+ const TREND_X_TICKS_PARAM = "trend_x_ticks";
18
+ const POINT_SIZE = 64;
19
+ const BAR_WIDTH_EXPR = "min(24, bandwidth('x') * 0.8)";
20
+ const PLOT_PADDING = 6;
21
+ const LABEL_LIMIT_PX = 64;
22
+ const LABEL_DODGE_PX = 14;
23
+ const LABEL_DODGE_ROOM_PX = 20;
24
+ const LABEL_INSET_PX = 4;
25
+ const BAND_OPACITY = .5;
26
+ const CONTEXT_OPACITY = .85;
27
+ const DISCRETE_DOMAIN_EXPR = `pluck(data('${TREND_PERIODS_DATASET}'), 'x')`;
28
+ /**
29
+ * Builds the plot: one mark per series on a SHARED y scale (never a second
30
+ * axis — series in different units are indexed to a common base instead, which
31
+ * the card does before it gets here), quiet labelled axes, an optional dotted
32
+ * target rule, washed period bands behind everything, and the documented
33
+ * multi-series hover: a transparent `point` layer carrying a `nearest`
34
+ * selection projected onto `x`, a crosshair rule filtered by that selection,
35
+ * and dots on every series at the pointed period.
36
+ *
37
+ * Gaps stay gaps — a `null` reading breaks the path rather than dropping it to
38
+ * zero. Lines may crop (`scale: "auto"`); areas and bars keep a zero baseline
39
+ * whatever `scale` says, because proportional ink is not negotiable.
40
+ */
41
+ function buildTrendPlotSpec(options, tokens) {
42
+ const { mark, scale, xType, stack, height, axes, yTicks, reference, bands, tooltip, labelSeries, emphasize, xTitle, yTitle, plotFormat, timeFormat, axisTimeFormat } = options;
43
+ const zero = mark !== "line" || scale === "zero";
44
+ const discreteX = mark === "bar" || xType === "ordinal";
45
+ const stackMode = mark === "line" ? null : stack === false ? null : stack;
46
+ const grouped = mark === "bar" && stackMode === null;
47
+ const xTickFormat = xType === "temporal" ? axisTimeFormat : "compact";
48
+ const xTickKind = xType === "temporal" ? "time" : xType === "quantitative" ? "number" : "text";
49
+ const axisArgs = `domain('x'), width, ${discreteX}, ${JSON.stringify(xTickFormat)}, ${JSON.stringify(xTickKind)}`;
50
+ const xAxisLabels = xType === "temporal" ? {
51
+ format: axisTimeFormat,
52
+ formatType: "arcTime"
53
+ } : xType === "quantitative" ? {
54
+ format: "compact",
55
+ formatType: "arcNumber"
56
+ } : {};
57
+ const xAxis = axes ? {
58
+ title: null,
59
+ orient: "bottom",
60
+ domain: true,
61
+ ticks: false,
62
+ grid: false,
63
+ values: { expr: TREND_X_TICKS_PARAM },
64
+ labelAngle: 0,
65
+ labelAlign: { expr: `arcAxisLabelAlign(datum.value, ${axisArgs})` },
66
+ labelFlush: false,
67
+ labelOverlap: false,
68
+ labelLimit: { expr: AXIS_LABEL_LIMIT_EXPR },
69
+ labelPadding: 4,
70
+ ...xAxisLabels
71
+ } : null;
72
+ const yAxis = axes ? {
73
+ title: null,
74
+ orient: "left",
75
+ domain: false,
76
+ ticks: false,
77
+ grid: true,
78
+ tickCount: yTicks,
79
+ labelOverlap: true,
80
+ labelPadding: 6,
81
+ format: plotFormat,
82
+ formatType: "arcNumber"
83
+ } : null;
84
+ const xField = discreteX ? {
85
+ field: "x",
86
+ type: "ordinal",
87
+ sort: null,
88
+ axis: xAxis,
89
+ ...discreteX ? { scale: {
90
+ domain: { expr: DISCRETE_DOMAIN_EXPR },
91
+ paddingOuter: .05
92
+ } } : {}
93
+ } : {
94
+ field: "x",
95
+ type: xType,
96
+ axis: xAxis,
97
+ scale: {
98
+ nice: false,
99
+ ...xType === "quantitative" ? { zero: false } : {}
100
+ }
101
+ };
102
+ const yField = {
103
+ field: "y",
104
+ type: "quantitative",
105
+ axis: yAxis,
106
+ scale: {
107
+ zero,
108
+ nice: axes
109
+ },
110
+ ...stackMode === null ? { stack: null } : { stack: stackMode }
111
+ };
112
+ const seriesDetail = {
113
+ field: "s",
114
+ type: "nominal"
115
+ };
116
+ const colorField = {
117
+ field: "c",
118
+ type: "nominal",
119
+ scale: null,
120
+ legend: null
121
+ };
122
+ const emphasisOpacity = emphasize ? { opacity: {
123
+ condition: {
124
+ test: "datum.f",
125
+ value: 1
126
+ },
127
+ value: CONTEXT_OPACITY
128
+ } } : {};
129
+ const tooltipChannel = [
130
+ xType === "temporal" ? {
131
+ field: "x",
132
+ type: "temporal",
133
+ title: xTitle,
134
+ format: timeFormat,
135
+ formatType: "arcTime"
136
+ } : xType === "quantitative" ? {
137
+ field: "x",
138
+ type: "quantitative",
139
+ title: xTitle,
140
+ format: "number",
141
+ formatType: "arcNumber"
142
+ } : {
143
+ field: "x",
144
+ type: "nominal",
145
+ title: xTitle
146
+ },
147
+ {
148
+ field: "n",
149
+ type: "nominal",
150
+ title: yTitle
151
+ },
152
+ {
153
+ field: "y",
154
+ type: "quantitative",
155
+ title: yTitle,
156
+ format: plotFormat,
157
+ formatType: "arcNumber"
158
+ }
159
+ ];
160
+ const layers = [];
161
+ if (bands) layers.push({
162
+ data: { name: TREND_BANDS_DATASET },
163
+ mark: {
164
+ type: "rect",
165
+ fill: tokens.brush,
166
+ opacity: BAND_OPACITY,
167
+ aria: false
168
+ },
169
+ encoding: {
170
+ x: {
171
+ ...xField,
172
+ field: "start",
173
+ axis: xAxis,
174
+ ...discreteX ? { bandPosition: 0 } : {}
175
+ },
176
+ x2: {
177
+ field: "end",
178
+ ...discreteX ? { bandPosition: 1 } : {}
179
+ }
180
+ }
181
+ });
182
+ if (mark === "area") {
183
+ layers.push({
184
+ mark: {
185
+ type: "area",
186
+ line: false,
187
+ fillOpacity: stackMode === null ? .12 : .85,
188
+ interpolate: "linear",
189
+ invalid: "break-paths-show-domains"
190
+ },
191
+ encoding: {
192
+ x: xField,
193
+ y: yField,
194
+ detail: seriesDetail,
195
+ fill: colorField,
196
+ ...emphasisOpacity
197
+ }
198
+ });
199
+ layers.push({
200
+ mark: {
201
+ type: "line",
202
+ strokeWidth: stackMode === null ? 2 : 1,
203
+ strokeCap: "round",
204
+ strokeJoin: "round",
205
+ interpolate: "linear",
206
+ invalid: "break-paths-show-domains",
207
+ ...stackMode === null ? {} : { stroke: tokens.background }
208
+ },
209
+ encoding: {
210
+ x: xField,
211
+ y: yField,
212
+ detail: seriesDetail,
213
+ ...stackMode === null ? { stroke: colorField } : {},
214
+ ...emphasisOpacity
215
+ }
216
+ });
217
+ } else if (mark === "bar") layers.push({
218
+ mark: {
219
+ type: "bar",
220
+ cornerRadiusEnd: 2,
221
+ ...grouped ? {} : { width: { expr: BAR_WIDTH_EXPR } },
222
+ ...stackMode === null ? {} : {
223
+ stroke: tokens.background,
224
+ strokeWidth: 1
225
+ }
226
+ },
227
+ encoding: {
228
+ x: xField,
229
+ y: yField,
230
+ ...grouped ? { xOffset: {
231
+ field: "i",
232
+ type: "ordinal",
233
+ sort: null
234
+ } } : { detail: seriesDetail },
235
+ fill: colorField,
236
+ ...emphasisOpacity
237
+ }
238
+ });
239
+ else layers.push({
240
+ mark: {
241
+ type: "line",
242
+ strokeWidth: 2,
243
+ strokeCap: "round",
244
+ strokeJoin: "round",
245
+ interpolate: "linear",
246
+ invalid: "break-paths-show-domains"
247
+ },
248
+ encoding: {
249
+ x: xField,
250
+ y: yField,
251
+ detail: seriesDetail,
252
+ stroke: colorField,
253
+ ...emphasisOpacity
254
+ }
255
+ });
256
+ if (reference) layers.push({
257
+ data: { name: TREND_REFERENCE_DATASET },
258
+ mark: {
259
+ type: "rule",
260
+ stroke: tokens.reference,
261
+ strokeWidth: 1.5,
262
+ strokeDash: [0, 4],
263
+ strokeCap: "round",
264
+ opacity: .9,
265
+ aria: false
266
+ },
267
+ encoding: {
268
+ y: {
269
+ ...yField,
270
+ field: "value",
271
+ stack: null
272
+ },
273
+ ...tooltip ? { tooltip: [{
274
+ field: "value",
275
+ type: "quantitative",
276
+ title: options.targetTitle ?? "Target",
277
+ format: plotFormat,
278
+ formatType: "arcNumber"
279
+ }] } : {}
280
+ }
281
+ });
282
+ if (tooltip) {
283
+ layers.push({
284
+ params: [{
285
+ name: TREND_HOVER_PARAM,
286
+ select: {
287
+ type: "point",
288
+ on: "pointermove",
289
+ nearest: true,
290
+ clear: "pointerout",
291
+ encodings: ["x"]
292
+ }
293
+ }],
294
+ mark: {
295
+ type: "point",
296
+ filled: true,
297
+ size: POINT_SIZE,
298
+ stroke: tokens.background,
299
+ strokeWidth: 1.5,
300
+ aria: false
301
+ },
302
+ encoding: {
303
+ x: xField,
304
+ y: {
305
+ ...yField,
306
+ stack: stackMode === null ? null : stackMode
307
+ },
308
+ detail: seriesDetail,
309
+ fill: colorField,
310
+ opacity: {
311
+ condition: {
312
+ param: TREND_HOVER_PARAM,
313
+ empty: false,
314
+ value: 1
315
+ },
316
+ value: 0
317
+ },
318
+ tooltip: tooltipChannel
319
+ }
320
+ });
321
+ layers.push({
322
+ data: { name: TREND_PERIODS_DATASET },
323
+ mark: {
324
+ type: "rule",
325
+ stroke: tokens.axis,
326
+ strokeWidth: 1,
327
+ aria: false
328
+ },
329
+ encoding: {
330
+ x: xField,
331
+ opacity: {
332
+ condition: {
333
+ param: TREND_HOVER_PARAM,
334
+ empty: false,
335
+ value: .6
336
+ },
337
+ value: 0
338
+ }
339
+ }
340
+ });
341
+ }
342
+ if (labelSeries) layers.push({
343
+ data: { name: TREND_LATEST_DATASET },
344
+ mark: {
345
+ type: "text",
346
+ align: "right",
347
+ baseline: "middle",
348
+ dx: LABEL_INSET_PX,
349
+ dy: { expr: `scale('y', datum.y) < height / 2 ? (scale('y', datum.y) >= ${LABEL_DODGE_ROOM_PX} ? -${LABEL_DODGE_PX} : ${LABEL_DODGE_PX}) : (height - scale('y', datum.y) >= ${LABEL_DODGE_ROOM_PX} ? ${LABEL_DODGE_PX} : -${LABEL_DODGE_PX})` },
350
+ fontSize: 11,
351
+ fontWeight: 500,
352
+ limit: { expr: `max(${LABEL_LIMIT_PX}, width / 3)` },
353
+ aria: false
354
+ },
355
+ encoding: {
356
+ x: xField,
357
+ y: {
358
+ ...yField,
359
+ stack: null
360
+ },
361
+ text: {
362
+ field: "n",
363
+ type: "nominal"
364
+ },
365
+ color: colorField
366
+ }
367
+ });
368
+ const params = [];
369
+ if (axes) params.push({
370
+ name: TREND_X_TICKS_PARAM,
371
+ expr: `arcAxisTicks(${axisArgs})`
372
+ });
373
+ return {
374
+ $schema: "https://vega.github.io/schema/vega-lite/v6.json",
375
+ width: 320,
376
+ height,
377
+ autosize: {
378
+ type: "fit",
379
+ contains: "padding"
380
+ },
381
+ padding: PLOT_PADDING,
382
+ background: "transparent",
383
+ data: { name: TREND_TABLE_DATASET },
384
+ ...params.length > 0 ? { params } : {},
385
+ layer: layers,
386
+ config: arcVegaConfig(tokens, {
387
+ locale: options.locale,
388
+ timeZone: options.timeZone
389
+ })
390
+ };
391
+ }
392
+ //#endregion
393
+ export { TREND_BANDS_DATASET, TREND_HOVER_PARAM, TREND_LATEST_DATASET, TREND_PERIODS_DATASET, TREND_REFERENCE_DATASET, TREND_TABLE_DATASET, TREND_X_TICKS_PARAM, buildTrendPlotSpec };
@@ -0,0 +1,224 @@
1
+ import { ArcTimeGranularity } from "../../lib/vega/formatters.js";
2
+ import { TrendBand, TrendCardLabels, TrendCardSize, TrendCardStatus, TrendDeltaMode, TrendGoodDirection, TrendHeadline, TrendMark, TrendNormalize, TrendScale, TrendSeries, TrendSeriesColor, TrendStack } from "./TrendCard.model.js";
3
+ import { ReactNode } from "react";
4
+ import { BoxProps } from "@arcfusionz/arc-primitive-ui";
5
+ import { TopLevelSpec } from "vega-lite";
6
+ import { Result } from "vega-embed";
7
+ //#region src/components/TrendCard/TrendCard.d.ts
8
+ /** What the legend chips do. `auto` follows the colour job — see `legendMode`. */
9
+ type TrendLegendMode = "auto" | "focus" | "visibility";
10
+ interface TrendCardProps extends Omit<BoxProps, "children" | "padding" | "title"> {
11
+ /** The trend's name — the panel's heading. Pass `name` too when this is not plain text. */
12
+ label: ReactNode;
13
+ /** Plain-text name used in the generated descriptions and control labels. Defaults to `label` when it is a string. */
14
+ name?: string;
15
+ /** Definition of the metric, shown in a tooltip behind an info control beside the label and exposed to assistive technology as the control's description. */
16
+ hint?: string;
17
+ /**
18
+ * The series to plot: `{ key?, label, points }` in the order that decides
19
+ * identity (a colour slot follows a series' index, never its rank, so a
20
+ * filter cannot repaint the survivors). `points` is `{ x, y }` — `x` a
21
+ * `Date`, ISO string, number or period label; `y` the value or `null` for a
22
+ * gap. A series need not cover every period: the periods it never mentions
23
+ * simply have no marks. Pass `[]` while loading to reserve the plot's height.
24
+ */
25
+ series: readonly TrendSeries[];
26
+ /**
27
+ * Key of the subject series, controlled — pair with `onFocusChange`. It
28
+ * carries the headline, the change badge, the generated insight and, while
29
+ * colour is doing emphasis, the one hue on a context-gray field. Omit for
30
+ * the uncontrolled card (`defaultFocus`, else the first series).
31
+ */
32
+ focus?: string;
33
+ /** The subject on first render when `focus` is uncontrolled. Default: the first series. */
34
+ defaultFocus?: string;
35
+ /** Called with the chosen series' key when the reader picks another subject from the legend (legend mode `focus`). */
36
+ onFocusChange?: (key: string) => void;
37
+ /**
38
+ * Keys of the series currently shown, controlled — pair with
39
+ * `onVisibleSeriesChange`. Omit for the uncontrolled card
40
+ * (`defaultVisibleSeries`, else every series). The card never hides the last
41
+ * one: a plot with nothing in it is not a state.
42
+ */
43
+ visibleSeries?: readonly string[];
44
+ /** The series shown on first render when `visibleSeries` is uncontrolled. Default: all of them. */
45
+ defaultVisibleSeries?: readonly string[];
46
+ /** Called with the remaining keys when the reader shows or hides a series from the legend (legend mode `visibility`). */
47
+ onVisibleSeriesChange?: (keys: string[]) => void;
48
+ /**
49
+ * Draw the legend — one chip per series, with a swatch in the plot's own mark
50
+ * shape and the series' latest reading. Default `true` for two or more
51
+ * series and `false` for one (a single series needs no key). The tooltip,
52
+ * table and description name every series regardless.
53
+ */
54
+ legend?: boolean;
55
+ /**
56
+ * What the legend chips do. `auto` (default) follows the colour job, one job
57
+ * per control: while colour marks ONE series out (`emphasis`) the chips are a
58
+ * radio group choosing the subject — the only meaningful interaction on a
59
+ * field of gray lines; while colour carries identity (`categorical` /
60
+ * `sequential`) they are toggles choosing which series are shown. `focus`
61
+ * and `visibility` force one. Stamped as `data-legend`.
62
+ */
63
+ legendMode?: TrendLegendMode;
64
+ /** `line` (default, may crop), `area` (zero baseline) or `bar` (zero baseline, discrete periods). */
65
+ mark?: TrendMark;
66
+ /** Y-scale baseline for a `line` plot: `auto` (default) fits the data range and reads for shape; `zero` includes zero. Areas and bars always include zero. */
67
+ scale?: TrendScale;
68
+ /**
69
+ * How several `area` or `bar` series sit together: `false` (default) overlays
70
+ * them against the same axis, `"zero"` stacks them into a total, and
71
+ * `"normalize"` stacks them to 100% — the composition-over-time reading, with
72
+ * a caption saying so. Ignored for `line`, which never stacks. Stamped as
73
+ * `data-stack`.
74
+ */
75
+ stack?: TrendStack;
76
+ /**
77
+ * `none` (default) plots the readings. `index` divides every series by its
78
+ * own first finite reading × 100, which is how series in DIFFERENT UNITS
79
+ * compare on one axis — this package draws no second y axis. The raw reading
80
+ * stays in the tooltip and the table, and a caption names the base period,
81
+ * so the transform is never silent. Stamped as `data-normalize`.
82
+ */
83
+ normalize?: TrendNormalize;
84
+ /** Number format for an indexed axis and its tooltip. Default `number:0` (index points). */
85
+ indexFormat?: string;
86
+ /**
87
+ * How colour is used. `auto` (default) picks by count against the theme's own
88
+ * identity budget: one series takes the emphasis hue, a handful take the
89
+ * `chart-1…N` slots, and past the budget the subject takes the hue on a
90
+ * context-gray field. `categorical` forces identity slots and degrades to
91
+ * `emphasis` when there are more series than slots — repeating a hue would
92
+ * make two series look like one. `sequential` is for ORDERED series
93
+ * (cohorts, years, buckets), low → high through the ramp. The resolved job
94
+ * is stamped as `data-series-color`.
95
+ */
96
+ seriesColor?: TrendSeriesColor;
97
+ /**
98
+ * Fold every series past this count (in the consumer's order) into one
99
+ * `Other` series whose readings are the sum of the folded ones — honest only
100
+ * for additive measures, which passing this asserts. The subject is never
101
+ * folded. Stamped as `data-folded`.
102
+ */
103
+ maxSeries?: number;
104
+ /**
105
+ * Named stretches of the axis worth annotating — a launch, an outage, a
106
+ * promotion — as `{ start, end, label? }` in the series' own `x` type. Drawn
107
+ * as a quiet wash in the brush role (never a series hue, so a band cannot be
108
+ * read as data), named in the legend, marked on the table's rows and added to
109
+ * the tooltip. Each bound snaps inward to a period the data actually has.
110
+ */
111
+ bands?: readonly TrendBand[];
112
+ /** A goal for the plotted measure. Draws a dotted reference rule that joins the y domain. */
113
+ target?: number | null;
114
+ /**
115
+ * The big number: `latest` (default) is the subject's latest reading with the
116
+ * change across the span in a polarity badge; `change` makes the change
117
+ * itself the headline, coloured by polarity, with the two readings beneath;
118
+ * `none` leaves the plot to carry the panel. Stamped as `data-headline`.
119
+ */
120
+ headline?: TrendHeadline;
121
+ /** `percent` (default) is relative change; `absolute` is the difference in the value's units — percentage points for a `percent` format. */
122
+ deltaMode?: TrendDeltaMode;
123
+ /**
124
+ * Which direction is good. Drives the change badge's polarity: `up`
125
+ * (revenue), `down` (churn, latency, cost) or `none` (headcount — the change
126
+ * stays neutral). Default `up`.
127
+ */
128
+ goodDirection?: TrendGoodDirection;
129
+ /**
130
+ * Number format for the headline, the axis, the legend, the table and the
131
+ * tooltip — one grammar so nothing rounds two ways: `number[:digits]`,
132
+ * `integer`, `compact[:digits]`, `percent[:digits]`,
133
+ * `currency:CODE[:digits|compact]`. Default `compact`.
134
+ */
135
+ format?: string;
136
+ /** Custom formatter for values. Takes precedence over `format` everywhere a reading is rendered. */
137
+ formatValue?: (value: number) => string;
138
+ /** Unit shown after the headline in the muted role (`ms`, `req/s`). Prefer `format="currency:…"` for money. */
139
+ unit?: ReactNode;
140
+ /**
141
+ * How many series the transport is about to return, so a FIRST load reserves
142
+ * the legend row it cannot yet count (`series` is still `[]`, so the card has
143
+ * no other way to know) and the skeleton shows that many chips. Without it a
144
+ * first load reserves no legend and the panel grows by a row when the data
145
+ * lands. Ignored once `series` has anything in it. ComparisonCard's
146
+ * `expectedItems`, for the same reason.
147
+ */
148
+ expectedSeries?: number;
149
+ /** Plot height in pixels, axes included. Defaults per `size` (120 / 160 / 200), plus 24 when `axes` draws the x labels. */
150
+ plotHeight?: number;
151
+ /** Draw both axes with grid lines and labels. Default `true`; `false` shrinks the plot toward a sparkline — the table still carries every value. */
152
+ axes?: boolean;
153
+ /**
154
+ * Label each visible series' last reading in a right-hand gutter, so a
155
+ * reader need not travel to the legend and back — label the endpoint, never
156
+ * every point. Default `false`; ignored while the plot is stacked, where a
157
+ * series' own reading is not where its band sits.
158
+ */
159
+ labelSeries?: boolean;
160
+ /** Period granularity of temporal `x` values for the axis, tooltips and the table. Inferred from the spacing when omitted. */
161
+ granularity?: ArcTimeGranularity;
162
+ /**
163
+ * The takeaway in a sentence, rendered beside the AI mark under the plot —
164
+ * the insight slot. Wrap values in `<strong>` to set them in bold. Omitted,
165
+ * the card generates one from the subject's movement across the span; pass
166
+ * `null` or `false` to render none.
167
+ */
168
+ insight?: ReactNode;
169
+ /** The transport's status. `loading` with series already present is a refresh: the previous render stays under the veil. Default `ready`. */
170
+ status?: TrendCardStatus;
171
+ /** The consumer's filter is active — no readings then reads as no-match rather than empty, with a clear-filters action when `onClearFilters` is set. */
172
+ filtered?: boolean;
173
+ /** The data is older than the product's freshness rule (TanStack Query's `isStale`). Shows a badge and stamps `data-stale`. */
174
+ stale?: boolean;
175
+ /** When the data was last true. Rendered as an "as of" line and included in the description. */
176
+ updatedAt?: Date | string | number;
177
+ /**
178
+ * How `updatedAt` is written, as a time-grammar granularity — `day`
179
+ * (default, `Sep 8, 2026`), `datetime`, `time`, `month`, `year` — or a
180
+ * formatter for a custom form. Applies to the as-of line and the description
181
+ * alike, in the card's `locale` and `timeZone`.
182
+ */
183
+ updatedAtFormat?: ArcTimeGranularity | ((date: Date) => string);
184
+ /** Recovery action for the error state; renders a retry button when set. */
185
+ onRetry?: () => void;
186
+ /** Recovery action for the no-match state; renders a clear-filters button when set. */
187
+ onClearFilters?: () => void;
188
+ /** Density: `sm` for dense grids, `md` (default), `lg` for a hero panel. Scales type, padding and the default plot height. */
189
+ size?: TrendCardSize;
190
+ /** Heading level of the label for the document outline. Default 3 — panels usually sit under a page's h2. */
191
+ titleLevel?: 2 | 3 | 4 | 5 | 6;
192
+ /** BCP 47 locale for every number and date. Defaults to the runtime's. Thai products on the Gregorian calendar pass `th-TH-u-ca-gregory`. */
193
+ locale?: string;
194
+ /** IANA time zone for dates. Defaults to the runtime's — pass it for deterministic output and single-business-zone reporting. */
195
+ timeZone?: string;
196
+ /** Overrides for every rendered or announced string. */
197
+ labels?: Partial<TrendCardLabels>;
198
+ /** Replaces the generated accessible description of the whole card (the figure's `aria-describedby` text). */
199
+ description?: string;
200
+ /** Trailing header slot — a ghost `Button` or `Menu` for drill-through, export, or settings. */
201
+ action?: ReactNode;
202
+ /** Open the data popover on first render, anchored to the card. */
203
+ defaultTableOpen?: boolean;
204
+ /** Hide the header info button for the data popover. Only when another surface exposes the same values to keyboard and screen-reader users. */
205
+ hideTableToggle?: boolean;
206
+ /** Called with vega-embed's result once the plot mounts — for `view` access in advanced compositions. */
207
+ onEmbed?: (result: Result) => void;
208
+ /** Escape hatch: transform the plot spec before it renders. Voids the token and accessibility guarantees for whatever it changes. */
209
+ patchSpec?: (spec: TopLevelSpec) => TopLevelSpec;
210
+ }
211
+ /**
212
+ * A trend panel for dashboards: several series over the same periods on one
213
+ * shared scale, with labelled axes, a legend the reader operates, a shared-x
214
+ * crosshair that reads every series at the pointed period, named period bands,
215
+ * an optional target rule, the subject's change across the span as a headline,
216
+ * and every loading, empty, error and stale state — layout-stable, with a
217
+ * generated text equivalent and a data table in an info popover.
218
+ *
219
+ * Where `MetricCard` answers "what is this number and is it good", TrendCard
220
+ * answers "what shape is this metric in, and which series is driving it".
221
+ */
222
+ declare const TrendCard: import("react").ForwardRefExoticComponent<TrendCardProps & import("react").RefAttributes<HTMLElement>>;
223
+ //#endregion
224
+ export { TrendCard, TrendCardProps, TrendLegendMode };