@macrostrat/map-interface 1.1.0 → 1.2.0

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 (133) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cjs/container.72611900.js +134 -0
  3. package/dist/cjs/container.72611900.js.map +1 -0
  4. package/dist/cjs/context-panel.8c4b009c.js +88 -0
  5. package/dist/cjs/context-panel.8c4b009c.js.map +1 -0
  6. package/dist/cjs/controls.7ce3e95c.js +79 -0
  7. package/dist/cjs/controls.7ce3e95c.js.map +1 -0
  8. package/dist/cjs/dev.7499151f.js +33 -0
  9. package/dist/cjs/dev.7499151f.js.map +1 -0
  10. package/dist/cjs/expansion-panel.08532cee.js +134 -0
  11. package/dist/cjs/expansion-panel.08532cee.js.map +1 -0
  12. package/dist/cjs/hash-string.62e84f08.js +67 -0
  13. package/dist/cjs/hash-string.62e84f08.js.map +1 -0
  14. package/dist/cjs/header.58c5c012.js +104 -0
  15. package/dist/cjs/header.58c5c012.js.map +1 -0
  16. package/dist/cjs/headers.20eae5f7.js +29 -0
  17. package/dist/cjs/headers.20eae5f7.js.map +1 -0
  18. package/dist/cjs/helpers.0f72ddaf.js +190 -0
  19. package/dist/cjs/helpers.0f72ddaf.js.map +1 -0
  20. package/dist/cjs/index.js +51 -0
  21. package/dist/cjs/index.js.map +1 -0
  22. package/dist/cjs/location-info.92e70042.js +119 -0
  23. package/dist/cjs/location-info.92e70042.js.map +1 -0
  24. package/dist/cjs/location-panel.c95f5e96.js +66 -0
  25. package/dist/cjs/location-panel.c95f5e96.js.map +1 -0
  26. package/dist/cjs/main.module.02c4de16.css +86 -0
  27. package/dist/cjs/main.module.02c4de16.css.map +1 -0
  28. package/dist/cjs/main.module.3f2b7c9f.js +38 -0
  29. package/dist/cjs/main.module.3f2b7c9f.js.map +1 -0
  30. package/dist/cjs/main.module.4ecbaaa5.js +62 -0
  31. package/dist/cjs/main.module.4ecbaaa5.js.map +1 -0
  32. package/dist/cjs/main.module.62939ea7.js +167 -0
  33. package/dist/cjs/main.module.62939ea7.js.map +1 -0
  34. package/dist/cjs/main.module.92978d8b.css +52 -0
  35. package/dist/cjs/main.module.92978d8b.css.map +1 -0
  36. package/dist/cjs/main.module.becc2fe7.css +92 -0
  37. package/dist/cjs/main.module.becc2fe7.css.map +1 -0
  38. package/dist/cjs/main.module.ccec47df.js +50 -0
  39. package/dist/cjs/main.module.ccec47df.js.map +1 -0
  40. package/dist/cjs/main.module.e958948e.js +26 -0
  41. package/dist/cjs/main.module.e958948e.js.map +1 -0
  42. package/dist/{index.css → cjs/main.module.f085a193.css} +9 -397
  43. package/dist/cjs/main.module.f085a193.css.map +1 -0
  44. package/dist/cjs/main.module.ff1b1aca.css +179 -0
  45. package/dist/cjs/main.module.ff1b1aca.css.map +1 -0
  46. package/dist/cjs/map-page.190b6723.js +182 -0
  47. package/dist/cjs/map-page.190b6723.js.map +1 -0
  48. package/dist/cjs/map-view.93363b41.js +167 -0
  49. package/dist/cjs/map-view.93363b41.js.map +1 -0
  50. package/dist/cjs/terrain.90f76b4e.js +59 -0
  51. package/dist/cjs/terrain.90f76b4e.js.map +1 -0
  52. package/dist/cjs/tile-extent.06a4b2ed.js +51 -0
  53. package/dist/cjs/tile-extent.06a4b2ed.js.map +1 -0
  54. package/dist/cjs/utils.09cef979.js +36 -0
  55. package/dist/cjs/utils.09cef979.js.map +1 -0
  56. package/dist/cjs/utils.26f02633.js +46 -0
  57. package/dist/cjs/utils.26f02633.js.map +1 -0
  58. package/dist/cjs/vector-tile-features.456f887b.js +268 -0
  59. package/dist/cjs/vector-tile-features.456f887b.js.map +1 -0
  60. package/dist/cjs/xray.a23f8660.js +89 -0
  61. package/dist/cjs/xray.a23f8660.js.map +1 -0
  62. package/dist/esm/container.16bde261.js +126 -0
  63. package/dist/esm/container.16bde261.js.map +1 -0
  64. package/dist/esm/context-panel.c288c5cd.js +81 -0
  65. package/dist/esm/context-panel.c288c5cd.js.map +1 -0
  66. package/dist/esm/controls.f757ce16.js +74 -0
  67. package/dist/esm/controls.f757ce16.js.map +1 -0
  68. package/dist/esm/dev.ccb6e774.js +13 -0
  69. package/dist/esm/dev.ccb6e774.js.map +1 -0
  70. package/dist/esm/expansion-panel.feff0e62.js +123 -0
  71. package/dist/esm/expansion-panel.feff0e62.js.map +1 -0
  72. package/dist/esm/hash-string.836601b2.js +61 -0
  73. package/dist/esm/hash-string.836601b2.js.map +1 -0
  74. package/dist/esm/header.0f535ab1.js +99 -0
  75. package/dist/esm/header.0f535ab1.js.map +1 -0
  76. package/dist/esm/headers.b25ff414.js +24 -0
  77. package/dist/esm/headers.b25ff414.js.map +1 -0
  78. package/dist/esm/helpers.fb1d7227.js +176 -0
  79. package/dist/esm/helpers.fb1d7227.js.map +1 -0
  80. package/dist/{types.d.ts → esm/index.d.ts} +102 -51
  81. package/dist/esm/index.d.ts.map +1 -0
  82. package/dist/esm/index.js +25 -0
  83. package/dist/esm/index.js.map +1 -0
  84. package/dist/esm/location-info.5543bb05.js +89 -0
  85. package/dist/esm/location-info.5543bb05.js.map +1 -0
  86. package/dist/esm/location-panel.0b1f4ed2.js +58 -0
  87. package/dist/esm/location-panel.0b1f4ed2.js.map +1 -0
  88. package/dist/esm/main.module.5eb366de.js +52 -0
  89. package/dist/esm/main.module.5eb366de.js.map +1 -0
  90. package/dist/esm/main.module.67a908da.js +40 -0
  91. package/dist/esm/main.module.67a908da.js.map +1 -0
  92. package/dist/esm/main.module.89579666.js +64 -0
  93. package/dist/esm/main.module.89579666.js.map +1 -0
  94. package/dist/esm/main.module.9c57cc95.js +28 -0
  95. package/dist/esm/main.module.9c57cc95.js.map +1 -0
  96. package/dist/esm/main.module.f70e002b.js +169 -0
  97. package/dist/esm/main.module.f70e002b.js.map +1 -0
  98. package/dist/esm/map-page.b953c404.js +175 -0
  99. package/dist/esm/map-page.b953c404.js.map +1 -0
  100. package/dist/esm/map-view.a3fe6257.js +161 -0
  101. package/dist/esm/map-view.a3fe6257.js.map +1 -0
  102. package/dist/esm/terrain.f65cf7c5.js +54 -0
  103. package/dist/esm/terrain.f65cf7c5.js.map +1 -0
  104. package/dist/esm/tile-extent.ca526996.js +46 -0
  105. package/dist/esm/tile-extent.ca526996.js.map +1 -0
  106. package/dist/esm/utils.122d1f2d.js +28 -0
  107. package/dist/esm/utils.122d1f2d.js.map +1 -0
  108. package/dist/esm/utils.d40349f0.js +40 -0
  109. package/dist/esm/utils.d40349f0.js.map +1 -0
  110. package/dist/esm/vector-tile-features.e1a24df0.js +258 -0
  111. package/dist/esm/vector-tile-features.e1a24df0.js.map +1 -0
  112. package/dist/esm/xray.c0663c25.js +83 -0
  113. package/dist/esm/xray.c0663c25.js.map +1 -0
  114. package/package.json +19 -36
  115. package/src/container.ts +29 -21
  116. package/src/context-panel/index.ts +4 -4
  117. package/src/context-panel/main.module.sass +1 -1
  118. package/src/dev/main.module.sass +16 -0
  119. package/src/dev/map-page.ts +19 -4
  120. package/src/dev/vector-tile-features.ts +44 -13
  121. package/src/location-panel/header.ts +27 -8
  122. package/src/location-panel/index.ts +4 -2
  123. package/src/location-panel/main.module.sass +7 -0
  124. package/src/main.module.sass +4 -1
  125. package/src/map-view/index.ts +1 -1
  126. package/dist/index.cjs.css +0 -961
  127. package/dist/index.cjs.css.map +0 -1
  128. package/dist/index.cjs.js +0 -1954
  129. package/dist/index.cjs.js.map +0 -1
  130. package/dist/index.css.map +0 -1
  131. package/dist/index.js +0 -1945
  132. package/dist/index.js.map +0 -1
  133. package/dist/types.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"mappings":"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","sources":["packages/map-interface/src/dev/vector-tile-features.ts"],"sourcesContent":["import { Spinner, Switch, Button, Intent } from \"@blueprintjs/core\";\nimport { useMapRef, useMapStatus } from \"@macrostrat/mapbox-react\";\nimport mapboxgl from \"mapbox-gl\";\nimport hyper from \"@macrostrat/hyper\";\nimport styles from \"./main.module.sass\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { JSONView } from \"@macrostrat/ui-components\";\nimport { group } from \"d3-array\";\nimport { ExpansionPanel } from \"../expansion-panel\";\n\nconst h = hyper.styled(styles);\n\nexport function FeatureProperties({ data, ...rest }) {\n // Instead of managing hover state with CSS, we use a state variable,\n // so that the button re-renders when the state changes\n const [showControls, setShowControls] = useState(false);\n const onMouseEnter = useCallback(() => setShowControls(true), []);\n const onMouseLeave = useCallback(() => setShowControls(false), []);\n\n return h(\"div.feature-properties\", { onMouseEnter, onMouseLeave }, [\n h.if(showControls)(\"div.controls\", h(CopyJSONButton, { data })),\n h(JSONView, {\n data,\n hideRoot: true,\n ...rest,\n }),\n ]);\n}\n\nexport function FeatureRecord({ feature }) {\n const props = feature.properties;\n return h(\"div.feature-record\", [\n h.if(Object.keys(props).length > 0)(FeatureProperties, { data: props }),\n ]);\n}\n\nfunction CopyJSONButton({ data }) {\n const [copied, setCopied] = useState(false);\n return h(Button, {\n icon: copied ? \"tick\" : \"clipboard\",\n intent: copied ? Intent.SUCCESS : Intent.NONE,\n minimal: true,\n small: true,\n onClick() {\n navigator.clipboard.writeText(JSON.stringify(data, null, 2));\n setCopied(true);\n },\n });\n}\n\n/** This component wraps queryRenderedFeatures to get features at a given location */\nexport function FeatureSelectionHandler({\n selectedLocation,\n setFeatures,\n radius = 2,\n}: {\n selectedLocation: mapboxgl.LngLat;\n setFeatures: (features: mapboxgl.MapboxGeoJSONFeature[]) => void;\n radius?: number;\n}) {\n const mapRef = useMapRef();\n const isLoading = useMapStatus((s) => s.isLoading);\n const isInitialized = useMapStatus((s) => s.isInitialized);\n const prevLocation = useRef(null);\n const prevFeatures = useRef([]);\n\n useEffect(() => {\n const map = mapRef?.current;\n if (map == null) return;\n if (selectedLocation == null) {\n setFeatures(null);\n return;\n }\n\n if (!isInitialized) return;\n\n const hasPreviouslyLoadedFeatures = prevFeatures.current.length > 0;\n\n const locationMemo = JSON.stringify(selectedLocation);\n if (locationMemo == prevLocation.current && hasPreviouslyLoadedFeatures)\n return;\n\n prevLocation.current = locationMemo;\n\n // Don't update if the location hasn't changed\n //if (selectedLocation == prevLocation) return;\n\n const r = radius;\n const pt = map.project(selectedLocation);\n\n const bbox: [mapboxgl.PointLike, mapboxgl.PointLike] = [\n [pt.x - r, pt.y - r],\n [pt.x + r, pt.y + r],\n ];\n const features = map.queryRenderedFeatures(bbox);\n prevFeatures.current = features ?? [];\n setFeatures(features);\n }, [isInitialized, selectedLocation, isLoading]);\n\n return null;\n}\n\nfunction FeatureHeader({ feature }) {\n return h(\"div.feature-header\", [\n h(\"h3\", [\n h(KeyValue, { label: \"Source\", value: feature.source }),\n h(KeyValue, { label: \"Source layer\", value: feature.sourceLayer }),\n ]),\n ]);\n}\n\nfunction KeyValue({ label, value }) {\n return h(\"span.key-value\", [h(\"span.key\", label), h(\"code.value\", value)]);\n}\n\nfunction LoadingAwareFeatureSet({ features, sourceID }) {\n const map = useMapRef();\n if (map?.current == null) return null;\n const [isLoaded, setIsLoaded] = useState(false);\n\n const sourceFeatures = features.filter((d) => d.source == \"burwell\");\n\n useEffect(() => {\n if (sourceFeatures.length > 0) {\n setIsLoaded(true);\n return;\n }\n\n const isLoaded = map.current.isSourceLoaded(sourceID);\n setIsLoaded(isLoaded);\n if (!isLoaded) {\n map.current.once(\"sourcedata\", (e) => {\n if (e.sourceId == sourceID) {\n setIsLoaded(true);\n }\n });\n }\n }, [map.current, sourceID, sourceFeatures.length]);\n\n if (!isLoaded) return h(Spinner);\n return h(Features, { features: sourceFeatures });\n}\n\nexport function TileInfo({ feature, showExtent, setShowExtent }) {\n if (feature == null) return null;\n const size = feature._vectorTileFeature._pbf.length;\n return h(\"div.tile-info\", [\n h(\"h3\", \"Tile\"),\n h(\"div.tile-index\", [\n h(KeyValue, { label: \"x\", value: feature._x }),\n h(KeyValue, { label: \"y\", value: feature._y }),\n h(KeyValue, { label: \"z\", value: feature._z }),\n ]),\n h(\"div.spacer\"),\n h(KeyValue, { label: \"Size\", value: formatSize(size) }),\n h(Switch, {\n label: \"Show extent\",\n alignIndicator: \"right\",\n checked: showExtent,\n onChange() {\n setShowExtent(!showExtent);\n },\n }),\n ]);\n}\n\nfunction formatSize(size: number) {\n if (size > 1000000)\n return h(UnitNumber, { value: size / 1000000, unit: \"Mb\" });\n if (size > 1000) return h(UnitNumber, { value: size / 1000, unit: \"Kb\" });\n return `${size} bytes`;\n}\n\nfunction UnitNumber({ value, unit, precision = 1 }) {\n return h(\"span.unit-number\", [\n h(\"span.number\", value.toFixed(precision)),\n h(\"span.unit\", unit),\n ]);\n}\n\nexport function FeaturePanel({ features, focusedSource = null }) {\n if (features == null) return null;\n\n let focusedSourcePanel = null;\n let filteredFeatures = features;\n let title = \"Features\";\n\n if (focusedSource != null) {\n title = \"Basemap features\";\n focusedSourcePanel = h(\n ExpansionPanel,\n {\n title: \"Macrostrat features\",\n className: \"macrostrat-features\",\n expanded: true,\n },\n [\n h(LoadingAwareFeatureSet, {\n features,\n sourceID: focusedSource,\n }),\n ]\n );\n filteredFeatures = features.filter((d) => d.source != focusedSource);\n }\n\n return h(\"div.feature-panel\", [\n focusedSourcePanel,\n h(\n ExpansionPanel,\n { title, className: \"basemap-features\", expanded: focusedSource == null },\n [\n h(FeatureGroups, {\n features: filteredFeatures,\n }),\n ]\n ),\n ]);\n}\n\nfunction FeatureGroups({ features }) {\n /** Group features by source and sourceLayer */\n if (features == null) return null;\n\n const groups = group(features, (d) => `${d.source} - ${d.sourceLayer}`);\n\n return h(\n \"div.feature-groups\",\n Array.from(groups).map(([key, features]) => {\n return h(\"div.feature-group\", [\n h(FeatureHeader, { feature: features[0] }),\n h(Features, { features }),\n ]);\n })\n );\n}\n\nexport function Features({ features }) {\n return h(\n \"div.features\",\n features.map((feature, i) => h(FeatureRecord, { key: i, feature }))\n );\n}\n"],"names":[],"version":3,"file":"vector-tile-features.e1a24df0.js.map"}
