@dxos/react-ui-geo 0.8.3 → 0.8.4-main.28f8d3d

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 (83) hide show
  1. package/data/airports.ts +1 -1
  2. package/data/cities.ts +1 -1
  3. package/data/countries-110m.ts +1 -1
  4. package/data/countries-dots-3.ts +1 -1
  5. package/data/countries-dots-4.ts +1 -1
  6. package/dist/lib/browser/chunk-GMWLKTLN.mjs +9 -0
  7. package/dist/lib/browser/{countries-110m-WI4PCLDF.mjs → countries-110m-ZM3ZIEFS.mjs} +2 -2
  8. package/dist/lib/browser/countries-110m-ZM3ZIEFS.mjs.map +7 -0
  9. package/dist/lib/browser/data.mjs +1 -1
  10. package/dist/lib/browser/index.mjs +187 -159
  11. package/dist/lib/browser/index.mjs.map +3 -3
  12. package/dist/lib/browser/meta.json +1 -1
  13. package/dist/lib/node-esm/{chunk-PIIEDZEU.mjs → chunk-JODBF4CC.mjs} +3 -3
  14. package/dist/lib/node-esm/{countries-110m-DQ4XRC4B.mjs → countries-110m-3SFASWVD.mjs} +2 -2
  15. package/dist/lib/node-esm/countries-110m-3SFASWVD.mjs.map +7 -0
  16. package/dist/lib/node-esm/data.mjs +1 -1
  17. package/dist/lib/node-esm/index.mjs +187 -159
  18. package/dist/lib/node-esm/index.mjs.map +3 -3
  19. package/dist/lib/node-esm/meta.json +1 -1
  20. package/dist/types/src/components/Globe/Globe.d.ts +1 -1
  21. package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
  22. package/dist/types/src/components/Globe/Globe.stories.d.ts +1 -1
  23. package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/Map/Map.d.ts +25 -12
  25. package/dist/types/src/components/Map/Map.d.ts.map +1 -1
  26. package/dist/types/src/components/Map/Map.stories.d.ts +3 -3
  27. package/dist/types/src/components/Map/Map.stories.d.ts.map +1 -1
  28. package/dist/types/src/components/Toolbar/Controls.d.ts.map +1 -1
  29. package/dist/types/src/components/index.d.ts +0 -1
  30. package/dist/types/src/components/index.d.ts.map +1 -1
  31. package/dist/types/src/hooks/context.d.ts +7 -7
  32. package/dist/types/src/hooks/context.d.ts.map +1 -1
  33. package/dist/types/src/hooks/useGlobeZoomHandler.d.ts +1 -1
  34. package/dist/types/src/hooks/useGlobeZoomHandler.d.ts.map +1 -1
  35. package/dist/types/src/hooks/useMapZoomHandler.d.ts +1 -1
  36. package/dist/types/src/hooks/useMapZoomHandler.d.ts.map +1 -1
  37. package/dist/types/src/hooks/useSpinner.d.ts +1 -1
  38. package/dist/types/src/hooks/useSpinner.d.ts.map +1 -1
  39. package/dist/types/src/hooks/useTour.d.ts +4 -3
  40. package/dist/types/src/hooks/useTour.d.ts.map +1 -1
  41. package/dist/types/src/index.d.ts +1 -1
  42. package/dist/types/src/index.d.ts.map +1 -1
  43. package/dist/types/src/types.d.ts +2 -1
  44. package/dist/types/src/types.d.ts.map +1 -1
  45. package/dist/types/src/util/path.d.ts +5 -8
  46. package/dist/types/src/util/path.d.ts.map +1 -1
  47. package/dist/types/src/util/render.d.ts +4 -4
  48. package/dist/types/src/util/render.d.ts.map +1 -1
  49. package/dist/types/tsconfig.tsbuildinfo +1 -1
  50. package/package.json +14 -11
  51. package/src/components/Globe/Globe.stories.tsx +29 -24
  52. package/src/components/Globe/Globe.tsx +74 -58
  53. package/src/components/Map/Map.stories.tsx +16 -7
  54. package/src/components/Map/Map.tsx +206 -91
  55. package/src/components/Toolbar/Controls.tsx +2 -6
  56. package/src/components/index.ts +0 -2
  57. package/src/hooks/context.tsx +10 -10
  58. package/src/hooks/useGlobeZoomHandler.ts +3 -3
  59. package/src/hooks/useMapZoomHandler.ts +1 -1
  60. package/src/hooks/useSpinner.ts +2 -1
  61. package/src/hooks/useTour.ts +9 -8
  62. package/src/index.ts +1 -1
  63. package/src/types.ts +3 -1
  64. package/src/util/inertia.ts +1 -1
  65. package/src/util/path.ts +5 -6
  66. package/src/util/render.ts +5 -3
  67. package/dist/lib/browser/chunk-ENCWOTYX.mjs +0 -9
  68. package/dist/lib/browser/countries-110m-WI4PCLDF.mjs.map +0 -7
  69. package/dist/lib/node/chunk-LAICG6L2.cjs +0 -40
  70. package/dist/lib/node/chunk-LAICG6L2.cjs.map +0 -7
  71. package/dist/lib/node/countries-110m-KQ5WAB2O.cjs +0 -37877
  72. package/dist/lib/node/countries-110m-KQ5WAB2O.cjs.map +0 -7
  73. package/dist/lib/node/data.cjs +0 -28
  74. package/dist/lib/node/data.cjs.map +0 -7
  75. package/dist/lib/node/index.cjs +0 -1187
  76. package/dist/lib/node/index.cjs.map +0 -7
  77. package/dist/lib/node/meta.json +0 -1
  78. package/dist/lib/node-esm/countries-110m-DQ4XRC4B.mjs.map +0 -7
  79. package/dist/types/src/components/types.d.ts +0 -15
  80. package/dist/types/src/components/types.d.ts.map +0 -1
  81. package/src/components/types.ts +0 -19
  82. /package/dist/lib/browser/{chunk-ENCWOTYX.mjs.map → chunk-GMWLKTLN.mjs.map} +0 -0
  83. /package/dist/lib/node-esm/{chunk-PIIEDZEU.mjs.map → chunk-JODBF4CC.mjs.map} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-geo",
