@dxos/react-ui-geo 0.8.4-main.c85a9c8dae → 0.8.4-main.d05539e30a
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.
- package/LICENSE +102 -5
- package/dist/lib/browser/{countries-110m-ZM3ZIEFS.mjs → countries-110m-RE5RNRQG.mjs} +1 -1
- package/dist/lib/browser/data.mjs +4 -3
- package/dist/lib/browser/data.mjs.map +4 -4
- package/dist/lib/browser/index.mjs +111 -120
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +19 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/{countries-110m-3SFASWVD.mjs → countries-110m-4EDBXSFJ.mjs} +1 -1
- package/dist/lib/node-esm/data.mjs +5 -3
- package/dist/lib/node-esm/data.mjs.map +4 -4
- package/dist/lib/node-esm/index.mjs +111 -119
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/translations.mjs +21 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/types/data/airports.d.ts +4 -4
- package/dist/types/data/airports.d.ts.map +1 -1
- package/dist/types/data/cities.d.ts.map +1 -1
- package/dist/types/data/countries-110m.d.ts.map +1 -1
- package/dist/types/data/countries-dots-3.d.ts.map +1 -1
- package/dist/types/data/countries-dots-4.d.ts.map +1 -1
- package/dist/types/src/components/Globe/Globe.d.ts +5 -3
- package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
- package/dist/types/src/components/Globe/Globe.stories.d.ts +6 -4
- package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
- package/dist/types/src/components/Map/Map.d.ts +20 -4
- package/dist/types/src/components/Map/Map.d.ts.map +1 -1
- package/dist/types/src/components/Map/Map.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Controls.d.ts.map +1 -1
- package/dist/types/src/hooks/context.d.ts +1 -3
- package/dist/types/src/hooks/context.d.ts.map +1 -1
- package/dist/types/src/hooks/useDrag.d.ts.map +1 -1
- package/dist/types/src/hooks/useGlobeZoomHandler.d.ts +1 -1
- package/dist/types/src/hooks/useGlobeZoomHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useMapZoomHandler.d.ts +1 -1
- package/dist/types/src/hooks/useMapZoomHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useSpinner.d.ts.map +1 -1
- package/dist/types/src/hooks/useTour.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +4 -4
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/debug.d.ts.map +1 -1
- package/dist/types/src/util/inertia.d.ts.map +1 -1
- package/dist/types/src/util/path.d.ts.map +1 -1
- package/dist/types/src/util/render.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +27 -24
- package/src/components/Globe/Globe.stories.tsx +5 -6
- package/src/components/Globe/Globe.tsx +56 -21
- package/src/components/Map/Map.stories.tsx +7 -6
- package/src/components/Map/Map.tsx +76 -31
- package/src/components/Toolbar/Controls.tsx +5 -5
- package/src/hooks/context.tsx +5 -34
- package/src/hooks/useSpinner.ts +0 -1
- package/src/index.ts +0 -2
- package/src/translations.ts +4 -4
- package/src/util/render.ts +0 -1
- package/dist/lib/browser/chunk-GMWLKTLN.mjs +0 -9
- package/dist/lib/browser/chunk-GMWLKTLN.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JODBF4CC.mjs +0 -11
- package/dist/lib/node-esm/chunk-JODBF4CC.mjs.map +0 -7
- /package/dist/lib/browser/{countries-110m-ZM3ZIEFS.mjs.map → countries-110m-RE5RNRQG.mjs.map} +0 -0
- /package/dist/lib/node-esm/{countries-110m-3SFASWVD.mjs.map → countries-110m-4EDBXSFJ.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.4-main.
|
|
3
|
+
"version": "0.8.4-main.d05539e30a",
|
|
4
4
|
"description": "Geo components.",
|
|
5
5
|
"homepage": "https://github.com/dxos",
|
|
6
6
|
"bugs": "https://github.com/dxos/issues",
|
|
@@ -8,38 +8,41 @@
|
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/dxos/dxos"
|
|
10
10
|
},
|
|
11
|
-
"license": "
|
|
11
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
12
12
|
"author": "DXOS.org",
|
|
13
13
|
"sideEffects": true,
|
|
14
14
|
"type": "module",
|
|
15
|
+
"imports": {
|
|
16
|
+
"#translations": "./src/translations.ts"
|
|
17
|
+
},
|
|
15
18
|
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"source": "./src/index.ts",
|
|
21
|
+
"types": "./dist/types/src/index.d.ts",
|
|
22
|
+
"browser": "./dist/lib/browser/index.mjs",
|
|
23
|
+
"node": "./dist/lib/node-esm/index.mjs"
|
|
24
|
+
},
|
|
16
25
|
"./data": {
|
|
17
26
|
"source": "./src/data.ts",
|
|
18
27
|
"types": "./dist/types/src/data.d.ts",
|
|
19
28
|
"browser": "./dist/lib/browser/data.mjs",
|
|
20
29
|
"node": "./dist/lib/node-esm/data.mjs"
|
|
21
30
|
},
|
|
22
|
-
"
|
|
23
|
-
"source": "./src/
|
|
24
|
-
"types": "./dist/types/src/
|
|
25
|
-
"browser": "./dist/lib/browser/
|
|
26
|
-
"node": "./dist/lib/node-esm/
|
|
31
|
+
"./translations": {
|
|
32
|
+
"source": "./src/translations.ts",
|
|
33
|
+
"types": "./dist/types/src/translations.d.ts",
|
|
34
|
+
"browser": "./dist/lib/browser/translations.mjs",
|
|
35
|
+
"node": "./dist/lib/node-esm/translations.mjs"
|
|
27
36
|
}
|
|
28
37
|
},
|
|
29
38
|
"types": "dist/types/src/index.d.ts",
|
|
30
|
-
"typesVersions": {
|
|
31
|
-
"*": {
|
|
32
|
-
"data": [
|
|
33
|
-
"dist/types/src/data.d.ts"
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
39
|
"files": [
|
|
38
40
|
"data",
|
|
39
41
|
"dist",
|
|
40
42
|
"src"
|
|
41
43
|
],
|
|
42
44
|
"dependencies": {
|
|
45
|
+
"@radix-ui/react-compose-refs": "1.1.1",
|
|
43
46
|
"@radix-ui/react-context": "1.1.1",
|
|
44
47
|
"d3": "^7.9.0",
|
|
45
48
|
"d3-geo-projection": "^4.0.0",
|
|
@@ -52,11 +55,11 @@
|
|
|
52
55
|
"topojson-client": "^3.1.0",
|
|
53
56
|
"topojson-simplify": "^3.0.3",
|
|
54
57
|
"versor": "^0.2.0",
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/log": "0.8.4-main.
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/node-std": "0.8.4-main.
|
|
59
|
-
"@dxos/util": "0.8.4-main.
|
|
58
|
+
"@dxos/async": "0.8.4-main.d05539e30a",
|
|
59
|
+
"@dxos/log": "0.8.4-main.d05539e30a",
|
|
60
|
+
"@dxos/debug": "0.8.4-main.d05539e30a",
|
|
61
|
+
"@dxos/node-std": "0.8.4-main.d05539e30a",
|
|
62
|
+
"@dxos/util": "0.8.4-main.d05539e30a"
|
|
60
63
|
},
|
|
61
64
|
"devDependencies": {
|
|
62
65
|
"@react-three/drei": "^10.7.7",
|
|
@@ -76,15 +79,15 @@
|
|
|
76
79
|
"react": "~19.2.3",
|
|
77
80
|
"react-dom": "~19.2.3",
|
|
78
81
|
"three": "^0.178.0",
|
|
79
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
80
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
81
|
-
"@dxos/storybook-utils": "0.8.4-main.
|
|
82
|
+
"@dxos/react-ui": "0.8.4-main.d05539e30a",
|
|
83
|
+
"@dxos/ui-theme": "0.8.4-main.d05539e30a",
|
|
84
|
+
"@dxos/storybook-utils": "0.8.4-main.d05539e30a"
|
|
82
85
|
},
|
|
83
86
|
"peerDependencies": {
|
|
84
87
|
"react": "~19.2.3",
|
|
85
88
|
"react-dom": "~19.2.3",
|
|
86
|
-
"@dxos/
|
|
87
|
-
"@dxos/ui
|
|
89
|
+
"@dxos/ui-theme": "0.8.4-main.d05539e30a",
|
|
90
|
+
"@dxos/react-ui": "0.8.4-main.d05539e30a"
|
|
88
91
|
},
|
|
89
92
|
"publishConfig": {
|
|
90
93
|
"access": "public"
|
|
@@ -15,7 +15,6 @@ import { type Vector, useDrag, useGlobeZoomHandler, useSpinner, useTour } from '
|
|
|
15
15
|
import { type LatLngLiteral } from '../../types';
|
|
16
16
|
import { type StyleSet, closestPoint } from '../../util';
|
|
17
17
|
import { type ControlProps } from '../Toolbar';
|
|
18
|
-
|
|
19
18
|
import { Globe, type GlobeCanvasProps, type GlobeController, type GlobeRootProps } from './Globe';
|
|
20
19
|
|
|
21
20
|
// TODO(burdon): Load from JSON at runtime?
|
|
@@ -128,7 +127,7 @@ const createTrip = (
|
|
|
128
127
|
);
|
|
129
128
|
};
|
|
130
129
|
|
|
131
|
-
type
|
|
130
|
+
type DefaultStoryProps = Pick<GlobeRootProps, 'zoom' | 'translation' | 'rotation'> &
|
|
132
131
|
Pick<GlobeCanvasProps, 'projection' | 'styles'> & {
|
|
133
132
|
drag?: boolean;
|
|
134
133
|
spin?: boolean;
|
|
@@ -137,7 +136,7 @@ type StoryProps = Pick<GlobeRootProps, 'zoom' | 'translation' | 'rotation'> &
|
|
|
137
136
|
};
|
|
138
137
|
|
|
139
138
|
const DefaultStory = ({
|
|
140
|
-
zoom:
|
|
139
|
+
zoom: zoomProp = 1,
|
|
141
140
|
translation,
|
|
142
141
|
rotation = [0, 0, 0],
|
|
143
142
|
projection,
|
|
@@ -146,7 +145,7 @@ const DefaultStory = ({
|
|
|
146
145
|
spin = false,
|
|
147
146
|
tour = false,
|
|
148
147
|
xAxis = false,
|
|
149
|
-
}:
|
|
148
|
+
}: DefaultStoryProps) => {
|
|
150
149
|
const controller = useRef<GlobeController>(null);
|
|
151
150
|
const [dots] = useAsyncState(async () => {
|
|
152
151
|
const points = (await import('../../../data/countries-dots-3.ts')).default;
|
|
@@ -203,13 +202,13 @@ const DefaultStory = ({
|
|
|
203
202
|
};
|
|
204
203
|
|
|
205
204
|
return (
|
|
206
|
-
<Globe.Root
|
|
205
|
+
<Globe.Root zoom={zoomProp} translation={translation} rotation={rotation}>
|
|
207
206
|
<Globe.Canvas
|
|
208
|
-
ref={controller}
|
|
209
207
|
topology={styles?.dots ? dots : topology}
|
|
210
208
|
projection={projection}
|
|
211
209
|
styles={styles}
|
|
212
210
|
features={tour ? { points: features?.points ?? [] } : features}
|
|
211
|
+
ref={controller}
|
|
213
212
|
/>
|
|
214
213
|
<Globe.Zoom onAction={handleAction} />
|
|
215
214
|
<Globe.Action onAction={handleAction} />
|
|
@@ -26,15 +26,17 @@ import React, {
|
|
|
26
26
|
import { useResizeDetector } from 'react-resize-detector';
|
|
27
27
|
import { type Topology } from 'topojson-specification';
|
|
28
28
|
|
|
29
|
-
import { type ThemeMode, type ThemedClassName, useDynamicRef, useThemeContext } from '@dxos/react-ui';
|
|
30
|
-
import { mx } from '@dxos/ui-theme';
|
|
31
|
-
|
|
32
29
|
import {
|
|
33
|
-
|
|
34
|
-
type
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
type ThemeMode,
|
|
31
|
+
type ThemedClassName,
|
|
32
|
+
useComposedRefs,
|
|
33
|
+
useControlledState,
|
|
34
|
+
useDynamicRef,
|
|
35
|
+
useThemeContext,
|
|
36
|
+
} from '@dxos/react-ui';
|
|
37
|
+
import { composable, composableProps, mx } from '@dxos/ui-theme';
|
|
38
|
+
|
|
39
|
+
import { GlobeContext, type GlobeContextType, type Point, type Vector, useGlobeContext } from '../../hooks';
|
|
38
40
|
import {
|
|
39
41
|
type Features,
|
|
40
42
|
type StyleSet,
|
|
@@ -126,19 +128,52 @@ const getProjection = (type: GlobeCanvasProps['projection'] = 'orthographic'): G
|
|
|
126
128
|
// Root
|
|
127
129
|
//
|
|
128
130
|
|
|
129
|
-
|
|
131
|
+
const DEFAULT_ZOOM = 1.5;
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
const { ref, width, height } = useResizeDetector<HTMLDivElement>();
|
|
133
|
+
type GlobeRootProps = Partial<Pick<GlobeContextType, 'center' | 'zoom' | 'translation' | 'rotation'>>;
|
|
133
134
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
135
|
+
const GlobeRoot = composable<HTMLDivElement, GlobeRootProps>(
|
|
136
|
+
(
|
|
137
|
+
{
|
|
138
|
+
children,
|
|
139
|
+
center: centerProp,
|
|
140
|
+
zoom: zoomProp = DEFAULT_ZOOM,
|
|
141
|
+
translation: translationProp,
|
|
142
|
+
rotation: rotationProp,
|
|
143
|
+
...props
|
|
144
|
+
},
|
|
145
|
+
forwardedRef,
|
|
146
|
+
) => {
|
|
147
|
+
const localRef = useRef<HTMLDivElement>(null);
|
|
148
|
+
const composedRef = useComposedRefs<HTMLDivElement>(localRef, forwardedRef);
|
|
149
|
+
const { width, height } = useResizeDetector<HTMLDivElement>({ targetRef: localRef });
|
|
150
|
+
|
|
151
|
+
const [center, setCenter] = useControlledState(centerProp);
|
|
152
|
+
const [zoom, setZoom] = useControlledState(zoomProp);
|
|
153
|
+
const [translation, setTranslation] = useControlledState<Point>(translationProp);
|
|
154
|
+
const [rotation, setRotation] = useControlledState<Vector>(rotationProp);
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<GlobeContext.Provider
|
|
158
|
+
value={{
|
|
159
|
+
size: { width, height },
|
|
160
|
+
center,
|
|
161
|
+
zoom,
|
|
162
|
+
translation,
|
|
163
|
+
rotation,
|
|
164
|
+
setCenter,
|
|
165
|
+
setZoom,
|
|
166
|
+
setTranslation,
|
|
167
|
+
setRotation,
|
|
168
|
+
}}
|
|
169
|
+
>
|
|
170
|
+
<div {...composableProps(props, { classNames: 'relative dx-container' })} ref={composedRef}>
|
|
171
|
+
{children}
|
|
172
|
+
</div>
|
|
173
|
+
</GlobeContext.Provider>
|
|
174
|
+
);
|
|
175
|
+
},
|
|
176
|
+
);
|
|
142
177
|
|
|
143
178
|
//
|
|
144
179
|
// Canvas
|
|
@@ -179,10 +214,10 @@ const GlobeCanvas = forwardRef<GlobeController, GlobeCanvasProps>(
|
|
|
179
214
|
useGlobeContext();
|
|
180
215
|
const zoomRef = useDynamicRef(zoom);
|
|
181
216
|
|
|
182
|
-
// Update rotation.
|
|
217
|
+
// Update rotation when the center changes. Preserve current zoom — callers can set zoom
|
|
218
|
+
// independently via the `zoom` prop or `setZoom` on the controller.
|
|
183
219
|
useEffect(() => {
|
|
184
220
|
if (center) {
|
|
185
|
-
setZoom(1);
|
|
186
221
|
setRotation(positionToRotation(geoToPosition(center)));
|
|
187
222
|
}
|
|
188
223
|
}, [center]);
|
|
@@ -9,7 +9,6 @@ import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
|
9
9
|
|
|
10
10
|
import { useMapZoomHandler } from '../../hooks';
|
|
11
11
|
import { type GeoMarker } from '../../types';
|
|
12
|
-
|
|
13
12
|
import { Map, type MapController } from './Map';
|
|
14
13
|
|
|
15
14
|
const DefaultStory = ({ markers = [] }: { markers?: GeoMarker[] }) => {
|
|
@@ -17,11 +16,13 @@ const DefaultStory = ({ markers = [] }: { markers?: GeoMarker[] }) => {
|
|
|
17
16
|
const handleZoomAction = useMapZoomHandler(controller);
|
|
18
17
|
|
|
19
18
|
return (
|
|
20
|
-
<Map.Root
|
|
21
|
-
<Map.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
<Map.Root>
|
|
20
|
+
<Map.Content ref={setController}>
|
|
21
|
+
<Map.Tiles />
|
|
22
|
+
<Map.Markers markers={markers} />
|
|
23
|
+
<Map.Zoom position='bottomleft' onAction={handleZoomAction} />
|
|
24
|
+
<Map.Action position='bottomright' />
|
|
25
|
+
</Map.Content>
|
|
25
26
|
</Map.Root>
|
|
26
27
|
);
|
|
27
28
|
};
|
|
@@ -6,12 +6,12 @@ import 'leaflet/dist/leaflet.css';
|
|
|
6
6
|
|
|
7
7
|
import { createContext } from '@radix-ui/react-context';
|
|
8
8
|
import L, { Control, type ControlPosition, DomEvent, DomUtil, type LatLngLiteral, latLngBounds } from 'leaflet';
|
|
9
|
-
import React, { type PropsWithChildren, forwardRef, useEffect, useImperativeHandle, useRef
|
|
9
|
+
import React, { type PropsWithChildren, forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
|
|
10
10
|
import { createRoot } from 'react-dom/client';
|
|
11
11
|
import { MapContainer, type MapContainerProps, Marker, Popup, TileLayer, useMap, useMapEvents } from 'react-leaflet';
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
import { defaultTx, mx } from '@dxos/ui-theme';
|
|
13
|
+
import { type ThemedClassName, ThemeProvider, Tooltip } from '@dxos/react-ui';
|
|
14
|
+
import { composable, composableProps, defaultTx, mx } from '@dxos/ui-theme';
|
|
15
15
|
|
|
16
16
|
import { type GeoMarker } from '../../types';
|
|
17
17
|
import { ActionControls, type ControlProps, ZoomControls, controlPositions } from '../Toolbar';
|
|
@@ -30,6 +30,8 @@ const defaults = {
|
|
|
30
30
|
//
|
|
31
31
|
|
|
32
32
|
type MapController = {
|
|
33
|
+
getCenter: () => LatLngLiteral | undefined;
|
|
34
|
+
getZoom: () => number | undefined;
|
|
33
35
|
setCenter: (center: LatLngLiteral, zoom?: number) => void;
|
|
34
36
|
setZoom: (cb: (zoom: number) => number) => void;
|
|
35
37
|
};
|
|
@@ -43,29 +45,65 @@ type MapContextValue = {
|
|
|
43
45
|
onChange?: (ev: { center: LatLngLiteral; zoom: number }) => void;
|
|
44
46
|
};
|
|
45
47
|
|
|
46
|
-
const [
|
|
48
|
+
const [MapContextProvider, useMapContext] = createContext<MapContextValue>('Map');
|
|
47
49
|
|
|
48
50
|
//
|
|
49
51
|
// Root
|
|
50
52
|
//
|
|
51
53
|
|
|
52
|
-
type MapRootProps =
|
|
54
|
+
type MapRootProps = Pick<MapContextValue, 'onChange'>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Context provider for the map. Must wrap Map.Content.
|
|
58
|
+
*/
|
|
59
|
+
const MapRoot = composable<HTMLDivElement, MapRootProps>(({ children, onChange, ...props }, forwardedRef) => {
|
|
60
|
+
// TODO(burdon): Use attention: const [attention, setAttention] = useState(false);
|
|
61
|
+
const attention = false;
|
|
62
|
+
return (
|
|
63
|
+
<MapContextProvider attention={attention} onChange={onChange}>
|
|
64
|
+
<div
|
|
65
|
+
{...composableProps(props, {
|
|
66
|
+
role: 'none',
|
|
67
|
+
classNames: 'dx-container grid dx-focus-ring-inset',
|
|
68
|
+
})}
|
|
69
|
+
ref={forwardedRef}
|
|
70
|
+
>
|
|
71
|
+
{children}
|
|
72
|
+
</div>
|
|
73
|
+
</MapContextProvider>
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
MapRoot.displayName = 'Map.Root';
|
|
78
|
+
|
|
79
|
+
//
|
|
80
|
+
// Content
|
|
81
|
+
//
|
|
82
|
+
|
|
83
|
+
type MapContentProps = ThemedClassName<Omit<MapContainerProps, 'children'> & PropsWithChildren>;
|
|
53
84
|
|
|
54
85
|
/**
|
|
55
86
|
* https://react-leaflet.js.org/docs/api-map
|
|
56
87
|
*/
|
|
57
|
-
const
|
|
88
|
+
const MAP_CONTENT_NAME = 'Map.Content';
|
|
89
|
+
|
|
90
|
+
const MapContent = forwardRef<MapController, MapContentProps>(
|
|
58
91
|
(
|
|
59
|
-
{ classNames, scrollWheelZoom = true, doubleClickZoom = true, touchZoom = true, center, zoom,
|
|
92
|
+
{ classNames, scrollWheelZoom = true, doubleClickZoom = true, touchZoom = true, center, zoom, children, ...props },
|
|
60
93
|
forwardedRef,
|
|
61
94
|
) => {
|
|
62
|
-
const
|
|
95
|
+
const { attention } = useMapContext(MAP_CONTENT_NAME);
|
|
63
96
|
const mapRef = useRef<L.Map>(null);
|
|
64
97
|
const map = mapRef.current;
|
|
65
98
|
|
|
66
99
|
useImperativeHandle(
|
|
67
100
|
forwardedRef,
|
|
68
101
|
() => ({
|
|
102
|
+
getCenter: () => {
|
|
103
|
+
const center = mapRef.current?.getCenter();
|
|
104
|
+
return center ? { lat: center.lat, lng: center.lng } : undefined;
|
|
105
|
+
},
|
|
106
|
+
getZoom: () => mapRef.current?.getZoom(),
|
|
69
107
|
setCenter: (center: LatLngLiteral, zoom?: number) => {
|
|
70
108
|
mapRef.current?.setView(center, zoom);
|
|
71
109
|
},
|
|
@@ -92,26 +130,26 @@ const MapRoot = forwardRef<MapController, MapRootProps>(
|
|
|
92
130
|
}, [map, attention]);
|
|
93
131
|
|
|
94
132
|
return (
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
</
|
|
133
|
+
<MapContainer
|
|
134
|
+
{...props}
|
|
135
|
+
className={mx('group relative grid bg-base-surface!', classNames)}
|
|
136
|
+
attributionControl={false}
|
|
137
|
+
zoomControl={false}
|
|
138
|
+
scrollWheelZoom={scrollWheelZoom}
|
|
139
|
+
doubleClickZoom={doubleClickZoom}
|
|
140
|
+
touchZoom={touchZoom}
|
|
141
|
+
center={center ?? defaults.center}
|
|
142
|
+
zoom={zoom ?? defaults.zoom}
|
|
143
|
+
whenReady={() => {}}
|
|
144
|
+
ref={mapRef}
|
|
145
|
+
>
|
|
146
|
+
{children}
|
|
147
|
+
</MapContainer>
|
|
110
148
|
);
|
|
111
149
|
},
|
|
112
150
|
);
|
|
113
151
|
|
|
114
|
-
|
|
152
|
+
MapContent.displayName = 'Map.Content';
|
|
115
153
|
|
|
116
154
|
//
|
|
117
155
|
// Tiles
|
|
@@ -127,7 +165,7 @@ const MapTiles = (_props: MapTilesProps) => {
|
|
|
127
165
|
const { onChange } = useMapContext(MAP_TILES_NAME);
|
|
128
166
|
|
|
129
167
|
useMapEvents({
|
|
130
|
-
|
|
168
|
+
moveend: (ev) => {
|
|
131
169
|
onChange?.({
|
|
132
170
|
center: ev.target.getCenter(),
|
|
133
171
|
zoom: ev.target.getZoom(),
|
|
@@ -192,15 +230,14 @@ type MapMarkersProps = {
|
|
|
192
230
|
const MapMarkers = ({ selected, markers }: MapMarkersProps) => {
|
|
193
231
|
const map = useMap();
|
|
194
232
|
|
|
195
|
-
//
|
|
233
|
+
// Fit the viewport around the markers. When there are no markers, leave the current view alone
|
|
234
|
+
// so caller-provided center/zoom (or the user's prior interaction) is preserved.
|
|
196
235
|
useEffect(() => {
|
|
197
|
-
if (markers.length > 0) {
|
|
236
|
+
if (markers && markers.length > 0) {
|
|
198
237
|
const bounds = latLngBounds(markers.map((marker) => marker.location));
|
|
199
238
|
map.fitBounds(bounds);
|
|
200
|
-
} else {
|
|
201
|
-
map.setView(defaults.center, defaults.zoom);
|
|
202
239
|
}
|
|
203
|
-
}, [markers]);
|
|
240
|
+
}, [markers, map]);
|
|
204
241
|
|
|
205
242
|
return (
|
|
206
243
|
<>
|
|
@@ -292,10 +329,18 @@ const MapAction = ({ onAction, position = 'bottomright', ...props }: MapControlP
|
|
|
292
329
|
|
|
293
330
|
export const Map = {
|
|
294
331
|
Root: MapRoot,
|
|
332
|
+
Content: MapContent,
|
|
295
333
|
Tiles: MapTiles,
|
|
296
334
|
Markers: MapMarkers,
|
|
297
335
|
Zoom: MapZoom,
|
|
298
336
|
Action: MapAction,
|
|
299
337
|
};
|
|
300
338
|
|
|
301
|
-
export {
|
|
339
|
+
export {
|
|
340
|
+
type MapController,
|
|
341
|
+
type MapRootProps,
|
|
342
|
+
type MapContentProps,
|
|
343
|
+
type MapTilesProps,
|
|
344
|
+
type MapMarkersProps,
|
|
345
|
+
type MapControlProps,
|
|
346
|
+
};
|
|
@@ -7,7 +7,7 @@ import React from 'react';
|
|
|
7
7
|
|
|
8
8
|
import { IconButton, type ThemedClassName, Toolbar, useTranslation } from '@dxos/react-ui';
|
|
9
9
|
|
|
10
|
-
import { translationKey } from '
|
|
10
|
+
import { translationKey } from '#translations';
|
|
11
11
|
|
|
12
12
|
export type ControlAction = 'toggle' | 'start' | 'zoom-in' | 'zoom-out';
|
|
13
13
|
|
|
@@ -30,13 +30,13 @@ export const ZoomControls = ({ classNames, onAction }: ControlProps) => {
|
|
|
30
30
|
<IconButton
|
|
31
31
|
icon='ph--plus--regular'
|
|
32
32
|
iconOnly
|
|
33
|
-
label={t('zoom
|
|
33
|
+
label={t('zoom-in-icon.button')}
|
|
34
34
|
onClick={() => onAction?.('zoom-in')}
|
|
35
35
|
/>
|
|
36
36
|
<IconButton
|
|
37
37
|
icon='ph--minus--regular'
|
|
38
38
|
iconOnly
|
|
39
|
-
label={t('zoom
|
|
39
|
+
label={t('zoom-out-icon.button')}
|
|
40
40
|
onClick={() => onAction?.('zoom-out')}
|
|
41
41
|
/>
|
|
42
42
|
</Toolbar.Root>
|
|
@@ -51,13 +51,13 @@ export const ActionControls = ({ classNames, onAction }: ControlProps) => {
|
|
|
51
51
|
<IconButton
|
|
52
52
|
icon='ph--path--regular'
|
|
53
53
|
iconOnly
|
|
54
|
-
label={t('start
|
|
54
|
+
label={t('start-icon.button')}
|
|
55
55
|
onClick={() => onAction?.('start')}
|
|
56
56
|
/>
|
|
57
57
|
<IconButton
|
|
58
58
|
icon='ph--globe-hemisphere-west--regular'
|
|
59
59
|
iconOnly
|
|
60
|
-
label={t('toggle
|
|
60
|
+
label={t('toggle-icon.button')}
|
|
61
61
|
onClick={() => onAction?.('toggle')}
|
|
62
62
|
/>
|
|
63
63
|
</Toolbar.Root>
|
package/src/hooks/context.tsx
CHANGED
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import { type Dispatch, type SetStateAction, createContext, useContext } from 'react';
|
|
6
6
|
|
|
7
7
|
import { raise } from '@dxos/debug';
|
|
8
|
-
import { useControlledState } from '@dxos/react-ui';
|
|
9
8
|
|
|
10
9
|
import { type LatLngLiteral } from '../types';
|
|
11
10
|
|
|
12
11
|
// TODO(burdon): Factor out common geometry types.
|
|
13
12
|
export type Size = { width: number; height: number };
|
|
13
|
+
|
|
14
14
|
export type Point = { x: number; y: number };
|
|
15
|
+
|
|
15
16
|
export type Vector = [number, number, number];
|
|
16
17
|
|
|
17
18
|
export type GlobeContextType = {
|
|
@@ -26,39 +27,9 @@ export type GlobeContextType = {
|
|
|
26
27
|
setRotation: Dispatch<SetStateAction<Vector>>;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
center: { lat: 51, lng: 0 } as LatLngLiteral,
|
|
31
|
-
zoom: 4,
|
|
32
|
-
} as const;
|
|
33
|
-
|
|
30
|
+
/** @internal */
|
|
34
31
|
// TODO(burdon): Replace with radix.
|
|
35
|
-
const GlobeContext = createContext<GlobeContextType>(undefined);
|
|
36
|
-
|
|
37
|
-
export type GlobeContextProviderProps = PropsWithChildren<
|
|
38
|
-
Partial<Pick<GlobeContextType, 'size' | 'center' | 'zoom' | 'translation' | 'rotation'>>
|
|
39
|
-
>;
|
|
40
|
-
|
|
41
|
-
export const GlobeContextProvider = ({
|
|
42
|
-
children,
|
|
43
|
-
size,
|
|
44
|
-
center: centerProp = defaults.center,
|
|
45
|
-
zoom: zoomProp = defaults.zoom,
|
|
46
|
-
translation: translationProp,
|
|
47
|
-
rotation: rotationProp,
|
|
48
|
-
}: GlobeContextProviderProps) => {
|
|
49
|
-
const [center, setCenter] = useControlledState(centerProp);
|
|
50
|
-
const [zoom, setZoom] = useControlledState(zoomProp);
|
|
51
|
-
const [translation, setTranslation] = useControlledState<Point>(translationProp);
|
|
52
|
-
const [rotation, setRotation] = useControlledState<Vector>(rotationProp);
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<GlobeContext.Provider
|
|
56
|
-
value={{ size, center, zoom, translation, rotation, setCenter, setZoom, setTranslation, setRotation }}
|
|
57
|
-
>
|
|
58
|
-
{children}
|
|
59
|
-
</GlobeContext.Provider>
|
|
60
|
-
);
|
|
61
|
-
};
|
|
32
|
+
export const GlobeContext = createContext<GlobeContextType>(undefined);
|
|
62
33
|
|
|
63
34
|
export const useGlobeContext = () => {
|
|
64
35
|
return useContext(GlobeContext) ?? raise(new Error('Missing GlobeContext'));
|
package/src/hooks/useSpinner.ts
CHANGED
package/src/index.ts
CHANGED
package/src/translations.ts
CHANGED
|
@@ -10,10 +10,10 @@ export const translations = [
|
|
|
10
10
|
{
|
|
11
11
|
'en-US': {
|
|
12
12
|
[translationKey]: {
|
|
13
|
-
'zoom
|
|
14
|
-
'zoom
|
|
15
|
-
'start
|
|
16
|
-
'toggle
|
|
13
|
+
'zoom-in-icon.button': 'Zoom in',
|
|
14
|
+
'zoom-out-icon.button': 'Zoom out',
|
|
15
|
+
'start-icon.button': 'Start',
|
|
16
|
+
'toggle-icon.button': 'Toggle',
|
|
17
17
|
},
|
|
18
18
|
},
|
|
19
19
|
},
|
package/src/util/render.ts
CHANGED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/data.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Topology } from 'topojson-specification';\n\nexport const loadTopology = async (): Promise<Topology> => {\n return (await import('../data/countries-110m.ts')).default;\n};\n"],
|
|
5
|
-
"mappings": ";AAMO,IAAMA,eAAe,YAAA;AAC1B,UAAQ,MAAM,OAAO,+BAAA,GAA8BC;AACrD;",
|
|
6
|
-
"names": ["loadTopology", "default"]
|
|
7
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
|
-
|
|
3
|
-
// src/data.ts
|
|
4
|
-
var loadTopology = async () => {
|
|
5
|
-
return (await import("./countries-110m-3SFASWVD.mjs")).default;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export {
|
|
9
|
-
loadTopology
|
|
10
|
-
};
|
|
11
|
-
//# sourceMappingURL=chunk-JODBF4CC.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/data.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Topology } from 'topojson-specification';\n\nexport const loadTopology = async (): Promise<Topology> => {\n return (await import('../data/countries-110m.ts')).default;\n};\n"],
|
|
5
|
-
"mappings": ";;;AAMO,IAAMA,eAAe,YAAA;AAC1B,UAAQ,MAAM,OAAO,+BAAA,GAA8BC;AACrD;",
|
|
6
|
-
"names": ["loadTopology", "default"]
|
|
7
|
-
}
|
/package/dist/lib/browser/{countries-110m-ZM3ZIEFS.mjs.map → countries-110m-RE5RNRQG.mjs.map}
RENAMED
|
File without changes
|
/package/dist/lib/node-esm/{countries-110m-3SFASWVD.mjs.map → countries-110m-4EDBXSFJ.mjs.map}
RENAMED
|
File without changes
|