@sybilion/uilib 1.3.22 → 1.3.25

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 (53) hide show
  1. package/dist/esm/components/widgets/DriversComparisonChart/DriversComparisonChart.js +139 -0
  2. package/dist/esm/components/widgets/DriversComparisonChart/DriversComparisonChart.styl.js +7 -0
  3. package/dist/esm/components/widgets/DriversComparisonChart/driversComparisonChart.helpers.js +159 -0
  4. package/dist/esm/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.js +34 -0
  5. package/dist/esm/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.styl.js +7 -0
  6. package/dist/esm/components/widgets/PerformanceChart/PerformanceChart.constants.js +17 -0
  7. package/dist/esm/components/widgets/PerformanceChart/PerformanceChart.js +807 -0
  8. package/dist/esm/components/widgets/PerformanceChart/PerformanceChart.styl.js +7 -0
  9. package/dist/esm/components/widgets/PerformanceChart/PerformanceTable.js +130 -0
  10. package/dist/esm/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.js +20 -0
  11. package/dist/esm/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.styl.js +7 -0
  12. package/dist/esm/components/widgets/PerformanceChart/performanceChart.helpers.js +591 -0
  13. package/dist/esm/components/widgets/PerformanceChart/performanceChartUserSeries.js +109 -0
  14. package/dist/esm/index.js +6 -0
  15. package/dist/esm/types/src/components/widgets/DriversComparisonChart/DriversComparisonChart.d.ts +18 -0
  16. package/dist/esm/types/src/components/widgets/DriversComparisonChart/driversComparisonChart.helpers.d.ts +26 -0
  17. package/dist/esm/types/src/components/widgets/DriversComparisonChart/index.d.ts +2 -0
  18. package/dist/esm/types/src/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.d.ts +7 -0
  19. package/dist/esm/types/src/components/widgets/PerformanceChart/PerformanceChart.constants.d.ts +3 -0
  20. package/dist/esm/types/src/components/widgets/PerformanceChart/PerformanceChart.d.ts +54 -0
  21. package/dist/esm/types/src/components/widgets/PerformanceChart/PerformanceTable.d.ts +31 -0
  22. package/dist/esm/types/src/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.d.ts +20 -0
  23. package/dist/esm/types/src/components/widgets/PerformanceChart/index.d.ts +4 -0
  24. package/dist/esm/types/src/components/widgets/PerformanceChart/performanceChart.helpers.d.ts +212 -0
  25. package/dist/esm/types/src/components/widgets/PerformanceChart/performanceChartUserSeries.d.ts +20 -0
  26. package/dist/esm/types/src/docs/pages/DriversComparisonChartPage.d.ts +1 -0
  27. package/dist/esm/types/src/docs/pages/PerformanceChartPage.d.ts +1 -0
  28. package/dist/esm/types/src/index.d.ts +2 -0
  29. package/dist/esm/utils/chartConnectionPoint.js +9 -1
  30. package/package.json +1 -1
  31. package/src/components/widgets/DriversComparisonChart/DriversComparisonChart.styl +145 -0
  32. package/src/components/widgets/DriversComparisonChart/DriversComparisonChart.styl.d.ts +29 -0
  33. package/src/components/widgets/DriversComparisonChart/DriversComparisonChart.tsx +325 -0
  34. package/src/components/widgets/DriversComparisonChart/driversComparisonChart.helpers.ts +206 -0
  35. package/src/components/widgets/DriversComparisonChart/index.ts +13 -0
  36. package/src/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.styl +25 -0
  37. package/src/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.styl.d.ts +11 -0
  38. package/src/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.tsx +67 -0
  39. package/src/components/widgets/PerformanceChart/PerformanceChart.constants.ts +17 -0
  40. package/src/components/widgets/PerformanceChart/PerformanceChart.styl +194 -0
  41. package/src/components/widgets/PerformanceChart/PerformanceChart.styl.d.ts +30 -0
  42. package/src/components/widgets/PerformanceChart/PerformanceChart.tsx +1251 -0
  43. package/src/components/widgets/PerformanceChart/PerformanceTable.tsx +381 -0
  44. package/src/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.styl +49 -0
  45. package/src/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.styl.d.ts +12 -0
  46. package/src/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.tsx +83 -0
  47. package/src/components/widgets/PerformanceChart/index.ts +28 -0
  48. package/src/components/widgets/PerformanceChart/performanceChart.helpers.ts +790 -0
  49. package/src/components/widgets/PerformanceChart/performanceChartUserSeries.ts +149 -0
  50. package/src/docs/pages/DriversComparisonChartPage.tsx +174 -0
  51. package/src/docs/pages/PerformanceChartPage.tsx +211 -0
  52. package/src/docs/registry.ts +12 -0
  53. package/src/index.ts +2 -0
