@sybilion/uilib 1.2.26 → 1.3.1

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 (137) hide show
  1. package/dist/esm/components/ui/Chart/Chart.js +5 -0
  2. package/dist/esm/components/ui/Chart/components/BaseChartWrapper.js +7 -32
  3. package/dist/esm/components/ui/Chart/components/ChartEmptyState/ChartEmptyState.js +21 -0
  4. package/dist/esm/components/ui/Chart/components/ChartEmptyState/ChartEmptyState.styl.js +7 -0
  5. package/dist/esm/components/ui/Chart/lightweight/LightweightForecastChart.js +460 -0
  6. package/dist/esm/components/ui/Chart/lightweight/LightweightForecastChart.styl.js +7 -0
  7. package/dist/esm/components/ui/Chart/lightweight/chartTime.js +16 -0
  8. package/dist/esm/components/ui/Chart/lightweight/lightweightForecastChart.helpers.js +114 -0
  9. package/dist/esm/components/ui/Chart/lightweight/quantileBandCustomSeries.js +147 -0
  10. package/dist/esm/components/ui/Chart/quantileBandConeChartData.js +131 -0
  11. package/dist/esm/components/ui/Chart/tools/chartPlotGeometry.js +65 -0
  12. package/dist/esm/components/ui/ChartAreaInteractive/ChartAreaInteractive.helpers.js +37 -1
  13. package/dist/esm/components/ui/ChartAreaInteractive/ChartAreaInteractive.js +5 -2
  14. package/dist/esm/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.js +205 -0
  15. package/dist/esm/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.styl.js +7 -0
  16. package/dist/esm/components/ui/ChartAreaInteractive/TimeRangeBrushLayout.helpers.js +37 -0
  17. package/dist/esm/components/ui/ChartAreaInteractive/overlays/IntervalsOverlay/IntervalsOverlay.hooks.js +1 -0
  18. package/dist/esm/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.js +7 -60
  19. package/dist/esm/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.styl.js +2 -2
  20. package/dist/esm/components/ui/ChartAreaInteractive/overlays/ThresholdsOverlay/ThresholdsOverlay.hooks.js +1 -0
  21. package/dist/esm/components/ui/ChartAreaInteractive/overlays/useChartYRange.js +2 -4
  22. package/dist/esm/components/ui/ChartAreaInteractive/overlays/useQuantileBands.js +4 -102
  23. package/dist/esm/components/ui/TimeRangeControls/TimeRangeControls.js +7 -2
  24. package/dist/esm/components/ui/WorldMap/WorldMap.js +11 -0
  25. package/dist/esm/components/ui/WorldMap/WorldMap.styl.js +7 -0
  26. package/dist/esm/components/widgets/DriverCard/DriverCard.js +89 -0
  27. package/dist/esm/components/widgets/DriverCard/DriverCard.styl.js +7 -0
  28. package/dist/esm/components/widgets/DriverCard/DriverPerformanceChart.js +83 -0
  29. package/dist/esm/components/widgets/DriverCard/DriverPerformanceChart.styl.js +7 -0
  30. package/dist/esm/components/widgets/DriverCard/driverPerformanceChartData.js +50 -0
  31. package/dist/esm/components/widgets/DriverMap/DriverMap.js +2 -2
  32. package/dist/esm/components/widgets/DriverMap/DriverMap.styl.js +2 -2
  33. package/dist/esm/index.js +4 -2
  34. package/dist/esm/types/src/components/ui/Chart/Chart.d.ts +2 -0
  35. package/dist/esm/types/src/components/ui/Chart/components/BaseChartWrapper.d.ts +2 -1
  36. package/dist/esm/types/src/components/ui/Chart/components/ChartEmptyState/ChartEmptyState.d.ts +14 -0
  37. package/dist/esm/types/src/components/ui/Chart/lightweight/LightweightForecastChart.d.ts +26 -0
  38. package/dist/esm/types/src/components/ui/Chart/lightweight/chartTime.d.ts +5 -0
  39. package/dist/esm/types/src/components/ui/Chart/lightweight/lightweightForecastChart.helpers.d.ts +13 -0
  40. package/dist/esm/types/src/components/ui/Chart/lightweight/quantileBandCustomSeries.d.ts +24 -0
  41. package/dist/esm/types/src/components/ui/Chart/quantileBandConeChartData.d.ts +7 -0
  42. package/dist/esm/types/src/components/ui/Chart/tools/chartPlotGeometry.d.ts +30 -0
  43. package/dist/esm/types/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.d.ts +1 -1
  44. package/dist/esm/types/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.helpers.d.ts +11 -2
  45. package/dist/esm/types/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.types.d.ts +2 -2
  46. package/dist/esm/types/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.d.ts +15 -0
  47. package/dist/esm/types/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayout.helpers.d.ts +14 -0
  48. package/dist/esm/types/src/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.d.ts +1 -1
  49. package/dist/esm/types/src/components/ui/Page/PageColumns/PageColumns.d.ts +1 -1
  50. package/dist/esm/types/src/components/ui/TimeRangeControls/TimeRangeControls.d.ts +5 -7
  51. package/dist/esm/types/src/components/ui/WorldMap/WorldMap.d.ts +4 -0
  52. package/dist/esm/types/src/components/ui/WorldMap/index.d.ts +2 -0
  53. package/dist/esm/types/src/components/widgets/DriverCard/DriverCard.d.ts +9 -0
  54. package/dist/esm/types/src/components/widgets/DriverCard/DriverPerformanceChart.d.ts +5 -0
  55. package/dist/esm/types/src/components/widgets/DriverCard/driverPerformanceChartData.d.ts +7 -0
  56. package/dist/esm/types/src/components/widgets/DriverCard/index.d.ts +1 -0
  57. package/dist/esm/types/src/components/widgets/DriverMap/index.d.ts +0 -2
  58. package/dist/esm/types/src/docs/pages/LightweightChartPage.d.ts +1 -0
  59. package/dist/esm/types/src/docs/pages/PageColumnsPage.d.ts +1 -0
  60. package/dist/esm/types/src/docs/pages/WorldMapPage.d.ts +1 -0
  61. package/dist/esm/types/src/index.d.ts +2 -0
  62. package/package.json +3 -2
  63. package/src/components/ui/Chart/Chart.tsx +9 -0
  64. package/src/components/ui/Chart/components/BaseChartWrapper.tsx +8 -41
  65. package/src/components/ui/Chart/components/ChartEmptyState/ChartEmptyState.styl +60 -0
  66. package/src/components/ui/Chart/components/ChartEmptyState/ChartEmptyState.styl.d.ts +15 -0
  67. package/src/components/ui/Chart/components/ChartEmptyState/ChartEmptyState.tsx +66 -0
  68. package/src/components/ui/Chart/lightweight/LightweightForecastChart.styl +25 -0
  69. package/src/components/ui/Chart/lightweight/LightweightForecastChart.styl.d.ts +11 -0
  70. package/src/components/ui/Chart/lightweight/LightweightForecastChart.tsx +721 -0
  71. package/src/components/ui/Chart/lightweight/chartTime.ts +18 -0
  72. package/src/components/ui/Chart/lightweight/lightweightForecastChart.helpers.ts +141 -0
  73. package/src/components/ui/Chart/lightweight/quantileBandCustomSeries.ts +215 -0
  74. package/src/components/ui/Chart/quantileBandConeChartData.ts +171 -0
  75. package/src/components/ui/Chart/tools/chartPlotGeometry.ts +89 -0
  76. package/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.helpers.ts +44 -2
  77. package/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.tsx +14 -1
  78. package/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.types.ts +2 -3
  79. package/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.styl +21 -0
  80. package/src/components/{widgets/DriverMap/LoadingSpinner/LoadingSpinner.styl.d.ts → ui/ChartAreaInteractive/TimeRangeBrushLayer.styl.d.ts} +3 -3
  81. package/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.tsx +285 -0
  82. package/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayout.helpers.ts +55 -0
  83. package/src/components/ui/ChartAreaInteractive/overlays/IntervalsOverlay/IntervalsOverlay.hooks.ts +1 -0
  84. package/src/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.styl +2 -7
  85. package/src/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.styl.d.ts +0 -1
  86. package/src/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.tsx +7 -71
  87. package/src/components/ui/ChartAreaInteractive/overlays/ThresholdsOverlay/ThresholdsOverlay.hooks.ts +1 -0
  88. package/src/components/ui/ChartAreaInteractive/overlays/useChartYRange.ts +2 -3
  89. package/src/components/ui/ChartAreaInteractive/overlays/useQuantileBands.ts +5 -131
  90. package/src/components/ui/Page/PageColumns/PageColumns.tsx +1 -1
  91. package/src/components/ui/TimeRangeControls/TimeRangeControls.tsx +16 -17
  92. package/src/components/{widgets/DriverMap/MapBackground/MapBackground.styl → ui/WorldMap/WorldMap.styl} +1 -3
  93. package/src/components/{widgets/DriverMap/MapBackground/MapBackground.styl.d.ts → ui/WorldMap/WorldMap.styl.d.ts} +1 -1
  94. package/src/components/ui/WorldMap/WorldMap.tsx +22 -0
  95. package/src/components/ui/WorldMap/index.ts +2 -0
  96. package/src/components/widgets/DriverCard/DriverCard.styl +169 -0
  97. package/src/components/widgets/DriverCard/DriverCard.styl.d.ts +40 -0
  98. package/src/components/widgets/DriverCard/DriverCard.tsx +219 -0
  99. package/src/components/widgets/DriverCard/DriverPerformanceChart.styl +43 -0
  100. package/src/components/widgets/DriverCard/DriverPerformanceChart.styl.d.ts +13 -0
  101. package/src/components/widgets/DriverCard/DriverPerformanceChart.tsx +150 -0
  102. package/src/components/widgets/DriverCard/driverPerformanceChartData.ts +64 -0
  103. package/src/components/widgets/DriverCard/index.ts +1 -0
  104. package/src/components/widgets/DriverMap/DriverIcon/DriverIcon.tsx +0 -2
  105. package/src/components/widgets/DriverMap/DriverMap.styl +6 -1
  106. package/src/components/widgets/DriverMap/DriverMap.styl.d.ts +1 -0
  107. package/src/components/widgets/DriverMap/DriverMap.tsx +2 -4
  108. package/src/components/widgets/DriverMap/driverCategoryIcon.tsx +0 -2
  109. package/src/components/widgets/DriverMap/index.ts +0 -2
  110. package/src/declarations.d.ts +2 -0
  111. package/src/docs/config/webpack.config.js +26 -3
  112. package/src/docs/index.tsx +1 -1
  113. package/src/docs/pages/ChartAreaInteractivePage.tsx +2 -3
  114. package/src/docs/pages/DriverMapPage.tsx +214 -60
  115. package/src/docs/pages/LightweightChartPage.styl +18 -0
  116. package/src/docs/pages/LightweightChartPage.styl.d.ts +10 -0
  117. package/src/docs/pages/LightweightChartPage.tsx +195 -0
  118. package/src/docs/pages/PageColumnsPage.tsx +92 -0
  119. package/src/docs/pages/TimeRangeControlsPage.tsx +2 -3
  120. package/src/docs/pages/WorldMapPage.styl +14 -0
  121. package/src/docs/pages/WorldMapPage.styl.d.ts +8 -0
  122. package/src/docs/pages/WorldMapPage.tsx +26 -0
  123. package/src/docs/registry.ts +19 -1
  124. package/src/index.ts +2 -0
  125. package/dist/esm/components/widgets/DriverMap/LoadingSpinner/LoadingSpinner.js +0 -8
  126. package/dist/esm/components/widgets/DriverMap/LoadingSpinner/LoadingSpinner.styl.js +0 -7
  127. package/dist/esm/components/widgets/DriverMap/MapBackground/MapBackground.js +0 -10
  128. package/dist/esm/components/widgets/DriverMap/MapBackground/MapBackground.styl.js +0 -7
  129. package/dist/esm/types/src/components/widgets/DriverMap/LoadingSpinner/LoadingSpinner.d.ts +0 -1
  130. package/dist/esm/types/src/components/widgets/DriverMap/MapBackground/MapBackground.d.ts +0 -1
  131. package/src/components/widgets/DriverMap/LoadingSpinner/LoadingSpinner.styl +0 -24
  132. package/src/components/widgets/DriverMap/LoadingSpinner/LoadingSpinner.tsx +0 -11
  133. package/src/components/widgets/DriverMap/MapBackground/MapBackground.tsx +0 -18
  134. /package/dist/esm/components/{widgets/DriverMap/MapBackground → ui/WorldMap}/map.svg.js +0 -0
  135. /package/src/components/{widgets/DriverMap/MapBackground → ui/WorldMap}/map.svg +0 -0
  136. /package/src/components/{widgets/DriverMap/MapBackground → ui/WorldMap}/mapAspect.mixin.styl +0 -0
  137. /package/src/components/{widgets/DriverMap/MapBackground → ui/WorldMap}/mapAspect.mixin.styl.d.ts +0 -0
