@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
@@ -0,0 +1,268 @@
1
+ import { useState } from 'react';
2
+
3
+ import { PageColumns, PageContentSection } from '#uilib/components/ui/Page';
4
+ import { Switch } from '#uilib/components/ui/Switch';
5
+ import { DriverCard } from '#uilib/components/widgets/DriverCard';
6
+ import {
7
+ type DriverData,
8
+ DriverMap,
9
+ getPreciseCoordinates,
10
+ } from '#uilib/components/widgets/DriverMap';
11
+ import { CaretLeft, CaretRight } from '@phosphor-icons/react';
12
+
13
+ import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
14
+ import { DocsHeaderActions } from '../docsHeaderActions';
15
+
16
+ /** ISO `YYYY-MM` keys, sorted ascending → series for DriverPerformanceChart. */
17
+ function buildMonthlySeries(
18
+ seed: number,
19
+ months: number,
20
+ drift = 0.15,
21
+ ): NonNullable<DriverData['normalized_series']> {
22
+ const out: NonNullable<DriverData['normalized_series']> = {};
23
+ const start = new Date('2019-01-01');
24
+ for (let i = 0; i < months; i++) {
25
+ const d = new Date(start);
26
+ d.setMonth(d.getMonth() + i);
27
+ const key = d.toISOString().slice(0, 7);
28
+ out[key] =
29
+ seed + Math.sin(i * 0.35) * 14 + Math.cos(i * 0.11) * 7 + i * drift;
30
+ }
31
+ return out;
32
+ }
33
+
34
+ function DriverPager({
35
+ drivers,
36
+ selectedDriver,
37
+ onSelect,
38
+ }: {
39
+ drivers: DriverData[];
40
+ selectedDriver: DriverData | null;
41
+ onSelect: (d: DriverData | null) => void;
42
+ }) {
43
+ const index = selectedDriver
44
+ ? drivers.findIndex(d => d.id === selectedDriver.id)
45
+ : -1;
46
+ const total = drivers.length;
47
+ const safeIndex = index >= 0 ? index : 0;
48
+ const displayIndex = index >= 0 ? index + 1 : 0;
49
+
50
+ const go = (nextIdx: number) => {
51
+ if (total === 0) {
52
+ onSelect(null);
53
+ return;
54
+ }
55
+ const wrapped = ((nextIdx % total) + total) % total;
56
+ onSelect(drivers[wrapped] ?? null);
57
+ };
58
+
59
+ return (
60
+ <div
61
+ style={{
62
+ display: 'flex',
63
+ alignItems: 'center',
64
+ gap: 6,
65
+ fontSize: 12,
66
+ color: 'var(--muted-foreground)',
67
+ }}
68
+ >
69
+ <button
70
+ type="button"
71
+ aria-label="Previous driver"
72
+ disabled={total === 0 || !selectedDriver}
73
+ onClick={() => go(safeIndex - 1)}
74
+ style={{
75
+ display: 'inline-flex',
76
+ alignItems: 'center',
77
+ justifyContent: 'center',
78
+ padding: 4,
79
+ borderRadius: 6,
80
+ border: '1px solid var(--border)',
81
+ background: 'var(--background)',
82
+ cursor: total && selectedDriver ? 'pointer' : 'default',
83
+ opacity: total && selectedDriver ? 1 : 0.45,
84
+ }}
85
+ >
86
+ <CaretLeft size={14} />
87
+ </button>
88
+ <span
89
+ aria-live="polite"
90
+ style={{ minWidth: '2.5rem', textAlign: 'center' }}
91
+ >
92
+ {displayIndex}/{total}
93
+ </span>
94
+ <button
95
+ type="button"
96
+ aria-label="Next driver"
97
+ disabled={total === 0 || !selectedDriver}
98
+ onClick={() => go(safeIndex + 1)}
99
+ style={{
100
+ display: 'inline-flex',
101
+ alignItems: 'center',
102
+ justifyContent: 'center',
103
+ padding: 4,
104
+ borderRadius: 6,
105
+ border: '1px solid var(--border)',
106
+ background: 'var(--background)',
107
+ cursor: total && selectedDriver ? 'pointer' : 'default',
108
+ opacity: total && selectedDriver ? 1 : 0.45,
109
+ }}
110
+ >
111
+ <CaretRight size={14} />
112
+ </button>
113
+ </div>
114
+ );
115
+ }
116
+
117
+ // Drivers ordered for pager: long title + USA→World, EU negative + decimal %, Asia positive + large %, global negative.
118
+ const MOCK_DRIVERS: DriverData[] = [
119
+ {
120
+ id: 'mock-us-world-long-title',
121
+ name: 'North American manufacturing PMI composite — orders, production, employment, supplier deliveries (SA, quarterly)',
122
+ region: ['North America', 'United States of America'],
123
+ category: 'Manufacturing',
124
+ isPublic: true,
125
+ importance: 84.2,
126
+ direction: 0.55,
127
+ lag: '1 quarter(s)',
128
+ coordinates: getPreciseCoordinates('United States of America'),
129
+ src_region: {
130
+ name: 'United States of America',
131
+ coordinates: { x: 0, y: 0 },
132
+ },
133
+ tgt_region: {
134
+ name: 'World',
135
+ coordinates: { x: 0, y: 0 },
136
+ },
137
+ rawImportance: { overall: { mean: 96 } },
138
+ summary:
139
+ 'U.S. factory activity leads global manufacturing cycles by roughly one quarter: strength here typically coincides with wider world demand, with inventory and orders transmitting across trade links.',
140
+ normalized_series: buildMonthlySeries(48, 42, 0.22),
141
+ },
142
+ {
143
+ id: 'mock-europe-germany-negative',
144
+ name: 'German industrial orders (domestic + foreign)',
145
+ region: ['Europe', 'Germany'],
146
+ category: 'Industrial',
147
+ isPublic: true,
148
+ importance: 81.6,
149
+ direction: -0.42,
150
+ lag: '2 month(s)',
151
+ coordinates: getPreciseCoordinates('Germany'),
152
+ summary:
153
+ 'New orders in Germany are a timely read on euro-area capex and export pipelines; pullbacks often precede broader EU production softness before PMI surveys fully reflect the turn.',
154
+ normalized_series: buildMonthlySeries(62, 42, -0.12),
155
+ },
156
+ {
157
+ id: 'mock-asia-japan-positive',
158
+ name: 'Japan machinery orders (core private-sector ex. ships)',
159
+ region: ['Asia', 'Japan'],
160
+ category: 'market',
161
+ isPublic: true,
162
+ importance: 77,
163
+ direction: 0.28,
164
+ lag: '~1 month(s)',
165
+ coordinates: getPreciseCoordinates('Japan'),
166
+ rawImportance: { overall: { mean: 99 } },
167
+ summary:
168
+ 'Core machinery orders capture forward-looking domestic investment and Asia supply-chain capex; spikes cluster around fiscal years and robotics/automation cycles.',
169
+ normalized_series: buildMonthlySeries(55, 42, 0.18),
170
+ },
171
+ {
172
+ id: 'mock-global-risk-negative',
173
+ name: 'Global equity risk appetite (cross-asset composite)',
174
+ region: ['World'],
175
+ category: 'Trade',
176
+ isPublic: true,
177
+ importance: 66.5,
178
+ direction: -0.05,
179
+ lag: 'Unknown',
180
+ coordinates: getPreciseCoordinates('World'),
181
+ rawImportance: { overall: { mean: 91 } },
182
+ summary:
183
+ 'Combines credit spreads, vol surfaces, and cyclical equity factor tilt into a single read on whether markets are paying for growth or for safety; sharp deterioration often coincides with funding stress.',
184
+ normalized_series: buildMonthlySeries(40, 42, 0.08),
185
+ },
186
+ ];
187
+
188
+ export default function DriverMapPage() {
189
+ const [selectedDriver, setSelectedDriver] = useState<DriverData | null>(
190
+ MOCK_DRIVERS[0],
191
+ );
192
+ const [isLoading, setIsLoading] = useState(false);
193
+ // DriverCard checks `inQueue` before `isLoading` — toggles queue empty state independent of mocks.
194
+ const [inQueue, setInQueue] = useState(false);
195
+
196
+ return (
197
+ <>
198
+ <AppPageHeader
199
+ breadcrumbs={[{ label: 'Driver map' }]}
200
+ title="DriverMap & DriverCard"
201
+ subheader="World map with driver badges and the driver detail card — map clicks and the selector sync selection; arrow keys navigate the map."
202
+ actions={<DocsHeaderActions />}
203
+ />
204
+ <PageContentSection>
205
+ <div
206
+ style={{
207
+ display: 'flex',
208
+ flexWrap: 'wrap',
209
+ alignItems: 'center',
210
+ gap: 16,
211
+ marginBottom: 16,
212
+ }}
213
+ >
214
+ <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
215
+ <Switch
216
+ id="loading-overlay"
217
+ checked={isLoading}
218
+ onCheckedChange={setIsLoading}
219
+ />
220
+ <label htmlFor="loading-overlay">Loading state</label>
221
+ </div>
222
+ <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
223
+ <Switch
224
+ id="in-queue"
225
+ checked={inQueue}
226
+ onCheckedChange={setInQueue}
227
+ />
228
+ <label htmlFor="in-queue">In queue (empty state)</label>
229
+ </div>
230
+ </div>
231
+ <PageColumns
232
+ fill="left"
233
+ columns={[
234
+ <div
235
+ key="map"
236
+ style={{
237
+ width: '100%',
238
+ maxWidth: '100%',
239
+ // @ts-expect-error CSS custom property on div
240
+ '--shimmer-color': 'var(--page-color)',
241
+ }}
242
+ >
243
+ <DriverMap
244
+ drivers={MOCK_DRIVERS}
245
+ isLoading={isLoading}
246
+ selectedDriver={selectedDriver}
247
+ setSelectedDriver={setSelectedDriver}
248
+ />
249
+ </div>,
250
+ <DriverCard
251
+ key="card"
252
+ selectedDriver={selectedDriver}
253
+ isLoading={isLoading}
254
+ inQueue={inQueue}
255
+ driverSelector={
256
+ <DriverPager
257
+ drivers={MOCK_DRIVERS}
258
+ selectedDriver={selectedDriver}
259
+ onSelect={setSelectedDriver}
260
+ />
261
+ }
262
+ />,
263
+ ]}
264
+ />
265
+ </PageContentSection>
266
+ </>
267
+ );
268
+ }
@@ -0,0 +1,92 @@
1
+ import type { CSSProperties } from 'react';
2
+
3
+ import { PageColumns, PageContentSection } from '#uilib/components/ui/Page';
4
+
5
+ import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
6
+ import { DocsHeaderActions } from '../docsHeaderActions';
7
+
8
+ const demoBlockStyle: CSSProperties = {
9
+ margin: 0,
10
+ padding: 'var(--p-4)',
11
+ borderRadius: 'var(--p-3)',
12
+ border: '1px solid var(--border)',
13
+ backgroundColor: 'var(--muted)',
14
+ };
15
+
16
+ function ColumnDemo({ label }: { label: string }) {
17
+ return <p style={demoBlockStyle}>{label}</p>;
18
+ }
19
+
20
+ export default function PageColumnsPage() {
21
+ return (
22
+ <>
23
+ <AppPageHeader
24
+ breadcrumbs={[{ label: 'PageColumns' }]}
25
+ title="PageColumns"
26
+ subheader="Responsive row of columns; fill prop controls which column(s) grow past the default width cap on wide viewports."
27
+ actions={<DocsHeaderActions />}
28
+ />
29
+ <PageContentSection
30
+ style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}
31
+ >
32
+ <section>
33
+ <h3 style={{ marginBottom: '0.75rem' }}>
34
+ fill=&quot;all&quot; (default)
35
+ </h3>
36
+ <p
37
+ style={{
38
+ marginBottom: '1rem',
39
+ color: 'var(--muted-foreground)',
40
+ }}
41
+ >
42
+ Both columns grow; max-width cap is removed on stretched columns.
43
+ </p>
44
+ <PageColumns
45
+ columns={[
46
+ <ColumnDemo key="a" label="Column A" />,
47
+ <ColumnDemo key="b" label="Column B" />,
48
+ ]}
49
+ />
50
+ </section>
51
+ <section>
52
+ <h3 style={{ marginBottom: '0.75rem' }}>fill=&quot;left&quot;</h3>
53
+ <p
54
+ style={{
55
+ marginBottom: '1rem',
56
+ color: 'var(--muted-foreground)',
57
+ }}
58
+ >
59
+ First column grows; second stays at the default fixed width on wide
60
+ screens.
61
+ </p>
62
+ <PageColumns
63
+ fill="left"
64
+ columns={[
65
+ <ColumnDemo key="a" label="Growing left column" />,
66
+ <ColumnDemo key="b" label="Fixed sidebar" />,
67
+ ]}
68
+ />
69
+ </section>
70
+ <section>
71
+ <h3 style={{ marginBottom: '0.75rem' }}>fill=&quot;right&quot;</h3>
72
+ <p
73
+ style={{
74
+ marginBottom: '1rem',
75
+ color: 'var(--muted-foreground)',
76
+ }}
77
+ >
78
+ Last column grows; first stays at the default fixed width on wide
79
+ screens.
80
+ </p>
81
+ <PageColumns
82
+ fill="right"
83
+ columns={[
84
+ <ColumnDemo key="a" label="Fixed sidebar" />,
85
+ <ColumnDemo key="b" label="Growing right column" />,
86
+ ]}
87
+ />
88
+ </section>
89
+ </PageContentSection>
90
+ </>
91
+ );
92
+ }
@@ -2,13 +2,12 @@ import { useState } from 'react';
2
2
 
