@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,4 @@
1
+ import { BuildChartDescriptionInput, CHART_OTHER_KEY, CHART_TABLE_ROW_CAP, CHART_TYPES, CHART_TYPE_ORDER, ChartAggregate, ChartCardLabels, ChartCardSize, ChartCardState, ChartCardStatus, ChartColorMode, ChartExtent, ChartExtremes, ChartFieldType, ChartIntent, ChartLegendKind, ChartRampBucket, ChartRecord, ChartRow, ChartSeriesColor, ChartSeriesInfo, ChartSort, ChartSummary, ChartTableColumn, ChartTableModel, ChartTextFormatters, ChartType, ChartTypeFields, ChartTypeInfo, ChartWebRow, CreateChartFormattersOptions, DEFAULT_CHART_LABELS, DeriveChartStateInput, NormalizeChartDataOptions, RADAR_RING_FRACTIONS, buildChartDescription, buildChartPlotDescription, buildChartTableModel, buildRadarWebRows, buildRampBuckets, chartSeriesColorAt, createChartFormatters, deriveChartState, hasEnoughData, inferFieldType, inferGranularity, missingChartFields, normalizeChartData, resolveChartColorMode, resolveChartLabels } from "./ChartCard.model.js";
2
+ import { ChartCard, ChartCardProps, ChartLegendPosition, ChartTableToggle } from "./ChartCard.js";
3
+ import { CHART_AXES_DATASET, CHART_HOVER_PARAM, CHART_SERIES_NAMES_PARAM, CHART_TABLE_DATASET, CHART_X_TICKS_PARAM, ChartSpecOptions, buildChartSpec } from "./ChartCard.chart.js";
4
+ export { type BuildChartDescriptionInput, CHART_AXES_DATASET, CHART_HOVER_PARAM, CHART_OTHER_KEY, CHART_SERIES_NAMES_PARAM, CHART_TABLE_DATASET, CHART_TABLE_ROW_CAP, CHART_TYPES, CHART_TYPE_ORDER, CHART_X_TICKS_PARAM, type ChartAggregate, ChartCard, type ChartCardLabels, type ChartCardProps, type ChartCardSize, type ChartCardState, type ChartCardStatus, type ChartColorMode, type ChartExtent, type ChartExtremes, type ChartFieldType, type ChartIntent, type ChartLegendKind, type ChartLegendPosition, type ChartRampBucket, type ChartRecord, type ChartRow, type ChartSeriesColor, type ChartSeriesInfo, type ChartSort, type ChartSpecOptions, type ChartSummary, type ChartTableColumn, type ChartTableModel, type ChartTableToggle, type ChartTextFormatters, type ChartType, type ChartTypeFields, type ChartTypeInfo, type ChartWebRow, type CreateChartFormattersOptions, DEFAULT_CHART_LABELS, type DeriveChartStateInput, type NormalizeChartDataOptions, RADAR_RING_FRACTIONS, buildChartDescription, buildChartPlotDescription, buildChartSpec, buildChartTableModel, buildRadarWebRows, buildRampBuckets, chartSeriesColorAt, createChartFormatters, deriveChartState, hasEnoughData, inferFieldType, inferGranularity, missingChartFields, normalizeChartData, resolveChartColorMode, resolveChartLabels };
@@ -0,0 +1,4 @@
1
+ import { CHART_OTHER_KEY, CHART_TABLE_ROW_CAP, CHART_TYPES, CHART_TYPE_ORDER, DEFAULT_CHART_LABELS, RADAR_RING_FRACTIONS, buildChartDescription, buildChartPlotDescription, buildChartTableModel, buildRadarWebRows, buildRampBuckets, chartSeriesColorAt, createChartFormatters, deriveChartState, hasEnoughData, inferFieldType, inferGranularity, missingChartFields, normalizeChartData, resolveChartColorMode, resolveChartLabels } from "./ChartCard.model.js";
2
+ import { CHART_AXES_DATASET, CHART_HOVER_PARAM, CHART_SERIES_NAMES_PARAM, CHART_TABLE_DATASET, CHART_X_TICKS_PARAM, buildChartSpec } from "./ChartCard.chart.js";
3
+ import { ChartCard } from "./ChartCard.js";
4
+ export { CHART_AXES_DATASET, CHART_HOVER_PARAM, CHART_OTHER_KEY, CHART_SERIES_NAMES_PARAM, CHART_TABLE_DATASET, CHART_TABLE_ROW_CAP, CHART_TYPES, CHART_TYPE_ORDER, CHART_X_TICKS_PARAM, ChartCard, DEFAULT_CHART_LABELS, RADAR_RING_FRACTIONS, buildChartDescription, buildChartPlotDescription, buildChartSpec, buildChartTableModel, buildRadarWebRows, buildRampBuckets, chartSeriesColorAt, createChartFormatters, deriveChartState, hasEnoughData, inferFieldType, inferGranularity, missingChartFields, normalizeChartData, resolveChartColorMode, resolveChartLabels };
@@ -0,0 +1,80 @@
1
+ import { ChartTokens } from "../../lib/vega/tokens.js";
2
+ import { ComparisonMark, ComparisonScale } from "./ComparisonCard.model.js";
3
+ import { TopLevelSpec } from "vega-lite";
4
+ //#region src/components/ComparisonCard/ComparisonCard.chart.d.ts
5
+ /** The rows: `{ key, label, value, from, role }` per `ComparisonRow`, in display order. */
6
+ declare const COMPARISON_TABLE_DATASET = "table";
7
+ /** Zero or one row `{ value }` — the target reference rule. */
8
+ declare const COMPARISON_REFERENCE_DATASET = "reference";
9
+ /** Zero or one row `{ value: 0 }` — a hairline at zero, pushed only when a value is negative. */
10
+ declare const COMPARISON_ZERO_DATASET = "zero";
11
+ /** The hovered row's point selection. */
12
+ declare const COMPARISON_HOVER_PARAM = "hover";
13
+ declare const MAX_BAR_HEIGHT = 24;
14
+ /** Which axis the value runs along. `slope` and `column` put the category on x. */
15
+ declare function comparisonOrientation(mark: ComparisonMark): "horizontal" | "vertical";
16
+ /** The marks that read two values per item — the `from` field is theirs alone. */
17
+ declare function comparisonUsesFrom(mark: ComparisonMark): boolean;
18
+ /**
19
+ * Whether length carries the comparison, which forces a zero baseline
20
+ * whatever `scale` asks for: proportional ink is not negotiable for a bar, a
21
+ * column or a lollipop's stem. Position marks (`dot`, `dumbbell`, `slope`) may
22
+ * crop — the card prints every value as text beside the mark, so a cropped
23
+ * scale is never the only reading.
24
+ */
25
+ declare function comparisonNeedsZero(mark: ComparisonMark): boolean;
26
+ /** The scale the plot actually draws with, after the marks that force zero. */
27
+ declare function resolveComparisonScale(mark: ComparisonMark, scale: ComparisonScale | undefined): ComparisonScale;
28
+ interface ComparisonPlotSpecOptions {
29
+ /** Which form the plot draws. */
30
+ mark: ComparisonMark;
31
+ /** Bar or column thickness in pixels, capped at 24. Centered in each band. */
32
+ barHeight: number;
33
+ /** Dot area in px² for `dot`, `lollipop`, `dumbbell` and the slope's endpoints. */
34
+ pointSize: number;
35
+ /** Initial plot height. Horizontal marks pass rows × step; vertical marks pass their own block height. The live value rides the View API. */
36
+ height: number;
37
+ /** Include zero in the value scale, or let it crop to the data. Bars, columns and lollipops always include zero — see `comparisonNeedsZero`. */
38
+ scale: ComparisonScale;
39
+ /** Draw the target reference rule (the `reference` dataset carries the value). */
40
+ reference: boolean;
41
+ /**
42
+ * Draw a hairline at zero (the `zero` dataset carries the one row) — only
43
+ * when a value is negative: for all-positive bars the left edge is the
44
+ * baseline already, and a hairline there would read as a border. Structural
45
+ * rather than data-driven because Vega warns about the infinite extent of an
46
+ * empty dataset that feeds a scale.
47
+ */
48
+ zeroRule: boolean;
49
+ /** Wire the hover selection and the tooltip channel. */
50
+ tooltip: boolean;
51
+ /** Paint the focus row in the emphasis hue and every other row in the context gray. Without a focus, all marks take the emphasis hue (nominal marks are one color). */
52
+ emphasize: boolean;
53
+ /** Tooltip titles. */
54
+ itemTitle: string;
55
+ valueTitle: string;
56
+ /** Names of the two readings a `dumbbell` or a `slope` compares — the axis labels of a slope, the tooltip rows of both. */
57
+ fromTitle: string;
58
+ toTitle: string;
59
+ /** Localised title for the target reference rule's hover value. */
60
+ targetTitle?: string;
61
+ /** `arcNumber` grammar for values (`currency:THB:compact@en-US`). */
62
+ valueFormat: string;
63
+ locale?: string;
64
+ }
65
+ /**
66
+ * Builds the plot. One mark per row on a shared value scale — length from
67
+ * zero for `bar`, `column` and `lollipop` (Cleveland & McGill's second-best
68
+ * channel, and the honest one for a zero baseline), position alone for `dot`,
69
+ * `dumbbell` and `slope` (the best channel, and the readable one when the
70
+ * values cluster far from zero) — the focus row in the emphasis hue and the
71
+ * rest in the context gray, a hairline at zero once a value is negative, an
72
+ * optional dotted target rule that joins the value domain, and a hover
73
+ * selection that keeps the pointed mark solid while its siblings recede.
74
+ *
75
+ * Horizontal bands have no padding, so the mark centers line up with the DOM
76
+ * rows that carry the names and values.
77
+ */
78
+ declare function buildComparisonPlotSpec(options: ComparisonPlotSpecOptions, tokens: ChartTokens): TopLevelSpec;
79
+ //#endregion
80
+ export { COMPARISON_HOVER_PARAM, COMPARISON_REFERENCE_DATASET, COMPARISON_TABLE_DATASET, COMPARISON_ZERO_DATASET, ComparisonPlotSpecOptions, MAX_BAR_HEIGHT, buildComparisonPlotSpec, comparisonNeedsZero, comparisonOrientation, comparisonUsesFrom, resolveComparisonScale };
@@ -0,0 +1,337 @@
1
+ import { arcVegaConfig } from "../../lib/vega/config.js";
2
+ //#region src/components/ComparisonCard/ComparisonCard.chart.ts
3
+ /** The rows: `{ key, label, value, from, role }` per `ComparisonRow`, in display order. */
4
+ const COMPARISON_TABLE_DATASET = "table";
5
+ /** Zero or one row `{ value }` — the target reference rule. */
6
+ const COMPARISON_REFERENCE_DATASET = "reference";
7
+ /** Zero or one row `{ value: 0 }` — a hairline at zero, pushed only when a value is negative. */
8
+ const COMPARISON_ZERO_DATASET = "zero";
9
+ /** The hovered row's point selection. */
10
+ const COMPARISON_HOVER_PARAM = "hover";
11
+ const MAX_BAR_HEIGHT = 24;
12
+ const RESTING_OPACITY = .6;
13
+ const CONNECTOR_WIDTH = 2;
14
+ const SLOPE_WIDTH = 2;
15
+ const CROP_PADDING = 8;
16
+ const ROW_DOMAIN_EXPR = `pluck(data('${COMPARISON_TABLE_DATASET}'), 'key')`;
17
+ const BAND_LABEL_EXPR = `((data('${COMPARISON_TABLE_DATASET}')[indexof(pluck(data('${COMPARISON_TABLE_DATASET}'), 'key'), datum.value)] || {}).label)`;
18
+ /** Which axis the value runs along. `slope` and `column` put the category on x. */
19
+ function comparisonOrientation(mark) {
20
+ return mark === "column" || mark === "slope" ? "vertical" : "horizontal";
21
+ }
22
+ /** The marks that read two values per item — the `from` field is theirs alone. */
23
+ function comparisonUsesFrom(mark) {
24
+ return mark === "dumbbell" || mark === "slope";
25
+ }
26
+ /**
27
+ * Whether length carries the comparison, which forces a zero baseline
28
+ * whatever `scale` asks for: proportional ink is not negotiable for a bar, a
29
+ * column or a lollipop's stem. Position marks (`dot`, `dumbbell`, `slope`) may
30
+ * crop — the card prints every value as text beside the mark, so a cropped
31
+ * scale is never the only reading.
32
+ */
33
+ function comparisonNeedsZero(mark) {
34
+ return mark === "bar" || mark === "column" || mark === "lollipop";
35
+ }
36
+ /** The scale the plot actually draws with, after the marks that force zero. */
37
+ function resolveComparisonScale(mark, scale) {
38
+ if (comparisonNeedsZero(mark)) return "zero";
39
+ return scale ?? "auto";
40
+ }
41
+ const SLOPE_FOLD = ["from", "value"];
42
+ /**
43
+ * Builds the plot. One mark per row on a shared value scale — length from
44
+ * zero for `bar`, `column` and `lollipop` (Cleveland & McGill's second-best
45
+ * channel, and the honest one for a zero baseline), position alone for `dot`,
46
+ * `dumbbell` and `slope` (the best channel, and the readable one when the
47
+ * values cluster far from zero) — the focus row in the emphasis hue and the
48
+ * rest in the context gray, a hairline at zero once a value is negative, an
49
+ * optional dotted target rule that joins the value domain, and a hover
50
+ * selection that keeps the pointed mark solid while its siblings recede.
51
+ *
52
+ * Horizontal bands have no padding, so the mark centers line up with the DOM
53
+ * rows that carry the names and values.
54
+ */
55
+ function buildComparisonPlotSpec(options, tokens) {
56
+ const { mark, barHeight, pointSize, height, scale, reference, zeroRule, tooltip, emphasize, itemTitle, valueTitle, fromTitle, toTitle, valueFormat, locale } = options;
57
+ const vertical = comparisonOrientation(mark) === "vertical";
58
+ const V = vertical ? "y" : "x";
59
+ const V2 = vertical ? "y2" : "x2";
60
+ const C = vertical ? "x" : "y";
61
+ const valueScale = scale === "auto" ? {
62
+ zero: false,
63
+ nice: true,
64
+ padding: CROP_PADDING
65
+ } : {
66
+ zero: true,
67
+ nice: false
68
+ };
69
+ const valueChannel = (field) => ({
70
+ field,
71
+ type: "quantitative",
72
+ axis: null,
73
+ scale: valueScale
74
+ });
75
+ const categoryChannel = {
76
+ field: "key",
77
+ type: "nominal",
78
+ sort: null,
79
+ axis: vertical ? {
80
+ title: null,
81
+ labelAngle: 0,
82
+ labelPadding: 6,
83
+ domain: false,
84
+ ticks: false,
85
+ grid: false,
86
+ labelExpr: BAND_LABEL_EXPR,
87
+ aria: false
88
+ } : null,
89
+ scale: vertical ? {
90
+ type: "band",
91
+ domain: { expr: ROW_DOMAIN_EXPR },
92
+ paddingInner: .35,
93
+ paddingOuter: .2
94
+ } : {
95
+ type: "band",
96
+ domain: { expr: ROW_DOMAIN_EXPR },
97
+ paddingInner: 0,
98
+ paddingOuter: 0
99
+ }
100
+ };
101
+ const valueTooltip = (field, title) => ({
102
+ field,
103
+ type: "quantitative",
104
+ title,
105
+ format: valueFormat,
106
+ formatType: "arcNumber"
107
+ });
108
+ const tooltipChannel = [
109
+ {
110
+ field: "label",
111
+ type: "nominal",
112
+ title: itemTitle
113
+ },
114
+ ...comparisonUsesFrom(mark) ? [valueTooltip("from", fromTitle)] : [],
115
+ valueTooltip("value", comparisonUsesFrom(mark) ? toTitle : valueTitle)
116
+ ];
117
+ const hue = emphasize ? {
118
+ condition: {
119
+ test: "datum.role === 'focus'",
120
+ value: tokens.emphasis
121
+ },
122
+ value: tokens.context
123
+ } : { value: tokens.emphasis };
124
+ const hoverOpacity = tooltip ? { opacity: {
125
+ condition: {
126
+ param: COMPARISON_HOVER_PARAM,
127
+ value: 1
128
+ },
129
+ value: RESTING_OPACITY
130
+ } } : {};
131
+ const hoverParam = tooltip ? { params: [{
132
+ name: COMPARISON_HOVER_PARAM,
133
+ select: {
134
+ type: "point",
135
+ on: "pointerover",
136
+ clear: "pointerout",
137
+ encodings: [C]
138
+ }
139
+ }] } : {};
140
+ const layers = [];
141
+ if (zeroRule) layers.push({
142
+ data: { name: COMPARISON_ZERO_DATASET },
143
+ mark: {
144
+ type: "rule",
145
+ stroke: tokens.axis,
146
+ strokeWidth: 1,
147
+ aria: false
148
+ },
149
+ encoding: { [V]: valueChannel("value") }
150
+ });
151
+ if (mark === "bar" || mark === "column") layers.push({
152
+ ...hoverParam,
153
+ mark: {
154
+ type: "bar",
155
+ [vertical ? "width" : "height"]: Math.min(24, barHeight),
156
+ cornerRadiusEnd: 2,
157
+ aria: false
158
+ },
159
+ encoding: {
160
+ [C]: categoryChannel,
161
+ [V]: valueChannel("value"),
162
+ fill: hue,
163
+ ...hoverOpacity,
164
+ ...tooltip ? { tooltip: tooltipChannel } : {}
165
+ }
166
+ });
167
+ if (mark === "lollipop") layers.push({
168
+ mark: {
169
+ type: "rule",
170
+ strokeWidth: CONNECTOR_WIDTH,
171
+ strokeCap: "round",
172
+ aria: false
173
+ },
174
+ encoding: {
175
+ [C]: categoryChannel,
176
+ [V]: valueChannel("value"),
177
+ [V2]: { datum: 0 },
178
+ stroke: hue,
179
+ ...hoverOpacity
180
+ }
181
+ });
182
+ if (mark === "dumbbell") {
183
+ layers.push({
184
+ mark: {
185
+ type: "rule",
186
+ strokeWidth: CONNECTOR_WIDTH,
187
+ strokeCap: "round",
188
+ aria: false
189
+ },
190
+ encoding: {
191
+ [C]: categoryChannel,
192
+ [V]: valueChannel("value"),
193
+ [V2]: { field: "from" },
194
+ stroke: hue,
195
+ ...hoverOpacity
196
+ }
197
+ });
198
+ layers.push({
199
+ mark: {
200
+ type: "point",
201
+ filled: true,
202
+ size: pointSize,
203
+ strokeWidth: 2,
204
+ aria: false
205
+ },
206
+ encoding: {
207
+ [C]: categoryChannel,
208
+ [V]: valueChannel("from"),
209
+ fill: { value: tokens.background },
210
+ stroke: hue,
211
+ ...hoverOpacity
212
+ }
213
+ });
214
+ }
215
+ if (mark === "slope") {
216
+ const slopeBase = {
217
+ data: { name: COMPARISON_TABLE_DATASET },
218
+ transform: [
219
+ {
220
+ fold: SLOPE_FOLD,
221
+ as: ["end", "reading"]
222
+ },
223
+ {
224
+ calculate: "datum.end === 'from' ? 0 : 1",
225
+ as: "endIndex"
226
+ },
227
+ { filter: "isValid(datum.reading)" }
228
+ ]
229
+ };
230
+ const slopeCategory = {
231
+ field: "endIndex",
232
+ type: "ordinal",
233
+ sort: null,
234
+ scale: {
235
+ type: "point",
236
+ padding: .3
237
+ },
238
+ axis: {
239
+ title: null,
240
+ labelAngle: 0,
241
+ labelPadding: 6,
242
+ domain: false,
243
+ ticks: false,
244
+ grid: false,
245
+ labelExpr: `datum.value === 0 ? ${JSON.stringify(fromTitle)} : ${JSON.stringify(toTitle)}`,
246
+ aria: false
247
+ }
248
+ };
249
+ layers.push({
250
+ ...slopeBase,
251
+ mark: {
252
+ type: "line",
253
+ strokeWidth: SLOPE_WIDTH,
254
+ aria: false
255
+ },
256
+ encoding: {
257
+ x: slopeCategory,
258
+ y: valueChannel("reading"),
259
+ detail: {
260
+ field: "key",
261
+ type: "nominal"
262
+ },
263
+ order: {
264
+ field: "endIndex",
265
+ type: "quantitative"
266
+ },
267
+ stroke: hue,
268
+ ...hoverOpacity
269
+ }
270
+ });
271
+ layers.push({
272
+ ...slopeBase,
273
+ ...hoverParam,
274
+ mark: {
275
+ type: "point",
276
+ filled: true,
277
+ size: pointSize,
278
+ aria: false
279
+ },
280
+ encoding: {
281
+ x: slopeCategory,
282
+ y: valueChannel("reading"),
283
+ fill: hue,
284
+ ...hoverOpacity,
285
+ ...tooltip ? { tooltip: tooltipChannel } : {}
286
+ }
287
+ });
288
+ }
289
+ if (mark === "dot" || mark === "lollipop" || mark === "dumbbell") layers.push({
290
+ ...hoverParam,
291
+ mark: {
292
+ type: "point",
293
+ filled: true,
294
+ size: pointSize,
295
+ aria: false
296
+ },
297
+ encoding: {
298
+ [C]: categoryChannel,
299
+ [V]: valueChannel("value"),
300
+ fill: hue,
301
+ ...hoverOpacity,
302
+ ...tooltip ? { tooltip: tooltipChannel } : {}
303
+ }
304
+ });
305
+ if (reference) layers.push({
306
+ data: { name: COMPARISON_REFERENCE_DATASET },
307
+ mark: {
308
+ type: "rule",
309
+ stroke: tokens.reference,
310
+ strokeWidth: 1.5,
311
+ strokeDash: [0, 4],
312
+ strokeCap: "round",
313
+ opacity: .9,
314
+ aria: false
315
+ },
316
+ encoding: {
317
+ [V]: valueChannel("value"),
318
+ ...tooltip ? { tooltip: [valueTooltip("value", options.targetTitle ?? "Target")] } : {}
319
+ }
320
+ });
321
+ return {
322
+ $schema: "https://vega.github.io/schema/vega-lite/v6.json",
323
+ width: 240,
324
+ height,
325
+ autosize: vertical ? {
326
+ type: "fit",
327
+ contains: "padding"
328
+ } : { type: "none" },
329
+ padding: 0,
330
+ background: "transparent",
331
+ data: { name: COMPARISON_TABLE_DATASET },
332
+ layer: layers,
333
+ config: arcVegaConfig(tokens, { locale })
334
+ };
335
+ }
336
+ //#endregion
337
+ export { COMPARISON_HOVER_PARAM, COMPARISON_REFERENCE_DATASET, COMPARISON_TABLE_DATASET, COMPARISON_ZERO_DATASET, MAX_BAR_HEIGHT, buildComparisonPlotSpec, comparisonNeedsZero, comparisonOrientation, comparisonUsesFrom, resolveComparisonScale };
@@ -0,0 +1,200 @@
1
+ import { ArcTimeGranularity } from "../../lib/vega/formatters.js";
2
+ import { ComparisonCardLabels, ComparisonCardSize, ComparisonCardStatus, ComparisonDeltaMode, ComparisonGoodDirection, ComparisonHeadline, ComparisonItem, ComparisonMark, ComparisonScale, ComparisonSort } from "./ComparisonCard.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/ComparisonCard/ComparisonCard.d.ts
8
+ interface ComparisonCardProps extends Omit<BoxProps, "children" | "padding" | "title"> {
9
+ /** The metric's name — the tile's heading. Pass `name` too when this is not plain text. */
10
+ label: ReactNode;
11
+ /** Plain-text name used in the generated descriptions and control labels. Defaults to `label` when it is a string. */
12
+ name?: string;
13
+ /** 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. */
14
+ hint?: string;
15
+ /**
16
+ * The things being compared — periods, segments, sources, plans — as
17
+ * `{ key?, label, value }` records in the order they should read (periods
18
+ * chronological, segments as the product lists them). `key` defaults to
19
+ * `label` and identifies an item for `focus` and `baseline`; `value: null`
20
+ * keeps the row with no bar. Pass `[]` while loading — `expectedItems` rows
21
+ * are reserved.
22
+ */
23
+ items: readonly ComparisonItem[];
24
+ /**
25
+ * Key of the subject, controlled: its bar takes the emphasis hue, its value
26
+ * is the `focus` headline, and the delta measures it against the baseline.
27
+ * Pair with `onFocusChange` to follow the reader's selection; omit it for
28
+ * the uncontrolled card (`defaultFocus`, else the first item). `null`
29
+ * designates none — every bar then takes the hue, there is no delta, the
30
+ * rows are not selectable, and a `focus` headline renders nothing.
31
+ */
32
+ focus?: string | null;
33
+ /** The subject on first render when `focus` is uncontrolled. Default: the first item. */
34
+ defaultFocus?: string | null;
35
+ /** Called with the selected row's key when the reader chooses another subject — by click, or with the arrow keys inside the rows. */
36
+ onFocusChange?: (key: string) => void;
37
+ /**
38
+ * Let the reader choose the subject and the reference: the rows become a
39
+ * radio group (click, or arrow keys once a row has focus), rank one selected
40
+ * by default, and the delta stack opens a compare-with menu to the right
41
+ * listing every other row. The headline, badge, hue, table and description
42
+ * follow both choices. A value the app controls without its change handler
43
+ * (`focus` without `onFocusChange`, `baseline` without `onBaselineChange`)
44
+ * is pinned and renders no control. Default `true`; `false` for a static
45
+ * tile. Stamped as `data-selectable`.
46
+ */
47
+ selectable?: boolean;
48
+ /**
49
+ * Key of the reference the focus is compared against, controlled — last
50
+ * month, the company average, the forecast. Pair with `onBaselineChange` to
51
+ * follow the reader's pick from the compare-with menu; omit it for the
52
+ * uncontrolled card (`defaultBaseline`, else the first item that is not the
53
+ * focus, so the leader is compared with the runner-up and every other row
54
+ * with the leader). A named baseline keeps its place until the reader
55
+ * selects it as the subject, then falls back to that rule. `null` draws the
56
+ * bars without a delta.
57
+ */
58
+ baseline?: string | null;
59
+ /** The reference on first render when `baseline` is uncontrolled. Default: the first item that is not the focus. */
60
+ defaultBaseline?: string;
61
+ /** Called with the chosen row's key when the reader picks another reference from the compare-with menu under the delta badge. */
62
+ onBaselineChange?: (key: string) => void;
63
+ /**
64
+ * What the big number is. `focus` (default) shows the focus item's value —
65
+ * the KPI-tile convention — with the delta badge beside it. `gap` shows the
66
+ * change of the focus against the baseline (in `deltaMode`) with the other
67
+ * form in the badge — for a variance card. `none` leaves the bars and the
68
+ * badge to carry the card. Stamped as `data-headline`.
69
+ */
70
+ headline?: ComparisonHeadline;
71
+ /**
72
+ * Name the subject in a chip under the headline value — a soft primary
73
+ * `Badge` with a swatch in the bar's hue, following the selection — so the
74
+ * number is never read without knowing whose it is. Default `true`; `false`
75
+ * when the card's title already names the subject. Not rendered with
76
+ * `headline="none"`.
77
+ */
78
+ focusChip?: boolean;
79
+ /** What the delta is against, under the badge. Default: `vs {baseline label}` (`labels.versus`), or `{focus} vs {baseline}` for a `gap` headline. */
80
+ comparisonLabel?: ReactNode;
81
+ /** `percent` (default) is relative change; `absolute` is the difference in the value's units — percentage points for a `percent` format. Also the form of every row's variance in the popover table and tooltip. */
82
+ deltaMode?: ComparisonDeltaMode;
83
+ /**
84
+ * Which direction is good for the focus item: `up` (revenue), `down`
85
+ * (churn, latency, cost) or `none` (headcount — the delta stays neutral).
86
+ * Drives the delta badge's polarity color. Default `up`.
87
+ */
88
+ goodDirection?: ComparisonGoodDirection;
89
+ /**
90
+ * Number format for the headline, rows, delta, table and tooltip — one
91
+ * grammar so nothing rounds two ways: `number[:digits]`, `integer`,
92
+ * `compact[:digits]`, `percent[:digits]`, `currency:CODE[:digits|compact]`.
93
+ * Default `compact` (`3.8M`); pass `percent` for ratio metrics.
94
+ */
95
+ format?: string;
96
+ /** Custom formatter for values. Takes precedence over `format` everywhere a value is rendered. */
97
+ formatValue?: (value: number) => string;
98
+ /** Unit shown after a `focus` headline in the muted role (`ms`, `req/s`). Prefer `format="currency:…"` for money. */
99
+ unit?: ReactNode;
100
+ /** A shared goal. Draws a dotted reference rule across every bar and adds a `vs target` column to the popover table; pass `null` while unknown. */
101
+ target?: number | null;
102
+ /**
103
+ * The form the plot draws — the channel the comparison rides, never a
104
+ * choice of variety. `bar` (default) and `column` put length on a zero
105
+ * baseline, `column` standing the bars up for two to five short-named
106
+ * items; `dot` drops the baseline so values clustered far from zero
107
+ * separate; `lollipop` keeps the baseline at a fraction of the ink;
108
+ * `dumbbell` and `slope` draw the two readings of each item (`value` and
109
+ * `from`) as a gap and as a path. `column` and `slope` run vertically, so
110
+ * the plot becomes a block above the rows instead of overlaying them.
111
+ * Stamped as `data-mark`.
112
+ */
113
+ mark?: ComparisonMark;
114
+ /**
115
+ * Whether the value scale includes zero. Ignored by `bar`, `column` and
116
+ * `lollipop`, where length carries the comparison and a cropped baseline
117
+ * would lie about the ratios. Default `auto` for the position marks
118
+ * (`dot`, `dumbbell`, `slope`), which is what lets NPS 40 and 47 read as
119
+ * different; pass `zero` when the distance from nothing is the point.
120
+ * Stamped as `data-scale`.
121
+ */
122
+ scale?: ComparisonScale;
123
+ /** Name of the earlier reading a `dumbbell` or a `slope` draws — the slope's left axis label and both marks' tooltip row. Default `labels.from` ("Before"). */
124
+ fromLabel?: string;
125
+ /** Name of the current reading a `dumbbell` or a `slope` draws — the slope's right axis label and both marks' tooltip row. Default `labels.to` ("After"). */
126
+ toLabel?: string;
127
+ /** Row order: `none` (default) keeps the consumer's order — periods stay chronological — while `desc` and `asc` rank by value with missing values last. The focus keeps its hue wherever it lands. */
128
+ sort?: ComparisonSort;
129
+ /**
130
+ * Fold every item past this count (after sorting) into one `Other` row
131
+ * whose value is the sum of the folded values — for additive measures
132
+ * (counts, revenue), never for rates or averages. The focus and the
133
+ * baseline are never folded. Default: no fold.
134
+ */
135
+ maxItems?: number;
136
+ /** Rows the skeleton reserves before `items` arrive, so the tile is already its final height. Default 2. */
137
+ expectedItems?: number;
138
+ /** The takeaway in a sentence, rendered beside the AI mark under the rows. Wrap values in `<strong>` to set them in bold. */
139
+ insight?: ReactNode;
140
+ /** The transport's status. `loading` with items already present is a refresh: the previous render stays under the veil. Default `ready`. */
141
+ status?: ComparisonCardStatus;
142
+ /** The consumer's filter is active — no values then reads as no-match rather than empty, with a clear-filters action when `onClearFilters` is set. */
143
+ filtered?: boolean;
144
+ /** The data is older than the product's freshness rule (TanStack Query's `isStale`). Shows a badge and stamps `data-stale`. */
145
+ stale?: boolean;
146
+ /** When the data was last true. Rendered as an "as of" line (the date by default — see `updatedAtFormat`) and included in the description. */
147
+ updatedAt?: Date | string | number;
148
+ /**
149
+ * How `updatedAt` is written, as a time-grammar granularity — `day`
150
+ * (default, `Sep 8, 2026`), `datetime` (`Sep 8, 2026, 04:30 PM`), `time`
151
+ * (`04:30 PM`), `month` (`Sep 2026`), `year` — or a formatter for a custom
152
+ * form. Applies to the as-of line and the description alike, in the card's
153
+ * `locale` and `timeZone`.
154
+ */
155
+ updatedAtFormat?: ArcTimeGranularity | ((date: Date) => string);
156
+ /** Recovery action for the error state; renders a retry button when set. */
157
+ onRetry?: () => void;
158
+ /** Recovery action for the no-match state; renders a clear-filters button when set. */
159
+ onClearFilters?: () => void;
160
+ /** Density: `sm` for dense grids, `md` (default), `lg` for a hero comparison. Scales type, padding, the row height (24 / 28 / 32px) and the bar thickness. */
161
+ size?: ComparisonCardSize;
162
+ /** Heading level of the label for the document outline. Default 3 — tiles usually sit under a page's h2. */
163
+ titleLevel?: 2 | 3 | 4 | 5 | 6;
164
+ /** 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`. */
165
+ locale?: string;
166
+ /** IANA time zone for the as-of date. Defaults to the runtime's — pass it for deterministic output. */
167
+ timeZone?: string;
168
+ /** Overrides for every rendered or announced string. */
169
+ labels?: Partial<ComparisonCardLabels>;
170
+ /** Replaces the generated accessible description of the whole card (the figure's `aria-describedby` text). */
171
+ description?: string;
172
+ /** Trailing header slot — a ghost `Button` or `Menu` for drill-through, export, or settings. */
173
+ action?: ReactNode;
174
+ /** Open the data popover on first render, anchored to the card. */
175
+ defaultTableOpen?: boolean;
176
+ /** Hide the header info button for the data popover. Only when another surface exposes the same values to keyboard and screen-reader users. */
177
+ hideTableToggle?: boolean;
178
+ /** Called with vega-embed's result once the bars mount — for `view` access in advanced compositions. */
179
+ onEmbed?: (result: Result) => void;
180
+ /** Escape hatch: transform the bars' spec before it renders. Voids the token and accessibility guarantees for whatever it changes. */
181
+ patchSpec?: (spec: TopLevelSpec) => TopLevelSpec;
182
+ }
183
+ /**
184
+ * A comparison tile for dashboard grids — the second subtype of the KPI card
185
+ * family beside `MetricCard`: one metric across a few items (periods,
186
+ * segments, sources, plans) on one shared scale, with every name and value as
187
+ * text beside the plot, the focus item in the emphasis hue, its delta against
188
+ * a baseline in a polarity badge, an optional target rule, and every loading,
189
+ * empty, error and stale state — layout-stable inside one `Box` frame, with a
190
+ * generated text equivalent and a data table in an info popover.
191
+ *
192
+ * `mark` picks the form the data calls for: `bar` (default), `column` and
193
+ * `lollipop` put length on a zero baseline; `dot` drops the baseline so
194
+ * values clustered far from zero separate; `dumbbell` and `slope` read a
195
+ * second reading per item (`ComparisonItem.from`) and draw the gap and the
196
+ * move between the two.
197
+ */
198
+ declare const ComparisonCard: import("react").ForwardRefExoticComponent<ComparisonCardProps & import("react").RefAttributes<HTMLElement>>;
199
+ //#endregion
200
+ export { ComparisonCard, ComparisonCardProps };