@dxos/react-ui-geo 0.8.4-main.f9ba587 → 0.8.4-main.fcfe5033a5

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 (77) 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-37VAAFCK.mjs → countries-110m-ZM3ZIEFS.mjs} +1 -1
  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 +400 -447
  11. package/dist/lib/browser/index.mjs.map +4 -4
  12. package/dist/lib/browser/meta.json +1 -1
  13. package/dist/lib/node-esm/{chunk-OPJPAAEK.mjs → chunk-JODBF4CC.mjs} +2 -2
  14. package/dist/lib/node-esm/{countries-110m-36TTKK5B.mjs → countries-110m-3SFASWVD.mjs} +1 -1
  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 +400 -447
  18. package/dist/lib/node-esm/index.mjs.map +4 -4
  19. package/dist/lib/node-esm/meta.json +1 -1
  20. package/dist/types/src/components/Globe/Globe.d.ts +6 -4
  21. package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
  22. package/dist/types/src/components/Globe/Globe.stories.d.ts +27 -9
  23. package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/Map/Map.d.ts +34 -18
  25. package/dist/types/src/components/Map/Map.d.ts.map +1 -1
  26. package/dist/types/src/components/Map/Map.stories.d.ts +14 -8
  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 +6 -8
  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 +2 -1
  42. package/dist/types/src/index.d.ts.map +1 -1
  43. package/dist/types/src/translations.d.ts +12 -0
  44. package/dist/types/src/translations.d.ts.map +1 -0
  45. package/dist/types/src/types.d.ts +2 -1
  46. package/dist/types/src/types.d.ts.map +1 -1
  47. package/dist/types/src/util/path.d.ts +5 -8
  48. package/dist/types/src/util/path.d.ts.map +1 -1
  49. package/dist/types/src/util/render.d.ts +4 -4
  50. package/dist/types/src/util/render.d.ts.map +1 -1
  51. package/dist/types/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +30 -23
  53. package/src/components/Globe/Globe.stories.tsx +82 -35
  54. package/src/components/Globe/Globe.tsx +124 -81
  55. package/src/components/Map/Map.stories.tsx +27 -15
  56. package/src/components/Map/Map.tsx +220 -94
  57. package/src/components/Toolbar/Controls.tsx +14 -20
  58. package/src/components/index.ts +0 -2
  59. package/src/hooks/context.tsx +11 -34
  60. package/src/hooks/useGlobeZoomHandler.ts +9 -3
  61. package/src/hooks/useMapZoomHandler.ts +1 -1
  62. package/src/hooks/useSpinner.ts +1 -1
  63. package/src/hooks/useTour.ts +10 -8
  64. package/src/index.ts +2 -1
  65. package/src/translations.ts +20 -0
  66. package/src/types.ts +3 -1
  67. package/src/util/inertia.ts +1 -1
  68. package/src/util/path.ts +5 -6
  69. package/src/util/render.ts +4 -3
  70. package/dist/lib/browser/chunk-CYCBMCOP.mjs +0 -9
  71. package/dist/lib/browser/countries-110m-37VAAFCK.mjs.map +0 -7
  72. package/dist/lib/node-esm/countries-110m-36TTKK5B.mjs.map +0 -7
  73. package/dist/types/src/components/types.d.ts +0 -15
  74. package/dist/types/src/components/types.d.ts.map +0 -1
  75. package/src/components/types.ts +0 -19
  76. /package/dist/lib/browser/{chunk-CYCBMCOP.mjs.map → chunk-GMWLKTLN.mjs.map} +0 -0
  77. /package/dist/lib/node-esm/{chunk-OPJPAAEK.mjs.map → chunk-JODBF4CC.mjs.map} +0 -0
@@ -1,46 +1,19 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
  import {
3
3
  loadTopology
4
- } from "./chunk-OPJPAAEK.mjs";
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
- import { geoMercator, geoOrthographic, geoPath as geoPath2, geoTransverseMercator, interpolateNumber, transition, easeLinear, easeSinOut } from "d3";
9
- import React3, { forwardRef, useEffect as useEffect4, useImperativeHandle, useMemo as useMemo2, useRef, useState as useState3 } from "react";
7
+ import { easeLinear, easeSinOut, geoMercator, geoOrthographic, geoPath as geoPath2, geoTransverseMercator, interpolateNumber, transition } from "d3";
8
+ import React2, { forwardRef, useEffect as useEffect4, useImperativeHandle, useMemo as useMemo2, useRef, useState as useState3 } from "react";
10
9
  import { useResizeDetector } from "react-resize-detector";
