@dxos/react-ui-geo 0.8.4-main.406dc2a → 0.8.4-main.40e3dcdf1b
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/dist/lib/browser/index.mjs +369 -451
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +369 -451
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
- package/dist/types/src/components/Map/Map.d.ts +7 -10
- package/dist/types/src/components/Map/Map.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 -1
- package/dist/types/src/hooks/context.d.ts.map +1 -1
- package/dist/types/src/hooks/useGlobeZoomHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useTour.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +12 -0
- package/dist/types/src/translations.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +26 -23
- package/src/components/Globe/Globe.stories.tsx +2 -2
- package/src/components/Globe/Globe.tsx +10 -9
- package/src/components/Map/Map.stories.tsx +2 -2
- package/src/components/Map/Map.tsx +25 -53
- package/src/components/Toolbar/Controls.tsx +12 -14
- package/src/hooks/context.tsx +14 -8
- package/src/hooks/useGlobeZoomHandler.ts +8 -2
- package/src/hooks/useTour.ts +1 -0
- package/src/index.ts +1 -0
- package/src/translations.ts +20 -0
|
@@ -3,42 +3,42 @@ import {
|
|
|
3
3
|
} from "./chunk-GMWLKTLN.mjs";
|
|
4
4
|
|
|
5
5
|
// src/components/Globe/Globe.tsx
|
|
6
|
-
import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
|
|
7
6
|
import { easeLinear, easeSinOut, geoMercator, geoOrthographic, geoPath as geoPath2, geoTransverseMercator, interpolateNumber, transition } from "d3";
|
|
8
7
|
import React3, { forwardRef, useEffect as useEffect4, useImperativeHandle, useMemo as useMemo2, useRef, useState as useState3 } from "react";
|
|
9
8
|
import { useResizeDetector } from "react-resize-detector";
|
|
10
9
|
import { useDynamicRef, useThemeContext } from "@dxos/react-ui";
|
|
11
|
-
import { mx } from "@dxos/
|
|
10
|
+
import { mx } from "@dxos/ui-theme";
|
|
12
11
|
|
|
13
12
|
// src/hooks/context.tsx
|
|
14
|
-
import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
|
|
15
13
|
import React, { createContext, useContext } from "react";
|
|
16
14
|
import { raise } from "@dxos/debug";
|
|
17
15
|
import { useControlledState } from "@dxos/react-ui";
|
|
16
|
+
var defaults = {
|
|
17
|
+
center: {
|
|
18
|
+
lat: 51,
|
|
19
|
+
lng: 0
|
|
20
|
+
},
|
|
21
|
+
zoom: 4
|
|
22
|
+
};
|
|
18
23
|
var GlobeContext = /* @__PURE__ */ createContext(void 0);
|
|
19
|
-
var GlobeContextProvider = ({ children, size, center:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
}, children);
|
|
39
|
-
} finally {
|
|
40
|
-
_effect.f();
|
|
41
|
-
}
|
|
24
|
+
var GlobeContextProvider = ({ children, size, center: centerProp = defaults.center, zoom: zoomProp = defaults.zoom, translation: translationProp, rotation: rotationProp }) => {
|
|
25
|
+
const [center, setCenter] = useControlledState(centerProp);
|
|
26
|
+
const [zoom, setZoom] = useControlledState(zoomProp);
|
|
27
|
+
const [translation, setTranslation] = useControlledState(translationProp);
|
|
28
|
+
const [rotation, setRotation] = useControlledState(rotationProp);
|
|
29
|
+
return /* @__PURE__ */ React.createElement(GlobeContext.Provider, {
|
|
30
|
+
value: {
|
|
31
|
+
size,
|
|
32
|
+
center,
|
|
33
|
+
zoom,
|
|
34
|
+
translation,
|
|
35
|
+
rotation,
|
|
36
|
+
setCenter,
|
|
37
|
+
setZoom,
|
|
38
|
+
setTranslation,
|
|
39
|
+
setRotation
|
|
40
|
+
}
|
|
41
|
+
}, children);
|
|
42
42
|
};
|
|
43
43
|
var useGlobeContext = () => {
|
|
44
44
|
return useContext(GlobeContext) ?? raise(new Error("Missing GlobeContext"));
|
|
@@ -376,8 +376,8 @@ var renderLayers = (generator, layers = [], scale, styles) => {
|
|
|
376
376
|
generator.pointRadius(value * scale);
|
|
377
377
|
} else {
|
|
378
378
|
context[key] = value;
|
|
379
|
-
fill
|
|
380
|
-
stroke
|
|
379
|
+
fill ||= key === "fillStyle";
|
|
380
|
+
stroke ||= key === "strokeStyle";
|
|
381
381
|
}
|
|
382
382
|
});
|
|
383
383
|
}
|
|
@@ -427,6 +427,7 @@ var cancelDrag = (node) => node.on(".drag", null);
|
|
|
427
427
|
|
|
428
428
|
// src/hooks/useGlobeZoomHandler.ts
|
|
429
429
|
import { useCallback } from "react";
|
|
430
|
+
var ZOOM_FACTOR = 0.1;
|
|
430
431
|
var useGlobeZoomHandler = (controller) => {
|
|
431
432
|
return useCallback((event) => {
|
|
432
433
|
if (!controller) {
|
|
@@ -434,11 +435,15 @@ var useGlobeZoomHandler = (controller) => {
|
|
|
434
435
|
}
|
|
435
436
|
switch (event) {
|
|
436
437
|
case "zoom-in": {
|
|
437
|
-
controller.setZoom((zoom) =>
|
|
438
|
+
controller.setZoom((zoom) => {
|
|
439
|
+
return zoom * (1 + ZOOM_FACTOR);
|
|
440
|
+
});
|
|
438
441
|
break;
|
|
439
442
|
}
|
|
440
443
|
case "zoom-out": {
|
|
441
|
-
controller.setZoom((zoom) =>
|
|
444
|
+
controller.setZoom((zoom) => {
|
|
445
|
+
return zoom * (1 - ZOOM_FACTOR);
|
|
446
|
+
});
|
|
442
447
|
break;
|
|
443
448
|
}
|
|
444
449
|
}
|
|
@@ -619,9 +624,25 @@ var useTour = (controller, points, options = {}) => {
|
|
|
619
624
|
};
|
|
620
625
|
|
|
621
626
|
// src/components/Toolbar/Controls.tsx
|
|
622
|
-
import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
|
|
623
627
|
import React2 from "react";
|
|
624
|
-
import { IconButton, Toolbar } from "@dxos/react-ui";
|
|
628
|
+
import { IconButton, Toolbar, useTranslation } from "@dxos/react-ui";
|
|
629
|
+
|
|
630
|
+
// src/translations.ts
|
|
631
|
+
var translationKey = "@dxos/react-ui-geo";
|
|
632
|
+
var translations = [
|
|
633
|
+
{
|
|
634
|
+
"en-US": {
|
|
635
|
+
[translationKey]: {
|
|
636
|
+
"zoom in icon button": "Zoom in",
|
|
637
|
+
"zoom out icon button": "Zoom out",
|
|
638
|
+
"start icon button": "Start",
|
|
639
|
+
"toggle icon button": "Toggle"
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
];
|
|
644
|
+
|
|
645
|
+
// src/components/Toolbar/Controls.tsx
|
|
625
646
|
var controlPositions = {
|
|
626
647
|
topleft: "top-2 left-2",
|
|
627
648
|
topright: "top-2 right-2",
|
|
@@ -629,58 +650,42 @@ var controlPositions = {
|
|
|
629
650
|
bottomright: "bottom-2 right-2"
|
|
630
651
|
};
|
|
631
652
|
var ZoomControls = ({ classNames, onAction }) => {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
iconOnly: true,
|
|
650
|
-
size: 5,
|
|
651
|
-
classNames: "px-0 aspect-square",
|
|
652
|
-
onClick: () => onAction?.("zoom-out")
|
|
653
|
-
}));
|
|
654
|
-
} finally {
|
|
655
|
-
_effect.f();
|
|
656
|
-
}
|
|
653
|
+
const { t } = useTranslation(translationKey);
|
|
654
|
+
return /* @__PURE__ */ React2.createElement(Toolbar.Root, {
|
|
655
|
+
classNames: [
|
|
656
|
+
"gap-2",
|
|
657
|
+
classNames
|
|
658
|
+
]
|
|
659
|
+
}, /* @__PURE__ */ React2.createElement(IconButton, {
|
|
660
|
+
icon: "ph--plus--regular",
|
|
661
|
+
iconOnly: true,
|
|
662
|
+
label: t("zoom in icon button"),
|
|
663
|
+
onClick: () => onAction?.("zoom-in")
|
|
664
|
+
}), /* @__PURE__ */ React2.createElement(IconButton, {
|
|
665
|
+
icon: "ph--minus--regular",
|
|
666
|
+
iconOnly: true,
|
|
667
|
+
label: t("zoom out icon button"),
|
|
668
|
+
onClick: () => onAction?.("zoom-out")
|
|
669
|
+
}));
|
|
657
670
|
};
|
|
658
671
|
var ActionControls = ({ classNames, onAction }) => {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
iconOnly: true,
|
|
677
|
-
size: 5,
|
|
678
|
-
classNames: "px-0 aspect-square",
|
|
679
|
-
onClick: () => onAction?.("toggle")
|
|
680
|
-
}));
|
|
681
|
-
} finally {
|
|
682
|
-
_effect.f();
|
|
683
|
-
}
|
|
672
|
+
const { t } = useTranslation(translationKey);
|
|
673
|
+
return /* @__PURE__ */ React2.createElement(Toolbar.Root, {
|
|
674
|
+
classNames: [
|
|
675
|
+
"gap-2",
|
|
676
|
+
classNames
|
|
677
|
+
]
|
|
678
|
+
}, /* @__PURE__ */ React2.createElement(IconButton, {
|
|
679
|
+
icon: "ph--path--regular",
|
|
680
|
+
iconOnly: true,
|
|
681
|
+
label: t("start icon button"),
|
|
682
|
+
onClick: () => onAction?.("start")
|
|
683
|
+
}), /* @__PURE__ */ React2.createElement(IconButton, {
|
|
684
|
+
icon: "ph--globe-hemisphere-west--regular",
|
|
685
|
+
iconOnly: true,
|
|
686
|
+
label: t("toggle icon button"),
|
|
687
|
+
onClick: () => onAction?.("toggle")
|
|
688
|
+
}));
|
|
684
689
|
};
|
|
685
690
|
|
|
686
691
|
// src/components/Globe/Globe.tsx
|
|
@@ -739,185 +744,146 @@ var getProjection = (type = "orthographic") => {
|
|
|
739
744
|
return type ?? geoOrthographic();
|
|
740
745
|
};
|
|
741
746
|
var GlobeRoot = ({ classNames, children, ...props }) => {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
...props
|
|
754
|
-
}, children));
|
|
755
|
-
} finally {
|
|
756
|
-
_effect.f();
|
|
757
|
-
}
|
|
747
|
+
const { ref, width, height } = useResizeDetector();
|
|
748
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
749
|
+
ref,
|
|
750
|
+
className: mx("relative flex grow overflow-hidden", classNames)
|
|
751
|
+
}, /* @__PURE__ */ React3.createElement(GlobeContextProvider, {
|
|
752
|
+
size: {
|
|
753
|
+
width,
|
|
754
|
+
height
|
|
755
|
+
},
|
|
756
|
+
...props
|
|
757
|
+
}, children));
|
|
758
758
|
};
|
|
759
|
-
var GlobeCanvas = /* @__PURE__ */ forwardRef(({ projection:
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
useImperativeHandle(forwardRef3, () => {
|
|
791
|
-
return {
|
|
792
|
-
canvas,
|
|
793
|
-
projection,
|
|
794
|
-
center,
|
|
795
|
-
get zoom() {
|
|
796
|
-
return zoomRef.current;
|
|
797
|
-
},
|
|
798
|
-
translation,
|
|
799
|
-
rotation,
|
|
800
|
-
setCenter,
|
|
801
|
-
setZoom: (s) => {
|
|
802
|
-
if (typeof s === "function") {
|
|
803
|
-
const is = interpolateNumber(zoomRef.current, s(zoomRef.current));
|
|
804
|
-
transition().ease(zooming.current ? easeLinear : easeSinOut).duration(200).tween("scale", () => (t) => setZoom(is(t))).on("end", () => {
|
|
805
|
-
zooming.current = false;
|
|
806
|
-
});
|
|
807
|
-
} else {
|
|
808
|
-
setZoom(s);
|
|
809
|
-
}
|
|
810
|
-
},
|
|
811
|
-
setTranslation,
|
|
812
|
-
setRotation
|
|
813
|
-
};
|
|
814
|
-
}, [
|
|
815
|
-
canvas
|
|
816
|
-
]);
|
|
817
|
-
const generator = useMemo2(() => canvas && projection && geoPath2(projection, canvas.getContext("2d", {
|
|
818
|
-
alpha: false
|
|
819
|
-
})), [
|
|
759
|
+
var GlobeCanvas = /* @__PURE__ */ forwardRef(({ projection: projectionProp, topology, features, styles: stylesProp }, forwardRef3) => {
|
|
760
|
+
const { themeMode } = useThemeContext();
|
|
761
|
+
const styles = useMemo2(() => stylesProp ?? defaultStyles[themeMode], [
|
|
762
|
+
stylesProp,
|
|
763
|
+
themeMode
|
|
764
|
+
]);
|
|
765
|
+
const [canvas, setCanvas] = useState3(null);
|
|
766
|
+
const canvasRef = (canvas2) => setCanvas(canvas2);
|
|
767
|
+
const projection = useMemo2(() => getProjection(projectionProp), [
|
|
768
|
+
projectionProp
|
|
769
|
+
]);
|
|
770
|
+
const layers = useMemo2(() => {
|
|
771
|
+
return timer(() => createLayers(topology, features, styles));
|
|
772
|
+
}, [
|
|
773
|
+
topology,
|
|
774
|
+
features,
|
|
775
|
+
styles
|
|
776
|
+
]);
|
|
777
|
+
const { size, center, zoom, translation, rotation, setCenter, setZoom, setTranslation, setRotation } = useGlobeContext();
|
|
778
|
+
const zoomRef = useDynamicRef(zoom);
|
|
779
|
+
useEffect4(() => {
|
|
780
|
+
if (center) {
|
|
781
|
+
setZoom(1);
|
|
782
|
+
setRotation(positionToRotation(geoToPosition(center)));
|
|
783
|
+
}
|
|
784
|
+
}, [
|
|
785
|
+
center
|
|
786
|
+
]);
|
|
787
|
+
const zooming = useRef(false);
|
|
788
|
+
useImperativeHandle(forwardRef3, () => {
|
|
789
|
+
return {
|
|
820
790
|
canvas,
|
|
821
|
-
projection
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
projection.scale(Math.min(size.width, size.height) / 2 * zoom).translate([
|
|
827
|
-
size.width / 2 + (translation?.x ?? 0),
|
|
828
|
-
size.height / 2 + (translation?.y ?? 0)
|
|
829
|
-
]).rotate(rotation ?? [
|
|
830
|
-
0,
|
|
831
|
-
0,
|
|
832
|
-
0
|
|
833
|
-
]);
|
|
834
|
-
renderLayers(generator, layers, zoom, styles);
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
}, [
|
|
838
|
-
generator,
|
|
839
|
-
size,
|
|
840
|
-
zoom,
|
|
791
|
+
projection,
|
|
792
|
+
center,
|
|
793
|
+
get zoom() {
|
|
794
|
+
return zoomRef.current;
|
|
795
|
+
},
|
|
841
796
|
translation,
|
|
842
797
|
rotation,
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
798
|
+
setCenter,
|
|
799
|
+
setZoom: (state) => {
|
|
800
|
+
if (typeof state === "function") {
|
|
801
|
+
const is = interpolateNumber(zoomRef.current, state(zoomRef.current));
|
|
802
|
+
transition().ease(zooming.current ? easeLinear : easeSinOut).duration(200).tween("scale", () => (t) => setZoom(is(t))).on("end", () => {
|
|
803
|
+
zooming.current = false;
|
|
804
|
+
});
|
|
805
|
+
} else {
|
|
806
|
+
setZoom(state);
|
|
807
|
+
}
|
|
808
|
+
},
|
|
809
|
+
setTranslation,
|
|
810
|
+
setRotation
|
|
811
|
+
};
|
|
812
|
+
}, [
|
|
813
|
+
canvas
|
|
814
|
+
]);
|
|
815
|
+
const generator = useMemo2(() => canvas && projection && geoPath2(projection, canvas.getContext("2d", {
|
|
816
|
+
alpha: false
|
|
817
|
+
})), [
|
|
818
|
+
canvas,
|
|
819
|
+
projection
|
|
820
|
+
]);
|
|
821
|
+
useEffect4(() => {
|
|
822
|
+
if (canvas && projection) {
|
|
823
|
+
timer(() => {
|
|
824
|
+
projection.scale(Math.min(size.width, size.height) / 2 * zoom).translate([
|
|
825
|
+
size.width / 2 + (translation?.x ?? 0),
|
|
826
|
+
size.height / 2 + (translation?.y ?? 0)
|
|
827
|
+
]).rotate(rotation ?? [
|
|
828
|
+
0,
|
|
829
|
+
0,
|
|
830
|
+
0
|
|
831
|
+
]);
|
|
832
|
+
renderLayers(generator, layers, zoom, styles);
|
|
833
|
+
});
|
|
847
834
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
835
|
+
}, [
|
|
836
|
+
generator,
|
|
837
|
+
size,
|
|
838
|
+
zoom,
|
|
839
|
+
translation,
|
|
840
|
+
rotation,
|
|
841
|
+
layers
|
|
842
|
+
]);
|
|
843
|
+
if (!size.width || !size.height) {
|
|
844
|
+
return null;
|
|
855
845
|
}
|
|
846
|
+
return /* @__PURE__ */ React3.createElement("canvas", {
|
|
847
|
+
ref: canvasRef,
|
|
848
|
+
width: size.width,
|
|
849
|
+
height: size.height
|
|
850
|
+
});
|
|
856
851
|
});
|
|
857
852
|
var GlobeDebug = ({ position = "topleft" }) => {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
rotation
|
|
870
|
-
}, null, 2)));
|
|
871
|
-
} finally {
|
|
872
|
-
_effect.f();
|
|
873
|
-
}
|
|
853
|
+
const { size, zoom, translation, rotation } = useGlobeContext();
|
|
854
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
855
|
+
className: mx("z-10 absolute w-96 p-2 overflow-hidden border border-green-700 rounded-sm", controlPositions[position])
|
|
856
|
+
}, /* @__PURE__ */ React3.createElement("pre", {
|
|
857
|
+
className: "font-mono text-xs text-green-700"
|
|
858
|
+
}, JSON.stringify({
|
|
859
|
+
size,
|
|
860
|
+
zoom,
|
|
861
|
+
translation,
|
|
862
|
+
rotation
|
|
863
|
+
}, null, 2)));
|
|
874
864
|
};
|
|
875
865
|
var GlobePanel = ({ position, classNames, children }) => {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
className: mx("z-10 absolute overflow-hidden", controlPositions[position], classNames)
|
|
880
|
-
}, children);
|
|
881
|
-
} finally {
|
|
882
|
-
_effect.f();
|
|
883
|
-
}
|
|
866
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
867
|
+
className: mx("z-10 absolute overflow-hidden", controlPositions[position], classNames)
|
|
868
|
+
}, children);
|
|
884
869
|
};
|
|
885
870
|
var CustomControl = ({ position, children }) => {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
className: mx("z-10 absolute overflow-hidden", controlPositions[position])
|
|
890
|
-
}, children);
|
|
891
|
-
} finally {
|
|
892
|
-
_effect.f();
|
|
893
|
-
}
|
|
894
|
-
};
|
|
895
|
-
var GlobeZoom = ({ onAction, position = "bottomleft", ...props }) => {
|
|
896
|
-
var _effect = _useSignals3();
|
|
897
|
-
try {
|
|
898
|
-
return /* @__PURE__ */ React3.createElement(CustomControl, {
|
|
899
|
-
position,
|
|
900
|
-
...props
|
|
901
|
-
}, /* @__PURE__ */ React3.createElement(ZoomControls, {
|
|
902
|
-
onAction
|
|
903
|
-
}));
|
|
904
|
-
} finally {
|
|
905
|
-
_effect.f();
|
|
906
|
-
}
|
|
907
|
-
};
|
|
908
|
-
var GlobeAction = ({ onAction, position = "bottomright", ...props }) => {
|
|
909
|
-
var _effect = _useSignals3();
|
|
910
|
-
try {
|
|
911
|
-
return /* @__PURE__ */ React3.createElement(CustomControl, {
|
|
912
|
-
position,
|
|
913
|
-
...props
|
|
914
|
-
}, /* @__PURE__ */ React3.createElement(ActionControls, {
|
|
915
|
-
onAction
|
|
916
|
-
}));
|
|
917
|
-
} finally {
|
|
918
|
-
_effect.f();
|
|
919
|
-
}
|
|
871
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
872
|
+
className: mx("z-10 absolute overflow-hidden", controlPositions[position])
|
|
873
|
+
}, children);
|
|
920
874
|
};
|
|
875
|
+
var GlobeZoom = ({ onAction, position = "bottomleft", ...props }) => /* @__PURE__ */ React3.createElement(CustomControl, {
|
|
876
|
+
position,
|
|
877
|
+
...props
|
|
878
|
+
}, /* @__PURE__ */ React3.createElement(ZoomControls, {
|
|
879
|
+
onAction
|
|
880
|
+
}));
|
|
881
|
+
var GlobeAction = ({ onAction, position = "bottomright", ...props }) => /* @__PURE__ */ React3.createElement(CustomControl, {
|
|
882
|
+
position,
|
|
883
|
+
...props
|
|
884
|
+
}, /* @__PURE__ */ React3.createElement(ActionControls, {
|
|
885
|
+
onAction
|
|
886
|
+
}));
|
|
921
887
|
var Globe = {
|
|
922
888
|
Root: GlobeRoot,
|
|
923
889
|
Canvas: GlobeCanvas,
|
|
@@ -928,17 +894,15 @@ var Globe = {
|
|
|
928
894
|
};
|
|
929
895
|
|
|
930
896
|
// src/components/Map/Map.tsx
|
|
931
|
-
import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
|
|
932
897
|
import "leaflet/dist/leaflet.css";
|
|
933
898
|
import { createContext as createContext2 } from "@radix-ui/react-context";
|
|
934
899
|
import L, { Control, DomEvent, DomUtil, latLngBounds } from "leaflet";
|
|
935
900
|
import React4, { forwardRef as forwardRef2, useEffect as useEffect5, useImperativeHandle as useImperativeHandle2, useRef as useRef2, useState as useState4 } from "react";
|
|
936
901
|
import { createRoot } from "react-dom/client";
|
|
937
|
-
import { MapContainer, Marker, Popup, TileLayer, useMap } from "react-leaflet";
|
|
938
|
-
import { debounce } from "@dxos/async";
|
|
902
|
+
import { MapContainer, Marker, Popup, TileLayer, useMap, useMapEvents } from "react-leaflet";
|
|
939
903
|
import { ThemeProvider, Tooltip } from "@dxos/react-ui";
|
|
940
|
-
import { defaultTx, mx as mx2 } from "@dxos/
|
|
941
|
-
var
|
|
904
|
+
import { defaultTx, mx as mx2 } from "@dxos/ui-theme";
|
|
905
|
+
var defaults2 = {
|
|
942
906
|
center: {
|
|
943
907
|
lat: 51,
|
|
944
908
|
lng: 0
|
|
@@ -946,213 +910,165 @@ var defaults = {
|
|
|
946
910
|
zoom: 4
|
|
947
911
|
};
|
|
948
912
|
var [MapContextProvier, useMapContext] = createContext2("Map");
|
|
949
|
-
var MapRoot = /* @__PURE__ */ forwardRef2(({ classNames, scrollWheelZoom = true, doubleClickZoom = true, touchZoom = true, center
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
if (!map) {
|
|
990
|
-
return;
|
|
991
|
-
}
|
|
992
|
-
if (attention) {
|
|
993
|
-
map.scrollWheelZoom.enable();
|
|
994
|
-
} else {
|
|
995
|
-
map.scrollWheelZoom.disable();
|
|
996
|
-
}
|
|
997
|
-
}, [
|
|
998
|
-
map,
|
|
999
|
-
attention
|
|
1000
|
-
]);
|
|
1001
|
-
return /* @__PURE__ */ React4.createElement(MapContextProvier, {
|
|
1002
|
-
attention
|
|
1003
|
-
}, /* @__PURE__ */ React4.createElement(MapContainer, {
|
|
1004
|
-
...props,
|
|
1005
|
-
ref: mapRef,
|
|
1006
|
-
className: mx2("group relative grid bs-full is-full !bg-baseSurface dx-focus-ring-inset", classNames),
|
|
1007
|
-
attributionControl: false,
|
|
1008
|
-
zoomControl: false,
|
|
1009
|
-
scrollWheelZoom,
|
|
1010
|
-
doubleClickZoom,
|
|
1011
|
-
touchZoom,
|
|
1012
|
-
center,
|
|
1013
|
-
zoom
|
|
1014
|
-
}));
|
|
1015
|
-
} finally {
|
|
1016
|
-
_effect.f();
|
|
1017
|
-
}
|
|
913
|
+
var MapRoot = /* @__PURE__ */ forwardRef2(({ classNames, scrollWheelZoom = true, doubleClickZoom = true, touchZoom = true, center, zoom, onChange, ...props }, forwardedRef) => {
|
|
914
|
+
const [attention, setAttention] = useState4(false);
|
|
915
|
+
const mapRef = useRef2(null);
|
|
916
|
+
const map = mapRef.current;
|
|
917
|
+
useImperativeHandle2(forwardedRef, () => ({
|
|
918
|
+
setCenter: (center2, zoom2) => {
|
|
919
|
+
mapRef.current?.setView(center2, zoom2);
|
|
920
|
+
},
|
|
921
|
+
setZoom: (cb) => {
|
|
922
|
+
mapRef.current?.setZoom(cb(mapRef.current?.getZoom() ?? 0));
|
|
923
|
+
}
|
|
924
|
+
}), []);
|
|
925
|
+
useEffect5(() => {
|
|
926
|
+
if (!map) {
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
if (attention) {
|
|
930
|
+
map.scrollWheelZoom.enable();
|
|
931
|
+
} else {
|
|
932
|
+
map.scrollWheelZoom.disable();
|
|
933
|
+
}
|
|
934
|
+
}, [
|
|
935
|
+
map,
|
|
936
|
+
attention
|
|
937
|
+
]);
|
|
938
|
+
return /* @__PURE__ */ React4.createElement(MapContextProvier, {
|
|
939
|
+
attention,
|
|
940
|
+
onChange
|
|
941
|
+
}, /* @__PURE__ */ React4.createElement(MapContainer, {
|
|
942
|
+
...props,
|
|
943
|
+
ref: mapRef,
|
|
944
|
+
className: mx2("group relative grid h-full w-full !bg-base-surface dx-focus-ring-inset", classNames),
|
|
945
|
+
attributionControl: false,
|
|
946
|
+
zoomControl: false,
|
|
947
|
+
scrollWheelZoom,
|
|
948
|
+
doubleClickZoom,
|
|
949
|
+
touchZoom,
|
|
950
|
+
center: center ?? defaults2.center,
|
|
951
|
+
zoom: zoom ?? defaults2.zoom
|
|
952
|
+
}));
|
|
1018
953
|
});
|
|
1019
954
|
MapRoot.displayName = "Map.Root";
|
|
955
|
+
var MAP_TILES_NAME = "Map.Tiles";
|
|
1020
956
|
var MapTiles = (_props) => {
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
957
|
+
const ref = useRef2(null);
|
|
958
|
+
const { onChange } = useMapContext(MAP_TILES_NAME);
|
|
959
|
+
useMapEvents({
|
|
960
|
+
zoomstart: (ev) => {
|
|
961
|
+
onChange?.({
|
|
962
|
+
center: ev.target.getCenter(),
|
|
963
|
+
zoom: ev.target.getZoom()
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
const { attention } = useMapContext(MAP_TILES_NAME);
|
|
968
|
+
useEffect5(() => {
|
|
969
|
+
if (ref.current) {
|
|
970
|
+
ref.current.getContainer().dataset.attention = attention ? "1" : "0";
|
|
971
|
+
}
|
|
972
|
+
}, [
|
|
973
|
+
attention
|
|
974
|
+
]);
|
|
975
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(TileLayer, {
|
|
976
|
+
ref,
|
|
977
|
+
"data-attention": attention,
|
|
978
|
+
detectRetina: true,
|
|
979
|
+
className: 'dark:grayscale dark:invert data-[attention="0"]:!opacity-80',
|
|
980
|
+
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
981
|
+
keepBuffer: 4
|
|
982
|
+
}));
|
|
1043
983
|
};
|
|
1044
|
-
MapTiles.displayName =
|
|
984
|
+
MapTiles.displayName = MAP_TILES_NAME;
|
|
1045
985
|
var MapMarkers = ({ selected, markers }) => {
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
}, title && /* @__PURE__ */ React4.createElement(Popup, null, title));
|
|
1092
|
-
}));
|
|
1093
|
-
} finally {
|
|
1094
|
-
_effect.f();
|
|
1095
|
-
}
|
|
986
|
+
const map = useMap();
|
|
987
|
+
useEffect5(() => {
|
|
988
|
+
if (markers.length > 0) {
|
|
989
|
+
const bounds = latLngBounds(markers.map((marker) => marker.location));
|
|
990
|
+
map.fitBounds(bounds);
|
|
991
|
+
} else {
|
|
992
|
+
map.setView(defaults2.center, defaults2.zoom);
|
|
993
|
+
}
|
|
994
|
+
}, [
|
|
995
|
+
markers
|
|
996
|
+
]);
|
|
997
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, null, markers?.map(({ id, title, location: { lat, lng } }) => {
|
|
998
|
+
return /* @__PURE__ */ React4.createElement(Marker, {
|
|
999
|
+
key: id,
|
|
1000
|
+
position: {
|
|
1001
|
+
lat,
|
|
1002
|
+
lng
|
|
1003
|
+
},
|
|
1004
|
+
icon: (
|
|
1005
|
+
// TODO(burdon): Create custom icon from bundled assets.
|
|
1006
|
+
// TODO(burdon): Selection state.
|
|
1007
|
+
new L.Icon({
|
|
1008
|
+
iconUrl: "https://dxos.network/marker-icon.png",
|
|
1009
|
+
iconRetinaUrl: "https://dxos.network/marker-icon-2x.png",
|
|
1010
|
+
shadowUrl: "https://dxos.network/marker-shadow.png",
|
|
1011
|
+
iconSize: [
|
|
1012
|
+
25,
|
|
1013
|
+
41
|
|
1014
|
+
],
|
|
1015
|
+
iconAnchor: [
|
|
1016
|
+
12,
|
|
1017
|
+
41
|
|
1018
|
+
],
|
|
1019
|
+
popupAnchor: [
|
|
1020
|
+
1,
|
|
1021
|
+
-34
|
|
1022
|
+
],
|
|
1023
|
+
shadowSize: [
|
|
1024
|
+
41,
|
|
1025
|
+
41
|
|
1026
|
+
]
|
|
1027
|
+
})
|
|
1028
|
+
)
|
|
1029
|
+
}, title && /* @__PURE__ */ React4.createElement(Popup, null, title));
|
|
1030
|
+
}));
|
|
1096
1031
|
};
|
|
1097
1032
|
MapMarkers.displayName = "Map.Markers";
|
|
1098
1033
|
var CustomControl2 = ({ position, children }) => {
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
const
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
control.
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
]);
|
|
1125
|
-
return null;
|
|
1126
|
-
} finally {
|
|
1127
|
-
_effect.f();
|
|
1128
|
-
}
|
|
1129
|
-
};
|
|
1130
|
-
var MapZoom = ({ onAction, position = "bottomleft", ...props }) => {
|
|
1131
|
-
var _effect = _useSignals4();
|
|
1132
|
-
try {
|
|
1133
|
-
return /* @__PURE__ */ React4.createElement(CustomControl2, {
|
|
1134
|
-
position,
|
|
1135
|
-
...props
|
|
1136
|
-
}, /* @__PURE__ */ React4.createElement(ZoomControls, {
|
|
1137
|
-
onAction
|
|
1138
|
-
}));
|
|
1139
|
-
} finally {
|
|
1140
|
-
_effect.f();
|
|
1141
|
-
}
|
|
1142
|
-
};
|
|
1143
|
-
var MapAction = ({ onAction, position = "bottomright", ...props }) => {
|
|
1144
|
-
var _effect = _useSignals4();
|
|
1145
|
-
try {
|
|
1146
|
-
return /* @__PURE__ */ React4.createElement(CustomControl2, {
|
|
1147
|
-
position,
|
|
1148
|
-
...props
|
|
1149
|
-
}, /* @__PURE__ */ React4.createElement(ActionControls, {
|
|
1150
|
-
onAction
|
|
1151
|
-
}));
|
|
1152
|
-
} finally {
|
|
1153
|
-
_effect.f();
|
|
1154
|
-
}
|
|
1034
|
+
const map = useMap();
|
|
1035
|
+
useEffect5(() => {
|
|
1036
|
+
const control = new Control({
|
|
1037
|
+
position
|
|
1038
|
+
});
|
|
1039
|
+
control.onAdd = () => {
|
|
1040
|
+
const container = DomUtil.create("div", mx2("m-0!", controlPositions[position]));
|
|
1041
|
+
DomEvent.disableClickPropagation(container);
|
|
1042
|
+
DomEvent.disableScrollPropagation(container);
|
|
1043
|
+
const root = createRoot(container);
|
|
1044
|
+
root.render(/* @__PURE__ */ React4.createElement(ThemeProvider, {
|
|
1045
|
+
tx: defaultTx
|
|
1046
|
+
}, /* @__PURE__ */ React4.createElement(Tooltip.Provider, null, children)));
|
|
1047
|
+
return container;
|
|
1048
|
+
};
|
|
1049
|
+
control.addTo(map);
|
|
1050
|
+
return () => {
|
|
1051
|
+
control.remove();
|
|
1052
|
+
};
|
|
1053
|
+
}, [
|
|
1054
|
+
map,
|
|
1055
|
+
position,
|
|
1056
|
+
children
|
|
1057
|
+
]);
|
|
1058
|
+
return null;
|
|
1155
1059
|
};
|
|
1060
|
+
var MapZoom = ({ onAction, position = "bottomleft", ...props }) => /* @__PURE__ */ React4.createElement(CustomControl2, {
|
|
1061
|
+
position,
|
|
1062
|
+
...props
|
|
1063
|
+
}, /* @__PURE__ */ React4.createElement(ZoomControls, {
|
|
1064
|
+
onAction
|
|
1065
|
+
}));
|
|
1066
|
+
var MapAction = ({ onAction, position = "bottomright", ...props }) => /* @__PURE__ */ React4.createElement(CustomControl2, {
|
|
1067
|
+
position,
|
|
1068
|
+
...props
|
|
1069
|
+
}, /* @__PURE__ */ React4.createElement(ActionControls, {
|
|
1070
|
+
onAction
|
|
1071
|
+
}));
|
|
1156
1072
|
var Map = {
|
|
1157
1073
|
Root: MapRoot,
|
|
1158
1074
|
Tiles: MapTiles,
|
|
@@ -1180,6 +1096,8 @@ export {
|
|
|
1180
1096
|
renderLayers,
|
|
1181
1097
|
restrictAxis,
|
|
1182
1098
|
timer,
|
|
1099
|
+
translationKey,
|
|
1100
|
+
translations,
|
|
1183
1101
|
useDrag,
|
|
1184
1102
|
useGlobeContext,
|
|
1185
1103
|
useGlobeZoomHandler,
|