3
3
  import { PageContentSection } from '#uilib/components/ui/Page';
4
4
  import { TimeRangeControls } from '#uilib/components/ui/TimeRangeControls';
5
- import type { TimeRange } from '#uilib/components/ui/TimeRangeControls/TimeRangeControls.types';
6
5
 
7
6
  import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
8
7
  import { DocsHeaderActions } from '../docsHeaderActions';
9
8
 
10
9
  export default function TimeRangeControlsPage() {
11
- const [range, setRange] = useState<TimeRange>('1y');
10
+ const [range, setRange] = useState<string>('1y');
12
11
 
13
12
  return (
14
13
  <>
@@ -21,7 +20,7 @@ export default function TimeRangeControlsPage() {
21
20
  <PageContentSection>
22
21
  <TimeRangeControls
23
22
  timeRange={range}
24
- onTimeRangeChange={v => setRange(v as TimeRange)}
23
+ onTimeRangeChange={setRange}
25
24
  loading={false}
26
25
  />
27
26
  </PageContentSection>
@@ -9,6 +9,8 @@ import {
9
9
  import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
10
10
  import { DocsHeaderActions } from '../docsHeaderActions';
11
11
 
12
+ const TOOLTIP_SIDES = ['left', 'top', 'bottom', 'right'] as const;
13
+
12
14
  export default function TooltipPage() {
13
15
  return (
14
16
  <>
@@ -19,16 +21,18 @@ export default function TooltipPage() {
19
21
  actions={<DocsHeaderActions />}
20
22
  />
21
23
  <PageContentSection>
22
- <span>
23
- <Tooltip>
24
- <TooltipTrigger asChild>
25
- <Button type="button" variant="outline">
26
- Hover me
27
- </Button>
28
- </TooltipTrigger>
29
- <TooltipContent>Tooltip text</TooltipContent>
30
- </Tooltip>
31
- </span>
24
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
25
+ {TOOLTIP_SIDES.map(side => (
26
+ <Tooltip key={side}>
27
+ <TooltipTrigger asChild>
28
+ <Button type="button" variant="outline">
29
+ {side.charAt(0).toUpperCase() + side.slice(1)}
30
+ </Button>
31
+ </TooltipTrigger>
32
+ <TooltipContent side={side}>Tooltip opens {side}</TooltipContent>
33
+ </Tooltip>
34
+ ))}
35
+ </div>
32
36
  </PageContentSection>
33
37
  </>
34
38
  );
@@ -0,0 +1,14 @@
1
+ @import '../../components/ui/WorldMap/mapAspect.mixin.styl'
2
+
3
+ .demoFrame
4
+ position relative
5
+ width 100%
6
+ max-width 42rem
7
+ mapAspect()
8
+ border-radius var(--p-4)
9
+ overflow hidden
10
+
11
+ .demoFill
12
+ position absolute
13
+ inset 0
14
+ box-sizing border-box
@@ -0,0 +1,8 @@
1
+ // This file is automatically generated.
2
+ // Please do not change this file!
3
+ interface CssExports {
4
+ 'demoFill': string;
5
+ 'demoFrame': string;
6
+ }
7
+ export const cssExports: CssExports;
8
+ export default cssExports;
@@ -0,0 +1,26 @@
1
+ import { PageContentSection } from '#uilib/components/ui/Page';
2
+ import { WorldMap } from '#uilib/components/ui/WorldMap';
3
+
4
+ import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
5
+ import { DocsHeaderActions } from '../docsHeaderActions';
6
+ import S from './WorldMapPage.styl';
7
+
8
+ export default function WorldMapPage() {
9
+ return (
10
+ <>
11
+ <AppPageHeader
12
+ breadcrumbs={[{ label: 'World map' }]}
13
+ title="WorldMap"
14
+ subheader="Bundled SVG world map for layouts such as DriverMap — optional className for positioning."
15
+ actions={<DocsHeaderActions />}
16
+ />
17
+ <PageContentSection>
18
+ <div className={S.demoFrame}>
19
+ <div className={S.demoFill}>
20
+ <WorldMap />
21
+ </div>
22
+ </div>
23
+ </PageContentSection>
24
+ </>
25
+ );
26
+ }
@@ -13,6 +13,7 @@ export const DOC_SECTION_ORDER = [
13
13
  'Feedback',
14
14
  'Layout',
15
15
  'Navigation',
16
+ 'Widgets',
16
17
  'Overlays',
17
18
  'Data display',
18
19
  'Charts',
@@ -115,10 +116,10 @@ export const DOC_REGISTRY: DocEntry[] = [
115
116
  load: () => import('./pages/DialogPage'),
116
117
  },
117
118
  {
118
- slug: 'drawer',
119
- title: 'Drawer',
120
- section: 'Overlays',
121
- load: () => import('./pages/DrawerPage'),
119
+ slug: 'driver-map',
120
+ title: 'DriverMap & DriverCard',
121
+ section: 'Widgets',
122
+ load: () => import('./pages/DriverMapPage'),
122
123
  },
123
124
  {
124
125
  slug: 'dropdown-menu',
@@ -222,6 +223,12 @@ export const DOC_REGISTRY: DocEntry[] = [
222
223
  section: 'Layout',
223
224
  load: () => import('./pages/PagePage'),
224
225
  },
226
+ {
227
+ slug: 'page-columns',
228
+ title: 'PageColumns',
229
+ section: 'Layout',
230
+ load: () => import('./pages/PageColumnsPage'),
231
+ },
225
232
  {
226
233
  slug: 'page-footer',
227
234
  title: 'PageFooter',
@@ -286,7 +293,7 @@ export const DOC_REGISTRY: DocEntry[] = [
286
293
  {
287
294
  slug: 'sidebar-datasets-items-grouped',
288
295
  title: 'SidebarDatasetsItemsGrouped',
289
- section: 'Navigation',
296
+ section: 'Widgets',
290
297
  load: () => import('./pages/SidebarDatasetsItemsGroupedPage'),
291
298
  },
292
299
  {
@@ -373,6 +380,12 @@ export const DOC_REGISTRY: DocEntry[] = [
373
380
  section: 'Media',
374
381
  load: () => import('./pages/VimeoEmbedPage'),
375
382
  },
383
+ {
384
+ slug: 'world-map',
385
+ title: 'WorldMap',
386
+ section: 'Media',
387
+ load: () => import('./pages/WorldMapPage'),
388
+ },
376
389
  ];
377
390
 
378
391
  export const docPageComponents: Record<
@@ -1 +1,2 @@
1
1
  export { useIsMobile } from './useIsMobile';
2
+ export { default as useEvent, type UseEventParams } from './useEvent';
@@ -20,11 +20,9 @@ export default function useEvent({
20
20
  const callbackRef = useRef(callback);
21
21
  callbackRef.current = callback;
22
22
 
23
- // Track when elem.current changes to force effect re-run
24
23
  const [elemKey, setElemKey] = useState(0);
25
24
  const prevElemRef = useRef<HTMLElement | null>(null);
26
25
 
27
- // Watch for elem.current changes and update state to trigger main effect re-run
28
26
  useEffect(() => {
29
27
  const currentElem = Array.isArray(elem)
30
28
  ? elem.find(ref => ref?.current)?.current || null
package/src/index.ts CHANGED
@@ -58,8 +58,11 @@ export * from './components/ui/Toggle';
58
58
  export * from './components/ui/ToggleGroup';
59
59
  export * from './components/ui/Tooltip';
60
60
  export * from './components/ui/VimeoEmbed';
61
+ export * from './components/ui/WorldMap';
61
62
  export * from './components/ui/WorkspaceAppSwitcher';
62
63
  export * from './components/widgets/SidebarDatasetsItemsGrouped';
64
+ export * from './components/widgets/DriverCard';
65
+ export * from './components/widgets/DriverMap';
63
66
  export * from './components/widgets/SybilionAppHeader';
64
67
  export * from './components/widgets/SybilionAuthLayout';
65
68
  export * from './components/widgets/SybilionSignInPanel';