@@ -0,0 +1,83 @@
1
+ import {getMapboxStyle as $gWtFU$getMapboxStyle, mergeStyles as $gWtFU$mergeStyles} from "@macrostrat/mapbox-utils";
2
+ import {asChromaColor as $gWtFU$asChromaColor, toRGBAString as $gWtFU$toRGBAString} from "@macrostrat/color-utils";
3
+
4
+
5
+
6
+ async function $64ee2eed3ed5ffbc$export$eff5fb2e10d05b1d(baseStyle, params = null) {
7
+ const { inDarkMode: inDarkMode = false, color: color = "rgb(74, 242, 161)", mapboxToken: mapboxToken, xRaySources: xRaySources } = params;
8
+ const style = await (0, $gWtFU$getMapboxStyle)(baseStyle, {
9
+ access_token: mapboxToken
10
+ });
11
+ const sources = xRaySources ?? Object.keys(style.sources);
12
+ let layers = [];
13
+ for (let layer of style.layers){
14
+ if (!sources.includes(layer.source)) {
15
+ layers.push(layer);
16
+ continue;
17
+ }
18
+ let newLayer = $64ee2eed3ed5ffbc$var$transformMapboxLayer(layer, color, inDarkMode);
19
+ if (newLayer != null) layers.push(newLayer);
20
+ }
21
+ return {
22
+ ...style,
23
+ layers: layers
24
+ };
25
+ }
26
+ function $64ee2eed3ed5ffbc$var$transformMapboxLayer(layer, color, inDarkMode) {
27
+ const c = (0, $gWtFU$asChromaColor)(color);
28
+ const xRayColor = (opacity = 1, darken = 0)=>{
29
+ if (!inDarkMode) return (0, $gWtFU$toRGBAString)(c.darken(2 - darken).alpha(opacity));
30
+ return (0, $gWtFU$toRGBAString)(c.alpha(opacity).darken(darken));
31
+ };
32
+ if (layer.type == "background") return null;
33
+ let newLayer = {
34
+ ...layer
35
+ };
36
+ console.log(xRayColor(0.5));
37
+ if (layer.type == "fill") newLayer.paint = {
38
+ "fill-color": xRayColor(0.1),
39
+ "fill-outline-color": xRayColor(0.5)
40
+ };
41
+ else if (layer.type == "line") newLayer.paint = {
42
+ "line-color": xRayColor(0.5, 0),
43
+ "line-width": 1.5
44
+ };
45
+ else if (layer.type == "symbol") newLayer.paint = {
46
+ "text-color": xRayColor(1, -0.5),
47
+ "text-halo-color": "#000"
48
+ };
49
+ else if (layer.type == "circle") newLayer.paint = {
50
+ "circle-color": xRayColor(0.5, 0),
51
+ "circle-stroke-color": xRayColor(0.5, 1),
52
+ "circle-radius": 2
53
+ };
54
+ return newLayer;
55
+ }
56
+ async function $64ee2eed3ed5ffbc$export$e739dc8dfc0db9a6(baseStyle, overlayStyle = null, params = {}) {
57
+ const { mapboxToken: mapboxToken, xRay: xRay = false, xRaySources: _xRaySources, ...rest } = params;
58
+ let xRaySources = _xRaySources;
59
+ let style = await (0, $gWtFU$getMapboxStyle)(baseStyle, {
60
+ access_token: mapboxToken
61
+ });
62
+ if (overlayStyle != null) {
63
+ const overlay = await (0, $gWtFU$getMapboxStyle)(overlayStyle, {
64
+ access_token: mapboxToken
65
+ });
66
+ style = (0, $gWtFU$mergeStyles)(style, overlay);
67
+ xRaySources ??= Object.keys(overlay.sources);
68
+ }
69
+ if (xRay) {
70
+ // If we haven't specified sources, then we'll use all of them
71
+ xRaySources ??= Object.keys(style.sources);
72
+ style = await $64ee2eed3ed5ffbc$export$eff5fb2e10d05b1d(style, {
73
+ ...rest,
74
+ mapboxToken: mapboxToken,
75
+ xRaySources: xRaySources
76
+ });
77
+ }
78
+ return style;
79
+ }
80
+
81
+
82
+ export {$64ee2eed3ed5ffbc$export$eff5fb2e10d05b1d as buildXRayStyle, $64ee2eed3ed5ffbc$export$e739dc8dfc0db9a6 as buildInspectorStyle};
83
+ //# sourceMappingURL=xray.c0663c25.js.map
@@ -0,0 +1 @@
1
+ {"mappings":";;;;;AAWO,eAAe,0CACpB,SAA0B,EAC1B,SAAsB,IAAI;IAE1B,MAAM,cACJ,aAAa,cACb,QAAQ,kCACR,WAAW,eACX,WAAW,EACZ,GAAG;IACJ,MAAM,QAAQ,MAAM,CAAA,GAAA,qBAAa,EAAE,WAAW;QAAE,cAAc;IAAY;IAC1E,MAAM,UAAU,eAAe,OAAO,IAAI,CAAC,MAAM,OAAO;IAExD,IAAI,SAAS,EAAE;IACf,KAAK,IAAI,SAAS,MAAM,MAAM,CAAE;QAC9B,IAAI,CAAC,QAAQ,QAAQ,CAAC,MAAM,MAAM,GAAG;YACnC,OAAO,IAAI,CAAC;YACZ;QACF;QACA,IAAI,WAAW,2CAAqB,OAAO,OAAO;QAClD,IAAI,YAAY,MACd,OAAO,IAAI,CAAC;IAEhB;IAEA,OAAO;QACL,GAAG,KAAK;gBACR;IACF;AACF;AAEA,SAAS,2CAAqB,KAAK,EAAE,KAAK,EAAE,UAAU;IACpD,MAAM,IAAI,CAAA,GAAA,oBAAY,EAAE;IACxB,MAAM,YAAY,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC;QACxC,IAAI,CAAC,YACH,OAAO,CAAA,GAAA,mBAAW,EAAE,EAAE,MAAM,CAAC,IAAI,QAAQ,KAAK,CAAC;QAEjD,OAAO,CAAA,GAAA,mBAAW,EAAE,EAAE,KAAK,CAAC,SAAS,MAAM,CAAC;IAC9C;IAEA,IAAI,MAAM,IAAI,IAAI,cAChB,OAAO;IAGT,IAAI,WAAW;QAAE,GAAG,KAAK;IAAC;IAE1B,QAAQ,GAAG,CAAC,UAAU;IAEtB,IAAI,MAAM,IAAI,IAAI,QAChB,SAAS,KAAK,GAAG;QACf,cAAc,UAAU;QACxB,sBAAsB,UAAU;IAClC;SACK,IAAI,MAAM,IAAI,IAAI,QACvB,SAAS,KAAK,GAAG;QACf,cAAc,UAAU,KAAK;QAC7B,cAAc;IAChB;SACK,IAAI,MAAM,IAAI,IAAI,UACvB,SAAS,KAAK,GAAG;QACf,cAAc,UAAU,GAAG;QAC3B,mBAAmB;IACrB;SACK,IAAI,MAAM,IAAI,IAAI,UACvB,SAAS,KAAK,GAAG;QACf,gBAAgB,UAAU,KAAK;QAC/B,uBAAuB,UAAU,KAAK;QACtC,iBAAiB;IACnB;IAGF,OAAO;AACT;AAMO,eAAe,0CACpB,SAAkC,EAClC,eAA+C,IAAI,EACnD,SAAgC,CAAC,CAAC;IAElC,MAAM,eACJ,WAAW,QACX,OAAO,OACP,aAAa,YAAY,EACzB,GAAG,MACJ,GAAG;IACJ,IAAI,cAAc;IAClB,IAAI,QAAQ,MAAM,CAAA,GAAA,qBAAa,EAAE,WAAW;QAC1C,cAAc;IAChB;IAEA,IAAI,gBAAgB,MAAM;QACxB,MAAM,UAAU,MAAM,CAAA,GAAA,qBAAa,EAAE,cAAc;YACjD,cAAc;QAChB;QACA,QAAQ,CAAA,GAAA,kBAAU,EAAE,OAAO;QAC3B,gBAAgB,OAAO,IAAI,CAAC,QAAQ,OAAO;IAC7C;IAEA,IAAI,MAAM;QACR,8DAA8D;QAC9D,gBAAgB,OAAO,IAAI,CAAC,MAAM,OAAO;QAEzC,QAAQ,MAAM,0CAAe,OAAO;YAAE,GAAG,IAAI;yBAAE;yBAAa;QAAY;IAC1E;IACA,OAAO;AACT","sources":["packages/map-interface/src/dev/xray.ts"],"sourcesContent":["import { getMapboxStyle, mergeStyles } from \"@macrostrat/mapbox-utils\";\nimport { asChromaColor, toRGBAString } from \"@macrostrat/color-utils\";\nimport mapboxgl from \"mapbox-gl\";\n\ninterface XRayOptions {\n color?: string;\n inDarkMode?: boolean;\n mapboxToken?: string;\n xRaySources?: string[];\n}\n\nexport async function buildXRayStyle(\n baseStyle: string | object,\n params: XRayOptions = null\n) {\n const {\n inDarkMode = false,\n color = \"rgb(74, 242, 161)\",\n mapboxToken,\n xRaySources,\n } = params;\n const style = await getMapboxStyle(baseStyle, { access_token: mapboxToken });\n const sources = xRaySources ?? Object.keys(style.sources);\n\n let layers = [];\n for (let layer of style.layers) {\n if (!sources.includes(layer.source)) {\n layers.push(layer);\n continue;\n }\n let newLayer = transformMapboxLayer(layer, color, inDarkMode);\n if (newLayer != null) {\n layers.push(newLayer);\n }\n }\n\n return {\n ...style,\n layers,\n };\n}\n\nfunction transformMapboxLayer(layer, color, inDarkMode) {\n const c = asChromaColor(color);\n const xRayColor = (opacity = 1, darken = 0) => {\n if (!inDarkMode) {\n return toRGBAString(c.darken(2 - darken).alpha(opacity));\n }\n return toRGBAString(c.alpha(opacity).darken(darken));\n };\n\n if (layer.type == \"background\") {\n return null;\n }\n\n let newLayer = { ...layer };\n\n console.log(xRayColor(0.5));\n\n if (layer.type == \"fill\") {\n newLayer.paint = {\n \"fill-color\": xRayColor(0.1),\n \"fill-outline-color\": xRayColor(0.5),\n };\n } else if (layer.type == \"line\") {\n newLayer.paint = {\n \"line-color\": xRayColor(0.5, 0),\n \"line-width\": 1.5,\n };\n } else if (layer.type == \"symbol\") {\n newLayer.paint = {\n \"text-color\": xRayColor(1, -0.5),\n \"text-halo-color\": \"#000\",\n };\n } else if (layer.type == \"circle\") {\n newLayer.paint = {\n \"circle-color\": xRayColor(0.5, 0),\n \"circle-stroke-color\": xRayColor(0.5, 1),\n \"circle-radius\": 2,\n };\n }\n\n return newLayer;\n}\n\ntype InspectorStyleOptions = XRayOptions & {\n xRay?: boolean;\n};\n\nexport async function buildInspectorStyle(\n baseStyle: mapboxgl.Style | string,\n overlayStyle: mapboxgl.Style | string | null = null,\n params: InspectorStyleOptions = {}\n) {\n const {\n mapboxToken,\n xRay = false,\n xRaySources: _xRaySources,\n ...rest\n } = params;\n let xRaySources = _xRaySources;\n let style = await getMapboxStyle(baseStyle, {\n access_token: mapboxToken,\n });\n\n if (overlayStyle != null) {\n const overlay = await getMapboxStyle(overlayStyle, {\n access_token: mapboxToken,\n });\n style = mergeStyles(style, overlay);\n xRaySources ??= Object.keys(overlay.sources);\n }\n\n if (xRay) {\n // If we haven't specified sources, then we'll use all of them\n xRaySources ??= Object.keys(style.sources);\n\n style = await buildXRayStyle(style, { ...rest, mapboxToken, xRaySources });\n }\n return style;\n}\n"],"names":[],"version":3,"file":"xray.c0663c25.js.map"}
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@macrostrat/map-interface",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Map interface for Macrostrat",
5
- "main": "dist/index.cjs.js",
6
- "module": "dist/index.js",
7
- "types": "dist/types.d.ts",
5
+ "main": "dist/cjs/index.js",
6
+ "module": "dist/esm/index.js",
8
7
  "source": "src/index.ts",
