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