@sybilion/uilib 1.2.24 → 1.3.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 (136) hide show
  1. package/dist/esm/components/ui/Chart/Chart.js +1 -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/tools/chartPlotGeometry.js +65 -0
  6. package/dist/esm/components/ui/ChartAreaInteractive/ChartAreaInteractive.helpers.js +37 -1
  7. package/dist/esm/components/ui/ChartAreaInteractive/ChartAreaInteractive.js +5 -2
  8. package/dist/esm/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.js +205 -0
  9. package/dist/esm/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.styl.js +7 -0
  10. package/dist/esm/components/ui/ChartAreaInteractive/TimeRangeBrushLayout.helpers.js +37 -0
  11. package/dist/esm/components/ui/ChartAreaInteractive/overlays/IntervalsOverlay/IntervalsOverlay.hooks.js +1 -0
  12. package/dist/esm/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.js +7 -60
  13. package/dist/esm/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.styl.js +2 -2
  14. package/dist/esm/components/ui/ChartAreaInteractive/overlays/ThresholdsOverlay/ThresholdsOverlay.hooks.js +1 -0
  15. package/dist/esm/components/ui/ChartAreaInteractive/overlays/useChartYRange.js +2 -4
  16. package/dist/esm/components/ui/Chat/ChatSheet/ChatSelector.js +1 -1
  17. package/dist/esm/components/ui/Chat/ChatSheet/ChatSelector.styl.js +1 -1
  18. package/dist/esm/components/ui/DropdownMenu/DropdownMenu.js +4 -4
  19. package/dist/esm/components/ui/TimeRangeControls/TimeRangeControls.js +7 -2
  20. package/dist/esm/components/ui/WorldMap/WorldMap.js +11 -0
  21. package/dist/esm/components/ui/WorldMap/WorldMap.styl.js +7 -0
  22. package/dist/esm/components/ui/WorldMap/map.svg.js +3 -0
  23. package/dist/esm/components/widgets/DriverCard/DriverCard.js +89 -0
  24. package/dist/esm/components/widgets/DriverCard/DriverCard.styl.js +7 -0
  25. package/dist/esm/components/widgets/DriverCard/DriverPerformanceChart.js +79 -0
  26. package/dist/esm/components/widgets/DriverCard/DriverPerformanceChart.styl.js +7 -0
  27. package/dist/esm/components/widgets/DriverCard/driverPerformanceChartData.js +50 -0
  28. package/dist/esm/components/widgets/DriverMap/DriverIcon/DriverIcon.constants.json.js +6 -0
  29. package/dist/esm/components/widgets/DriverMap/DriverIcon/DriverIcon.js +21 -0
  30. package/dist/esm/components/widgets/DriverMap/DriverIcon/DriverIcon.styl.js +7 -0
  31. package/dist/esm/components/widgets/DriverMap/DriverMap.helpers.js +107 -0
  32. package/dist/esm/components/widgets/DriverMap/DriverMap.js +129 -0
  33. package/dist/esm/components/widgets/DriverMap/DriverMap.styl.js +7 -0
  34. package/dist/esm/components/widgets/DriverMap/driverCategoryIcon.js +194 -0
  35. package/dist/esm/components/widgets/DriverMap/driverMapGeography.js +345 -0
  36. package/dist/esm/components/widgets/DriverMap/driverMapSelection.js +17 -0
  37. package/dist/esm/hooks/index.js +1 -0
  38. package/dist/esm/hooks/useEvent.js +0 -2
  39. package/dist/esm/index.js +7 -0
  40. package/dist/esm/types/src/components/ui/Chart/Chart.d.ts +1 -0
  41. package/dist/esm/types/src/components/ui/Chart/components/BaseChartWrapper.d.ts +2 -1
  42. package/dist/esm/types/src/components/ui/Chart/components/ChartEmptyState/ChartEmptyState.d.ts +14 -0
  43. package/dist/esm/types/src/components/ui/Chart/tools/chartPlotGeometry.d.ts +30 -0
  44. package/dist/esm/types/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.d.ts +1 -1
  45. package/dist/esm/types/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.helpers.d.ts +11 -2
  46. package/dist/esm/types/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.types.d.ts +2 -2
  47. package/dist/esm/types/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.d.ts +15 -0
  48. package/dist/esm/types/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayout.helpers.d.ts +14 -0
  49. package/dist/esm/types/src/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.d.ts +1 -1
  50. package/dist/esm/types/src/components/ui/DropdownMenu/DropdownMenu.d.ts +2 -2
  51. package/dist/esm/types/src/components/ui/Page/PageColumns/PageColumns.d.ts +1 -1
  52. package/dist/esm/types/src/components/ui/TimeRangeControls/TimeRangeControls.d.ts +5 -7
  53. package/dist/esm/types/src/components/ui/WorldMap/WorldMap.d.ts +4 -0
  54. package/dist/esm/types/src/components/ui/WorldMap/index.d.ts +2 -0
  55. package/dist/esm/types/src/components/widgets/DriverCard/DriverCard.d.ts +9 -0
  56. package/dist/esm/types/src/components/widgets/DriverCard/DriverPerformanceChart.d.ts +5 -0
  57. package/dist/esm/types/src/components/widgets/DriverCard/driverPerformanceChartData.d.ts +7 -0
  58. package/dist/esm/types/src/components/widgets/DriverCard/index.d.ts +1 -0
  59. package/dist/esm/types/src/components/widgets/DriverMap/DriverIcon/DriverIcon.d.ts +17 -0
  60. package/dist/esm/types/src/components/widgets/DriverMap/DriverMap.d.ts +8 -0
  61. package/dist/esm/types/src/components/widgets/DriverMap/DriverMap.helpers.d.ts +21 -0
  62. package/dist/esm/types/src/components/widgets/DriverMap/driverCategoryIcon.d.ts +1 -0
  63. package/dist/esm/types/src/components/widgets/DriverMap/driverMapGeography.d.ts +80 -0
  64. package/dist/esm/types/src/components/widgets/DriverMap/driverMapSelection.d.ts +3 -0
  65. package/dist/esm/types/src/components/widgets/DriverMap/index.d.ts +6 -0
  66. package/dist/esm/types/src/docs/pages/DriverMapPage.d.ts +1 -0
  67. package/dist/esm/types/src/docs/pages/PageColumnsPage.d.ts +1 -0
  68. package/dist/esm/types/src/docs/pages/WorldMapPage.d.ts +1 -0
  69. package/dist/esm/types/src/docs/registry.d.ts +1 -1
  70. package/dist/esm/types/src/hooks/index.d.ts +1 -0
  71. package/dist/esm/types/src/index.d.ts +3 -0
  72. package/package.json +1 -1
  73. package/src/components/ui/Chart/Chart.tsx +5 -0
  74. package/src/components/ui/Chart/components/BaseChartWrapper.tsx +8 -41
  75. package/src/components/ui/Chart/components/ChartEmptyState/ChartEmptyState.styl +60 -0
  76. package/src/components/ui/Chart/components/ChartEmptyState/ChartEmptyState.styl.d.ts +15 -0
  77. package/src/components/ui/Chart/components/ChartEmptyState/ChartEmptyState.tsx +66 -0
  78. package/src/components/ui/Chart/tools/chartPlotGeometry.ts +89 -0
  79. package/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.helpers.ts +44 -2
  80. package/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.tsx +14 -1
  81. package/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.types.ts +2 -3
  82. package/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.styl +21 -0
  83. package/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.styl.d.ts +9 -0
  84. package/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayer.tsx +285 -0
  85. package/src/components/ui/ChartAreaInteractive/TimeRangeBrushLayout.helpers.ts +55 -0
  86. package/src/components/ui/ChartAreaInteractive/overlays/IntervalsOverlay/IntervalsOverlay.hooks.ts +1 -0
  87. package/src/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.styl +2 -7
  88. package/src/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.styl.d.ts +0 -1
  89. package/src/components/ui/ChartAreaInteractive/overlays/PinOverlay/PinOverlay.tsx +7 -71
  90. package/src/components/ui/ChartAreaInteractive/overlays/ThresholdsOverlay/ThresholdsOverlay.hooks.ts +1 -0
  91. package/src/components/ui/ChartAreaInteractive/overlays/useChartYRange.ts +2 -3
  92. package/src/components/ui/Chat/ChatSheet/ChatSelector.styl +3 -1
  93. package/src/components/ui/Chat/ChatSheet/ChatSelector.tsx +1 -1
  94. package/src/components/ui/DropdownMenu/DropdownMenu.tsx +4 -0
  95. package/src/components/ui/Page/PageColumns/PageColumns.tsx +1 -1
  96. package/src/components/ui/TimeRangeControls/TimeRangeControls.tsx +16 -17
  97. package/src/components/ui/WorldMap/WorldMap.styl +11 -0
  98. package/src/components/ui/WorldMap/WorldMap.styl.d.ts +7 -0
  99. package/src/components/ui/WorldMap/WorldMap.tsx +22 -0
  100. package/src/components/ui/WorldMap/index.ts +2 -0
  101. package/src/components/ui/WorldMap/map.svg +4337 -0
  102. package/src/components/ui/WorldMap/mapAspect.mixin.styl +3 -0
  103. package/src/components/ui/WorldMap/mapAspect.mixin.styl.d.ts +2 -0
  104. package/src/components/widgets/DriverCard/DriverCard.styl +169 -0
  105. package/src/components/widgets/DriverCard/DriverCard.styl.d.ts +40 -0
  106. package/src/components/widgets/DriverCard/DriverCard.tsx +219 -0
  107. package/src/components/widgets/DriverCard/DriverPerformanceChart.styl +43 -0
  108. package/src/components/widgets/DriverCard/DriverPerformanceChart.styl.d.ts +13 -0
  109. package/src/components/widgets/DriverCard/DriverPerformanceChart.tsx +150 -0
  110. package/src/components/widgets/DriverCard/driverPerformanceChartData.ts +64 -0
  111. package/src/components/widgets/DriverCard/index.ts +1 -0
  112. package/src/components/widgets/DriverMap/DriverIcon/DriverIcon.constants.json +3 -0
  113. package/src/components/widgets/DriverMap/DriverIcon/DriverIcon.styl +125 -0
  114. package/src/components/widgets/DriverMap/DriverIcon/DriverIcon.styl.d.ts +22 -0
  115. package/src/components/widgets/DriverMap/DriverIcon/DriverIcon.tsx +79 -0
  116. package/src/components/widgets/DriverMap/DriverMap.helpers.ts +164 -0
  117. package/src/components/widgets/DriverMap/DriverMap.styl +50 -0
  118. package/src/components/widgets/DriverMap/DriverMap.styl.d.ts +12 -0
  119. package/src/components/widgets/DriverMap/DriverMap.tsx +212 -0
  120. package/src/components/widgets/DriverMap/driverCategoryIcon.tsx +277 -0
  121. package/src/components/widgets/DriverMap/driverMapGeography.ts +478 -0
  122. package/src/components/widgets/DriverMap/driverMapSelection.ts +23 -0
  123. package/src/components/widgets/DriverMap/index.ts +16 -0
  124. package/src/docs/config/webpack.config.js +25 -9
  125. package/src/docs/pages/ChartAreaInteractivePage.tsx +2 -3
  126. package/src/docs/pages/DriverMapPage.tsx +268 -0
  127. package/src/docs/pages/PageColumnsPage.tsx +92 -0
  128. package/src/docs/pages/TimeRangeControlsPage.tsx +2 -3
  129. package/src/docs/pages/TooltipPage.tsx +14 -10
  130. package/src/docs/pages/WorldMapPage.styl +14 -0
  131. package/src/docs/pages/WorldMapPage.styl.d.ts +8 -0
  132. package/src/docs/pages/WorldMapPage.tsx +26 -0
  133. package/src/docs/registry.ts +18 -5
  134. package/src/hooks/index.ts +1 -0
  135. package/src/hooks/useEvent.ts +0 -2
  136. package/src/index.ts +3 -0