9
- "style": "dist/index.css",
8
+ "types": "dist/esm/index.d.ts",
10
9
  "dependencies": {
11
- "@macrostrat/color-utils": "^1.0.0",
12
- "@macrostrat/hyper": "^3.0.0",
13
- "@macrostrat/mapbox-react": "^2.4.0",
14
- "@macrostrat/mapbox-utils": "^1.3.2",
15
- "@macrostrat/ui-components": "^4.0.4",
10
+ "@blueprintjs/core": "^5.0.0",
11
+ "@macrostrat/color-utils": "^1.0.1",
12
+ "@macrostrat/hyper": "^3.0.6",
13
+ "@macrostrat/mapbox-react": "^2.5.0",
14
+ "@macrostrat/mapbox-utils": "^1.4.0",
15
+ "@macrostrat/ui-components": "^4.1.0",
16
16
  "@mapbox/tilebelt": "^2.0.0",
17
17
  "classnames": "^2.5.1",
18
18
  "d3-array": "^3.2.4",
@@ -23,47 +23,30 @@
23
23
  "underscore": "^1.13.6",
24
24
  "use-resize-observer": "^9.1.0"
25
25
  },
26
+ "devDependencies": {
27
+ "parcel": "^2.13.3",
28
+ "ui-box": "^5.4.1"
29
+ },
26
30
  "peerDependencies": {
27
- "@blueprintjs/core": "^5.0.0",
28
31
  "react": "^16.8.6||^17.0.0||^18.0.0",
29
32
  "react-dom": "^16.8.6||^17.0.0||^18.0.0"
30
33
  },
