@dxos/react-ui-geo 0.8.4-main.b97322e → 0.8.4-main.dedc0f3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/lib/browser/index.mjs +173 -145
  2. package/dist/lib/browser/index.mjs.map +3 -3
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +173 -145
  5. package/dist/lib/node-esm/index.mjs.map +3 -3
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/Globe/Globe.d.ts +1 -1
  8. package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
  9. package/dist/types/src/components/Globe/Globe.stories.d.ts +22 -8
  10. package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
  11. package/dist/types/src/components/Map/Map.d.ts +25 -12
  12. package/dist/types/src/components/Map/Map.d.ts.map +1 -1
  13. package/dist/types/src/components/Map/Map.stories.d.ts +11 -7
  14. package/dist/types/src/components/Map/Map.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/Toolbar/Controls.d.ts.map +1 -1
  16. package/dist/types/src/components/index.d.ts +0 -1
  17. package/dist/types/src/components/index.d.ts.map +1 -1
  18. package/dist/types/src/hooks/context.d.ts +7 -7
  19. package/dist/types/src/hooks/context.d.ts.map +1 -1
  20. package/dist/types/src/hooks/useGlobeZoomHandler.d.ts +1 -1
  21. package/dist/types/src/hooks/useGlobeZoomHandler.d.ts.map +1 -1
  22. package/dist/types/src/hooks/useMapZoomHandler.d.ts +1 -1
  23. package/dist/types/src/hooks/useMapZoomHandler.d.ts.map +1 -1
  24. package/dist/types/src/hooks/useSpinner.d.ts +1 -1
  25. package/dist/types/src/hooks/useSpinner.d.ts.map +1 -1
  26. package/dist/types/src/hooks/useTour.d.ts +4 -3
  27. package/dist/types/src/hooks/useTour.d.ts.map +1 -1
  28. package/dist/types/src/types.d.ts +2 -1
  29. package/dist/types/src/types.d.ts.map +1 -1
  30. package/dist/types/src/util/path.d.ts +5 -8
  31. package/dist/types/src/util/path.d.ts.map +1 -1
  32. package/dist/types/src/util/render.d.ts +4 -4
  33. package/dist/types/src/util/render.d.ts.map +1 -1
  34. package/dist/types/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +14 -11
  36. package/src/components/Globe/Globe.stories.tsx +77 -30
  37. package/src/components/Globe/Globe.tsx +50 -30
  38. package/src/components/Map/Map.stories.tsx +20 -10
  39. package/src/components/Map/Map.tsx +206 -91
  40. package/src/components/Toolbar/Controls.tsx +2 -6
  41. package/src/components/index.ts +0 -2
  42. package/src/hooks/context.tsx +10 -10
  43. package/src/hooks/useGlobeZoomHandler.ts +3 -3
  44. package/src/hooks/useMapZoomHandler.ts +1 -1
  45. package/src/hooks/useSpinner.ts +2 -1
  46. package/src/hooks/useTour.ts +9 -8
  47. package/src/types.ts +3 -1
  48. package/src/util/inertia.ts +1 -1
  49. package/src/util/path.ts +5 -6
  50. package/src/util/render.ts +5 -3
  51. package/dist/types/src/components/types.d.ts +0 -15
  52. package/dist/types/src/components/types.d.ts.map +0 -1
  53. package/src/components/types.ts +0 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-geo",
3
- "version": "0.8.4-main.b97322e",
3
+ "version": "0.8.4-main.dedc0f3",
4
4
  "description": "Geo components.",
5
5
  "homepage": "https://github.com/dxos",
6
6
  "bugs": "https://github.com/dxos/issues",
@@ -10,11 +10,13 @@
10
10
  "type": "module",