@@ -0,0 +1,89 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import React__default, { useMemo } from 'react';
3
+ import { CoffeeIcon, TrendUpIcon, TrendDownIcon } from '@phosphor-icons/react';
4
+ import { Badge } from '../../ui/Badge/Badge.js';
5
+ import { Card, CardContent } from '../../ui/Card/Card.js';
6
+ import { LabelWithId } from '../../ui/LabelWithId/LabelWithId.js';
7
+ import { Skeleton } from '../../ui/Skeleton/Skeleton.js';
8
+ import { Tooltip, TooltipTrigger, TooltipContent } from '../../ui/Tooltip/Tooltip.js';
9
+ import { getCategoryIcon } from '../DriverMap/driverCategoryIcon.js';
10
+ import S from './DriverCard.styl.js';
11
+ import { DriverPerformanceChart } from './DriverPerformanceChart.js';
12
+
13
+ function DriverCard({ selectedDriver, isLoading, inQueue = false, driverSelector, }) {
14
+ const importanceDisplay = useMemo(() => {
15
+ if (!selectedDriver)
16
+ return '';
17
+ let importance = 0;
18
+ if (selectedDriver.rawImportance &&
19
+ typeof selectedDriver.rawImportance === 'object') {
20
+ const importanceObj = selectedDriver.rawImportance;
21
+ if (importanceObj.overall && typeof importanceObj.overall === 'object') {
22
+ const overall = importanceObj.overall;
23
+ if (typeof overall.mean === 'number') {
24
+ importance = Math.round(overall.mean);
25
+ }
26
+ }
27
+ }
28
+ return importance > 0
29
+ ? `${importance}%`
30
+ : `${selectedDriver.importance.toFixed(1)}%`;
31
+ }, [selectedDriver]);
32
+ const regionDisplay = React__default.useMemo(() => {
33
+ if (!selectedDriver)
34
+ return '';
35
+ // Check for src_region and tgt_region properties first
36
+ const driver = selectedDriver;
37
+ const srcRegion = driver.src_region;
38
+ const tgtRegion = driver.tgt_region;
39
+ const srcName = srcRegion?.name;
40
+ const tgtName = tgtRegion?.name;
41
+ // If both src_region and tgt_region have valid names
42
+ if (srcName && tgtName) {
43
+ // If source and target are the same, just show one
44
+ if (srcName === tgtName) {
45
+ return srcName;
46
+ }
47
+ return `${srcName} → ${tgtName}`;
48
+ }
49
+ // If only src_region has a valid name
50
+ if (srcName) {
51
+ if (srcName === 'World') {
52
+ return 'World';
53
+ }
54
+ return `${srcName} → World`;
55
+ }
56
+ // If only tgt_region has a valid name
57
+ if (tgtName) {
58
+ if (tgtName === 'World') {
59
+ return 'World';
60
+ }
61
+ return `World → ${tgtName}`;
62
+ }
63
+ if (selectedDriver.region.length === 1)
64
+ return selectedDriver.region[0];
65
+ if (selectedDriver.region.length > 1) {
66
+ return (selectedDriver.region
67
+ // .filter(region => region !== 'World')
68
+ .join(' → '));
69
+ }
70
+ // Fallback to "World" when no region information is available
71
+ return 'World';
72
+ }, [selectedDriver]);
73
+ if (inQueue) {
74
+ return (jsx(Card, { className: S.root, children: jsx(CardContent, { centered: true, fullHeight: true, noScroll: true, children: jsxs("div", { className: S.queueMessage, children: [jsx(CoffeeIcon, { size: 24, weight: "regular" }), jsxs("div", { children: [jsx("p", { children: "Retrieving drivers data." }), jsx("p", { children: "This may take a while." })] })] }) }) }));
75
+ }
76
+ if (isLoading) {
77
+ return (jsx(Card, { className: S.root, children: jsx(CardContent, { noScroll: true, children: jsxs("div", { className: S.skeletonContainer, children: [jsx(Skeleton, { className: `${S.skeletonItem} ${S.hs} ${S.w75}` }), jsx(Skeleton, { className: `${S.skeletonItem} ${S.hm} ${S.w50}` }), jsx(Skeleton, { className: `${S.skeletonItem} ${S.hs} ${S.w33}` }), jsxs("div", { className: S.skeletonGroup, children: [jsx(Skeleton, { className: `${S.skeletonItem} ${S.hs} ${S.wFull}` }), jsx(Skeleton, { className: `${S.skeletonItem} ${S.hs} ${S.w75}` }), jsx(Skeleton, { className: `${S.skeletonItem} ${S.hs} ${S.w50}` })] }), jsx(Skeleton, { className: `${S.skeletonItem} ${S.hl} ${S.wFull}` }), jsxs("div", { className: S.skeletonGroup, children: [jsx(Skeleton, { className: `${S.skeletonItem} ${S.hs} ${S.wFull}` }), jsx(Skeleton, { className: `${S.skeletonItem} ${S.hs} ${S.w75}` })] })] }) }) }));
78
+ }
79
+ if (!selectedDriver) {
80
+ return (jsx(Card, { className: S.root, children: jsx(CardContent, { centered: true, fullHeight: true, noScroll: true, children: jsx("span", { className: S.noDriverSelected, children: "No driver selected" }) }) }));
81
+ }
82
+ const { id, name, category, direction, lag, summary } = selectedDriver;
83
+ const directionText = direction > 0 ? 'Positive' : 'Negative';
84
+ const DirectionIcon = direction > 0 ? TrendUpIcon : TrendDownIcon;
85
+ const nameElem = (jsx("h4", { className: `${S.driverTitle} ${S.truncated}`, children: name }));
86
+ return (jsx(Card, { className: S.root, paddingSize: "l", children: jsx(CardContent, { noScroll: true, children: jsxs("div", { className: S.cardContent, children: [jsx("div", { className: S.driverHeader, children: jsxs("div", { className: S.headerContent, children: [jsxs("div", { className: S.topHeader, children: [jsxs("p", { className: S.categoryInfo, children: [jsx("span", { className: S.categoryIcon, children: getCategoryIcon(category) }), jsx("span", { className: S.categoryText, children: category })] }), driverSelector] }), name.length > 60 ? (jsxs(Tooltip, { children: [jsx(LabelWithId, { id: id, label: jsx(TooltipTrigger, { asChild: true, children: nameElem }) }), jsx(TooltipContent, { side: "left", className: S.tooltipContent, children: jsx("div", { className: S.tooltipTitle, children: name }) })] })) : (jsx(LabelWithId, { id: id, label: nameElem })), jsx("p", { className: S.regionDisplay, children: regionDisplay })] }) }), jsx("div", { className: S.metricsSection, children: jsx("div", { className: S.importanceScore, children: importanceDisplay }) }), jsxs("div", { className: S.directionLagSection, children: [jsxs(Badge, { variant: direction > 0 ? 'green' : 'red', className: S.directionBadge, children: [jsx(DirectionIcon, { className: S.trendIcon }), directionText, " correlation"] }), jsxs("span", { className: S.lagInfo, children: ["Lag: ", lag] })] }), jsx(DriverPerformanceChart, { driver: selectedDriver }), jsx("p", { className: S.description, children: summary ?? '' })] }) }) }));
87
+ }
88
+
89
+ export { DriverCard };
@@ -0,0 +1,7 @@
1
+ import styleInject from 'style-inject';
2
+
3
+ var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.DriverCard_root__Kr5Xz{height:auto;min-height:500px;width:100%}@media (min-width:640px){.DriverCard_root__Kr5Xz{min-height:25rem}}@media (min-width:768px){.DriverCard_root__Kr5Xz{min-height:31.25rem}}.DriverCard_cardContent__zB8UV{display:flex;flex-direction:column;gap:.5rem}.DriverCard_noDriverSelected__-mVm-{color:var(--muted-foreground)}.DriverCard_driverHeader__0aeJ-{align-items:flex-start;display:flex;flex-direction:column;gap:.75rem;padding-bottom:.25rem}.DriverCard_headerContent__YNqtK{display:flex;flex-direction:column;flex-grow:1;gap:.5rem;width:100%}.DriverCard_topHeader__sUDUc{align-items:center;display:flex;justify-content:space-between;margin-top:-12px;min-height:36px}.DriverCard_categoryInfo__8Dhqn{align-items:center;color:var(--muted-foreground);display:flex;font-size:.75rem;gap:.25rem}.DriverCard_categoryIcon__lSIM8{color:var(--muted-foreground);height:.75rem;width:.75rem}.DriverCard_categoryText__DuifF{display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden;text-transform:lowercase}.DriverCard_categoryText__DuifF:first-letter{text-transform:uppercase}.DriverCard_driverTitle__tYQO1{color:var(--foreground);font-size:1.1rem;font-weight:500;line-height:1.4;-webkit-user-select:text;-moz-user-select:text;user-select:text}.DriverCard_driverTitle__tYQO1.DriverCard_truncated__RIn6f{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;cursor:help;overflow:hidden}.DriverCard_regionDisplay__QYVWx{color:var(--muted-foreground);font-size:.75rem}.DriverCard_metricsSection__uZViQ{margin-bottom:.5rem;text-align:left}.DriverCard_importanceScore__RGh5Y{align-items:center;color:var(--foreground);display:flex;font-size:2.25rem;font-weight:400;height:auto;line-height:1;-webkit-user-select:text;-moz-user-select:text;user-select:text}.DriverCard_directionLagSection__Mh-ep{align-items:center;display:flex;justify-content:space-between}.DriverCard_directionBadge__7EAHe{align-items:center;display:flex;gap:.5rem}.DriverCard_trendIcon__GtkDe{height:.75rem;width:.75rem}.DriverCard_lagInfo__enbxl{color:var(--muted-foreground);font-size:.75rem}.DriverCard_description__fNR4e{font-size:.875rem;line-height:1.625;-webkit-user-select:text;-moz-user-select:text;user-select:text}.DriverCard_skeletonContainer__AE9MP{display:flex;flex-direction:column;gap:1rem}.DriverCard_skeletonGroup__lQXls{display:flex;flex-direction:column;gap:.5rem}.DriverCard_skeletonItem__pmx4S.DriverCard_hxs__taJow{height:.75rem}.DriverCard_skeletonItem__pmx4S.DriverCard_hs__PlDPB{height:1rem}.DriverCard_skeletonItem__pmx4S.DriverCard_hm__oFwUK{height:2rem}.DriverCard_skeletonItem__pmx4S.DriverCard_hl__McKZn{height:8rem}.DriverCard_skeletonItem__pmx4S.DriverCard_w33__cI-vq{width:33.333333%}.DriverCard_skeletonItem__pmx4S.DriverCard_w50__DcUSo{width:50%}.DriverCard_skeletonItem__pmx4S.DriverCard_w75__To5oR{width:75%}.DriverCard_skeletonItem__pmx4S.DriverCard_w80__y8wQl{width:80%}.DriverCard_skeletonItem__pmx4S.DriverCard_wFull__TnaxF{width:100%}.DriverCard_tooltipContent__F6DUH{font-size:.75rem;max-width:20rem}.DriverCard_tooltipTitle__NieWB{font-family:var(--font-family-body);font-weight:400}.DriverCard_queueMessage__4hQxI{align-items:center;color:var(--muted-foreground);display:flex;flex-direction:column;font-size:.875rem;gap:var(--p-4);line-height:1.5;padding:var(--p-8) var(--p-4);text-align:center}.DriverCard_queueMessage__4hQxI svg{color:var(--muted-foreground);flex-shrink:0;opacity:.8}";
4
+ var S = {"root":"DriverCard_root__Kr5Xz","cardContent":"DriverCard_cardContent__zB8UV","noDriverSelected":"DriverCard_noDriverSelected__-mVm-","driverHeader":"DriverCard_driverHeader__0aeJ-","headerContent":"DriverCard_headerContent__YNqtK","topHeader":"DriverCard_topHeader__sUDUc","categoryInfo":"DriverCard_categoryInfo__8Dhqn","categoryIcon":"DriverCard_categoryIcon__lSIM8","categoryText":"DriverCard_categoryText__DuifF","driverTitle":"DriverCard_driverTitle__tYQO1","truncated":"DriverCard_truncated__RIn6f","regionDisplay":"DriverCard_regionDisplay__QYVWx","metricsSection":"DriverCard_metricsSection__uZViQ","importanceScore":"DriverCard_importanceScore__RGh5Y","directionLagSection":"DriverCard_directionLagSection__Mh-ep","directionBadge":"DriverCard_directionBadge__7EAHe","trendIcon":"DriverCard_trendIcon__GtkDe","lagInfo":"DriverCard_lagInfo__enbxl","description":"DriverCard_description__fNR4e","skeletonContainer":"DriverCard_skeletonContainer__AE9MP","skeletonGroup":"DriverCard_skeletonGroup__lQXls","skeletonItem":"DriverCard_skeletonItem__pmx4S","hxs":"DriverCard_hxs__taJow","hs":"DriverCard_hs__PlDPB","hm":"DriverCard_hm__oFwUK","hl":"DriverCard_hl__McKZn","w33":"DriverCard_w33__cI-vq","w50":"DriverCard_w50__DcUSo","w75":"DriverCard_w75__To5oR","w80":"DriverCard_w80__y8wQl","wFull":"DriverCard_wFull__TnaxF","tooltipContent":"DriverCard_tooltipContent__F6DUH","tooltipTitle":"DriverCard_tooltipTitle__NieWB","queueMessage":"DriverCard_queueMessage__4hQxI"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,83 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import { useMemo } from 'react';
4
+ import { LineChart, CartesianGrid, XAxis, YAxis, Tooltip, Line } from 'recharts';
5
+ import '../../ui/Chart/components/BaseChartWrapper.js';
6
+ import { ChartContainer } from '../../ui/Chart/components/ChartContainer.js';
7
+ import '../../ui/Chart/Chart.context.js';
8
+ import '../../ui/Chart/Chart.styl.js';
9
+ import '../../ui/AnalysisLineIcon/AnalysisLineIcon.styl.js';
10
+ import '@radix-ui/react-slot';
11
+ import '../../ui/Badge/Badge.styl.js';
12
+ import '../../ui/LabelWithId/LabelWithId.styl.js';
13
+ import '@radix-ui/react-select';
14
+ import 'lucide-react';
15
+ import '../../ui/Select/Select.styl.js';
16
+ import '../../ui/TextShimmer/TextShimmer.js';
17
+ import '@phosphor-icons/react';
18
+ import '../../ui/AnalysesSelector/AnalysesSelector.styl.js';
19
+ import '../../ui/Chart/components/CustomChartLegend/CustomChartLegend.styl.js';
20
+ import '../../ui/ChartAreaInteractive/ChartLines.js';
21
+ import '../../ui/Skeleton/Skeleton.styl.js';
22
+ import 'lightweight-charts';
23
+ import '../../ui/Chart/lightweight/LightweightForecastChart.styl.js';
24
+ import { ChartEmptyState } from '../../ui/Chart/components/ChartEmptyState/ChartEmptyState.js';
25
+ import S from './DriverPerformanceChart.styl.js';
26
+ import { generateDriverChartData } from './driverPerformanceChartData.js';
27
+
28
+ const driverChartConfig = {
29
+ value: {
30
+ label: 'Performance',
31
+ color: 'var(--primary)',
32
+ },
33
+ };
34
+ function DriverPerformanceChart({ driver, }) {
35
+ const precision = useMemo(() => {
36
+ if (!driver.normalized_series)
37
+ return 7;
38
+ const values = Object.values(driver.normalized_series).filter((v) => typeof v === 'number' && v !== null);
39
+ if (values.length === 0)
40
+ return 7;
41
+ const absoluteValues = values.map(Math.abs).filter(v => v > 0);
42
+ if (absoluteValues.length === 0)
43
+ return 7;
44
+ const minAbs = Math.min(...absoluteValues);
45
+ if (minAbs < 0.0001)
46
+ return 7;
47
+ if (minAbs < 0.001)
48
+ return 6;
49
+ if (minAbs < 0.01)
50
+ return 5;
51
+ if (minAbs < 0.1)
52
+ return 4;
53
+ if (minAbs < 1)
54
+ return 3;
55
+ return 2;
56
+ }, [driver.normalized_series]);
57
+ const chartData = useMemo(() => generateDriverChartData(driver, precision), [driver, precision]);
58
+ const noSeriesData = useMemo(() => {
59
+ if (!driver.normalized_series)
60
+ return false;
61
+ return Object.values(driver.normalized_series).every(value => value === null);
62
+ }, [driver.normalized_series]);
63
+ const renderTooltipContent = ({ active, payload, }) => {
64
+ if (active && payload?.length) {
65
+ const dataPoint = payload[0];
66
+ const row = dataPoint?.payload;
67
+ const date = row?.date;
68
+ const value = dataPoint?.value;
69
+ return (jsxs("div", { className: S.chartTooltip, children: [jsx("div", { className: S.tooltipDate, children: date instanceof Date
70
+ ? date.toLocaleDateString('en-US', {
71
+ month: 'long',
72
+ year: 'numeric',
73
+ })
74
+ : 'Unknown Date' }), jsxs("div", { className: S.tooltipPerformance, children: ["Performance:", ' ', typeof value === 'number'
75
+ ? value.toFixed(precision)
76
+ : String(value ?? '')] })] }));
77
+ }
78
+ return null;
79
+ };
80
+ return (jsxs("div", { className: S.driverChartContainer, children: [jsx(ChartContainer, { config: driverChartConfig, className: cn(S.chartContainer, noSeriesData && S.chartContainerDisabled), children: jsxs(LineChart, { data: chartData, margin: { left: 8, right: 8, top: 8, bottom: -20 }, children: [jsx(CartesianGrid, { vertical: false }), jsx(XAxis, { dataKey: "date", tickLine: false, axisLine: false, tick: false, tickMargin: 0, minTickGap: 0 }), jsx(YAxis, { tickLine: false, axisLine: false, tick: false, tickMargin: 0, minTickGap: 0, width: 0, domain: ['dataMin', 'dataMax'] }), jsx(Tooltip, { cursor: false, content: renderTooltipContent }), jsx(Line, { dataKey: "value", type: "natural", stroke: "var(--color-value)" })] }) }), noSeriesData && (jsx(ChartEmptyState, { variant: "inline", align: "center", status: "No series data", className: S.noDataMessage }))] }));
81
+ }
82
+
83
+ export { DriverPerformanceChart };
@@ -0,0 +1,7 @@
1
+ import styleInject from 'style-inject';
2
+
3
+ var css_248z = ".DriverPerformanceChart_driverChartContainer__27xZ-{position:relative;width:100%}.DriverPerformanceChart_driverChartContainer__27xZ- svg{overflow:visible}.DriverPerformanceChart_chartContainer__--rGL{height:214px;margin-left:-.5rem;padding:var(--p-4) 0;width:100%}.DriverPerformanceChart_chartContainerDisabled__ndtPZ{opacity:.1}.DriverPerformanceChart_noDataMessage__RO3u1{color:var(--foreground);font-size:.875rem;font-weight:500;left:50%;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%);z-index:10}.DriverPerformanceChart_chartTooltip__cpaQw{background-color:var(--popover);border:1px solid var(--border);border-radius:.5rem;box-shadow:0 10px 15px -3px rgba(0,0,0,.1);padding:.75rem}.DriverPerformanceChart_tooltipDate__B2aeP{color:var(--popover-foreground);font-size:.875rem;font-weight:500}.DriverPerformanceChart_tooltipPerformance__3hfgE{color:var(--muted-foreground);font-size:.875rem}";
4
+ var S = {"driverChartContainer":"DriverPerformanceChart_driverChartContainer__27xZ-","chartContainer":"DriverPerformanceChart_chartContainer__--rGL","chartContainerDisabled":"DriverPerformanceChart_chartContainerDisabled__ndtPZ","noDataMessage":"DriverPerformanceChart_noDataMessage__RO3u1","chartTooltip":"DriverPerformanceChart_chartTooltip__cpaQw","tooltipDate":"DriverPerformanceChart_tooltipDate__B2aeP","tooltipPerformance":"DriverPerformanceChart_tooltipPerformance__3hfgE"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,50 @@
1
+ /** Last non-null points from `normalized_series`, or deterministic fallback sample. */
2
+ function generateDriverChartData(driver, precision = 7) {
3
+ if (driver.normalized_series) {
4
+ const entries = Object.entries(driver.normalized_series);
5
+ const seriesData = entries
6
+ .filter(([, value]) => value !== null)
7
+ .map(([date, value]) => {
8
+ let parsedDate;
9
+ try {
10
+ const dateStr = date.toString();
11
+ if (dateStr.includes('-')) {
12
+ parsedDate = new Date(`${dateStr}T00:00:00`);
13
+ }
14
+ else {
15
+ parsedDate = new Date(dateStr);
16
+ }
17
+ if (Number.isNaN(parsedDate.getTime())) {
18
+ return null;
19
+ }
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ const numericValue = parseFloat(value.toFixed(precision));
25
+ return {
26
+ date: parsedDate,
27
+ value: numericValue,
28
+ };
29
+ })
30
+ .filter((item) => item !== null)
31
+ .sort((a, b) => a.date.getTime() - b.date.getTime())
32
+ .slice(-24);
33
+ if (seriesData.length > 0) {
34
+ return seriesData;
35
+ }
36
+ }
37
+ const data = [];
38
+ const baseValue = driver.importance / 100;
39
+ for (let i = 0; i < 12; i++) {
40
+ const randomVariation = (Math.random() - 0.5) * 0.2;
41
+ const value = Math.max(0, Math.min(1, baseValue + randomVariation));
42
+ data.push({
43
+ date: new Date(2023, i, 1),
44
+ value: parseFloat(value.toFixed(precision)),
45
+ });
46
+ }
47
+ return data;
48
+ }
49
+
50
+ export { generateDriverChartData };
@@ -1,13 +1,13 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import cn from 'classnames';
3
3
  import { useRef, useState, useMemo, useEffect, useCallback } from 'react';
4
+ import { WorldMap } from '../../ui/WorldMap/WorldMap.js';
4
5
  import useEvent from '../../../hooks/useEvent.js';
5
6
  import { Shimmer } from '@homecode/ui';
6
7
  import { DriverIcon } from './DriverIcon/DriverIcon.js';
7
8
  import constants from './DriverIcon/DriverIcon.constants.json.js';
8
9
  import { findMostSpecificRegion, getDriverCoordinates, hasValidCoords, calculateBadgeSizes } from './DriverMap.helpers.js';
9
10
  import S from './DriverMap.styl.js';
10
- import { MapBackground } from './MapBackground/MapBackground.js';
11
11
  import { getHighestImportanceDriver } from './driverMapSelection.js';
12
12
 
13
13
  const delay = (ms) => new Promise(r => setTimeout(r, ms));
@@ -113,7 +113,7 @@ function DriverMap({ drivers, isLoading, setSelectedDriver, selectedDriver, }) {
113
113
  callback: handleKeyDown,
114
114
  isCapture: true,
115
115
  });
116
- return (jsxs("div", { className: cn(S.root, isTransitioning && S.inTransition), children: [jsxs("div", { className: S.mapInner, children: [jsx(MapBackground, {}), isLoading && jsx(Shimmer, { className: S.shimmerOverlay, size: "l" }), otherDrivers.map(driver => (jsx(DriverIcon, { isLoading: isLoading, isVisible: isVisible, driver: driver, size: badgeSizes[driver.id] || 's', isSelected: selectedDriver?.id === driver.id, onClick: () => setSelectedDriver(driver) }, driver.id)))] }), jsx("div", { className: S.worldDrivers, children: worldDrivers.map(driver => {
116
+ return (jsxs("div", { className: cn(S.root, isTransitioning && S.inTransition), children: [jsxs("div", { className: S.mapInner, children: [jsx(WorldMap, { className: S.mapWorld }), isLoading && jsx(Shimmer, { className: S.shimmerOverlay, size: "l" }), otherDrivers.map(driver => (jsx(DriverIcon, { isLoading: isLoading, isVisible: isVisible, driver: driver, size: badgeSizes[driver.id] || 's', isSelected: selectedDriver?.id === driver.id, onClick: () => setSelectedDriver(driver) }, driver.id)))] }), jsx("div", { className: S.worldDrivers, children: worldDrivers.map(driver => {
117
117
  const driverWithCoords = {
118
118
  ...driver,
119
119
  coordinates: driver.coordinates || {
@@ -1,7 +1,7 @@
1
1
  import styleInject from 'style-inject';
2
2
 
3
- var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.DriverMap_root__JszhG{aspect-ratio:623.2/341.276;max-width:100%;overflow:hidden;padding:0;position:relative;width:100%}@media (min-width:768px){.DriverMap_root__JszhG{flex:1;height:35rem;width:-moz-fit-content;width:fit-content}}.DriverMap_mapInner__E7rZR{aspect-ratio:623.2/341.276;border-radius:var(--p-4);margin:0 auto;max-height:100%;max-width:100%;overflow:hidden;position:relative}.DriverMap_shimmerOverlay__UH2qz{z-index:20}.DriverMap_inTransition__lvYwJ{pointer-events:none}.DriverMap_worldDrivers__sZOIW{align-items:center;bottom:0;display:flex;gap:.5rem;padding:.5rem;position:absolute}.DriverMap_worldDrivers__sZOIW button{position:static!important;transform:none!important}.DriverMap_worldDrivers__sZOIW button>span{opacity:1!important;transform:none!important}";
4
- var S = {"root":"DriverMap_root__JszhG","mapInner":"DriverMap_mapInner__E7rZR","shimmerOverlay":"DriverMap_shimmerOverlay__UH2qz","inTransition":"DriverMap_inTransition__lvYwJ","worldDrivers":"DriverMap_worldDrivers__sZOIW"};
3
+ var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.DriverMap_root__JszhG{aspect-ratio:623.2/341.276;max-width:100%;overflow:hidden;padding:0;position:relative;width:100%}@media (min-width:768px){.DriverMap_root__JszhG{flex:1;height:35rem;width:-moz-fit-content;width:fit-content}}.DriverMap_mapInner__E7rZR{aspect-ratio:623.2/341.276;border-radius:var(--p-4);margin:0 auto;max-height:100%;max-width:100%;overflow:hidden;position:relative}.DriverMap_mapWorld__vmPp-{box-sizing:border-box;inset:0;position:absolute}.DriverMap_shimmerOverlay__UH2qz{z-index:20}.DriverMap_inTransition__lvYwJ{pointer-events:none}.DriverMap_worldDrivers__sZOIW{align-items:center;bottom:0;display:flex;gap:.5rem;padding:.5rem;position:absolute}.DriverMap_worldDrivers__sZOIW button{position:static!important;transform:none!important}.DriverMap_worldDrivers__sZOIW button>span{opacity:1!important;transform:none!important}";
4
+ var S = {"root":"DriverMap_root__JszhG","mapInner":"DriverMap_mapInner__E7rZR","mapWorld":"DriverMap_mapWorld__vmPp-","shimmerOverlay":"DriverMap_shimmerOverlay__UH2qz","inTransition":"DriverMap_inTransition__lvYwJ","worldDrivers":"DriverMap_worldDrivers__sZOIW"};
5
5
  styleInject(css_248z);
6
6
 
7
7
  export { S as default };
package/dist/esm/index.js CHANGED
@@ -81,6 +81,7 @@ export { Toggle } from './components/ui/Toggle/Toggle.js';
81
81
  export { ToggleGroup, ToggleGroupItem } from './components/ui/ToggleGroup/ToggleGroup.js';
82
82
  export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './components/ui/Tooltip/Tooltip.js';
83
83
  export { VimeoEmbed } from './components/ui/VimeoEmbed/VimeoEmbed.js';
84
+ export { WorldMap } from './components/ui/WorldMap/WorldMap.js';
84
85
  export { WorkspaceAppSwitcher } from './components/ui/WorkspaceAppSwitcher/WorkspaceAppSwitcher.js';
85
86
  export { WORKSPACE_APP_SLUG_BASE_PATH } from './components/ui/WorkspaceAppSwitcher/workspaceApp.types.js';
86
87
  export { WORKSPACE_APPS_LS_KEY } from './components/ui/WorkspaceAppSwitcher/workspaceAppsConstants.js';
@@ -89,12 +90,11 @@ export { WORKSPACE_APP_ICONS, isWorkspaceAppIconKey } from './components/ui/Work
89
90
  export { findWorkspaceAppByPathname, workspaceAppSlugPath } from './components/ui/WorkspaceAppSwitcher/workspaceAppPaths.js';
90
91
  export { SidebarDatasetsItemsGrouped } from './components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.js';
91
92
  export { groupSidebarDatasets } from './components/widgets/SidebarDatasetsItemsGrouped/groupSidebarDatasets.js';
93
+ export { DriverCard } from './components/widgets/DriverCard/DriverCard.js';
92
94
  export { DriverMap } from './components/widgets/DriverMap/DriverMap.js';
93
95
  export { getCategoryIcon } from './components/widgets/DriverMap/driverCategoryIcon.js';
94
96
  export { getDriverImportance, getHighestImportanceDriver } from './components/widgets/DriverMap/driverMapSelection.js';
95
97
  export { geographicCoordinates, geographicToSVG, getContinentFromRegion, getPreciseCoordinates, getResponsiveCoordinates, svgToPercentage } from './components/widgets/DriverMap/driverMapGeography.js';
96
- export { MapBackground } from './components/widgets/DriverMap/MapBackground/MapBackground.js';
97
- export { LoadingSpinner } from './components/widgets/DriverMap/LoadingSpinner/LoadingSpinner.js';
98
98
  export { SybilionAppHeader } from './components/widgets/SybilionAppHeader/SybilionAppHeader.js';
99
99
  export { SybilionAuthLayout } from './components/widgets/SybilionAuthLayout/SybilionAuthLayout.js';
100
100
  export { SybilionAuthHeadline } from './components/widgets/SybilionAuthLayout/SybilionAuthHeadline.js';
@@ -103,6 +103,8 @@ export { SignInPage } from './components/widgets/SignInPage/SignInPage.js';
103
103
  export { ChartTooltipItem } from './components/ui/Chart/components/ChartTooltipItem.js';
104
104
  export { ChartLegendItem } from './components/ui/Chart/components/ChartLegendItem.js';
105
105
  export { CustomChartLegend } from './components/ui/Chart/components/CustomChartLegend/CustomChartLegend.js';
106
+ export { LightweightForecastChart } from './components/ui/Chart/lightweight/LightweightForecastChart.js';
107
+ export { ChartEmptyState } from './components/ui/Chart/components/ChartEmptyState/ChartEmptyState.js';
106
108
  export { ChartContainer, ChartStyle } from './components/ui/Chart/components/ChartContainer.js';
107
109
  export { ChartTooltipContent } from './components/ui/Chart/components/ChartTooltipContent.js';
108
110
  export { ChartLegendContent } from './components/ui/Chart/components/ChartLegendContent.js';
@@ -10,3 +10,5 @@ export { ChartTooltipItem } from './components/ChartTooltipItem';
10
10
  export { ChartLegendItem } from './components/ChartLegendItem';
11
11
  export { CustomChartLegend } from './components/CustomChartLegend/CustomChartLegend';
12
12
  export { ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartStyle, BaseChartWrapper, };
13
+ export { LightweightForecastChart, type LightweightForecastChartProps, } from './lightweight/LightweightForecastChart';
14
+ export { ChartEmptyState, type ChartEmptyStateProps, type ChartEmptyStatusTone, } from './components/ChartEmptyState/ChartEmptyState';
@@ -1,8 +1,9 @@
1
1
  import { ComponentProps, ReactNode } from 'react';
2
- import { ChartConfig, ChartContainer } from '#uilib/components/ui/Chart/Chart';
3
2
  import type { QuantileBandConfig } from '#uilib/components/ui/Chart/chartForecastVisualization.types';
4
3
  import { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
5
4
  import { ForecastItemData } from '#uilib/components/ui/ChartAreaInteractive/ChartLines';
5
+ import type { ChartConfig } from '../Chart.types';
6
+ import { ChartContainer } from './ChartContainer';
6
7
  import { LegendPayload } from 'recharts/types/component/DefaultLegendContent';
7
8
  export interface BaseChartWrapperProps {
8
9
  renderId?: string;
@@ -0,0 +1,14 @@
1
+ import { ReactNode } from 'react';
2
+ export type ChartEmptyStatusTone = 'muted' | 'destructive';
3
+ export interface ChartEmptyStateProps {
4
+ className?: string;
5
+ /** Primary guidance (muted). */
6
+ hint?: ReactNode;
7
+ /** Status / technical detail. */
8
+ status?: ReactNode;
9
+ statusTone?: ChartEmptyStatusTone;
10
+ /** `panel`: chart-sized block with light fill. `inline`: text only (e.g. above chart). */
11
+ variant?: 'panel' | 'inline';
12
+ align?: 'center' | 'start';
13
+ }
14
+ export declare function ChartEmptyState({ className, hint, status, statusTone, variant, align, }: ChartEmptyStateProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,26 @@
1
+ import type { ChartConfig } from '#uilib/components/ui/Chart/Chart.types';
2
+ import type { QuantileBandConfig } from '#uilib/components/ui/Chart/chartForecastVisualization.types';
3
+ import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
4
+ import { ForecastItemData } from '#uilib/components/ui/ChartAreaInteractive/ChartLines';
5
+ export interface LightweightForecastChartProps {
6
+ chartData: ChartDataPoint[];
7
+ forecastData?: ForecastItemData[];
8
+ quantileBands?: QuantileBandConfig[];
9
+ chartConfig?: ChartConfig;
10
+ historicalLineColor?: string;
11
+ isDarkTheme: boolean;
12
+ height?: number;
13
+ className?: string;
14
+ hiddenSeries?: Set<string>;
15
+ onLegendClick?: (data: unknown, index: number, event: unknown) => void;
16
+ disableForecastHistoricalBridge?: boolean;
17
+ forecastLineStyle?: 'dashed' | 'solid';
18
+ formatDate?: (value: string, detailed?: boolean) => string;
19
+ formatNumber?: (value: number) => string;
20
+ loading?: boolean;
21
+ error?: string | null;
22
+ noDataMessage?: string;
23
+ showLegend?: boolean;
24
+ showTooltip?: boolean;
25
+ }
26
+ export declare function LightweightForecastChart(props: LightweightForecastChartProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import type { UTCTimestamp } from 'lightweight-charts';
2
+ /**
3
+ * Parse `YYYY-MM-DD` dates as UTC midnight → Lightweight Charts unix seconds.
4
+ */
5
+ export declare function chartDateToUtcTimestamp(dateStr: string): UTCTimestamp;
@@ -0,0 +1,13 @@
1
+ import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
2
+ import type { ChartOptions, DeepPartial, LineData, UTCTimestamp } from 'lightweight-charts';
3
+ import type { QuantileBandCustomData } from './quantileBandCustomSeries';
4
+ export declare function buildLightweightChartOptions(args: {
5
+ isDarkTheme: boolean;
6
+ width: number;
7
+ height: number;
8
+ autoSize?: boolean;
9
+ }): DeepPartial<ChartOptions>;
10
+ export declare function buildHistoricalLineData(rows: ChartDataPoint[]): LineData<UTCTimestamp>[];
11
+ export declare function buildForecastLineData(rows: ChartDataPoint[], forecastKey: string): LineData<UTCTimestamp>[];
12
+ export declare function buildQuantileBandCustomData(rows: ChartDataPoint[], bandKey: string): QuantileBandCustomData[];
13
+ export declare function findNearestChartRow(rows: ChartDataPoint[], time: UTCTimestamp): ChartDataPoint | null;
@@ -0,0 +1,24 @@
1
+ import type { CustomData, CustomSeriesOptions, CustomSeriesWhitespaceData, ICustomSeriesPaneRenderer, ICustomSeriesPaneView, PaneRendererCustomData, UTCTimestamp } from 'lightweight-charts';
2
+ export interface QuantileBandCustomData extends CustomData<UTCTimestamp> {
3
+ lower: number;
4
+ upper: number;
5
+ }
6
+ export type QuantileBandStyle = {
7
+ fill: string;
8
+ stroke?: string;
9
+ strokeWidth: number;
10
+ strokeDasharray?: string;
11
+ strokeOpacity?: number;
12
+ };
13
+ export declare class QuantileBandPaneView implements ICustomSeriesPaneView<UTCTimestamp, QuantileBandCustomData, CustomSeriesOptions> {
14
+ private _paneData;
15
+ private _style;
16
+ constructor(initialStyle: QuantileBandStyle);
17
+ updateStyle(style: QuantileBandStyle): void;
18
+ renderer(): ICustomSeriesPaneRenderer;
19
+ update(paneData: PaneRendererCustomData<UTCTimestamp, QuantileBandCustomData>, seriesOptions: CustomSeriesOptions): void;
20
+ priceValueBuilder(plotRow: QuantileBandCustomData): number[];
21
+ isWhitespace(data: QuantileBandCustomData | CustomSeriesWhitespaceData<UTCTimestamp>): data is CustomSeriesWhitespaceData<UTCTimestamp>;
22
+ defaultOptions(): CustomSeriesOptions;
23
+ destroy(): void;
24
+ }
@@ -0,0 +1,7 @@
1
+ import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
2
+ /**
3
+ * Matches ChartAreaInteractive `mode="intervals"`: cone / fan chart hand-off — collapse the
4
+ * interval to a point at the historical→forecast boundary, then expand along forecast anchors.
5
+ * (Same rules as `useQuantileBands`, without requiring `ForecastData` — reads tuples from each row.)
6
+ */
7
+ export declare function applyQuantileBandConeToChartData(chartData: ChartDataPoint[], bandKey: string): ChartDataPoint[];
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shared Recharts plot / margin math (DOM-agnostic except measurement entry points).
3
+ * Keeps BaseChartWrapper tooltip clamp and ChartAreaInteractive brush in sync.
4
+ */
5
+ export type ChartMargin = {
6
+ top: number;
7
+ right: number;
8
+ bottom: number;
9
+ left: number;
10
+ };
11
+ export declare const DEFAULT_CHART_MARGIN: ChartMargin;
12
+ export declare function resolveChartMargin(margin: Partial<ChartMargin> | undefined): ChartMargin;
13
+ /** Plot box inside `.recharts-wrapper` (Recharts cartesian convention). */
14
+ export declare function getPlotViewBox(wrapper: HTMLElement, m: ChartMargin): {
15
+ x: number;
16
+ y: number;
17
+ width: number;
18
+ height: number;
19
+ };
20
+ export type PlotRect = {
21
+ left: number;
22
+ top: number;
23
+ width: number;
24
+ height: number;
25
+ };
26
+ /**
27
+ * Plot area in `host` local px: prefer painted `.recharts-cartesian-grid`, else
28
+ * last `.recharts-wrapper` + margins. One `hostRect` read; grid/wrapper rects as needed.
29
+ */
30
+ export declare function measureHostRelativePlotRect(host: HTMLElement, margin: ChartMargin): PlotRect | null;
@@ -1,3 +1,3 @@
1
1
  import { ChartAreaInteractiveProps } from './ChartAreaInteractive.types';
2
2
  export declare const chartConfig: {};
3
- export declare function ChartAreaInteractive({ className, chartContainerClassName, legendClassName, xAxisClassName, yAxisClassName, timeRange, onTimeRangeChange, pinMonth, onPinMonthChange, onPreviewMonthChange, chartData, forecastData, error, loading, isDarkTheme, footerActions, mode, selectedForecast, upperQuantiles, lowerQuantiles, selectedLowerQuantile, selectedUpperQuantile, onLowerQuantileChange, onUpperQuantileChange, lowerThreshold, upperThreshold, onLowerThresholdChange, onUpperThresholdChange, discreteThresholdValues, headerActions, excludeLegendIds, loadingAnalyses, onLegendClick, onAnalysisSelect, disableTimeRangeSelector, forecastLineStyle, selectedAnalysisId, chartRenderId, toggleLegendSeries, ensureAnalysisSeriesVisible, overlayForecastData, hiddenSeries, disableForecastHistoricalBridge, ...restProps }: ChartAreaInteractiveProps): import("react/jsx-runtime").JSX.Element;
3
+ export declare function ChartAreaInteractive({ className, chartContainerClassName, legendClassName, xAxisClassName, yAxisClassName, timeRange, onTimeRangeChange, pinMonth, onPinMonthChange, onPreviewMonthChange, chartData, forecastData, error, loading, isDarkTheme, footerActions, mode, selectedForecast, upperQuantiles, lowerQuantiles, selectedLowerQuantile, selectedUpperQuantile, onLowerQuantileChange, onUpperQuantileChange, lowerThreshold, upperThreshold, onLowerThresholdChange, onUpperThresholdChange, discreteThresholdValues, headerActions, excludeLegendIds, loadingAnalyses, onLegendClick, onAnalysisSelect, disableTimeRangeSelector, forecastLineStyle, selectedAnalysisId, chartRenderId, toggleLegendSeries, ensureAnalysisSeriesVisible, overlayForecastData, hiddenSeries, disableForecastHistoricalBridge, overlayElements: overlayElementsProp, ...restProps }: ChartAreaInteractiveProps): import("react/jsx-runtime").JSX.Element;
@@ -8,13 +8,22 @@ declare const timeRangeToMonths: {
8
8
  readonly '5y': 60;
9
9
  readonly All: 12;
10
10
  };
11
- export type TimeRange = keyof typeof timeRangeToMonths;
11
+ export type TimeRangePreset = keyof typeof timeRangeToMonths;
12
+ /** @deprecated Use `TimeRangePreset` or `string` for brush-encoded ranges. */
13
+ export type TimeRange = TimeRangePreset;
14
+ export declare const DRAG_TIME_RANGE_PREFIX: "__drag:";
15
+ export declare function encodeDragTimeRange(a: Date, b: Date): string;
16
+ export declare function parseDragTimeRange(s: string): {
17
+ start: Date;
18
+ end: Date;
19
+ } | null;
20
+ export declare function isTimeRangePreset(s: string): s is TimeRangePreset;
12
21
  export type FilterDataForTimeRangeOptions = {
13
22
  /** When set (e.g. selected forecast on Forecast tab), the window ends at the
14
23
  * latest point that has shared historical or that analysis — not at another run. */
15
24
  endDateAnchorAnalysisId?: number | null;
16
25
  };
17
- export declare const filterDataForTimeRange: (data: ChartDataPoint[], currentTimeRange: TimeRange, options?: FilterDataForTimeRangeOptions) => ChartDataPoint[];
26
+ export declare const filterDataForTimeRange: (data: ChartDataPoint[], currentTimeRange: string, options?: FilterDataForTimeRangeOptions) => ChartDataPoint[];
18
27
  export declare const shortDateFormatter: (value: string) => string;
19
28
  export declare const longDateFormatter: (value: string) => string;
20
29
  /**
@@ -1,7 +1,6 @@
1
1
  import { BaseChartWrapperProps } from '#uilib/components/ui/Chart/components/BaseChartWrapper';
2
2
  import type { ForecastData } from '#uilib/types/forecast-data';
3
3
  import { LegendPayload } from 'recharts';
4
- import { TimeRange } from './ChartAreaInteractive.helpers';
5
4
  export type OverlayMode = 'pin' | 'intervals' | 'thresholds';
6
5
  export interface ChartDataPoint {
7
6
  date: string;
@@ -22,7 +21,8 @@ export interface Analysis {
22
21
  }
23
22
  export interface ChartAreaInteractiveProps extends BaseChartWrapperProps {
24
23
  chartContainerClassName?: string;
25
- timeRange: TimeRange;
24
+ /** Preset (`6m`, `1y`, …, `All`) or `__drag:startMs,endMs` from chart brush. */
25
+ timeRange: string;
26
26
  onTimeRangeChange: (range: string) => void;
27
27
  pinMonth: string | undefined;
28
28
  onPinMonthChange: (month: string | undefined) => void;
@@ -0,0 +1,15 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
3
+ export interface TimeRangeBrushHostProps {
4
+ chartData: ChartDataPoint[];
5
+ onTimeRangeChange: (range: string) => void;
6
+ enabled: boolean;
7
+ /** Bumps layout sync when chart remounts (e.g. dataset / render id). */
8
+ layoutKey?: string | number | null;
9
+ children: ReactNode;
10
+ }
11
+ /**
12
+ * Wraps chart; pointerdown on SVG starts horizontal brush. Plot box tracks the
13
+ * painted grid / Recharts plot (see TimeRangeBrushLayout.helpers).
14
+ */
15
+ export declare function TimeRangeBrushHost({ chartData, onTimeRangeChange, enabled, layoutKey, children, }: TimeRangeBrushHostProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { type ChartMargin, type PlotRect, measureHostRelativePlotRect, resolveChartMargin } from '#uilib/components/ui/Chart/tools/chartPlotGeometry';
2
+ import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
3
+ /** Debounce for `window` resize only (RO uses rAF-coalesced sync). */
4
+ export declare const BRUSH_LAYOUT_RESIZE_DEBOUNCE_MS = 500;
5
+ export declare const BRUSH_MIN_DRAG_PX = 8;
6
+ export declare const BRUSH_DOUBLE_TAP_MS = 300;
7
+ export declare const BRUSH_DOUBLE_TAP_MAX_DIST_PX = 24;
8
+ export type { ChartMargin };
9
+ export { resolveChartMargin };
10
+ export type BrushPlotLayout = PlotRect;
11
+ /** Host-relative plot rect (grid-first, then wrapper + margins). */
12
+ export declare const measureBrushPlotLayout: typeof measureHostRelativePlotRect;
13
+ export declare function brushPlotLayoutsEqual(a: BrushPlotLayout | null, b: BrushPlotLayout | null): boolean;
14
+ export declare function brushClientXToDate(clientX: number, plotRect: DOMRect, chartData: ChartDataPoint[]): Date | null;
@@ -6,5 +6,5 @@ interface PinOverlayProps {
6
6
  onPreviewMonthChange?: (month: string | undefined) => void;
7
7
  className?: string;
8
8
  }
9
- export declare function PinOverlay({ baseChartProps, pinMonth, onPinMonthChange, onPreviewMonthChange, className, }: PinOverlayProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function PinOverlay({ baseChartProps, pinMonth, onPinMonthChange, onPreviewMonthChange: _onPreviewMonthChange, className, }: PinOverlayProps): import("react/jsx-runtime").JSX.Element;
10
10
  export {};
@@ -1,5 +1,5 @@
1
1
  export declare function PageColumns({ columns, fill, className, }: {
2
2
  columns: React.ReactNode[];
3
- fill: 'left' | 'right' | 'all';
3
+ fill?: 'left' | 'right' | 'all';
4
4
  className?: string;
5
5
  }): import("react/jsx-runtime").JSX.Element;
@@ -1,11 +1,9 @@
1
- import { TimeRange } from './TimeRangeControls.types';
2
- export declare const TimeRangeControls: import("react").MemoExoticComponent<({ timeRange, onTimeRangeChange, loading, }: {
3
- timeRange: TimeRange;
1
+ export type TimeRangeControlsProps = {
2
+ timeRange: string;
4
3
  onTimeRangeChange: (range: string) => void;
5
4
  loading?: boolean;
6
- }) => import("react/jsx-runtime").JSX.Element>;
7
- export declare const TimeRangeSelect: import("react").MemoExoticComponent<({ timeRange, onTimeRangeChange, loading, }: {
8
- timeRange: TimeRange;
9
- onTimeRangeChange: (range: string) => void;
5
+ };
6
+ export declare const TimeRangeControls: import("react").MemoExoticComponent<({ timeRange, onTimeRangeChange, loading }: TimeRangeControlsProps) => import("react/jsx-runtime").JSX.Element>;
7
+ export declare const TimeRangeSelect: import("react").MemoExoticComponent<({ timeRange, onTimeRangeChange, loading, }: TimeRangeControlsProps & {
10
8
  loading: boolean;
11
9
  }) => import("react/jsx-runtime").JSX.Element>;
@@ -0,0 +1,4 @@
1
+ export type WorldMapProps = {
2
+ className?: string;
3
+ };
4
+ export declare function WorldMap({ className }: WorldMapProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export { WorldMap } from './WorldMap';
2
+ export type { WorldMapProps } from './WorldMap';
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { DriverData } from '../DriverMap/driverMapGeography';
3
+ export interface DriverCardProps {
4
+ selectedDriver: DriverData | null;
5
+ isLoading: boolean;
6
+ inQueue?: boolean;
7
+ driverSelector?: React.ReactNode;
8
+ }
9
+ export declare function DriverCard({ selectedDriver, isLoading, inQueue, driverSelector, }: DriverCardProps): import("react/jsx-runtime").JSX.Element;