3
- "version": "0.8.3",
3
+ "version": "0.8.4-main.28f8d3d",
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.3",
50
- "@dxos/log": "0.8.3",
51
- "@dxos/debug": "0.8.3",
52
- "@dxos/util": "0.8.3",
53
- "@dxos/node-std": "0.8.3"
52
+ "@dxos/async": "0.8.4-main.28f8d3d",
53
+ "@dxos/debug": "0.8.4-main.28f8d3d",
54
+ "@dxos/log": "0.8.4-main.28f8d3d",
55
+ "@dxos/node-std": "0.8.4-main.28f8d3d",
56
+ "@dxos/util": "0.8.4-main.28f8d3d"
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": "0.8.3",
74
- "@dxos/react-ui-theme": "0.8.3",
75
- "@dxos/storybook-utils": "0.8.3"
76
+ "@dxos/react-ui": "0.8.4-main.28f8d3d",
77
+ "@dxos/react-ui-theme": "0.8.4-main.28f8d3d",
78
+ "@dxos/storybook-utils": "0.8.4-main.28f8d3d"
76
79
  },
77
80
  "peerDependencies": {
78
81
  "react": "~18.2.0",
79
82
  "react-dom": "~18.2.0",
80
- "@dxos/react-ui": "0.8.3",
81
- "@dxos/react-ui-theme": "0.8.3"
83
+ "@dxos/react-ui": "0.8.4-main.28f8d3d",
84
+ "@dxos/react-ui-theme": "0.8.4-main.28f8d3d"
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';
7
+ import { type Meta } 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;
@@ -134,11 +139,11 @@ type StoryProps = Pick<GlobeRootProps, 'scale' | 'translation' | 'rotation'> &
134
139
  };
135
140
 