11
11
  "exports": {
12
12
  "./data": {
13
+ "source": "./src/data.ts",
13
14
  "types": "./dist/types/src/data.d.ts",
14
15
  "browser": "./dist/lib/browser/data.mjs",
15
16
  "node": "./dist/lib/node-esm/data.mjs"
16
17
  },
17
18
  ".": {
19
+ "source": "./src/index.ts",
18
20
  "types": "./dist/types/src/index.d.ts",
19
21
  "browser": "./dist/lib/browser/index.mjs",
20
22
  "node": "./dist/lib/node-esm/index.mjs"
@@ -35,6 +37,7 @@
35
37
  ],
36
38
  "dependencies": {
37
39
  "@preact-signals/safe-react": "^0.9.0",
40
+ "@radix-ui/react-context": "^1.0.5",
38
41
  "d3": "^7.9.0",
39
42
  "d3-geo-projection": "^4.0.0",
40
43
  "d3-hexbin": "^0.2.2",
@@ -46,11 +49,11 @@
46
49
  "topojson-client": "^3.1.0",
47
50
  "topojson-simplify": "^3.0.3",
48
51
  "versor": "^0.2.0",
49
- "@dxos/async": "0.8.4-main.b97322e",
50
- "@dxos/debug": "0.8.4-main.b97322e",
51
- "@dxos/log": "0.8.4-main.b97322e",
52
- "@dxos/node-std": "0.8.4-main.b97322e",
53
- "@dxos/util": "0.8.4-main.b97322e"
52
+ "@dxos/async": "0.8.4-main.dedc0f3",
53
+ "@dxos/node-std": "0.8.4-main.dedc0f3",
54
+ "@dxos/util": "0.8.4-main.dedc0f3",
55
+ "@dxos/log": "0.8.4-main.dedc0f3",
56
+ "@dxos/debug": "0.8.4-main.dedc0f3"
54
57
  },
55
58
  "devDependencies": {
56
59
  "@react-three/drei": "^9.99.0",
@@ -70,15 +73,15 @@
70
73
  "react": "~18.2.0",
71
74
  "react-dom": "~18.2.0",
72
75
  "three": "0.165.0",
73
- "@dxos/react-ui-theme": "0.8.4-main.b97322e",
74
- "@dxos/react-ui": "0.8.4-main.b97322e",
75
- "@dxos/storybook-utils": "0.8.4-main.b97322e"
76
+ "@dxos/react-ui": "0.8.4-main.dedc0f3",
77
+ "@dxos/react-ui-theme": "0.8.4-main.dedc0f3",
78
+ "@dxos/storybook-utils": "0.8.4-main.dedc0f3"
76
79
  },
77
80
  "peerDependencies": {
78
81
  "react": "~18.2.0",
79
82
  "react-dom": "~18.2.0",
80
- "@dxos/react-ui": "0.8.4-main.b97322e",
81
- "@dxos/react-ui-theme": "0.8.4-main.b97322e"
83
+ "@dxos/react-ui": "0.8.4-main.dedc0f3",
84
+ "@dxos/react-ui-theme": "0.8.4-main.dedc0f3"
82
85
  },
83
86
  "publishConfig": {
84
87
  "access": "public"
@@ -4,20 +4,22 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type Meta } from '@storybook/react-vite';
7
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
8
  import { type FeatureCollection, type Geometry, type Position } from 'geojson';
9
9
  import { Leva } from 'leva';
10
10
  import React, { useMemo, useRef, useState } from 'react';
11
11
  import { type Topology } from 'topojson-specification';
12
12
 
13
13
  import { useAsyncState } from '@dxos/react-ui';
14
- import { withTheme, withLayout } from '@dxos/storybook-utils';
14
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
15
15
 
16
- import { Globe, type GlobeCanvasProps, type GlobeController, type GlobeRootProps } from './Globe';
17
- import { useDrag, useGlobeZoomHandler, useSpinner, useTour, type Vector } from '../../hooks';
18
- import { closestPoint, type LatLng, type StyleSet } from '../../util';
16
+ import { type Vector, useDrag, useGlobeZoomHandler, useSpinner, useTour } from '../../hooks';
17
+ import { type LatLngLiteral } from '../../types';
18
+ import { type StyleSet, closestPoint } from '../../util';
19
19
  import { type ControlProps } from '../Toolbar';
20
20
 
21
+ import { Globe, type GlobeCanvasProps, type GlobeController, type GlobeRootProps } from './Globe';
22
+
21
23
  // TODO(burdon): Load from JSON at runtime?
22
24
  const useTopology = () => {
23
25
  return useAsyncState(async () => (await import('../../../data/countries-110m.ts')).default);
@@ -95,8 +97,11 @@ const createTrip = (
95
97
  routes: Record<string, string[]>,
96
98
  points: Position[] = [],
97
99
  ) => {
98
- let previousHub: LatLng;
99
- return Object.entries(routes).reduce<{ points: LatLng[]; lines: { source: LatLng; target: LatLng }[] }>(
100
+ let previousHub: LatLngLiteral;
101
+ return Object.entries(routes).reduce<{
102
+ points: LatLngLiteral[];
103
+ lines: { source: LatLngLiteral; target: LatLngLiteral }[];
104
+ }>(
100
105
  (features, [hub, regional]) => {
101
106
  const hubAirport = airports.features.find(({ properties }) => properties.iata === hub);
102
107
  if (hubAirport) {
@@ -125,7 +130,7 @@ const createTrip = (
125
130
  );
126
131
  };
127
132
 
128
- type StoryProps = Pick<GlobeRootProps, 'scale' | 'translation' | 'rotation'> &
133
+ type StoryProps = Pick<GlobeRootProps, 'zoom' | 'translation' | 'rotation'> &
129
134
  Pick<GlobeCanvasProps, 'projection' | 'styles'> & {
130
135
  drag?: boolean;
131
136
  spin?: boolean;
@@ -133,8 +138,8 @@ type StoryProps = Pick<GlobeRootProps, 'scale' | 'translation' | 'rotation'> &
133
138
  xAxis?: boolean;
134
139
  };
135
140
 
136
- const Story = ({
137
- scale: _scale = 1,
141
+ const DefaultStory = ({
142
+ zoom: _zoom = 1,
138
143
  translation,
139
144
  rotation = [0, 0, 0],
140
145
  projection,
@@ -154,6 +159,7 @@ const Story = ({
154
159
  });
155
160
  const [topology] = useTopology();
156
161
  const [airports] = useAsyncState(async () => (await import('../../../data/airports.ts')).default);
162
+
157
163
  const features = useMemo(() => {
158
164
  return airports ? createTrip(airports, routes, (dots?.objects.dots as any)?.geometries[0].coordinates) : undefined;
159
165
  }, [airports, routes, dots]);
@@ -188,18 +194,18 @@ const Story = ({
188
194
  break;
189
195
  }
190
196
  case 'zoom-in': {
191
- controller.current.setScale((scale) => scale * 1.1);
197
+ controller.current.setZoom((scale) => scale * 1.1);
192
198
  break;
193
199
  }
194
200
  case 'zoom-out': {
195
- controller.current.setScale((scale) => scale * 0.9);
201
+ controller.current.setZoom((scale) => scale * 0.9);
196
202
  break;
197
203
  }
198
204
  }
199
205
  };
200
206
 
201
207
  return (
202
- <Globe.Root classNames='absolute inset-0' scale={_scale} translation={translation} rotation={rotation}>
208
+ <Globe.Root classNames='absolute inset-0' zoom={_zoom} translation={translation} rotation={rotation}>
203
209
  <Globe.Canvas
204
210
  ref={controller}
205
211
  topology={styles?.dots ? dots : topology}
@@ -219,11 +225,12 @@ const Story = ({
219
225
 
220
226
  const initialRotation: Vector = [0, -40, 0];
221
227
 
222
- const meta: Meta = {
228
+ const meta = {
223
229
  title: 'ui/react-ui-geo/Globe',
224
230
  component: Globe.Root,
231
+ render: DefaultStory,
225
232
  decorators: [withTheme, withLayout({ fullscreen: true, classNames: 'bg-[#000]' })],
226
- };
233
+ } satisfies Meta;
227
234
 
228
235
  export default meta;
229
236
 
@@ -234,7 +241,7 @@ export const Earth1 = () => {
234
241
  useDrag(controller);
235
242
 
236
243
  return (
237
- <Globe.Root scale={1.2} rotation={[Math.random() * 360, 0, 0]}>
244
+ <Globe.Root zoom={1.2} rotation={[Math.random() * 360, 0, 0]}>
238
245
  <Globe.Canvas ref={setController} topology={topology} styles={defaultStyles} />
239
246
  <Globe.Zoom onAction={handleAction} />
240
247
  </Globe.Root>
@@ -249,7 +256,7 @@ export const Earth2 = () => {
249
256
 
250
257
  return (
251
258
  <div className='absolute bottom-0 left-0 right-0 '>
252
- <Globe.Root classNames='h-[400px]' scale={2.8} translation={{ x: 0, y: 400 }}>
259
+ <Globe.Root classNames='h-[400px]' zoom={2.8} translation={{ x: 0, y: 400 }}>
253
260
  <Globe.Canvas ref={setController} topology={topology} styles={defaultStyles} />
254
261
  <Globe.Zoom onAction={handleAction} />
255
262
  </Globe.Root>
@@ -283,33 +290,73 @@ export const Mercator = () => {
283
290
  useDrag(controller);
284
291
 
285
292
  return (
286
- <Globe.Root classNames='flex grow overflow-hidden' scale={0.7} rotation={initialRotation}>
293
+ <Globe.Root classNames='flex grow overflow-hidden' zoom={0.7} rotation={initialRotation}>
287
294
  <Globe.Canvas ref={setController} topology={topology} projection='mercator' styles={monochrome} />
288
295
  <Globe.Zoom onAction={handleAction} />
289
296
  </Globe.Root>
290
297
  );
291
298
  };
292
299
 
293
- export const Globe1 = () => {
294
- return <Story drag projection='mercator' scale={0.8} rotation={initialRotation} styles={defaultStyles} />;
300
+ type Story = StoryObj<typeof DefaultStory>;
301
+
302
+ export const Globe1: Story = {
303
+ args: {
304
+ drag: true,
305
+ projection: 'mercator',
306
+ zoom: 0.8,
307
+ rotation: initialRotation,
308
+ styles: defaultStyles,
309
+ },
295
310
  };
296
311
 
297
- export const Globe2 = () => {
298
- return <Story drag projection='transverse-mercator' scale={0.8} rotation={initialRotation} styles={defaultStyles} />;
312
+ export const Globe2: Story = {
313
+ args: {
314
+ drag: true,
315
+ projection: 'transverse-mercator',
316
+ zoom: 0.8,
317
+ rotation: initialRotation,
318
+ styles: defaultStyles,
319
+ },
299
320
  };
300
321
 
301
- export const Globe3 = () => {
302
- return <Story drag spin scale={1.5} rotation={initialRotation} styles={defaultStyles} />;
322
+ export const Globe3: Story = {
323
+ args: {
324
+ drag: true,
325
+ spin: true,
326
+ zoom: 1.5,
327
+ rotation: initialRotation,
328
+ styles: defaultStyles,
329
+ },
303
330
  };
304
331
 
305
- export const Globe4 = () => {
306
- return <Story drag tour scale={2} rotation={initialRotation} styles={defaultStyles} />;
332
+ export const Globe4: Story = {
333
+ args: {
334
+ drag: true,
335
+ tour: true,
336
+ zoom: 2,
337
+ rotation: initialRotation,
338
+ styles: defaultStyles,
339
+ },
307
340
  };
308
341
 
309
- export const Globe5 = () => {
310
- return <Story drag tour scale={0.9} rotation={initialRotation} styles={dotStyles} />;
342
+ export const Globe5: Story = {
343
+ args: {
344
+ drag: true,
345
+ tour: true,
346
+ zoom: 0.9,
347
+ rotation: initialRotation,
348
+ styles: dotStyles,
349
+ },
311
350
  };
312
351
 
313
- export const Globe6 = () => {
314
- return <Story drag xAxis tour scale={2} translation={{ x: 0, y: 600 }} rotation={[0, -20, 0]} styles={dotStyles} />;
352
+ export const Globe6: Story = {
353
+ args: {
354
+ drag: true,
355
+ xAxis: true,
356
+ tour: true,
357
+ zoom: 2,
358
+ translation: { x: 0, y: 600 },
359
+ rotation: [0, -20, 0],
360
+ styles: dotStyles,
361
+ },
315
362
  };
@@ -4,14 +4,14 @@
4
4
 
5
5
  import {
6
6
  type GeoProjection,
7
+ easeLinear,
8
+ easeSinOut,
7
9
  geoMercator,
8
10
  geoOrthographic,
9
11
  geoPath,
10
12
  geoTransverseMercator,
11
13
  interpolateNumber,
12
14
  transition,
13
- easeLinear,
14
- easeSinOut,
15
15
  } from 'd3';
16
16
  import { type ControlPosition } from 'leaflet';
17
17
  import React, {
@@ -26,7 +26,7 @@ import React, {
26
26
  import { useResizeDetector } from 'react-resize-detector';
27
27
  import { type Topology } from 'topojson-specification';
28
28
 
29
- import { type ThemedClassName, type ThemeMode, useDynamicRef, useThemeContext } from '@dxos/react-ui';
29
+ import { type ThemeMode, type ThemedClassName, useDynamicRef, useThemeContext } from '@dxos/react-ui';
30
30
  import { mx } from '@dxos/react-ui-theme';
31
31
 
32
32
  import {
@@ -44,7 +44,7 @@ import {
44
44
  renderLayers,
45
45
  timer,
46
46
  } from '../../util';
47
- import { ZoomControls, ActionControls, type ControlProps, controlPositions } from '../Toolbar';
47
+ import { ActionControls, type ControlProps, ZoomControls, controlPositions } from '../Toolbar';
48
48
 
49
49
  /**
50
50
  * https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute
@@ -103,7 +103,7 @@ const defaultStyles: Record<ThemeMode, StyleSet> = {
103
103
  export type GlobeController = {
104
104
  canvas: HTMLCanvasElement;
105
105
  projection: GeoProjection;
106
- } & Pick<GlobeContextType, 'scale' | 'translation' | 'rotation' | 'setScale' | 'setTranslation' | 'setRotation'>;
106
+ } & Pick<GlobeContextType, 'zoom' | 'translation' | 'rotation' | 'setZoom' | 'setTranslation' | 'setRotation'>;
107
107
 
108
108
  export type ProjectionType = 'orthographic' | 'mercator' | 'transverse-mercator';
109
109
 
@@ -154,6 +154,7 @@ type GlobeCanvasProps = {
154
154
  * Basic globe renderer.
155
155
  * https://github.com/topojson/world-atlas
156
156
  */
157
+ // TODO(burdon): Move controller to root.
157
158
  const GlobeCanvas = forwardRef<GlobeController, GlobeCanvasProps>(
158
159
  ({ projection: _projection, topology, features, styles: _styles }, forwardRef) => {
159
160
  const { themeMode } = useThemeContext();
@@ -173,15 +174,14 @@ const GlobeCanvas = forwardRef<GlobeController, GlobeCanvasProps>(
173
174
  }, [topology, features, styles]);
174
175
 
175
176
  // State.
176
- const { size, center, scale, translation, rotation, setCenter, setScale, setTranslation, setRotation } =
177
+ const { size, center, zoom, translation, rotation, setCenter, setZoom, setTranslation, setRotation } =
177
178
  useGlobeContext();
178
-
179
- const scaleRef = useDynamicRef(scale);
179
+ const zoomRef = useDynamicRef(zoom);
180
180
 
181
181
  // Update rotation.
182
182
  useEffect(() => {
183
183
  if (center) {
184
- setScale(1);
184
+ setZoom(1);
185
185
  setRotation(positionToRotation(geoToPosition(center)));
186
186
  }
187
187
  }, [center]);
@@ -193,25 +193,25 @@ const GlobeCanvas = forwardRef<GlobeController, GlobeCanvasProps>(
193
193
  canvas,
194
194
  projection,
195
195
  center,
196
- get scale() {
197
- return scaleRef.current;
196
+ get zoom() {
197
+ return zoomRef.current;
198
198
  },
199
199
  translation,
200
200
  rotation,
201
201
  setCenter,
202
- setScale: (s) => {
202
+ setZoom: (s) => {
203
203
  if (typeof s === 'function') {
204
- const is = interpolateNumber(scaleRef.current, s(scaleRef.current));
204
+ const is = interpolateNumber(zoomRef.current, s(zoomRef.current));
205
205
  // Stop easing if already zooming.
206
206
  transition()
207
207
  .ease(zooming.current ? easeLinear : easeSinOut)
208
208
  .duration(200)
209
- .tween('scale', () => (t) => setScale(is(t)))
209
+ .tween('scale', () => (t) => setZoom(is(t)))
210
210
  .on('end', () => {
211
211
  zooming.current = false;
212
212
  });
213
213
  } else {
214
- setScale(s);
214
+ setZoom(s);
215
215
  }
216
216
  },
217
217
  setTranslation,
@@ -232,14 +232,14 @@ const GlobeCanvas = forwardRef<GlobeController, GlobeCanvasProps>(
232
232
  timer(() => {
233
233
  // https://d3js.org/d3-geo/projection
234
234
  projection
235
- .scale((Math.min(size.width, size.height) / 2) * scale)
235
+ .scale((Math.min(size.width, size.height) / 2) * zoom)
236
236
  .translate([size.width / 2 + (translation?.x ?? 0), size.height / 2 + (translation?.y ?? 0)])
237
237
  .rotate(rotation ?? [0, 0, 0]);
238
238
 
239
- renderLayers(generator, layers, scale, styles);
239
+ renderLayers(generator, layers, zoom, styles);
240
240
  });
241
241
  }
242
- }, [generator, size, scale, translation, rotation, layers]);
242
+ }, [generator, size, zoom, translation, rotation, layers]);
243
243
 
244
244
  if (!size.width || !size.height) {
245
245
  return null;
@@ -249,8 +249,12 @@ const GlobeCanvas = forwardRef<GlobeController, GlobeCanvasProps>(
249
249
  },
250
250
  );
251
251
 
252
+ //
253
+ // Debug
254
+ //
255
+
252
256
  const GlobeDebug = ({ position = 'topleft' }: { position?: ControlPosition }) => {
253
- const { size, scale, translation, rotation } = useGlobeContext();
257
+ const { size, zoom, translation, rotation } = useGlobeContext();
254
258
  return (
255
259
  <div
256
260
  className={mx(
@@ -259,12 +263,16 @@ const GlobeDebug = ({ position = 'topleft' }: { position?: ControlPosition }) =>
259
263
  )}
260
264
  >
261
265
  <pre className='font-mono text-xs text-green-700'>
262
- {JSON.stringify({ size, scale, translation, rotation }, null, 2)}
266
+ {JSON.stringify({ size, zoom, translation, rotation }, null, 2)}
263
267
  </pre>
264
268
  </div>
265
269
  );
266
270
  };
267
271
 
272
+ //
273
+ // Panel
274
+ //
275
+
268
276
  const GlobePanel = ({
269
277
  position,
270
278
  classNames,
@@ -273,25 +281,37 @@ const GlobePanel = ({
273
281
  return <div className={mx('z-10 absolute overflow-hidden', controlPositions[position], classNames)}>{children}</div>;
274
282
  };
275
283
 
284
+ //
285
+ // Controls
286
+ //
287
+
276
288
  const CustomControl = ({ position, children }: PropsWithChildren<{ position: ControlPosition }>) => {
277
289
  return <div className={mx('z-10 absolute overflow-hidden', controlPositions[position])}>{children}</div>;
278
290
  };
279
291
 
280
292
  type GlobeControlProps = { position?: ControlPosition } & Pick<ControlProps, 'onAction'>;
281
293
 
294
+ const GlobeZoom = ({ onAction, position = 'bottomleft', ...props }: GlobeControlProps) => (
295
+ <CustomControl position={position} {...props}>
296
+ <ZoomControls onAction={onAction} />
297
+ </CustomControl>
298
+ );
299
+
300
+ const GlobeAction = ({ onAction, position = 'bottomright', ...props }: GlobeControlProps) => (
301
+ <CustomControl position={position} {...props}>
302
+ <ActionControls onAction={onAction} />
303
+ </CustomControl>
304
+ );
305
+
306
+ //
307
+ // Globe
308
+ //
309
+
282
310
  export const Globe = {
283
311
  Root: GlobeRoot,
284
312
  Canvas: GlobeCanvas,
285
- Zoom: ({ onAction, position = 'bottomleft', ...props }: GlobeControlProps) => (
286
- <CustomControl position={position} {...props}>
287
- <ZoomControls onAction={onAction} />
288
- </CustomControl>
289
- ),
290
- Action: ({ onAction, position = 'bottomright', ...props }: GlobeControlProps) => (
291
- <CustomControl position={position} {...props}>
292
- <ActionControls onAction={onAction} />
293
- </CustomControl>
294
- ),
313
+ Zoom: GlobeZoom,
314
+ Action: GlobeAction,
295
315
  Debug: GlobeDebug,
296
316
  Panel: GlobePanel,
297
317
  };
@@ -4,43 +4,53 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type StoryObj, type Meta } from '@storybook/react-vite';
7
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
8
  import React, { useState } from 'react';
9
9
 
10
10
  import { withLayout, withTheme } from '@dxos/storybook-utils';
11
11
 
12
- import { Map, type MapController } from './Map';
13
12
  import { useMapZoomHandler } from '../../hooks';
14
- import { type MapMarker } from '../../types';
13
+ import { type GeoMarker } from '../../types';
14
+
15
+ import { Map, type MapController } from './Map';
15
16
 
16
- const DefaultStory = ({ markers = [] }: { markers?: MapMarker[] }) => {
17
+ const DefaultStory = ({ markers = [] }: { markers?: GeoMarker[] }) => {
17
18
  const [controller, setController] = useState<MapController>();
18
19
  const handleZoomAction = useMapZoomHandler(controller);
19
20
 
20
21
  return (
21
- <Map.Root>
22
- <Map.Canvas ref={setController} markers={markers} />
22
+ <Map.Root ref={setController}>
23
+ <Map.Tiles />
24
+ <Map.Markers markers={markers} />
23
25
  <Map.Zoom position='bottomleft' onAction={handleZoomAction} />
24
26
  <Map.Action position='bottomright' />
25
27
  </Map.Root>
26
28
  );
27
29
  };
28
30
 
29
- const meta: Meta<typeof DefaultStory> = {
31
+ const meta = {
30
32
  title: 'ui/react-ui-geo/Map',
33
+ component: Map.Root as any,
31
34
  render: DefaultStory,
32
35
  decorators: [withTheme, withLayout({ fullscreen: true })],
33
- };
36
+ } satisfies Meta<typeof DefaultStory>;
34
37
 
35
38
  export default meta;
36
39
 
37
- type Story = StoryObj<typeof DefaultStory>;
40
+ type Story = StoryObj<typeof meta>;
38
41
 
39
42
  export const Default: Story = {};
40
43
 
41
44
  export const WithMarkers: Story = {
42
45
  args: {
43
46
  markers: [
47
+ { id: 'los angeles', title: 'Los Angeles', location: { lat: 34.0522, lng: -118.2437 } },
48
+ { id: 'new york', title: 'New York', location: { lat: 40.7128, lng: -74.006 } },
49
+ { id: 'warsaw', title: 'Warsaw', location: { lat: 52.2297, lng: 21.0122 } },
50
+ { id: 'london', title: 'London', location: { lat: 51.5074, lng: -0.1278 } },
51
+ { id: 'toronto', title: 'Toronto', location: { lat: 43.6532, lng: -79.3832 } },
52
+ { id: 'seattle', title: 'Seattle', location: { lat: 47.6062, lng: -122.3321 } },
53
+ { id: 'barcelona', title: 'Barcelona', location: { lat: 41.3851, lng: 2.1734 } },
44
54
  { id: 'tokyo', title: 'Tokyo', location: { lat: 35.6762, lng: 139.6503 } },
45
55
  { id: 'sydney', title: 'Sydney', location: { lat: -33.8688, lng: 151.2093 } },
46
56
  { id: 'auckland', title: 'Auckland', location: { lat: -36.8509, lng: 174.7645 } },
@@ -56,6 +66,6 @@ export const WithMarkers: Story = {
56
66
  { id: 'phnom-penh', title: 'Phnom Penh', location: { lat: 11.5564, lng: 104.9282 } },
57
67
  { id: 'vientiane', title: 'Vientiane', location: { lat: 17.9757, lng: 102.6331 } },
58
68
  { id: 'yangon', title: 'Yangon', location: { lat: 16.8661, lng: 96.1951 } },
59
- ] as MapMarker[],
69
+ ] as GeoMarker[],
60
70
  },
61
71
  };