@@ -0,0 +1,149 @@
1
+ import type { ForecastData } from '#uilib/types/forecast-data';
2
+ import { normalizeToMonthStart } from '#uilib/utils/chartConnectionPoint';
3
+
4
+ export const SPAGHETTI_TIME_SERIES_MATRIX_V = 2 as const;
5
+
6
+ export interface SpaghettiPerformanceMatrixPayload {
7
+ v: typeof SPAGHETTI_TIME_SERIES_MATRIX_V;
8
+ dates: string[];
9
+ horizonKeys: string[];
10
+ grid: number[][];
11
+ perHorizonDates?: string[][];
12
+ }
13
+
14
+ export const SPAGHETTI_MATRIX_SYNTHETIC_BASE = 9_800_000;
15
+ export const SPAGHETTI_MATRIX_MAX_COLS = 128;
16
+ export const SPAGHETTI_LOCAL_LS_USER_SERIES_ROW_ID = 9_000_001;
17
+
18
+ const PER_HORIZON_VIEW_CUSTOM_LINE_ID_BASE =
19
+ SPAGHETTI_MATRIX_SYNTHETIC_BASE + 4_000_000;
20
+
21
+ export function spaghettiMatrixSyntheticId(
22
+ userSeriesRowId: number,
23
+ horizonIndex: number,
24
+ ): number {
25
+ return (
26
+ SPAGHETTI_MATRIX_SYNTHETIC_BASE +
27
+ userSeriesRowId * SPAGHETTI_MATRIX_MAX_COLS +
28
+ horizonIndex
29
+ );
30
+ }
31
+
32
+ export function isSpaghettiMatrixSyntheticLineId(id: number): boolean {
33
+ return id >= SPAGHETTI_MATRIX_SYNTHETIC_BASE;
34
+ }
35
+
36
+ function perHorizonViewCustomMatrixSyntheticId(colIdx: number): number {
37
+ return PER_HORIZON_VIEW_CUSTOM_LINE_ID_BASE + colIdx;
38
+ }
39
+
40
+ function matrixHasValidPerHorizonDates(
41
+ matrix: SpaghettiPerformanceMatrixPayload,
42
+ ): boolean {
43
+ const ph = matrix.perHorizonDates;
44
+ if (!ph || ph.length !== matrix.grid.length) return false;
45
+ const h = matrix.horizonKeys.length;
46
+ return ph.every(
47
+ (row, r) =>
48
+ Array.isArray(row) &&
49
+ row.length === h &&
50
+ row.length === matrix.grid[r].length,
51
+ );
52
+ }
53
+
54
+ export function getCustomMatrixSeriesForHorizonTab(
55
+ matrix: SpaghettiPerformanceMatrixPayload,
56
+ horizonKey: string,
57
+ rowId: number,
58
+ forecastData: Record<string, ForecastData> | undefined,
59
+ ): {
60
+ lineId: number;
61
+ dates: string[];
62
+ forecastValues: number[];
63
+ } | null {
64
+ const colIdx = matrix.horizonKeys.indexOf(horizonKey);
65
+ if (colIdx < 0) return null;
66
+
67
+ if (matrixHasValidPerHorizonDates(matrix)) {
68
+ const ph = matrix.perHorizonDates!;
69
+ const dates: string[] = [];
70
+ const forecastValues: number[] = [];
71
+ for (let r = 0; r < matrix.grid.length; r++) {
72
+ const rawD = ph[r][colIdx];
73
+ const v = matrix.grid[r][colIdx];
74
+ if (typeof v !== 'number' || !Number.isFinite(v)) continue;
75
+ dates.push(
76
+ normalizeToMonthStart(typeof rawD === 'string' ? rawD : String(rawD)),
77
+ );
78
+ forecastValues.push(v);
79
+ }
80
+ if (dates.length === 0) return null;
81
+ return {
82
+ lineId: perHorizonViewCustomMatrixSyntheticId(colIdx),
83
+ dates,
84
+ forecastValues,
85
+ };
86
+ }
87
+
88
+ const lineId = spaghettiMatrixSyntheticId(rowId, colIdx);
89
+ const fd = forecastData?.[String(lineId)];
90
+ if (!fd?.dates?.length || fd.forecastValues.length !== fd.dates.length) {
91
+ return null;
92
+ }
93
+ return {
94
+ lineId,
95
+ dates: fd.dates,
96
+ forecastValues: fd.forecastValues,
97
+ };
98
+ }
99
+
100
+ function isRecord(value: unknown): value is Record<string, unknown> {
101
+ return typeof value === 'object' && value !== null;
102
+ }
103
+
104
+ export function tryParseSpaghettiPerformanceMatrix(
105
+ parsed: unknown,
106
+ ): SpaghettiPerformanceMatrixPayload | null {
107
+ if (!isRecord(parsed)) return null;
108
+ if (parsed.v !== SPAGHETTI_TIME_SERIES_MATRIX_V) return null;
109
+ const dates = parsed.dates;
110
+ const horizonKeys = parsed.horizonKeys;
111
+ const grid = parsed.grid;
112
+ if (
113
+ !Array.isArray(dates) ||
114
+ !Array.isArray(horizonKeys) ||
115
+ !Array.isArray(grid)
116
+ ) {
117
+ return null;
118
+ }
119
+ if (
120
+ dates.length === 0 ||
121
+ horizonKeys.length === 0 ||
122
+ grid.length !== dates.length
123
+ ) {
124
+ return null;
125
+ }
126
+ const h = horizonKeys.length;
127
+ if (!grid.every(row => Array.isArray(row) && row.length === h)) return null;
128
+ const perHorizonDates = parsed.perHorizonDates;
129
+ let ph: string[][] | undefined;
130
+ if (perHorizonDates !== undefined) {
131
+ if (
132
+ !Array.isArray(perHorizonDates) ||
133
+ perHorizonDates.length !== grid.length
134
+ ) {
135
+ return null;
136
+ }
137
+ ph = perHorizonDates.map(row => {
138
+ if (!Array.isArray(row) || row.length !== h) return [];
139
+ return row.map(d => String(d));
140
+ });
141
+ }
142
+ return {
143
+ v: SPAGHETTI_TIME_SERIES_MATRIX_V,
144
+ dates: dates.map(d => String(d)),
145
+ horizonKeys: horizonKeys.map(k => String(k)),
146
+ grid: grid.map(row => row.map(v => Number(v))),
147
+ ...(ph ? { perHorizonDates: ph } : {}),
148
+ };
149
+ }
@@ -0,0 +1,174 @@
1
+ import { useMemo, useState } from 'react';
2
+
3
+ import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
4
+ import { PageContentSection } from '#uilib/components/ui/Page';
5
+ import { Switch } from '#uilib/components/ui/Switch';
6
+ import { TIME_RANGES } from '#uilib/components/ui/TimeRangeControls/TimeRangeControls.constants';
7
+ import { DriversComparisonChart } from '#uilib/components/widgets/DriversComparisonChart';
8
+ import { useTheme } from '#uilib/contexts/theme-context';
9
+ import type { BacktestsComponentPayload } from '@sybilion/platform-sdk';
10
+
11
+ import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
12
+ import { DocsHeaderActions } from '../docsHeaderActions';
13
+
14
+ const ALL_TIME_RANGE = TIME_RANGES[TIME_RANGES.length - 1];
15
+
16
+ function monthKey(year: number, month: number): string {
17
+ return `${year}-${String(month).padStart(2, '0')}-01`;
18
+ }
19
+
20
+ function buildMonthlySeries(
21
+ startYear: number,
22
+ startMonth: number,
23
+ count: number,
24
+ base: number,
25
+ drift = 0.08,
26
+ phase = 0,
27
+ ): Record<string, number> {
28
+ const out: Record<string, number> = {};
29
+ let y = startYear;
30
+ let m = startMonth;
31
+ for (let i = 0; i < count; i++) {
32
+ out[monthKey(y, m)] = base + Math.sin(i * 0.4 + phase) * 0.35 + i * drift;
33
+ m += 1;
34
+ if (m > 12) {
35
+ m = 1;
36
+ y += 1;
37
+ }
38
+ }
39
+ return out;
40
+ }
41
+
42
+ function buildTargetSeries(): Record<string, number> {
43
+ return buildMonthlySeries(2018, 1, 48, 1.0, 0.012, 0.2);
44
+ }
45
+
46
+ const MOCK_PAYLOAD: BacktestsComponentPayload = {
47
+ target: {
48
+ id: 'target',
49
+ name: 'Normalized target',
50
+ normalized_series: buildTargetSeries(),
51
+ },
52
+ drivers: [
53
+ {
54
+ id: 'driver-us-pmi',
55
+ name: 'U.S. manufacturing PMI composite',
56
+ importance: 84.2,
57
+ lag: '1 quarter(s)',
58
+ normalized_series: buildMonthlySeries(2019, 4, 42, 0.45, 0.015, 0),
59
+ },
60
+ {
61
+ id: 'driver-eu-orders',
62
+ name: 'German industrial orders (domestic + foreign)',
63
+ importance: 81.6,
64
+ lag: '2 month(s)',
65
+ normalized_series: buildMonthlySeries(2019, 1, 42, 0.52, -0.006, 1.1),
66
+ },
67
+ {
68
+ id: 'driver-jp-machinery',
69
+ name: 'Japan machinery orders (core private-sector)',
70
+ importance: 77,
71
+ lag: '~1 month(s)',
72
+ normalized_series: buildMonthlySeries(2019, 7, 42, 0.38, 0.01, 2.4),
73
+ },
74
+ {
75
+ id: 'driver-global-risk',
76
+ name: 'Global equity risk appetite composite',
77
+ importance: 66.5,
78
+ lag: 'Unknown',
79
+ normalized_series: buildMonthlySeries(2018, 10, 42, 0.41, 0.004, 3.8),
80
+ },
81
+ {
82
+ id: 'driver-china-credit',
83
+ name: 'China aggregate financing impulse',
84
+ importance: 58.3,
85
+ lag: '3 month(s)',
86
+ normalized_series: buildMonthlySeries(2020, 1, 36, 0.29, 0.018, 4.2),
87
+ },
88
+ ],
89
+ };
90
+
91
+ function buildDatasetHistorical(): ChartDataPoint[] {
92
+ const raw = buildMonthlySeries(2017, 7, 54, 112, 0.9, 0.5);
93
+ return Object.entries(raw).map(([date, historical]) => ({
94
+ date,
95
+ historical,
96
+ }));
97
+ }
98
+
99
+ export default function DriversComparisonChartPage() {
100
+ const { isDarkMode } = useTheme();
101
+ const [loading, setLoading] = useState(false);
102
+ const [runAnalysisHint, setRunAnalysisHint] = useState(false);
103
+ const [emptyPayload, setEmptyPayload] = useState(false);
104
+ const [timeRange, setTimeRange] = useState<string>(ALL_TIME_RANGE);
105
+
106
+ const payload = useMemo(
107
+ () => (emptyPayload ? null : MOCK_PAYLOAD),
108
+ [emptyPayload],
109
+ );
110
+ const datasetHistorical = useMemo(() => buildDatasetHistorical(), []);
111
+
112
+ return (
113
+ <>
114
+ <AppPageHeader
115
+ breadcrumbs={[{ label: 'Drivers comparison chart' }]}
116
+ title="DriversComparisonChart"
117
+ subheader="Normalized target line with driver series; table rows toggle chart visibility."
118
+ actions={<DocsHeaderActions />}
119
+ />
120
+ <PageContentSection>
121
+ <div
122
+ style={{
123
+ display: 'flex',
124
+ flexWrap: 'wrap',
125
+ alignItems: 'center',
126
+ gap: 16,
127
+ marginBottom: 16,
128
+ }}
129
+ >
130
+ <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
131
+ <Switch
132
+ id="loading-overlay"
133
+ checked={loading}
134
+ onCheckedChange={setLoading}
135
+ />
136
+ <label htmlFor="loading-overlay">Loading overlay</label>
137
+ </div>
138
+ <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
139
+ <Switch
140
+ id="run-analysis-hint"
141
+ checked={runAnalysisHint}
142
+ onCheckedChange={setRunAnalysisHint}
143
+ />
144
+ <label htmlFor="run-analysis-hint">Run analysis hint</label>
145
+ </div>
146
+ <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
147
+ <Switch
148
+ id="empty-payload"
149
+ checked={emptyPayload}
150
+ onCheckedChange={setEmptyPayload}
151
+ />
152
+ <label htmlFor="empty-payload">Empty payload</label>
153
+ </div>
154
+ </div>
155
+ <DriversComparisonChart
156
+ payload={payload}
157
+ datasetHistorical={datasetHistorical}
158
+ loading={loading}
159
+ chartLoading={false}
160
+ runAnalysisHint={runAnalysisHint}
161
+ statusHint={
162
+ emptyPayload
163
+ ? 'No normalized driver series in the response yet.'
164
+ : null
165
+ }
166
+ timeRange={timeRange}
167
+ onTimeRangeChange={setTimeRange}
168
+ isDarkTheme={isDarkMode}
169
+ seriesInitKey={emptyPayload ? 'empty' : 'mock'}
170
+ />
171
+ </PageContentSection>
172
+ </>
173
+ );
174
+ }
@@ -0,0 +1,211 @@
1
+ import { useMemo, useState } from 'react';
2
+
3
+ import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
4
+ import { PageContentSection } from '#uilib/components/ui/Page';
5
+ import { Switch } from '#uilib/components/ui/Switch';
6
+ import {
7
+ PerformanceChart,
8
+ type PerformanceChartPayload,
9
+ SPAGHETTI_TIME_SERIES_MATRIX_V,
10
+ } from '#uilib/components/widgets/PerformanceChart';
11
+ import { useTheme } from '#uilib/contexts/theme-context';
12
+
13
+ import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
14
+ import { DocsHeaderActions } from '../docsHeaderActions';
15
+
16
+ function monthKey(year: number, month: number): string {
17
+ return `${year}-${String(month).padStart(2, '0')}-01`;
18
+ }
19
+
20
+ function buildMonthlyHistorical(
21
+ startYear: number,
22
+ startMonth: number,
23
+ count: number,
24
+ base: number,
25
+ ): ChartDataPoint[] {
26
+ const out: ChartDataPoint[] = [];
27
+ let y = startYear;
28
+ let m = startMonth;
29
+ for (let i = 0; i < count; i++) {
30
+ out.push({
31
+ date: monthKey(y, m),
32
+ historical: base + Math.sin(i * 0.25) * 8 + i * 0.4,
33
+ });
34
+ m += 1;
35
+ if (m > 12) {
36
+ m = 1;
37
+ y += 1;
38
+ }
39
+ }
40
+ return out;
41
+ }
42
+
43
+ function buildHorizonForecasts(
44
+ horizonKey: string,
45
+ startYear: number,
46
+ startMonth: number,
47
+ count: number,
48
+ base: number,
49
+ drift: number,
50
+ ): Record<string, number> {
51
+ const out: Record<string, number> = {};
52
+ let y = startYear;
53
+ let m = startMonth;
54
+ for (let i = 0; i < count; i++) {
55
+ out[monthKey(y, m)] = base + Math.cos(i * 0.3 + drift) * 3 + i * 0.15;
56
+ m += 1;
57
+ if (m > 12) {
58
+ m = 1;
59
+ y += 1;
60
+ }
61
+ }
62
+ return out;
63
+ }
64
+
65
+ const MOCK_PERFORMANCE: PerformanceChartPayload = {
66
+ model: {
67
+ forecasts: {
68
+ horizon_1: buildHorizonForecasts('horizon_1', 2022, 1, 24, 112, 0),
69
+ horizon_2: buildHorizonForecasts('horizon_2', 2022, 1, 24, 112, 0.5),
70
+ horizon_3: buildHorizonForecasts('horizon_3', 2022, 1, 24, 112, 1),
71
+ },
72
+ metrics_history: {
73
+ horizon_1: {
74
+ mae: { '24m': 0.42 },
75
+ mape: { '24m': 0.038 },
76
+ },
77
+ horizon_2: {
78
+ mae: { '24m': 0.51 },
79
+ mape: { '24m': 0.045 },
80
+ },
81
+ horizon_3: {
82
+ mae: { '24m': 0.58 },
83
+ mape: { '24m': 0.052 },
84
+ },
85
+ },
86
+ },
87
+ drift: {
88
+ forecasts: {
89
+ horizon_1: buildHorizonForecasts('horizon_1', 2022, 1, 24, 112, 1.2),
90
+ horizon_2: buildHorizonForecasts('horizon_2', 2022, 1, 24, 112, 1.4),
91
+ horizon_3: buildHorizonForecasts('horizon_3', 2022, 1, 24, 112, 1.6),
92
+ },
93
+ metrics_history: {
94
+ horizon_1: {
95
+ mae: { '24m': 0.62 },
96
+ mape: { '24m': 0.055 },
97
+ },
98
+ horizon_2: {
99
+ mae: { '24m': 0.71 },
100
+ mape: { '24m': 0.061 },
101
+ },
102
+ horizon_3: {
103
+ mae: { '24m': 0.79 },
104
+ mape: { '24m': 0.068 },
105
+ },
106
+ },
107
+ },
108
+ };
109
+
110
+ export default function PerformanceChartPage() {
111
+ const { isDarkMode } = useTheme();
112
+ const [loading, setLoading] = useState(false);
113
+ const [runAnalysisHint, setRunAnalysisHint] = useState(false);
114
+ const [emptyPayload, setEmptyPayload] = useState(false);
115
+ const [timeRange, setTimeRange] = useState<string>('All');
116
+
117
+ const performanceData = useMemo(
118
+ () => (emptyPayload ? null : MOCK_PERFORMANCE),
119
+ [emptyPayload],
120
+ );
121
+ const historicalData = useMemo(
122
+ () => buildMonthlyHistorical(2020, 1, 48, 108),
123
+ [],
124
+ );
125
+
126
+ return (
127
+ <>
128
+ <AppPageHeader
129
+ breadcrumbs={[{ label: 'Performance chart' }]}
130
+ title="PerformanceChart"
131
+ subheader="Per-horizon and spaghetti performance plots with linked metrics table."
132
+ actions={<DocsHeaderActions />}
133
+ />
134
+ <PageContentSection>
135
+ <div
136
+ style={{
137
+ display: 'flex',
138
+ flexWrap: 'wrap',
139
+ alignItems: 'center',
140
+ gap: 16,
141
+ marginBottom: 16,
142
+ }}
143
+ >
144
+ <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
145
+ <Switch
146
+ id="loading-overlay"
147
+ checked={loading}
148
+ onCheckedChange={setLoading}
149
+ />
150
+ <label htmlFor="loading-overlay">Loading overlay</label>
151
+ </div>
152
+ <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
153
+ <Switch
154
+ id="run-analysis-hint"
155
+ checked={runAnalysisHint}
156
+ onCheckedChange={setRunAnalysisHint}
157
+ />
158
+ <label htmlFor="run-analysis-hint">Run analysis hint</label>
159
+ </div>
160
+ <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
161
+ <Switch
162
+ id="empty-payload"
163
+ checked={emptyPayload}
164
+ onCheckedChange={setEmptyPayload}
165
+ />
166
+ <label htmlFor="empty-payload">Empty payload</label>
167
+ </div>
168
+ </div>
169
+ <PerformanceChart
170
+ performanceData={performanceData}
171
+ historicalData={historicalData}
172
+ combinedData={historicalData}
173
+ loading={loading}
174
+ chartLoading={loading}
175
+ performanceSectionPending={loading}
176
+ performanceDataLoading={loading}
177
+ perfFetchSettled={!loading}
178
+ isEmpty={emptyPayload}
179
+ runAnalysisHint={runAnalysisHint}
180
+ statusHint={
181
+ emptyPayload ? 'No performance data for this dataset.' : null
182
+ }
183
+ timeRange={timeRange}
184
+ onTimeRangeChange={setTimeRange}
185
+ isDarkTheme={isDarkMode}
186
+ performanceAnalysisId={1}
187
+ seriesInitKey={emptyPayload ? 'empty' : 'mock'}
188
+ showAddEditCustomDataButton
189
+ customPerformanceMatrix={
190
+ emptyPayload
191
+ ? null
192
+ : {
193
+ v: SPAGHETTI_TIME_SERIES_MATRIX_V,
194
+ dates: ['2022-01-01', '2022-02-01'],
195
+ horizonKeys: ['horizon_1', 'horizon_2', 'horizon_3'],
196
+ grid: [
197
+ [111, 110.5, 110],
198
+ [112, 111.2, 110.8],
199
+ ],
200
+ perHorizonDates: [
201
+ ['2022-01-01', '2022-01-01', '2022-01-01'],
202
+ ['2022-02-01', '2022-02-01', '2022-02-01'],
203
+ ],
204
+ }
205
+ }
206
+ customPerformanceLabel="Demo custom series"
207
+ />
208
+ </PageContentSection>
209
+ </>
210
+ );
211
+ }
@@ -145,6 +145,18 @@ export const DOC_REGISTRY: DocEntry[] = [
145
145
  section: 'Widgets',
146
146
  load: () => import('./pages/DriverMapPage'),
147
147
  },
148
+ {
149
+ slug: 'drivers-comparison-chart',
150
+ title: 'DriversComparisonChart',
151
+ section: 'Widgets',
152
+ load: () => import('./pages/DriversComparisonChartPage'),
153
+ },
154
+ {
155
+ slug: 'performance-chart',
156
+ title: 'PerformanceChart',
157
+ section: 'Widgets',
158
+ load: () => import('./pages/PerformanceChartPage'),
159
+ },
148
160
  {
149
161
  slug: 'dropdown-menu',
150
162
  title: 'DropdownMenu',
package/src/index.ts CHANGED
@@ -73,6 +73,8 @@ export * from './components/ui/WorkspaceAppSwitcher';
73
73
  export * from './components/widgets/SidebarDatasetsItemsGrouped';
74
74
  export * from './components/widgets/DriverCard';
75
75
  export * from './components/widgets/DriverMap';
76
+ export * from './components/widgets/DriversComparisonChart';
77
+ export * from './components/widgets/PerformanceChart';
76
78
  export * from './components/widgets/SybilionAppHeader';
77
79
  export * from './components/widgets/SybilionAuthLayout';
78
80
  export * from './components/widgets/SybilionSignInPanel';