11
- import { useDynamicRef, useThemeContext } from "@dxos/react-ui";
12
- import { mx } from "@dxos/react-ui-theme";
10
+ import { useComposedRefs, useControlledState, useDynamicRef, useThemeContext } from "@dxos/react-ui";
11
+ import { composable, composableProps, 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
- import React, { createContext, useContext } from "react";
14
+ import { createContext, useContext } from "react";
17
15
  import { raise } from "@dxos/debug";
18
- import { useControlledState } from "@dxos/react-ui";
19
16
  var GlobeContext = /* @__PURE__ */ createContext(void 0);
20
- var GlobeContextProvider = ({ children, size, center: _center, scale: _scale, translation: _translation, rotation: _rotation }) => {
21
- var _effect = _useSignals();
22
- try {
23
- const [center, setCenter] = useControlledState(_center);
24
- const [scale, setScale] = useControlledState(_scale);
25
- const [translation, setTranslation] = useControlledState(_translation);
26
- const [rotation, setRotation] = useControlledState(_rotation);
27
- return /* @__PURE__ */ React.createElement(GlobeContext.Provider, {
28
- value: {
29
- size,
30
- center,
31
- scale,
32
- translation,
33
- rotation,
34
- setCenter,
35
- setScale,
36
- setTranslation,
37
- setRotation
38
- }
39
- }, children);
40
- } finally {
41
- _effect.f();
42
- }
43
- };
44
17
  var useGlobeContext = () => {
45
18
  return useContext(GlobeContext) ?? raise(new Error("Missing GlobeContext"));
46
19
  };
@@ -65,7 +38,7 @@ var timer = (cb) => {
65
38
  };
66
39
 
67
40
  // src/util/inertia.ts
68
- import { select, drag, timer as timer2 } from "d3";
41
+ import { drag, select, timer as timer2 } from "d3";
69
42
  import versor from "versor";
70
43
  var restrictAxis = (axis) => (original, current) => current.map((d, i) => axis[i] ? d : original[i]);
71
44
  var geoInertiaDrag = (target, render, projection, options) => {
@@ -428,6 +401,7 @@ var cancelDrag = (node) => node.on(".drag", null);
428
401
 
429
402
  // src/hooks/useGlobeZoomHandler.ts
430
403
  import { useCallback } from "react";
404
+ var ZOOM_FACTOR = 0.1;
431
405
  var useGlobeZoomHandler = (controller) => {
432
406
  return useCallback((event) => {
433
407
  if (!controller) {
@@ -435,11 +409,15 @@ var useGlobeZoomHandler = (controller) => {
435
409
  }
436
410
  switch (event) {
437
411
  case "zoom-in": {
438
- controller.setScale((scale) => scale * 1.1);
412
+ controller.setZoom((zoom) => {
413
+ return zoom * (1 + ZOOM_FACTOR);
414
+ });
439
415
  break;
440
416
  }
441
417
  case "zoom-out": {
442
- controller.setScale((scale) => scale * 0.9);
418
+ controller.setZoom((zoom) => {
419
+ return zoom * (1 - ZOOM_FACTOR);
420
+ });
443
421
  break;
444
422
  }
445
423
  }
@@ -524,8 +502,8 @@ var useSpinner = (controller, options = {}) => {
524
502
  };
525
503
 
526
504
  // src/hooks/useTour.ts
527
- import { geoPath, geoInterpolate, geoDistance, selection as d3Selection } from "d3";
528
- import { useEffect as useEffect3, useState as useState2, useMemo } from "react";
505
+ import { selection as d3Selection, geoDistance, geoInterpolate, geoPath } from "d3";
506
+ import { useEffect as useEffect3, useMemo, useState as useState2 } from "react";
529
507
  import versor2 from "versor";
530
508
  var TRANSITION_NAME = "globe-tour";
531
509
  var defaultDuration = 1500;
@@ -572,7 +550,7 @@ var useTour = (controller, points, options = {}) => {
572
550
  {
573
551
  context.beginPath();
574
552
  context.strokeStyle = options?.styles?.arc?.strokeStyle ?? "yellow";
575
- context.lineWidth = (options?.styles?.arc?.lineWidth ?? 1.5) * (controller?.scale ?? 1);
553
+ context.lineWidth = (options?.styles?.arc?.lineWidth ?? 1.5) * (controller?.zoom ?? 1);
576
554
  context.setLineDash(options?.styles?.arc?.lineDash ?? []);
577
555
  path({
578
556
  type: "LineString",
@@ -584,7 +562,7 @@ var useTour = (controller, points, options = {}) => {
584
562
  context.stroke();
585
563
  context.beginPath();
586
564
  context.fillStyle = options?.styles?.cursor?.fillStyle ?? "orange";
587
- path.pointRadius((options?.styles?.cursor?.pointRadius ?? 2) * (controller?.scale ?? 1));
565
+ path.pointRadius((options?.styles?.cursor?.pointRadius ?? 2) * (controller?.zoom ?? 1));
588
566
  path({
589
567
  type: "Point",
590
568
  coordinates: ip(t22)
@@ -598,7 +576,7 @@ var useTour = (controller, points, options = {}) => {
598
576
  await transition2.end();
599
577
  last = next;
600
578
  }
601
- } catch (err) {
579
+ } catch {
602
580
  } finally {
603
581
  setRunning(false);
604
582
  }
@@ -620,9 +598,25 @@ var useTour = (controller, points, options = {}) => {
620
598
  };
621
599
 
622
600
  // src/components/Toolbar/Controls.tsx
623
- import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
624
- import React2 from "react";
625
- import { IconButton, Toolbar } from "@dxos/react-ui";
601
+ import React from "react";
602
+ import { IconButton, Toolbar, useTranslation } from "@dxos/react-ui";
603
+
604
+ // src/translations.ts
605
+ var translationKey = "@dxos/react-ui-geo";
606
+ var translations = [
607
+ {
608
+ "en-US": {
609
+ [translationKey]: {
610
+ "zoom-in-icon.button": "Zoom in",
611
+ "zoom-out-icon.button": "Zoom out",
612
+ "start-icon.button": "Start",
613
+ "toggle-icon.button": "Toggle"
614
+ }
615
+ }
616
+ }
617
+ ];
618
+
619
+ // src/components/Toolbar/Controls.tsx
626
620
  var controlPositions = {
627
621
  topleft: "top-2 left-2",
628
622
  topright: "top-2 right-2",
@@ -630,62 +624,42 @@ var controlPositions = {
630
624
  bottomright: "bottom-2 right-2"
631
625
  };
632
626
  var ZoomControls = ({ classNames, onAction }) => {
633
- var _effect = _useSignals2();
634
- try {
635
- return /* @__PURE__ */ React2.createElement(Toolbar.Root, {
636
- classNames: [
637
- "gap-1",
638
- classNames
639
- ]
640
- }, /* @__PURE__ */ React2.createElement(IconButton, {
641
- //
642
- icon: "ph--plus--regular",
643
- label: "zoom in",
644
- iconOnly: true,
645
- size: 5,
646
- classNames: "px-0 aspect-square",
647
- onClick: () => onAction?.("zoom-in")
648
- }), /* @__PURE__ */ React2.createElement(IconButton, {
649
- //
650
- icon: "ph--minus--regular",
651
- label: "zoom out",
652
- iconOnly: true,
653
- size: 5,
654
- classNames: "px-0 aspect-square",
655
- onClick: () => onAction?.("zoom-out")
656
- }));
657
- } finally {
658
- _effect.f();
659
- }
627
+ const { t } = useTranslation(translationKey);
628
+ return /* @__PURE__ */ React.createElement(Toolbar.Root, {
629
+ classNames: [
630
+ "gap-2",
631
+ classNames
632
+ ]
633
+ }, /* @__PURE__ */ React.createElement(IconButton, {
634
+ icon: "ph--plus--regular",
635
+ iconOnly: true,
636
+ label: t("zoom-in-icon.button"),
637
+ onClick: () => onAction?.("zoom-in")
638
+ }), /* @__PURE__ */ React.createElement(IconButton, {
639
+ icon: "ph--minus--regular",
640
+ iconOnly: true,
641
+ label: t("zoom-out-icon.button"),
642
+ onClick: () => onAction?.("zoom-out")
643
+ }));
660
644
  };
661
645
  var ActionControls = ({ classNames, onAction }) => {
662
- var _effect = _useSignals2();
663
- try {
664
- return /* @__PURE__ */ React2.createElement(Toolbar.Root, {
665
- classNames: [
666
- "gap-1",
667
- classNames
668
- ]
669
- }, /* @__PURE__ */ React2.createElement(IconButton, {
670
- //
671
- icon: "ph--play--regular",
672
- label: "start",
673
- iconOnly: true,
674
- size: 5,
675
- classNames: "px-0 aspect-square",
676
- onClick: () => onAction?.("start")
677
- }), /* @__PURE__ */ React2.createElement(IconButton, {
678
- //
679
- icon: "ph--globe-hemisphere-west--regular",
680
- label: "toggle",
681
- iconOnly: true,
682
- size: 5,
683
- classNames: "px-0 aspect-square",
684
- onClick: () => onAction?.("toggle")
685
- }));
686
- } finally {
687
- _effect.f();
688
- }
646
+ const { t } = useTranslation(translationKey);
647
+ return /* @__PURE__ */ React.createElement(Toolbar.Root, {
648
+ classNames: [
649
+ "gap-2",
650
+ classNames
651
+ ]
652
+ }, /* @__PURE__ */ React.createElement(IconButton, {
653
+ icon: "ph--path--regular",
654
+ iconOnly: true,
655
+ label: t("start-icon.button"),
656
+ onClick: () => onAction?.("start")
657
+ }), /* @__PURE__ */ React.createElement(IconButton, {
658
+ icon: "ph--globe-hemisphere-west--regular",
659
+ iconOnly: true,
660
+ label: t("toggle-icon.button"),
661
+ onClick: () => onAction?.("toggle")
662
+ }));
689
663
  };
690
664
 
691
665
  // src/components/Globe/Globe.tsx
@@ -743,400 +717,377 @@ var getProjection = (type = "orthographic") => {
743
717
  }
744
718
  return type ?? geoOrthographic();
745
719
  };
746
- var GlobeRoot = ({ classNames, children, ...props }) => {
747
- var _effect = _useSignals3();
748
- try {
749
- const { ref, width, height } = useResizeDetector();
750
- return /* @__PURE__ */ React3.createElement("div", {
751
- ref,
752
- className: mx("relative flex grow overflow-hidden", classNames)
753
- }, /* @__PURE__ */ React3.createElement(GlobeContextProvider, {
720
+ var GlobeRoot = composable(({ children, center: centerProp, zoom: zoomProp, translation: translationProp, rotation: rotationProp, ...props }, forwardedRef) => {
721
+ const localRef = useRef(null);
722
+ const composedRef = useComposedRefs(localRef, forwardedRef);
723
+ const { width, height } = useResizeDetector({
724
+ targetRef: localRef
725
+ });
726
+ const [center, setCenter] = useControlledState(centerProp);
727
+ const [zoom, setZoom] = useControlledState(zoomProp ?? 4);
728
+ const [translation, setTranslation] = useControlledState(translationProp);
729
+ const [rotation, setRotation] = useControlledState(rotationProp);
730
+ return /* @__PURE__ */ React2.createElement(GlobeContext.Provider, {
731
+ value: {
754
732
  size: {
755
733
  width,
756
734
  height
757
735
  },
758
- ...props
759
- }, children));
760
- } finally {
761
- _effect.f();
762
- }
763
- };
764
- var GlobeCanvas = /* @__PURE__ */ forwardRef(({ projection: _projection, topology, features, styles: _styles }, forwardRef3) => {
765
- var _effect = _useSignals3();
766
- try {
767
- const { themeMode } = useThemeContext();
768
- const styles = useMemo2(() => _styles ?? defaultStyles[themeMode], [
769
- _styles,
770
- themeMode
771
- ]);
772
- const [canvas, setCanvas] = useState3(null);
773
- const canvasRef = (canvas2) => setCanvas(canvas2);
774
- const projection = useMemo2(() => getProjection(_projection), [
775
- _projection
776
- ]);
777
- const layers = useMemo2(() => {
778
- return timer(() => createLayers(topology, features, styles));
779
- }, [
780
- topology,
781
- features,
782
- styles
783
- ]);
784
- const { size, center, scale, translation, rotation, setCenter, setScale, setTranslation, setRotation } = useGlobeContext();
785
- const scaleRef = useDynamicRef(scale);
786
- useEffect4(() => {
787
- if (center) {
788
- setScale(1);
789
- setRotation(positionToRotation(geoToPosition(center)));
790
- }
791
- }, [
792
- center
793
- ]);
794
- const zooming = useRef(false);
795
- useImperativeHandle(forwardRef3, () => {
796
- return {
797
- canvas,
798
- projection,
799
- center,
800
- get scale() {
801
- return scaleRef.current;
802
- },
803
- translation,
804
- rotation,
805
- setCenter,
806
- setScale: (s) => {
807
- if (typeof s === "function") {
808
- const is = interpolateNumber(scaleRef.current, s(scaleRef.current));
809
- transition().ease(zooming.current ? easeLinear : easeSinOut).duration(200).tween("scale", () => (t) => setScale(is(t))).on("end", () => {
810
- zooming.current = false;
811
- });
812
- } else {
813
- setScale(s);
814
- }
815
- },
816
- setTranslation,
817
- setRotation
818
- };
819
- }, [
820
- canvas
821
- ]);
822
- const generator = useMemo2(() => canvas && projection && geoPath2(projection, canvas.getContext("2d", {
823
- alpha: false
824
- })), [
736
+ center,
737
+ zoom,
738
+ translation,
739
+ rotation,
740
+ setCenter,
741
+ setZoom,
742
+ setTranslation,
743
+ setRotation
744
+ }
745
+ }, /* @__PURE__ */ React2.createElement("div", {
746
+ ...composableProps(props, {
747
+ classNames: "relative dx-container"
748
+ }),
749
+ ref: composedRef
750
+ }, children));
751
+ });
752
+ var GlobeCanvas = /* @__PURE__ */ forwardRef(({ projection: projectionProp, topology, features, styles: stylesProp }, forwardRef3) => {
753
+ const { themeMode } = useThemeContext();
754
+ const styles = useMemo2(() => stylesProp ?? defaultStyles[themeMode], [
755
+ stylesProp,
756
+ themeMode
757
+ ]);
758
+ const [canvas, setCanvas] = useState3(null);
759
+ const canvasRef = (canvas2) => setCanvas(canvas2);
760
+ const projection = useMemo2(() => getProjection(projectionProp), [
761
+ projectionProp
762
+ ]);
763
+ const layers = useMemo2(() => {
764
+ return timer(() => createLayers(topology, features, styles));
765
+ }, [
766
+ topology,
767
+ features,
768
+ styles
769
+ ]);
770
+ const { size, center, zoom, translation, rotation, setCenter, setZoom, setTranslation, setRotation } = useGlobeContext();
771
+ const zoomRef = useDynamicRef(zoom);
772
+ useEffect4(() => {
773
+ if (center) {
774
+ setZoom(1);
775
+ setRotation(positionToRotation(geoToPosition(center)));
776
+ }
777
+ }, [
778
+ center
779
+ ]);
780
+ const zooming = useRef(false);
781
+ useImperativeHandle(forwardRef3, () => {
782
+ return {
825
783
  canvas,
826
- projection
827
- ]);
828
- useEffect4(() => {
829
- if (canvas && projection) {
830
- timer(() => {
831
- projection.scale(Math.min(size.width, size.height) / 2 * scale).translate([
832
- size.width / 2 + (translation?.x ?? 0),
833
- size.height / 2 + (translation?.y ?? 0)
834
- ]).rotate(rotation ?? [
835
- 0,
836
- 0,
837
- 0
838
- ]);
839
- renderLayers(generator, layers, scale, styles);
840
- });
841
- }
842
- }, [
843
- generator,
844
- size,
845
- scale,
784
+ projection,
785
+ center,
786
+ get zoom() {
787
+ return zoomRef.current;
788
+ },
846
789
  translation,
847
790
  rotation,
848
- layers
849
- ]);
850
- if (!size.width || !size.height) {
851
- return null;
791
+ setCenter,
792
+ setZoom: (state) => {
793
+ if (typeof state === "function") {
794
+ const is = interpolateNumber(zoomRef.current, state(zoomRef.current));
795
+ transition().ease(zooming.current ? easeLinear : easeSinOut).duration(200).tween("scale", () => (t) => setZoom(is(t))).on("end", () => {
796
+ zooming.current = false;
797
+ });
798
+ } else {
799
+ setZoom(state);
800
+ }
801
+ },
802
+ setTranslation,
803
+ setRotation
804
+ };
805
+ }, [
806
+ canvas
807
+ ]);
808
+ const generator = useMemo2(() => canvas && projection && geoPath2(projection, canvas.getContext("2d", {
809
+ alpha: false
810
+ })), [
811
+ canvas,
812
+ projection
813
+ ]);
814
+ useEffect4(() => {
815
+ if (canvas && projection) {
816
+ timer(() => {
817
+ projection.scale(Math.min(size.width, size.height) / 2 * zoom).translate([
818
+ size.width / 2 + (translation?.x ?? 0),
819
+ size.height / 2 + (translation?.y ?? 0)
820
+ ]).rotate(rotation ?? [
821
+ 0,
822
+ 0,
823
+ 0
824
+ ]);
825
+ renderLayers(generator, layers, zoom, styles);
826
+ });
852
827
  }
853
- return /* @__PURE__ */ React3.createElement("canvas", {
854
- ref: canvasRef,
855
- width: size.width,
856
- height: size.height
857
- });
858
- } finally {
859
- _effect.f();
828
+ }, [
829
+ generator,
830
+ size,
831
+ zoom,
832
+ translation,
833
+ rotation,
834
+ layers
835
+ ]);
836
+ if (!size.width || !size.height) {
837
+ return null;
860
838
  }
839
+ return /* @__PURE__ */ React2.createElement("canvas", {
840
+ ref: canvasRef,
841
+ width: size.width,
842
+ height: size.height
843
+ });
861
844
  });
862
845
  var GlobeDebug = ({ position = "topleft" }) => {
863
- var _effect = _useSignals3();
864
- try {
865
- const { size, scale, translation, rotation } = useGlobeContext();
866
- return /* @__PURE__ */ React3.createElement("div", {
867
- className: mx("z-10 absolute w-96 p-2 overflow-hidden border border-green-700 rounded", controlPositions[position])
868
- }, /* @__PURE__ */ React3.createElement("pre", {
869
- className: "font-mono text-xs text-green-700"
870
- }, JSON.stringify({
871
- size,
872
- scale,
873
- translation,
874
- rotation
875
- }, null, 2)));
876
- } finally {
877
- _effect.f();
878
- }
846
+ const { size, zoom, translation, rotation } = useGlobeContext();
847
+ return /* @__PURE__ */ React2.createElement("div", {
848
+ className: mx("z-10 absolute w-96 p-2 overflow-hidden border border-green-700 rounded-sm", controlPositions[position])
849
+ }, /* @__PURE__ */ React2.createElement("pre", {
850
+ className: "font-mono text-xs text-green-700"
851
+ }, JSON.stringify({
852
+ size,
853
+ zoom,
854
+ translation,
855
+ rotation
856
+ }, null, 2)));
879
857
  };
880
858
  var GlobePanel = ({ position, classNames, children }) => {
881
- var _effect = _useSignals3();
882
- try {
883
- return /* @__PURE__ */ React3.createElement("div", {
884
- className: mx("z-10 absolute overflow-hidden", controlPositions[position], classNames)
885
- }, children);
886
- } finally {
887
- _effect.f();
888
- }
859
+ return /* @__PURE__ */ React2.createElement("div", {
860
+ className: mx("z-10 absolute overflow-hidden", controlPositions[position], classNames)
861
+ }, children);
889
862
  };
890
863
  var CustomControl = ({ position, children }) => {
891
- var _effect = _useSignals3();
892
- try {
893
- return /* @__PURE__ */ React3.createElement("div", {
894
- className: mx("z-10 absolute overflow-hidden", controlPositions[position])
895
- }, children);
896
- } finally {
897
- _effect.f();
898
- }
864
+ return /* @__PURE__ */ React2.createElement("div", {
865
+ className: mx("z-10 absolute overflow-hidden", controlPositions[position])
866
+ }, children);
899
867
  };
868
+ var GlobeZoom = ({ onAction, position = "bottomleft", ...props }) => /* @__PURE__ */ React2.createElement(CustomControl, {
869
+ position,
870
+ ...props
871
+ }, /* @__PURE__ */ React2.createElement(ZoomControls, {
872
+ onAction
873
+ }));
874
+ var GlobeAction = ({ onAction, position = "bottomright", ...props }) => /* @__PURE__ */ React2.createElement(CustomControl, {
875
+ position,
876
+ ...props
877
+ }, /* @__PURE__ */ React2.createElement(ActionControls, {
878
+ onAction
879
+ }));
900
880
  var Globe = {
901
881
  Root: GlobeRoot,
902
882
  Canvas: GlobeCanvas,
903
- Zoom: ({ onAction, position = "bottomleft", ...props }) => {
904
- var _effect = _useSignals3();
905
- try {
906
- return /* @__PURE__ */ React3.createElement(CustomControl, {
907
- position,
908
- ...props
909
- }, /* @__PURE__ */ React3.createElement(ZoomControls, {
910
- onAction
911
- }));
912
- } finally {
913
- _effect.f();
914
- }
915
- },
916
- Action: ({ onAction, position = "bottomright", ...props }) => {
917
- var _effect = _useSignals3();
918
- try {
919
- return /* @__PURE__ */ React3.createElement(CustomControl, {
920
- position,
921
- ...props
922
- }, /* @__PURE__ */ React3.createElement(ActionControls, {
923
- onAction
924
- }));
925
- } finally {
926
- _effect.f();
927
- }
928
- },
883
+ Zoom: GlobeZoom,
884
+ Action: GlobeAction,
929
885
  Debug: GlobeDebug,
930
886
  Panel: GlobePanel
931
887
  };
932
888
 
933
889
  // src/components/Map/Map.tsx
934
- import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
935
890
  import "leaflet/dist/leaflet.css";
891
+ import { createContext as createContext2 } from "@radix-ui/react-context";
936
892
  import L, { Control, DomEvent, DomUtil, latLngBounds } from "leaflet";
937
- import React4, { forwardRef as forwardRef2, useEffect as useEffect5, useImperativeHandle as useImperativeHandle2 } from "react";
893
+ import React3, { forwardRef as forwardRef2, useEffect as useEffect5, useImperativeHandle as useImperativeHandle2, useRef as useRef2 } from "react";
938
894
  import { createRoot } from "react-dom/client";
939
- import { MapContainer, Marker, Popup, TileLayer, useMap } from "react-leaflet";
940
- import { useResizeDetector as useResizeDetector2 } from "react-resize-detector";
941
- import { debounce } from "@dxos/async";
895
+ import { MapContainer, Marker, Popup, TileLayer, useMap, useMapEvents } from "react-leaflet";
942
896
  import { ThemeProvider, Tooltip } from "@dxos/react-ui";
943
- import { defaultTx, mx as mx2 } from "@dxos/react-ui-theme";
897
+ import { composable as composable2, composableProps as composableProps2, defaultTx, mx as mx2 } from "@dxos/ui-theme";
944
898
  var defaults = {
945
- // TODO(burdon): Guess location.
946
899
  center: {
947
900
  lat: 51,
948
901
  lng: 0
949
902
  },
950
903
  zoom: 4
951
904
  };
952
- var MapRoot = ({ classNames, center = defaults.center, zoom = defaults.zoom, ...props }) => {
953
- var _effect = _useSignals4();
954
- try {
955
- return /* @__PURE__ */ React4.createElement(MapContainer, {
956
- className: mx2("relative grid grow bg-baseSurface", classNames),
957
- attributionControl: false,
958
- // TODO(burdon): Only if attention.
959
- scrollWheelZoom: true,
960
- zoomControl: false,
961
- center,
962
- zoom,
963
- ...props
964
- });
965
- } finally {
966
- _effect.f();
967
- }
905
+ var [MapContextProvider, useMapContext] = createContext2("Map");
906
+ var MapRoot = composable2(({ children, onChange, ...props }, forwardedRef) => {
907
+ const attention = false;
908
+ return /* @__PURE__ */ React3.createElement(MapContextProvider, {
909
+ attention,
910
+ onChange
911
+ }, /* @__PURE__ */ React3.createElement("div", {
912
+ ...composableProps2(props, {
913
+ role: "none",
914
+ classNames: "dx-container grid dx-focus-ring-inset"
915
+ }),
916
+ ref: forwardedRef
917
+ }, children));
918
+ });
919
+ MapRoot.displayName = "Map.Root";
920
+ var MAP_CONTENT_NAME = "Map.Content";
921
+ var MapContent = /* @__PURE__ */ forwardRef2(({ classNames, scrollWheelZoom = true, doubleClickZoom = true, touchZoom = true, center, zoom, children, ...props }, forwardedRef) => {
922
+ const { attention } = useMapContext(MAP_CONTENT_NAME);
923
+ const mapRef = useRef2(null);
924
+ const map = mapRef.current;
925
+ useImperativeHandle2(forwardedRef, () => ({
926
+ setCenter: (center2, zoom2) => {
927
+ mapRef.current?.setView(center2, zoom2);
928
+ },
929
+ setZoom: (cb) => {
930
+ mapRef.current?.setZoom(cb(mapRef.current?.getZoom() ?? 0));
931
+ }
932
+ }), []);
933
+ useEffect5(() => {
934
+ if (!map) {
935
+ return;
936
+ }
937
+ if (attention) {
938
+ map.scrollWheelZoom.enable();
939
+ } else {
940
+ map.scrollWheelZoom.disable();
941
+ }
942
+ }, [
943
+ map,
944
+ attention
945
+ ]);
946
+ return /* @__PURE__ */ React3.createElement(MapContainer, {
947
+ ...props,
948
+ className: mx2("group relative grid bg-base-surface!", classNames),
949
+ attributionControl: false,
950
+ zoomControl: false,
951
+ scrollWheelZoom,
952
+ doubleClickZoom,
953
+ touchZoom,
954
+ center: center ?? defaults.center,
955
+ zoom: zoom ?? defaults.zoom,
956
+ whenReady: () => {
957
+ },
958
+ ref: mapRef
959
+ }, children);
960
+ });
961
+ MapContent.displayName = "Map.Content";
962
+ var MAP_TILES_NAME = "Map.Tiles";
963
+ var MapTiles = (_props) => {
964
+ const ref = useRef2(null);
965
+ const { onChange } = useMapContext(MAP_TILES_NAME);
966
+ useMapEvents({
967
+ zoomstart: (ev) => {
968
+ onChange?.({
969
+ center: ev.target.getCenter(),
970
+ zoom: ev.target.getZoom()
971
+ });
972
+ }
973
+ });
974
+ const { attention } = useMapContext(MAP_TILES_NAME);
975
+ useEffect5(() => {
976
+ if (ref.current) {
977
+ ref.current.getContainer().dataset.attention = attention ? "1" : "0";
978
+ }
979
+ }, [
980
+ attention
981
+ ]);
982
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(TileLayer, {
983
+ ref,
984
+ "data-attention": attention,
985
+ detectRetina: true,
986
+ className: 'dark:grayscale dark:invert data-[attention="0"]:!opacity-80',
987
+ url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
988
+ keepBuffer: 4
989
+ }));
968
990
  };
969
- var MapCanvas = /* @__PURE__ */ forwardRef2(({ markers, center, zoom, onChange }, forwardedRef) => {
970
- var _effect = _useSignals4();
971
- try {
972
- const { ref, width, height } = useResizeDetector2({
973
- refreshRate: 200
974
- });
975
- const map = useMap();
976
- useImperativeHandle2(forwardedRef, () => ({
977
- setCenter: (center2, zoom2) => {
978
- map.setView(center2, zoom2);
991
+ MapTiles.displayName = MAP_TILES_NAME;
992
+ var MapMarkers = ({ selected, markers }) => {
993
+ const map = useMap();
994
+ useEffect5(() => {
995
+ if (markers.length > 0) {
996
+ const bounds = latLngBounds(markers.map((marker) => marker.location));
997
+ map.fitBounds(bounds);
998
+ } else {
999
+ map.setView(defaults.center, defaults.zoom);
1000
+ }
1001
+ }, [
1002
+ markers
1003
+ ]);
1004
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, markers?.map(({ id, title, location: { lat, lng } }) => {
1005
+ return /* @__PURE__ */ React3.createElement(Marker, {
1006
+ key: id,
1007
+ position: {
1008
+ lat,
1009
+ lng
979
1010
  },
980
- setZoom: (cb) => {
981
- map.setZoom(cb(map.getZoom()));
982
- }
983
- }), [
984
- map
985
- ]);
986
- useEffect5(() => {
987
- if (width && height) {
988
- map.invalidateSize();
989
- }
990
- }, [
991
- width,
992
- height
993
- ]);
994
- useEffect5(() => {
995
- if (center) {
996
- map.setView(center, zoom);
997
- } else if (zoom !== void 0) {
998
- map.setZoom(zoom);
999
- }
1000
- }, [
1001
- center,
1002
- zoom
1003
- ]);
1004
- useEffect5(() => {
1005
- const handler = debounce(() => {
1006
- onChange?.({
1007
- center: map.getCenter(),
1008
- zoom: map.getZoom()
1009
- });
1010
- }, 100);
1011
- map.on("move", handler);
1012
- map.on("zoom", handler);
1013
- return () => {
1014
- map.off("move", handler);
1015
- map.off("zoom", handler);
1016
- };
1017
- }, [
1018
- map,
1019
- onChange
1020
- ]);
1021
- useEffect5(() => {
1022
- if (markers.length > 0) {
1023
- const bounds = latLngBounds(markers.map((marker) => marker.location));
1024
- map.fitBounds(bounds);
1025
- } else {
1026
- map.setView(defaults.center, defaults.zoom);
1027
- }
1028
- }, [
1029
- markers
1030
- ]);
1031
- return /* @__PURE__ */ React4.createElement("div", {
1032
- ref,
1033
- className: "flex w-full h-full overflow-hidden bg-baseSurface"
1034
- }, /* @__PURE__ */ React4.createElement(TileLayer, {
1035
- className: "dark:filter dark:grayscale dark:invert",
1036
- url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
1037
- }), markers?.map(({ id, title, location: { lat, lng } }) => {
1038
- return /* @__PURE__ */ React4.createElement(Marker, {
1039
- key: id,
1040
- position: {
1041
- lat,
1042
- lng
1043
- },
1044
- icon: (
1045
- // TODO(burdon): Create custom icon from bundled assets.
1046
- new L.Icon({
1047
- iconUrl: "https://dxos.network/marker-icon.png",
1048
- iconRetinaUrl: "https://dxos.network/marker-icon-2x.png",
1049
- shadowUrl: "https://dxos.network/marker-shadow.png",
1050
- iconSize: [
1051
- 25,
1052
- 41
1053
- ],
1054
- iconAnchor: [
1055
- 12,
1056
- 41
1057
- ],
1058
- popupAnchor: [
1059
- 1,
1060
- -34
1061
- ],
1062
- shadowSize: [
1063
- 41,
1064
- 41
1065
- ]
1066
- })
1067
- )
1068
- }, title && /* @__PURE__ */ React4.createElement(Popup, null, title));
1069
- }));
1070
- } finally {
1071
- _effect.f();
1072
- }
1073
- });
1011
+ icon: (
1012
+ // TODO(burdon): Create custom icon from bundled assets.
1013
+ // TODO(burdon): Selection state.
1014
+ new L.Icon({
1015
+ iconUrl: "https://dxos.network/marker-icon.png",
1016
+ iconRetinaUrl: "https://dxos.network/marker-icon-2x.png",
1017
+ shadowUrl: "https://dxos.network/marker-shadow.png",
1018
+ iconSize: [
1019
+ 25,
1020
+ 41
1021
+ ],
1022
+ iconAnchor: [
1023
+ 12,
1024
+ 41
1025
+ ],
1026
+ popupAnchor: [
1027
+ 1,
1028
+ -34
1029
+ ],
1030
+ shadowSize: [
1031
+ 41,
1032
+ 41
1033
+ ]
1034
+ })
1035
+ )
1036
+ }, title && /* @__PURE__ */ React3.createElement(Popup, null, title));
1037
+ }));
1038
+ };
1039
+ MapMarkers.displayName = "Map.Markers";
1074
1040
  var CustomControl2 = ({ position, children }) => {
1075
- var _effect = _useSignals4();
1076
- try {
1077
- const map = useMap();
1078
- useEffect5(() => {
1079
- const control = new Control({
1080
- position
1081
- });
1082
- control.onAdd = () => {
1083
- const container = DomUtil.create("div", mx2("!m-0", controlPositions[position]));
1084
- DomEvent.disableClickPropagation(container);
1085
- DomEvent.disableScrollPropagation(container);
1086
- const root = createRoot(container);
1087
- root.render(/* @__PURE__ */ React4.createElement(ThemeProvider, {
1088
- tx: defaultTx
1089
- }, /* @__PURE__ */ React4.createElement(Tooltip.Provider, null, children)));
1090
- return container;
1091
- };
1092
- control.addTo(map);
1093
- return () => {
1094
- control.remove();
1095
- };
1096
- }, [
1097
- map,
1098
- position,
1099
- children
1100
- ]);
1101
- return null;
1102
- } finally {
1103
- _effect.f();
1104
- }
1041
+ const map = useMap();
1042
+ useEffect5(() => {
1043
+ const control = new Control({
1044
+ position
1045
+ });
1046
+ control.onAdd = () => {
1047
+ const container = DomUtil.create("div", mx2("m-0!", controlPositions[position]));
1048
+ DomEvent.disableClickPropagation(container);
1049
+ DomEvent.disableScrollPropagation(container);
1050
+ const root = createRoot(container);
1051
+ root.render(/* @__PURE__ */ React3.createElement(ThemeProvider, {
1052
+ tx: defaultTx
1053
+ }, /* @__PURE__ */ React3.createElement(Tooltip.Provider, null, children)));
1054
+ return container;
1055
+ };
1056
+ control.addTo(map);
1057
+ return () => {
1058
+ control.remove();
1059
+ };
1060
+ }, [
1061
+ map,
1062
+ position,
1063
+ children
1064
+ ]);
1065
+ return null;
1105
1066
  };
1067
+ var MapZoom = ({ onAction, position = "bottomleft", ...props }) => /* @__PURE__ */ React3.createElement(CustomControl2, {
1068
+ position,
1069
+ ...props
1070
+ }, /* @__PURE__ */ React3.createElement(ZoomControls, {
1071
+ onAction
1072
+ }));
1073
+ var MapAction = ({ onAction, position = "bottomright", ...props }) => /* @__PURE__ */ React3.createElement(CustomControl2, {
1074
+ position,
1075
+ ...props
1076
+ }, /* @__PURE__ */ React3.createElement(ActionControls, {
1077
+ onAction
1078
+ }));
1106
1079
  var Map = {
1107
1080
  Root: MapRoot,
1108
- Canvas: MapCanvas,
1109
- Zoom: ({ onAction, position = "bottomleft", ...props }) => {
1110
- var _effect = _useSignals4();
1111
- try {
1112
- return /* @__PURE__ */ React4.createElement(CustomControl2, {
1113
- position,
1114
- ...props
1115
- }, /* @__PURE__ */ React4.createElement(ZoomControls, {
1116
- onAction
1117
- }));
1118
- } finally {
1119
- _effect.f();
1120
- }
1121
- },
1122
- Action: ({ onAction, position = "bottomright", ...props }) => {
1123
- var _effect = _useSignals4();
1124
- try {
1125
- return /* @__PURE__ */ React4.createElement(CustomControl2, {
1126
- position,
1127
- ...props
1128
- }, /* @__PURE__ */ React4.createElement(ActionControls, {
1129
- onAction
1130
- }));
1131
- } finally {
1132
- _effect.f();
1133
- }
1134
- }
1081
+ Content: MapContent,
1082
+ Tiles: MapTiles,
1083
+ Markers: MapMarkers,
1084
+ Zoom: MapZoom,
1085
+ Action: MapAction
1135
1086
  };
1136
1087
  export {
1137
1088
  ActionControls,
1138
1089
  Globe,
1139
- GlobeContextProvider,
1090
+ GlobeContext,
1140
1091
  Map,
1141
1092
  ZoomControls,
1142
1093
  closestPoint,
@@ -1153,6 +1104,8 @@ export {
1153
1104
  renderLayers,
1154
1105
  restrictAxis,
1155
1106
  timer,
1107
+ translationKey,
1108
+ translations,
1156
1109
  useDrag,
1157
1110
  useGlobeContext,
1158
1111
  useGlobeZoomHandler,