31
34
  "scripts": {
32
35
  "dev": "parcel watch",
33
- "build": "parcel build"
36
+ "build": "rm -rf dist && parcel build"
34
37
  },
35
38
  "exports": {
36
39
  ".": {
37
- "typescript": "./src",
38
- "import": {
39
- "types": "./dist/types.d.ts",
40
- "default": "./dist/index.js"
41
- },
42
- "require": {
43
- "types": "./dist/types.d.ts",
44
- "default": "./dist/index.cjs.js"
45
- },
46
- "types:": "./dist/types.d.ts",
47
- "style": "./dist/index.css"
48
- },
49
- "./dist/": {
50
- "import": "./dist/",
51
- "require": "./dist/"
52
- },
53
- "./dist/index.css": {
54
- "import": "./dist/index.css",
55
- "require": "./dist/index.css"
40
+ "source": "./src/index.ts",
41
+ "import": "./dist/esm/index.js",
42
+ "require": "./dist/cjs/index.js",
43
+ "types": "./dist/esm/index.d.ts"
56
44
  }
57
45
  },
58
46
  "files": [
59
47
  "dist",
60
48
  "src"
61
49
  ],
62
- "devDependencies": {
63
- "parcel": "^2.12.0",
64
- "postcss": "^8.0.0",
65
- "postcss-modules": "^4.3.0"
66
- },
67
50
  "repository": {
68
51
  "type": "git",
69
52
  "url": "https://github.com/UW-Macrostrat/web-components.git",
package/src/container.ts CHANGED
@@ -35,6 +35,26 @@ export enum DetailPanelStyle {
35
35
  export const MapAreaContainer = (props) =>
36
36
  h(MapProviders, h(_MapAreaContainer, props));
37
37
 
38
+ interface MapAreaContainerProps {
39
+ navbar: AnyElement;
40
+ children?: AnyElement;
41
+ mapControls?: AnyElement;
42
+ contextPanel?: AnyElement;
43
+ contextStack?: AnyElement;
44
+ mainPanel?: AnyElement;
45
+ detailPanel?: AnyElement;
46
+ bottomPanel?: AnyElement;
47
+ className?: string;
48
+ detailPanelOpen?: boolean;
49
+ contextPanelOpen?: boolean;
50
+ contextStackProps?: ContextStackProps;
51
+ detailStackProps?: HTMLDivProps;
52
+ detailPanelStyle: DetailPanelStyle;
53
+ fitViewport?: boolean;
54
+ showPanelOutlines?: boolean;
55
+ preventMapInteraction?: boolean;
56
+ }
57
+
38
58
  function _MapAreaContainer({
39
59
  children,
40
60
  className,
@@ -53,24 +73,7 @@ function _MapAreaContainer({
53
73
  showPanelOutlines = false,
54
74
  preventMapInteraction = false,
55
75
  ...rest
56
- }: {
57
- navbar: AnyElement;
58
- children?: AnyElement;
59
- mapControls?: AnyElement;
60
- contextPanel?: AnyElement;
61
- contextStack?: AnyElement;
62
- mainPanel?: AnyElement;
63
- detailPanel?: AnyElement;
64
- bottomPanel?: AnyElement;
65
- className?: string;
66
- detailPanelOpen?: boolean;
67
- contextPanelOpen?: boolean;
68
- contextStackProps?: ContextStackProps;
69
- detailStackProps?: HTMLDivProps;
70
- detailPanelStyle: DetailPanelStyle;
71
- fitViewport?: boolean;
72
- showPanelOutlines?: boolean;
73
- }) {
76
+ }: MapAreaContainerProps) {
74
77
  const _detailPanelOpen = detailPanelOpen ?? detailPanel != null;
75
78
  const contextPanelTrans = useTransition(contextPanelOpen, 800);
76
79
  const detailPanelTrans = useTransition(_detailPanelOpen, 800);
@@ -114,12 +117,17 @@ function _MapAreaContainer({
114
117
  ]
115
118
  );
116
119
 
120
+ let contextStack = null;
121
+ if (navbar != null && contextPanel != null) {
122
+ contextStack = h(ContextStack, { navbar, ...contextStackProps }, [
123
+ h.if(contextPanelTrans.shouldMount)([contextPanel]),
124
+ ]);
125
+ }
126
+
117
127
  return h(MapStyledContainer, { className: mainUIClassNames }, [
118
128
  h("div.main-row", [
119
129
  h("div.map-ui", { ...rest }, [
120
- h(ContextStack, { navbar, ...contextStackProps }, [
121
- h.if(contextPanelTrans.shouldMount)([contextPanel]),
122
- ]),
130
+ contextStack,
123
131
  //h(MapView),
124
132
  children ?? mainPanel,
125
133
  h.if(detailPanelStyle == DetailPanelStyle.FLOATING)([detailStackExt]),
@@ -13,7 +13,7 @@ export function LoadingButton({
13
13
  isLoading = false,
14
14
  onClick,
15
15
  active = false,
16
- large = false,
16
+ large = true,
17
17
  icon = "menu",
18
18
  style,
19
19
  }) {
@@ -37,13 +37,13 @@ type AnyChildren = React.ReactNode;
37
37
 
38
38
  export interface FloatingNavbarProps {
39
39
  className?: string;
40
- children: AnyChildren;
40
+ children?: AnyChildren;
41
41
  headerElement?: AnyChildren;
42
42
  title?: AnyChildren;
43
43
  statusElement?: AnyChildren;
44
44
  rightElement?: AnyChildren;
45
- height: number | string;
46
- width: number | string;
45
+ height?: number | string;
46
+ width?: number | string;
47
47
  style?: object;
48
48
  }
49
49
 
@@ -11,7 +11,7 @@
11
11
  .searchbar
12
12
  width: 100%
13
13
  background-color: var(--panel-background-color)
14
- border-radius: 5px
14
+ border-radius: var(--map-panel-border-radius, 5px)
15
15
  padding: var(--navbar-padding, 10px)
16
16
  display: flex
17
17
  flex-direction: row
@@ -5,22 +5,35 @@
5
5
  .key-value
6
6
  display: inline-block
7
7
  margin-right: 1em
8
+
8
9
  .key
9
10
  font-weight: bold
10
11
  font-size: 0.9em
12
+
11
13
  &:after
12
14
  content: ': '
15
+
13
16
  .value
14
17
  font-size: 0.9em
15
18
 
16
19
  .feature-properties
17
20
  position: relative
21
+
18
22
  &:before
19
23
  content: "–"
20
24
  position: absolute
21
25
  top: 4px
22
26
  left: 0
23
27
 
28
+ .controls
29
+ display: flex
30
+ flex-direction: row
31
+ align-items: flex-end
32
+ position: absolute
33
+ top: 0
34
+ right: 0
35
+ gap: 0.5em
36
+
24
37
  .feature-header h3
25
38
  margin-bottom: 0
26
39
  margin-top: 0.5em
@@ -28,6 +41,7 @@
28
41
  .feature-group
29
42
  border-bottom: 1px solid var(--panel-rule-inner)
30
43
  margin-bottom: 0.5em
44
+
31
45
  &:last-child
32
46
  border-bottom: none
33
47
 
@@ -35,11 +49,13 @@
35
49
  display: flex
36
50
  flex-direction: row
37
51
  align-items: baseline
52
+
38
53
  h3
39
54
  margin-right: 0.5em
40
55
 
41
56
  .opacity-slider
42
57
  margin: 0 1em 0.5em
58
+
43
59
  :global
44
60
  .bp5-slider-handle .bp5-slider-label
45
61
  background-color: var(--secondary-color)
@@ -21,14 +21,15 @@ import { MapPosition } from "@macrostrat/mapbox-utils";
21
21
 
22
22
  export const h = hyper.styled(styles);
23
23
 
24
- export function MapInspector({
24
+ export function MapInspectorV2({
25
25
  title = "Map inspector",
26
26
  headerElement = null,
27
27
  transformRequest = null,
28
28
  mapPosition = null,
29
29
  mapboxToken = null,
30
30
  overlayStyle = null,
31
- children,
31
+ controls = null,
32
+ children = null,
32
33
  style,
33
34
  bounds = null,
34
35
  focusedSource = null,
@@ -40,6 +41,7 @@ export function MapInspector({
40
41
  transformRequest?: mapboxgl.TransformRequestFunction;
41
42
  title?: string;
42
43
  style?: mapboxgl.Style | string;
44
+ controls?: React.ReactNode;
43
45
  children?: React.ReactNode;
44
46
  mapboxToken?: string;
45
47
  overlayStyle?: mapboxgl.Style | string;
@@ -49,7 +51,7 @@ export function MapInspector({
49
51
  mapPosition?: MapPosition;
50
52
  bounds?: [number, number, number, number];
51
53
  fitViewport?: boolean;
52
- styleType: "standard" | "macrostrat";
54
+ styleType?: "standard" | "macrostrat";
53
55
  }) {
54
56
  /* We apply a custom style to the panel container when we are interacting
55
57
  with the search bar, so that we can block map interactions until search
@@ -147,7 +149,7 @@ export function MapInspector({
147
149
  title,
148
150
  }),
149
151
  contextPanel: h(PanelCard, [
150
- children,
152
+ controls,
151
153
  h(Switch, {
152
154
  checked: xRay,
153
155
  label: "X-ray mode",
@@ -180,10 +182,23 @@ export function MapInspector({
180
182
  setPosition: onSelectPosition,
181
183
  }),
182
184
  h(TileExtentLayer, { tile, color: isEnabled ? "white" : "black" }),
185
+ children,
183
186
  ]
184
187
  )
185
188
  );
186
189
  }
187
190
 
191
+ function MapInspector(props) {
192
+ const { children, controls, ...rest } = props;
193
+ /** Compatibility wrapper for MapInspectorV2 */
194
+ // React warning about this legacy usage
195
+ console.warn("MapInspector is deprecated. Use MapInspectorV2 instead");
196
+
197
+ return h(MapInspectorV2, {
198
+ ...rest,
199
+ controls: [children, controls],
200
+ });
201
+ }
202
+
188
203
  // Legacy export
189
204
  export const DevMapPage = MapInspector;
@@ -1,17 +1,24 @@
1
- import { Spinner, Switch } from "@blueprintjs/core";
1
+ import { Spinner, Switch, Button, Intent } from "@blueprintjs/core";
2
2
  import { useMapRef, useMapStatus } from "@macrostrat/mapbox-react";
3
3
  import mapboxgl from "mapbox-gl";
4
4
  import hyper from "@macrostrat/hyper";
5
5
  import styles from "./main.module.sass";
6
- import { useEffect, useState } from "react";
7
- import { JSONView, usePrevious } from "@macrostrat/ui-components";
6
+ import { useCallback, useEffect, useRef, useState } from "react";
7
+ import { JSONView } from "@macrostrat/ui-components";
8
8
  import { group } from "d3-array";
9
9
  import { ExpansionPanel } from "../expansion-panel";
10
10
 
11
11
  const h = hyper.styled(styles);
12
12
 
13
13
  export function FeatureProperties({ data, ...rest }) {
14
- return h("div.feature-properties", [
14
+ // Instead of managing hover state with CSS, we use a state variable,
15
+ // so that the button re-renders when the state changes
16
+ const [showControls, setShowControls] = useState(false);
17
+ const onMouseEnter = useCallback(() => setShowControls(true), []);
18
+ const onMouseLeave = useCallback(() => setShowControls(false), []);
19
+
20
+ return h("div.feature-properties", { onMouseEnter, onMouseLeave }, [
21
+ h.if(showControls)("div.controls", h(CopyJSONButton, { data })),
15
22
  h(JSONView, {
16
23
  data,
17
24
  hideRoot: true,
@@ -27,6 +34,21 @@ export function FeatureRecord({ feature }) {
27
34
  ]);
28
35
  }
29
36
 
37
+ function CopyJSONButton({ data }) {
38
+ const [copied, setCopied] = useState(false);
39
+ return h(Button, {
40
+ icon: copied ? "tick" : "clipboard",
41
+ intent: copied ? Intent.SUCCESS : Intent.NONE,
42
+ minimal: true,
43
+ small: true,
44
+ onClick() {
45
+ navigator.clipboard.writeText(JSON.stringify(data, null, 2));
46
+ setCopied(true);
47
+ },
48
+ });
49
+ }
50
+
51
+ /** This component wraps queryRenderedFeatures to get features at a given location */
30
52
  export function FeatureSelectionHandler({
31
53
  selectedLocation,
32
54
  setFeatures,
@@ -37,8 +59,10 @@ export function FeatureSelectionHandler({
37
59
  radius?: number;
38
60
  }) {
39
61
  const mapRef = useMapRef();
40
- const { isLoading } = useMapStatus();
41
- const prevLocation = usePrevious(selectedLocation);
62
+ const isLoading = useMapStatus((s) => s.isLoading);
63
+ const isInitialized = useMapStatus((s) => s.isInitialized);
64
+ const prevLocation = useRef(null);
65
+ const prevFeatures = useRef([]);
42
66
 
43
67
  useEffect(() => {
44
68
  const map = mapRef?.current;
@@ -48,8 +72,18 @@ export function FeatureSelectionHandler({
48
72
  return;
49
73
  }
50
74
 
75
+ if (!isInitialized) return;
76
+
77
+ const hasPreviouslyLoadedFeatures = prevFeatures.current.length > 0;
78
+
79
+ const locationMemo = JSON.stringify(selectedLocation);
80
+ if (locationMemo == prevLocation.current && hasPreviouslyLoadedFeatures)
81
+ return;
82
+
83
+ prevLocation.current = locationMemo;
84
+
51
85
  // Don't update if the location hasn't changed
52
- if (selectedLocation == prevLocation) return;
86
+ //if (selectedLocation == prevLocation) return;
53
87
 
54
88
  const r = radius;
55
89
  const pt = map.project(selectedLocation);
@@ -59,8 +93,9 @@ export function FeatureSelectionHandler({
59
93
  [pt.x + r, pt.y + r],
60
94
  ];
61
95
  const features = map.queryRenderedFeatures(bbox);
96
+ prevFeatures.current = features ?? [];
62
97
  setFeatures(features);
63
- }, [mapRef.current, prevLocation?.current, selectedLocation, isLoading]);
98
+ }, [isInitialized, selectedLocation, isLoading]);
64
99
 
65
100
  return null;
66
101
  }
@@ -143,11 +178,7 @@ function UnitNumber({ value, unit, precision = 1 }) {
143
178
  ]);
144
179
  }
145
180
 
146
- export function FeaturePanel({
147
- features,
148
- focusedSource = null,
149
- focusedSourceTitle = null,
150
- }) {
181
+ export function FeaturePanel({ features, focusedSource = null }) {
151
182
  if (features == null) return null;
152
183
 
153
184
  let focusedSourcePanel = null;
@@ -11,14 +11,16 @@ import {
11
11
 
12
12
  const h = hyper.styled(styles);
13
13
 
14
- function PositionButton({ position, showCopyLink = false }) {
14
+ function PositionButton({ position, bounds, showCopyLink = false }) {
15
15
  const focusState = useFocusState(position);
16
16
 
17
17
  const copyLinkIsVisible = isCentered(focusState) && showCopyLink;
18
18
 
19
19
  return h("div.position-controls", [
20
- h(LocationFocusButton, { location: position, focusState }, []),
21
- h.if(copyLinkIsVisible)(CopyLinkButton, { itemName: "position" }),
20
+ h(LocationFocusButton, { location: position, bounds, focusState }, []),
21
+ h.if(copyLinkIsVisible && position != null)(CopyLinkButton, {
22
+ itemName: "position",
23
+ }),
22
24
  ]);
23
25
  }
24
26
 
@@ -66,26 +68,39 @@ function CopyLinkButton({ itemName, children, onClick, ...rest }) {
66
68
  }
67
69
 
68
70
  export interface InfoDrawerHeaderProps {
69
- onClose: () => void;
70
- position: mapboxgl.LngLat;
71
+ onClose?: () => void;
72
+ position?: mapboxgl.LngLat;
71
73
  zoom?: number;
72
74
  elevation?: number;
73
75
  showCopyPositionButton?: boolean;
76
+ bounds?: mapboxgl.LngLatBounds;
74
77
  }
75
78
 
76
79
  export function InfoDrawerHeader(props: InfoDrawerHeaderProps) {
77
80
  const {
78
81
  onClose,
79
82
  position,
83
+ bounds,
80
84
  zoom = 7,
81
85
  elevation,
82
86
  showCopyPositionButton,
87
+ children,
83
88
  } = props;
84
89
 
90
+ let leftButton = null;
91
+ if (bounds != null || position != null) {
92
+ leftButton = h(PositionButton, {
93
+ position,
94
+ bounds,
95
+ showCopyLink: showCopyPositionButton,
96
+ });
97
+ }
98
+
85
99
  return h("header.location-panel-header", [
86
- h(PositionButton, { position, showCopyLink: showCopyPositionButton }),
100
+ leftButton,
101
+ children,
87
102
  h("div.spacer"),
88
- h(LngLatCoords, {
103
+ h.if(position != null)(LngLatCoords, {
89
104
  position,
90
105
  zoom,
91
106
  className: "infodrawer-header-item",
@@ -94,6 +109,10 @@ export function InfoDrawerHeader(props: InfoDrawerHeaderProps) {
94
109
  elevation,
95
110
  className: "infodrawer-header-item",
96
111
  }),
97
- h(Button, { minimal: true, icon: "cross", onClick: onClose }),
112
+ h.if(onClose != null)(Button, {
113
+ minimal: true,
114
+ icon: "cross",
115
+ onClick: onClose,
116
+ }),
98
117
  ]);
99
118
  }
@@ -1,15 +1,15 @@
1
- import { Card } from "@blueprintjs/core";
2
1
  import hyper from "@macrostrat/hyper";
3
2
  import { InfoDrawerHeader, InfoDrawerHeaderProps } from "./header";
4
3
  import classNames from "classnames";
5
4
  import styles from "./main.module.sass";
6
5
  import { ErrorBoundary } from "@macrostrat/ui-components";
6
+ import { PanelCard } from "../container";
7
7
 
8
8
  const h = hyper.styled(styles);
9
9
 
10
10
  export function InfoDrawerContainer(props) {
11
11
  const className = classNames("infodrawer", props.className);
12
- return h(Card, { ...props, className });
12
+ return h(PanelCard, { ...props, className });
13
13
  }
14
14
 
15
15
  interface BaseInfoDrawerProps extends InfoDrawerHeaderProps {
@@ -42,6 +42,8 @@ export function BaseInfoDrawer(props: BaseInfoDrawerProps) {
42
42
  ]);
43
43
  }
44
44
 
45
+ export const DetailsPanel = BaseInfoDrawer;
46
+
45
47
  export function LocationPanel(props) {
46
48
  const { children, className, loading = false, ...rest } = props;
47
49
  const cls = classNames("location-panel", className, { loading });
@@ -10,6 +10,7 @@
10
10
  flex-direction: row
11
11
  align-items: center
12
12
  gap: 1em
13
+ min-height: 40px
13
14
  border-bottom: 1px solid var(--panel-rule-color)
14
15
 
15
16
  .spacer
@@ -21,6 +22,12 @@
21
22
  .position-controls :global(.bp5-button)
22
23
  font-size: 12px !important
23
24
 
25
+ // Text elements should
26
+ h1, h2, h3, h4, h5, h6, p
27
+ margin: 0
28
+ &:first-child
29
+ margin-left: 10px
30
+
24
31
  .infodrawer-header-item
25
32
  font-size: 12px
26
33