@@ -4,7 +4,6 @@ import { useEffect, useRef, useState } from 'react';
4
4
  import { BaseChartWrapper } from '#uilib/components/ui/Chart/components';
5
5
  import { BaseChartWrapperProps } from '#uilib/components/ui/Chart/components/BaseChartWrapper';
6
6
  import { useDebounceCallback } from '#uilib/hooks/useDebounceCallback';
7
- import useDragElem, { Delta } from '#uilib/hooks/useDragElem';
8
7
  import { ChevronsLeftRight } from 'lucide-react';
9
8
 
10
9
  import CAS from '../../ChartAreaInteractive.styl';
@@ -23,7 +22,7 @@ export function PinOverlay({
23
22
  baseChartProps,
24
23
  pinMonth,
25
24
  onPinMonthChange,
26
- onPreviewMonthChange,
25
+ onPreviewMonthChange: _onPreviewMonthChange,
27
26
  className,
28
27
  }: PinOverlayProps) {
29
28
  const { chartData } = baseChartProps;
@@ -32,12 +31,9 @@ export function PinOverlay({
32
31
  const pinPlaceholderRef = useRef<HTMLDivElement>(null);
33
32
  const pinContainerRef = useRef<HTMLDivElement>(null);
34
33
 
35
- const [isDraggingPin, setIsDraggingPin] = useState(false);
36
- const [isPinAnimating, setIsPinAnimating] = useState(true);
37
34
  const [isPinHovered, setIsPinHovered] = useState(false);
38
35
 
39
36
  const pinPosRef = useRef<number>(0);
40
- const containerRectRef = useRef<DOMRect | null>(null);
41
37
  const currPinMonthRef = useRef<string | undefined>(pinMonth);
42
38
 
43
39
  const debouncedOnPinMonthChange = useDebounceCallback(
@@ -61,7 +57,6 @@ export function PinOverlay({
61
57
  }
62
58
  };
63
59
 
64
- // Get full month and year for pin position to send to parent component
65
60
  const getPinMonthAndYear = (position?: number) => {
66
61
  if (!chartData.length) return null;
67
62
 
@@ -79,7 +74,6 @@ export function PinOverlay({
79
74
  }
80
75
  };
81
76
 
82
- // Handle chart click to move pin to specific position
83
77
  const snapPinToPosition = (
84
78
  eventX: number,
85
79
  needMonthUpdate: boolean = true,
@@ -91,7 +85,6 @@ export function PinOverlay({
91
85
  const effectiveLeft = pinContainerRect.left;
92
86
  const effectiveWidth = pinContainerRect.width;
93
87
 
94
- // Calculate relative position within plotted area
95
88
  const relativeX = eventX - effectiveLeft;
96
89
  const rawPercentage =
97
90
  effectiveWidth > 0 ? (relativeX / effectiveWidth) * 100 : 0;
@@ -100,7 +93,6 @@ export function PinOverlay({
100
93
  Math.min(100, isNaN(rawPercentage) ? 0 : rawPercentage),
101
94
  );
102
95
 
103
- // Snap to nearest data point
104
96
  const totalPoints = chartData.length;
105
97
  if (totalPoints > 1) {
106
98
  const nearestIndex = Math.round((percentage / 100) * (totalPoints - 1));
@@ -110,12 +102,10 @@ export function PinOverlay({
110
102
  setPinPosition(isNaN(snappedPercentage) ? 0 : snappedPercentage);
111
103
 
112
104
  if (needMonthUpdate) {
113
- // Update news for all months (historical and forecast)
114
105
  const monthAndYear = getPinMonthAndYear();
115
106
  if (monthAndYear) {
116
107
  const isNewMonth = monthAndYear !== currPinMonthRef.current;
117
108
  if (isNewMonth) currPinMonthRef.current = monthAndYear;
118
- // When immediate (e.g. dragEnd), always notify parent so showFutureOutlook is correct
119
109
  if (immediateMonthUpdate) {
120
110
  onPinMonthChange?.(monthAndYear);
121
111
  } else if (isNewMonth) {
@@ -126,11 +116,9 @@ export function PinOverlay({
126
116
  }
127
117
  };
128
118
 
129
- // Update pin position when pinMonth prop changes
130
119
  useEffect(() => {
131
120
  if (!pinMonth || !chartData.length) return;
132
121
 
133
- // Find the data point index for the given month
134
122
  const dataPointIndex = chartData.findIndex(point => {
135
123
  const date = new Date(point.date);
136
124
  const month = date.toLocaleDateString('en-US', { month: 'short' });
@@ -147,59 +135,10 @@ export function PinOverlay({
147
135
  }
148
136
  }, [pinMonth, chartData]);
149
137
 
150
- useDragElem({
151
- elem: [chartRef],
152
- onDragStart: () => {
153
- setIsDraggingPin(true);
154
-
155
- containerRectRef.current =
156
- pinContainerRef.current?.getBoundingClientRect() || null;
157
- },
158
- onDrag: (delta: Delta) => {
159
- if (pinRef.current) {
160
- const containerRect = containerRectRef.current;
161
- if (!containerRect) return;
162
-
163
- const pinCurrentLeft = (pinPosRef.current / 100) * containerRect.width;
164
-
165
- const leftLimit = -pinCurrentLeft;
166
- const rightLimit = containerRect.width - pinCurrentLeft;
167
-
168
- const clampedDeltaX = Math.max(
169
- leftLimit,
170
- Math.min(rightLimit, delta.x),
171
- );
172
-
173
- setIsPinAnimating(false);
174
- pinRef.current.style.transform = `translateX(${clampedDeltaX}px)`;
175
-
176
- // Calculate preview month based on current drag position
177
- if (onPreviewMonthChange && chartData.length > 0) {
178
- const newPositionPixels = pinCurrentLeft + clampedDeltaX;
179
- const newPercentage = (newPositionPixels / containerRect.width) * 100;
180
- const clampedPercentage = Math.max(0, Math.min(100, newPercentage));
181
- const previewMonth = getPinMonthAndYear(clampedPercentage);
182
-
183
- if (previewMonth) {
184
- onPreviewMonthChange(previewMonth);
185
- }
186
- }
187
- }
188
- },
189
- onDragEnd: (e: PointerEvent) => {
190
- setIsDraggingPin(false);
191
- setTimeout(() => setIsPinAnimating(true), 200);
192
- if (pinRef.current) pinRef.current.style.transform = '';
193
- // Snap first so onPinMonthChange runs before we clear preview (avoids showFutureOutlook fallback)
194
- snapPinToPosition(e.clientX, true, true);
195
- if (onPreviewMonthChange) {
196
- onPreviewMonthChange(undefined);
197
- }
198
- },
199
- });
200
-
201
- const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
202
- if ((e.target as HTMLElement).tagName !== 'svg') return;
138
+ const onChartClick = (e: React.MouseEvent<HTMLDivElement>) => {
139
+ if (e.button !== 0) return;
140
+ const target = e.target as HTMLElement;
141
+ if (!target.closest?.('svg')) return;
203
142
  snapPinToPosition(e.clientX, true, false);
204
143
  };
205
144
 
@@ -220,7 +159,6 @@ export function PinOverlay({
220
159
  </div>
221
160
  </div>
222
161
  </div>
223
- {/* Hover placeholder for easier pin access - on top of everything */}
224
162
  <div
225
163
  className={S.pinPlaceholder}
226
164
  style={{ left: `${pinPosRef.current}%` }}
@@ -236,12 +174,10 @@ export function PinOverlay({
236
174
  className={cn(
237
175
  className,
238
176
  S.root,
239
- isDraggingPin && S.pinDragging,
240
- isPinAnimating && S.pinAnimating,
177
+ S.pinAnimating,
241
178
  isPinHovered && S.pinHovered,
242
179
  )}
243
- onPointerDown={onPointerDown}
244
- // onClick={e => snapPinToPosition(e.clientX)}
180
+ onClick={onChartClick}
245
181
  ref={chartRef}
246
182
  >
247
183
  <BaseChartWrapper
@@ -127,6 +127,7 @@ export function useThresholdButton({
127
127
 
128
128
  const handleDragStart = useCallback(
129
129
  (e: PointerEvent) => {
130
+ e.stopPropagation();
130
131
  initialValueRef.current = initialValue;
131
132
  startYRef.current = e.clientY;
132
133
  setIsDragging(true);
@@ -42,10 +42,9 @@ export function useChartYRange({
42
42
  Object.entries(point).forEach(([key, value]) => {
43
43
  if (key === 'date') return;
44
44
 
45
- // When selectedForecastId is provided, scale only from selected forecast + its quantile band
46
- // (exclude historical, other forecasts, and other forecasts' quantile values)
45
+ // When selectedForecastId is provided, scale from historical + selected forecast + its
46
+ // quantile band (exclude other forecasts and their quantile values only).
47
47
  if (forecastId !== undefined) {
48
- if (key === 'historical') return;
49
48
  if (key.startsWith('forecast_') && key !== `forecast_${forecastId}`)
50
49
  return;
51
50
  // Exclude q{quantile}_{otherAnalysisId} - only include selected forecast's quantiles
@@ -18,7 +18,9 @@
18
18
  .deleteBtn
19
19
  flex-shrink 0
20
20
  border-radius 50px
21
- opacity 0.3
21
+ opacity 0
22
+ pointer-events none
22
23
 
23
24
  .wrapper:hover .deleteBtn
24
25
  opacity 1
26
+ pointer-events auto
@@ -54,7 +54,7 @@ export function ChatSelector({
54
54
  (firstMessage.text.length > 30 ? '...' : '')
55
55
  );
56
56
  }
57
- return `Chat ${chat.session_id}`;
57
+ return 'New chat';
58
58
  };
59
59
 
60
60
  return (
@@ -44,6 +44,7 @@ function DropdownMenuTrigger({ ...props }: DropdownMenuTriggerProps) {
44
44
  function DropdownMenuContent({
45
45
  className,
46
46
  sideOffset = 4,
47
+ collisionPadding = 8,
47
48
  elevation = 'sm',
48
49
  ...props
49
50
  }: DropdownMenuContentProps) {
@@ -52,6 +53,7 @@ function DropdownMenuContent({
52
53
  <DropdownMenuPrimitive.Content
53
54
  data-slot="dropdown-menu-content"
54
55
  sideOffset={sideOffset}
56
+ collisionPadding={collisionPadding}
55
57
  className={cn(S.content, S[`elevation-${elevation}`], className)}
56
58
  {...props}
57
59
  />
@@ -201,11 +203,13 @@ function DropdownMenuSubTrigger({
201
203
 
202
204
  function DropdownMenuSubContent({
203
205
  className,
206
+ collisionPadding = 8,
204
207
  ...props
205
208
  }: DropdownMenuSubContentProps) {
206
209
  return (
207
210
  <DropdownMenuPrimitive.SubContent
208
211
  data-slot="dropdown-menu-sub-content"
212
+ collisionPadding={collisionPadding}
209
213
  className={cn(S.subContent, className)}
210
214
  {...props}
211
215
  />
@@ -8,7 +8,7 @@ export function PageColumns({
8
8
  className,
9
9
  }: {
10
10
  columns: React.ReactNode[];
11
- fill: 'left' | 'right' | 'all';
11
+ fill?: 'left' | 'right' | 'all';
12
12
  className?: string;
13
13
  }) {
14
14
  return (
@@ -14,22 +14,25 @@ import {
14
14
 
15
15
  import { TIME_RANGES } from './TimeRangeControls.constants';
16
16
  import S from './TimeRangeControls.styl';
17
- import { TimeRange } from './TimeRangeControls.types';
17
+
18
+ function toggleValueForTimeRange(timeRange: string): string {
19
+ return (TIME_RANGES as readonly string[]).includes(timeRange)
20
+ ? timeRange
21
+ : '';
22
+ }
23
+
24
+ export type TimeRangeControlsProps = {
25
+ timeRange: string;
26
+ onTimeRangeChange: (range: string) => void;
27
+ loading?: boolean;
28
+ };
18
29
 
19
30
  export const TimeRangeControls = memo(
20
- ({
21
- timeRange,
22
- onTimeRangeChange,
23
- loading,
24
- }: {
25
- timeRange: TimeRange;
26
- onTimeRangeChange: (range: string) => void;
27
- loading?: boolean;
28
- }) => (
31
+ ({ timeRange, onTimeRangeChange, loading }: TimeRangeControlsProps) => (
29
32
  <div className={S.timeRangeContainer}>
30
33
  <ToggleGroup
31
34
  type="single"
32
- value={timeRange}
35
+ value={toggleValueForTimeRange(timeRange)}
33
36
  onValueChange={onTimeRangeChange}
34
37
  variant="outline"
35
38
  disabled={loading}
@@ -56,13 +59,9 @@ export const TimeRangeSelect = memo(
56
59
  timeRange,
57
60
  onTimeRangeChange,
58
61
  loading,
59
- }: {
60
- timeRange: TimeRange;
61
- onTimeRangeChange: (range: string) => void;
62
- loading: boolean;
63
- }) => (
62
+ }: TimeRangeControlsProps & { loading: boolean }) => (
64
63
  <Select
65
- value={timeRange}
64
+ value={toggleValueForTimeRange(timeRange) || undefined}
66
65
  onValueChange={onTimeRangeChange}
67
66
  disabled={loading}
68
67
  >
@@ -0,0 +1,11 @@
1
+ @import './mapAspect.mixin.styl'
2
+
3
+ .worldMap
4
+ display block
5
+ width 100%
6
+ height 100%
7
+ mapAspect()
8
+ object-fit contain
9
+ object-position center
10
+ pointer-events none
11
+ user-select none
@@ -0,0 +1,7 @@
1
+ // This file is automatically generated.
2
+ // Please do not change this file!
3
+ interface CssExports {
4
+ 'worldMap': string;
5
+ }
6
+ export const cssExports: CssExports;
7
+ export default cssExports;
@@ -0,0 +1,22 @@
1
+ import cn from 'classnames';
2
+
3
+ import S from './WorldMap.styl';
4
+ import mapBgUrl from './map.svg';
5
+
6
+ export type WorldMapProps = {
7
+ className?: string;
8
+ };
9
+
10
+ export function WorldMap({ className }: WorldMapProps) {
11
+ const src = mapBgUrl as unknown as string;
12
+
13
+ return (
14
+ <img
15
+ alt=""
16
+ className={cn(S.worldMap, className)}
17
+ decoding="async"
18
+ draggable={false}
19
+ src={src}
20
+ />
21
+ );
22
+ }
@@ -0,0 +1,2 @@
1
+ export { WorldMap } from './WorldMap';
2
+ export type { WorldMapProps } from './WorldMap';