136
141
  const Story = ({
137
- scale: _scale = 1,
142
+ zoom: _zoom = 1,
138
143
  translation,
139
144
  rotation = [0, 0, 0],
140
145
  projection,
141
- styles,
146
+ styles = defaultStyles,
142
147
  drag = false,
143
148
  spin = false,
144
149
  tour = false,
@@ -188,18 +193,18 @@ const Story = ({
188
193
  break;
189
194
  }
190
195
  case 'zoom-in': {
191
- controller.current.setScale((scale) => scale * 1.1);
196
+ controller.current.setZoom((scale) => scale * 1.1);
192
197
  break;
193
198
  }
194
199
  case 'zoom-out': {
195
- controller.current.setScale((scale) => scale * 0.9);
200
+ controller.current.setZoom((scale) => scale * 0.9);
196
201
  break;
197
202
  }
198
203
  }
199
204
  };
200
205
 
201
206
  return (
202
- <Globe.Root classNames='absolute inset-0' scale={_scale} translation={translation} rotation={rotation}>
207
+ <Globe.Root classNames='absolute inset-0' zoom={_zoom} translation={translation} rotation={rotation}>
203
208
  <Globe.Canvas
204
209
  ref={controller}
205
210
  topology={styles?.dots ? dots : topology}
@@ -234,8 +239,8 @@ export const Earth1 = () => {
234
239
  useDrag(controller);
235
240
 
236
241
  return (
237
- <Globe.Root scale={1.2} rotation={[Math.random() * 360, 0, 0]}>
238
- <Globe.Canvas ref={setController} topology={topology} />
242
+ <Globe.Root zoom={1.2} rotation={[Math.random() * 360, 0, 0]}>
243
+ <Globe.Canvas ref={setController} topology={topology} styles={defaultStyles} />
239
244
  <Globe.Zoom onAction={handleAction} />
240
245
  </Globe.Root>
241
246
  );
@@ -249,8 +254,8 @@ export const Earth2 = () => {
249
254
 
250
255
  return (
251
256
  <div className='absolute bottom-0 left-0 right-0 '>
252
- <Globe.Root classNames='h-[400px]' scale={2.8} translation={{ x: 0, y: 400 }}>
253
- <Globe.Canvas ref={setController} topology={topology} />
257
+ <Globe.Root classNames='h-[400px]' zoom={2.8} translation={{ x: 0, y: 400 }}>
258
+ <Globe.Canvas ref={setController} topology={topology} styles={defaultStyles} />
254
259
  <Globe.Zoom onAction={handleAction} />
255
260
  </Globe.Root>
256
261
  </div>
@@ -283,7 +288,7 @@ export const Mercator = () => {
283
288
  useDrag(controller);
284
289
 
285
290
  return (
286
- <Globe.Root classNames='flex grow overflow-hidden' scale={0.7} rotation={initialRotation}>
291
+ <Globe.Root classNames='flex grow overflow-hidden' zoom={0.7} rotation={initialRotation}>
287
292
  <Globe.Canvas ref={setController} topology={topology} projection='mercator' styles={monochrome} />
288
293
  <Globe.Zoom onAction={handleAction} />
289
294
  </Globe.Root>
@@ -291,25 +296,25 @@ export const Mercator = () => {
291
296
  };
292
297
 
293
298
  export const Globe1 = () => {
294
- return <Story drag projection='mercator' scale={0.8} rotation={initialRotation} />;
299
+ return <Story drag projection='mercator' zoom={0.8} rotation={initialRotation} styles={defaultStyles} />;
295
300
  };
296
301
 
297
302
  export const Globe2 = () => {
298
- return <Story drag projection='transverse-mercator' scale={0.8} rotation={initialRotation} styles={defaultStyles} />;
303
+ return <Story drag projection='transverse-mercator' zoom={0.8} rotation={initialRotation} styles={defaultStyles} />;
299
304
  };
300
305
 
301
306
  export const Globe3 = () => {
302
- return <Story drag spin scale={1.5} rotation={initialRotation} styles={defaultStyles} />;
307
+ return <Story drag spin zoom={1.5} rotation={initialRotation} styles={defaultStyles} />;
303
308
  };
304
309
 
305
310
  export const Globe4 = () => {
306
- return <Story drag tour scale={2} rotation={initialRotation} styles={defaultStyles} />;
311
+ return <Story drag tour zoom={2} rotation={initialRotation} styles={defaultStyles} />;
307
312
  };
308
313
 
309
314
  export const Globe5 = () => {
310
- return <Story drag tour scale={0.9} rotation={initialRotation} styles={dotStyles} />;
315
+ return <Story drag tour zoom={0.9} rotation={initialRotation} styles={dotStyles} />;
311
316
  };
312
317
 
313
318
  export const Globe6 = () => {
314
- return <Story drag xAxis tour scale={2} translation={{ x: 0, y: 600 }} rotation={[0, -20, 0]} styles={dotStyles} />;
319
+ return <Story drag xAxis tour zoom={2} translation={{ x: 0, y: 600 }} rotation={[0, -20, 0]} styles={dotStyles} />;
315
320
  };
@@ -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,55 +174,50 @@ 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]);
188
188
 
189
189
  // External controller.
190
190
  const zooming = useRef(false);
191
- useImperativeHandle<GlobeController, GlobeController>(
192
- forwardRef,
193
- () => {
194
- return {
195
- canvas,
196
- projection,
197
- center,
198
- get scale() {
199
- return scaleRef.current;
200
- },
201
- translation,
202
- rotation,
203
- setCenter,
204
- setScale: (s) => {
205
- if (typeof s === 'function') {
206
- const is = interpolateNumber(scaleRef.current, s(scaleRef.current));
207
- // Stop easing if already zooming.
208
- transition()
209
- .ease(zooming.current ? easeLinear : easeSinOut)
210
- .duration(200)
211
- .tween('scale', () => (t) => setScale(is(t)))
212
- .on('end', () => {
213
- zooming.current = false;
214
- });
215
- } else {
216
- setScale(s);
217
- }
218
- },
219
- setTranslation,
220
- setRotation,
221
- };
222
- },
223
- [canvas],
224
- );
191
+ useImperativeHandle<GlobeController, GlobeController>(forwardRef, () => {
192
+ return {
193
+ canvas,
194
+ projection,
195
+ center,
196
+ get zoom() {
197
+ return zoomRef.current;
198
+ },
199
+ translation,
200
+ rotation,
201
+ setCenter,
202
+ setZoom: (s) => {
203
+ if (typeof s === 'function') {
204
+ const is = interpolateNumber(zoomRef.current, s(zoomRef.current));
205
+ // Stop easing if already zooming.
206
+ transition()
207
+ .ease(zooming.current ? easeLinear : easeSinOut)
208
+ .duration(200)
209
+ .tween('scale', () => (t) => setZoom(is(t)))
210
+ .on('end', () => {
211
+ zooming.current = false;
212
+ });
213
+ } else {
214
+ setZoom(s);
215
+ }
216
+ },
217
+ setTranslation,
218
+ setRotation,
219
+ };
220
+ }, [canvas]);
225
221
 
226
222
  // https://d3js.org/d3-geo/path#geoPath
227
223
  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext
@@ -236,14 +232,14 @@ const GlobeCanvas = forwardRef<GlobeController, GlobeCanvasProps>(
236
232
  timer(() => {
237
233
  // https://d3js.org/d3-geo/projection
238
234
  projection
239
- .scale((Math.min(size.width, size.height) / 2) * scale)
235
+ .scale((Math.min(size.width, size.height) / 2) * zoom)
240
236
  .translate([size.width / 2 + (translation?.x ?? 0), size.height / 2 + (translation?.y ?? 0)])
241
237
  .rotate(rotation ?? [0, 0, 0]);
242
238
 
243
- renderLayers(generator, layers, scale, styles);
239
+ renderLayers(generator, layers, zoom, styles);
244
240
  });
245
241
  }
246
- }, [generator, size, scale, translation, rotation, layers]);
242
+ }, [generator, size, zoom, translation, rotation, layers]);
247
243
 
248
244
  if (!size.width || !size.height) {
249
245
  return null;
@@ -253,8 +249,12 @@ const GlobeCanvas = forwardRef<GlobeController, GlobeCanvasProps>(
253
249
  },
254
250
  );
255
251
 
252
+ //
253
+ // Debug
254
+ //
255
+
256
256
  const GlobeDebug = ({ position = 'topleft' }: { position?: ControlPosition }) => {
257
- const { size, scale, translation, rotation } = useGlobeContext();
257
+ const { size, zoom, translation, rotation } = useGlobeContext();
258
258
  return (
259
259
  <div
260
260
  className={mx(
@@ -263,12 +263,16 @@ const GlobeDebug = ({ position = 'topleft' }: { position?: ControlPosition }) =>
263
263
  )}
264
264
  >
265
265
  <pre className='font-mono text-xs text-green-700'>
266
- {JSON.stringify({ size, scale, translation, rotation }, null, 2)}
266
+ {JSON.stringify({ size, zoom, translation, rotation }, null, 2)}
267
267
  </pre>
268
268
  </div>
269
269
  );
270
270
  };
271
271
 
272
+ //
273
+ // Panel
274
+ //
275
+
272
276
  const GlobePanel = ({
273
277
  position,
274
278
  classNames,
@@ -277,25 +281,37 @@ const GlobePanel = ({
277
281
  return <div className={mx('z-10 absolute overflow-hidden', controlPositions[position], classNames)}>{children}</div>;
278
282
  };
279
283
 
284
+ //
285
+ // Controls
286
+ //
287
+
280
288
  const CustomControl = ({ position, children }: PropsWithChildren<{ position: ControlPosition }>) => {
281
289
  return <div className={mx('z-10 absolute overflow-hidden', controlPositions[position])}>{children}</div>;
282
290
  };
283
291
 
284
292
  type GlobeControlProps = { position?: ControlPosition } & Pick<ControlProps, 'onAction'>;
285
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
+
286
310
  export const Globe = {
287
311
  Root: GlobeRoot,
288
312
  Canvas: GlobeCanvas,
289
- Zoom: ({ onAction, position = 'bottomleft', ...props }: GlobeControlProps) => (
290
- <CustomControl position={position} {...props}>
291
- <ZoomControls onAction={onAction} />
292
- </CustomControl>
293
- ),
294
- Action: ({ onAction, position = 'bottomright', ...props }: GlobeControlProps) => (
295
- <CustomControl position={position} {...props}>
296
- <ActionControls onAction={onAction} />
297
- </CustomControl>
298
- ),
313
+ Zoom: GlobeZoom,
314
+ Action: GlobeAction,
299
315
  Debug: GlobeDebug,
300
316
  Panel: GlobePanel,
301
317
  };
@@ -4,22 +4,24 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type StoryObj, type Meta } from '@storybook/react';
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>
@@ -41,6 +43,13 @@ export const Default: Story = {};
41
43
  export const WithMarkers: Story = {
42
44
  args: {
43
45
  markers: [
46
+ { id: 'los angeles', title: 'Los Angeles', location: { lat: 34.0522, lng: -118.2437 } },
47
+ { id: 'new york', title: 'New York', location: { lat: 40.7128, lng: -74.006 } },
48
+ { id: 'warsaw', title: 'Warsaw', location: { lat: 52.2297, lng: 21.0122 } },
49
+ { id: 'london', title: 'London', location: { lat: 51.5074, lng: -0.1278 } },
50
+ { id: 'toronto', title: 'Toronto', location: { lat: 43.6532, lng: -79.3832 } },
51
+ { id: 'seattle', title: 'Seattle', location: { lat: 47.6062, lng: -122.3321 } },
52
+ { id: 'barcelona', title: 'Barcelona', location: { lat: 41.3851, lng: 2.1734 } },
44
53
  { id: 'tokyo', title: 'Tokyo', location: { lat: 35.6762, lng: 139.6503 } },
45
54
  { id: 'sydney', title: 'Sydney', location: { lat: -33.8688, lng: 151.2093 } },
46
55
  { id: 'auckland', title: 'Auckland', location: { lat: -36.8509, lng: 174.7645 } },
@@ -56,6 +65,6 @@ export const WithMarkers: Story = {
56
65
  { id: 'phnom-penh', title: 'Phnom Penh', location: { lat: 11.5564, lng: 104.9282 } },
57
66
  { id: 'vientiane', title: 'Vientiane', location: { lat: 17.9757, lng: 102.6331 } },
58
67
  { id: 'yangon', title: 'Yangon', location: { lat: 16.8661, lng: 96.1951 } },
59
- ] as MapMarker[],
68
+ ] as GeoMarker[],
60
69
  },
61
70
  };