@metastringfoundation/map-list 0.1.1 → 0.1.2

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 (96) hide show
  1. package/dist/components/Handler/MapComparisonControl.d.ts +7 -0
  2. package/dist/components/Handler/MapComparisonControl.d.ts.map +1 -0
  3. package/dist/components/Handler/MapComparisonControl.js +8 -0
  4. package/dist/components/core/button.js +1 -1
  5. package/dist/components/core/input.d.ts.map +1 -1
  6. package/dist/components/core/input.js +1 -1
  7. package/dist/components/dualMap/MapLayerCard.d.ts +8 -0
  8. package/dist/components/dualMap/MapLayerCard.d.ts.map +1 -0
  9. package/dist/components/dualMap/MapLayerCard.js +68 -0
  10. package/dist/components/dualMap/index.d.ts +2 -1
  11. package/dist/components/dualMap/index.d.ts.map +1 -1
  12. package/dist/components/dualMap/index.js +219 -56
  13. package/dist/components/map/compare-sidebar.d.ts +2 -0
  14. package/dist/components/map/compare-sidebar.d.ts.map +1 -0
  15. package/dist/components/map/compare-sidebar.js +34 -0
  16. package/dist/components/map/compare.d.ts +2 -0
  17. package/dist/components/map/compare.d.ts.map +1 -0
  18. package/dist/components/map/compare.js +42 -0
  19. package/dist/components/map/index.d.ts.map +1 -1
  20. package/dist/components/map/index.js +14 -1
  21. package/dist/components/map/layers/grid/index.d.ts.map +1 -1
  22. package/dist/components/map/layers/grid/index.js +11 -1
  23. package/dist/components/map/layers/index.d.ts.map +1 -1
  24. package/dist/components/map/layers/index.js +0 -1
  25. package/dist/components/map/layers/raster/index.d.ts.map +1 -1
  26. package/dist/components/map/layers/raster/index.js +5 -3
  27. package/dist/components/map/layers/vector/index.d.ts.map +1 -1
  28. package/dist/components/map/layers/vector/index.js +25 -2
  29. package/dist/components/map/search.d.ts +2 -0
  30. package/dist/components/map/search.d.ts.map +1 -0
  31. package/dist/components/map/search.js +122 -0
  32. package/dist/components/map-comparison/attribute-selector.d.ts +11 -0
  33. package/dist/components/map-comparison/attribute-selector.d.ts.map +1 -0
  34. package/dist/components/map-comparison/attribute-selector.js +10 -0
  35. package/dist/components/map-comparison/comparison-panel.d.ts +2 -0
  36. package/dist/components/map-comparison/comparison-panel.d.ts.map +1 -0
  37. package/dist/components/map-comparison/comparison-panel.js +45 -0
  38. package/dist/components/map-comparison/comparison-stats.d.ts +2 -0
  39. package/dist/components/map-comparison/comparison-stats.d.ts.map +1 -0
  40. package/dist/components/map-comparison/comparison-stats.js +35 -0
  41. package/dist/components/map-comparison/comparison-view.d.ts +2 -0
  42. package/dist/components/map-comparison/comparison-view.d.ts.map +1 -0
  43. package/dist/components/map-comparison/comparison-view.js +152 -0
  44. package/dist/components/map-comparison/comparison-wrapper.d.ts +8 -0
  45. package/dist/components/map-comparison/comparison-wrapper.d.ts.map +1 -0
  46. package/dist/components/map-comparison/comparison-wrapper.js +26 -0
  47. package/dist/components/map-comparison/index.d.ts +3 -0
  48. package/dist/components/map-comparison/index.d.ts.map +1 -0
  49. package/dist/components/map-comparison/index.js +165 -0
  50. package/dist/components/map-comparison/types.d.ts +30 -0
  51. package/dist/components/map-comparison/types.d.ts.map +1 -0
  52. package/dist/components/map-comparison/types.js +2 -0
  53. package/dist/components/map-comparison/use-map-comparison.d.ts +18 -0
  54. package/dist/components/map-comparison/use-map-comparison.d.ts.map +1 -0
  55. package/dist/components/map-comparison/use-map-comparison.js +139 -0
  56. package/dist/components/sidebar/common/attribute-compare-addon.d.ts +7 -0
  57. package/dist/components/sidebar/common/attribute-compare-addon.d.ts.map +1 -0
  58. package/dist/components/sidebar/common/attribute-compare-addon.js +36 -0
  59. package/dist/components/sidebar/common/layer-item-style.d.ts.map +1 -1
  60. package/dist/components/sidebar/common/layer-item-style.js +46 -1
  61. package/dist/components/sidebar/common/layer-item.d.ts.map +1 -1
  62. package/dist/components/sidebar/common/layer-item.js +1 -2
  63. package/dist/components/sidebar/common/opacity-handler-addon.d.ts +5 -2
  64. package/dist/components/sidebar/common/opacity-handler-addon.d.ts.map +1 -1
  65. package/dist/components/sidebar/common/opacity-handler-addon.js +101 -4
  66. package/dist/components/sidebar/common/style-legend.d.ts.map +1 -1
  67. package/dist/components/sidebar/common/style-legend.js +1 -2
  68. package/dist/components/sidebar/comparison/index.d.ts +4 -0
  69. package/dist/components/sidebar/comparison/index.d.ts.map +1 -0
  70. package/dist/components/sidebar/comparison/index.js +34 -0
  71. package/dist/components/sidebar/search/attribute-comparison.d.ts +10 -0
  72. package/dist/components/sidebar/search/attribute-comparison.d.ts.map +1 -0
  73. package/dist/components/sidebar/search/attribute-comparison.js +137 -0
  74. package/dist/components/sidebar/search/index.d.ts +2 -0
  75. package/dist/components/sidebar/search/index.d.ts.map +1 -0
  76. package/dist/components/sidebar/search/index.js +29 -0
  77. package/dist/components/sidebar/selected/index.d.ts.map +1 -1
  78. package/dist/components/sidebar/selected/index.js +4 -1
  79. package/dist/components/sidebar/tabs.js +2 -2
  80. package/dist/hooks/use-layers.d.ts +8 -0
  81. package/dist/hooks/use-layers.d.ts.map +1 -1
  82. package/dist/hooks/use-layers.js +101 -1
  83. package/dist/hooks/use-polygon-data.d.ts +34 -0
  84. package/dist/hooks/use-polygon-data.d.ts.map +1 -0
  85. package/dist/hooks/use-polygon-data.js +74 -0
  86. package/dist/index.css +659 -30
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +9 -36
  89. package/dist/services/naksha.d.ts.map +1 -1
  90. package/dist/services/naksha.js +16 -158
  91. package/dist/services/polygon.d.ts +36 -0
  92. package/dist/services/polygon.d.ts.map +1 -0
  93. package/dist/services/polygon.js +67 -0
  94. package/dist/utils/naksha.d.ts.map +1 -1
  95. package/dist/utils/naksha.js +4 -2
  96. package/package.json +16 -15
@@ -27,5 +27,15 @@ function GridLayer({ data, beforeId, }) {
27
27
  (0, react_1.useEffect)(() => {
28
28
  mapl?.on("idle", fetchGridData);
29
29
  }, []);
30
- return ((0, jsx_runtime_1.jsx)(maplibre_1.Source, { id: data.id, type: "geojson", data: layerData.geojson, children: (0, jsx_runtime_1.jsx)(maplibre_1.Layer, { beforeId: beforeId, id: data.id, type: "fill", paint: layerData.paint }) }));
30
+ const opacity = layer.getLayerOpacity(data.id);
31
+ // Merge opacity into grid layer paint
32
+ const paintWithOpacity = (0, react_1.useMemo)(() => {
33
+ if (!layerData.paint)
34
+ return layerData.paint;
35
+ return {
36
+ ...layerData.paint,
37
+ "fill-opacity": opacity,
38
+ };
39
+ }, [layerData.paint, opacity]);
40
+ return ((0, jsx_runtime_1.jsx)(maplibre_1.Source, { id: data.id, type: "geojson", data: layerData.geojson, children: (0, jsx_runtime_1.jsx)(maplibre_1.Layer, { beforeId: beforeId, id: data.id, type: "fill", paint: paintWithOpacity }) }));
31
41
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/map/layers/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,kDAsBA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/map/layers/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,kDAqBA"}
@@ -10,7 +10,6 @@ const grid_1 = __importDefault(require("./grid"));
10
10
  const vector_1 = __importDefault(require("./vector"));
11
11
  const raster_1 = __importDefault(require("./raster"));
12
12
  function MapLayer({ layer, beforeId, }) {
13
- console.log("layer.source.type", layer?.source?.type);
14
13
  const maps = (0, maplibre_1.useMap)();
15
14
  // if (!mapl) {
16
15
  // return null;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/map/layers/raster/index.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,CAAC,EAAC,MAAM,CAAA;CACjB,2CA8BA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/map/layers/raster/index.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,CAAC,EAAC,MAAM,CAAA;CACjB,2CA6BA"}
@@ -8,10 +8,12 @@ const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const maplibre_1 = require("react-map-gl/maplibre");
9
9
  const use_layers_1 = __importDefault(require("../../../../hooks/use-layers"));
10
10
  function RasterLayer({ data, beforeId, }) {
11
- const { mp } = (0, use_layers_1.default)();
12
- console.log(data, "datataatata");
11
+ const { mp, layer } = (0, use_layers_1.default)();
12
+ const opacity = layer.getLayerOpacity(data.id);
13
13
  return ((0, jsx_runtime_1.jsx)(maplibre_1.Source, { id: data.id, type: "raster", tiles: [
14
14
  // @ts-ignore
15
15
  `${mp?.geoserver?.endpoint}/wms?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:3857&width=256&height=256&transparent=true&layers=metastring:${data.name}`,
16
- ], tileSize: 256, children: (0, jsx_runtime_1.jsx)(maplibre_1.Layer, { id: data.id, beforeId: beforeId, type: "raster", source: "biodiv", layout: { visibility: "visible" }, paint: {} }) }));
16
+ ], tileSize: 256, children: (0, jsx_runtime_1.jsx)(maplibre_1.Layer, { id: data.id, beforeId: beforeId, type: "raster", source: "biodiv", layout: { visibility: "visible" }, paint: {
17
+ "raster-opacity": opacity,
18
+ } }) }));
17
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/map/layers/vector/index.tsx"],"names":[],"mappings":"AAmBA,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE;;;CAAA,2CAgC5D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/map/layers/vector/index.tsx"],"names":[],"mappings":"AAmBA,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE;;;CAAA,2CA8D5D"}
@@ -24,7 +24,30 @@ const paint = {
24
24
  function VectorLayer({ layer: data, beforeId }) {
25
25
  const { layer } = (0, use_layers_1.default)();
26
26
  const layerProps = (0, react_1.useMemo)(() => data.data?.styles?.[data.data?.styleIndex]?.colors, [data, layer.selectedFeatures]);
27
+ const opacity = layer.getLayerOpacity(data.id);
27
28
  const highlightData = layer.selectedFeaturesId?.[data.id];
28
- console.log(data.source, "data.source ....");
29
- return ((0, jsx_runtime_1.jsxs)(maplibre_1.Source, { ...data.source, children: [layerProps && (0, jsx_runtime_1.jsx)(maplibre_1.Layer, { beforeId: beforeId, ...layerProps }), highlightData && layerProps && ((0, jsx_runtime_1.jsx)(maplibre_1.Layer, { ...layerProps, beforeId: beforeId, id: `hl_${data.id}`, filter: ["in", constants_1.PROPERTY_ID, ...highlightData], type: layerProps.type === "fill" ? "line" : layerProps.type, paint: paint[layerProps.type] }))] }));
29
+ // Merge opacity into layer paint properties based on layer type
30
+ const layerPaintWithOpacity = (0, react_1.useMemo)(() => {
31
+ if (!layerProps?.type)
32
+ return layerProps?.paint;
33
+ const paint = layerProps.paint ? { ...layerProps.paint } : {};
34
+ const layerType = layerProps.type;
35
+ // Apply opacity based on layer type
36
+ if (layerType === "fill") {
37
+ paint["fill-opacity"] = opacity;
38
+ }
39
+ else if (layerType === "line") {
40
+ paint["line-opacity"] = opacity;
41
+ }
42
+ else if (layerType === "circle") {
43
+ paint["circle-opacity"] = opacity;
44
+ }
45
+ else if (layerType === "symbol") {
46
+ paint["icon-opacity"] = opacity;
47
+ paint["text-opacity"] = opacity;
48
+ }
49
+ return paint;
50
+ }, [layerProps, opacity]);
51
+ const baseId = data?.id;
52
+ return ((0, jsx_runtime_1.jsxs)(maplibre_1.Source, { id: baseId, ...data.source, children: [layerProps && ((0, jsx_runtime_1.jsx)(maplibre_1.Layer, { beforeId: beforeId, id: baseId, ...layerProps, paint: layerPaintWithOpacity !== undefined ? layerPaintWithOpacity : layerProps.paint })), highlightData && layerProps && ((0, jsx_runtime_1.jsx)(maplibre_1.Layer, { ...layerProps, beforeId: beforeId, id: `hl_${baseId}`, filter: ["in", constants_1.PROPERTY_ID, ...highlightData], type: layerProps.type === "fill" ? "line" : layerProps.type, paint: paint[layerProps.type] }))] }));
30
53
  }
@@ -0,0 +1,2 @@
1
+ export default function MapSearch(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/components/map/search.tsx"],"names":[],"mappings":"AAUA,MAAM,CAAC,OAAO,UAAU,SAAS,4CA6OhC"}
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = MapSearch;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const maplibre_1 = require("react-map-gl/maplibre");
7
+ const core_1 = require("../core");
8
+ function MapSearch() {
9
+ const { mapl } = (0, maplibre_1.useMap)();
10
+ const [searchTerm, setSearchTerm] = (0, react_1.useState)("");
11
+ const [results, setResults] = (0, react_1.useState)([]);
12
+ const [isSearching, setIsSearching] = (0, react_1.useState)(false);
13
+ const [showResults, setShowResults] = (0, react_1.useState)(false);
14
+ const searchTimeoutRef = (0, react_1.useRef)(null);
15
+ const resultsRef = (0, react_1.useRef)(null);
16
+ // Close results when clicking outside
17
+ (0, react_1.useEffect)(() => {
18
+ const handleClickOutside = (event) => {
19
+ if (resultsRef.current && !resultsRef.current.contains(event.target)) {
20
+ setShowResults(false);
21
+ }
22
+ };
23
+ document.addEventListener("mousedown", handleClickOutside);
24
+ return () => document.removeEventListener("mousedown", handleClickOutside);
25
+ }, []);
26
+ const handleSearch = async (query) => {
27
+ if (!query.trim()) {
28
+ setResults([]);
29
+ setShowResults(false);
30
+ return;
31
+ }
32
+ setIsSearching(true);
33
+ try {
34
+ // Using Nominatim (OpenStreetMap) geocoding service as a free alternative
35
+ // You can replace this with Mapbox Geocoding API or any other service
36
+ const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(query)}&limit=5`, {
37
+ headers: {
38
+ "User-Agent": "MapSearch/1.0", // Required by Nominatim
39
+ },
40
+ });
41
+ if (!response.ok) {
42
+ throw new Error("Geocoding request failed");
43
+ }
44
+ const data = await response.json();
45
+ const formattedResults = data.map((item) => ({
46
+ place_name: item.display_name,
47
+ center: [parseFloat(item.lon), parseFloat(item.lat)],
48
+ bbox: item.boundingbox
49
+ ? [
50
+ parseFloat(item.boundingbox[2]), // min lat
51
+ parseFloat(item.boundingbox[0]), // min lon
52
+ parseFloat(item.boundingbox[3]), // max lat
53
+ parseFloat(item.boundingbox[1]), // max lon
54
+ ]
55
+ : undefined,
56
+ }));
57
+ setResults(formattedResults);
58
+ setShowResults(true);
59
+ }
60
+ catch (error) {
61
+ console.error("Error searching location:", error);
62
+ setResults([]);
63
+ }
64
+ finally {
65
+ setIsSearching(false);
66
+ }
67
+ };
68
+ const handleInputChange = (e) => {
69
+ const value = e.target.value;
70
+ setSearchTerm(value);
71
+ // Debounce search
72
+ if (searchTimeoutRef.current) {
73
+ clearTimeout(searchTimeoutRef.current);
74
+ }
75
+ if (value.trim()) {
76
+ searchTimeoutRef.current = setTimeout(() => {
77
+ handleSearch(value);
78
+ }, 500);
79
+ }
80
+ else {
81
+ setResults([]);
82
+ setShowResults(false);
83
+ }
84
+ };
85
+ const handleSelectResult = (result) => {
86
+ if (!mapl)
87
+ return;
88
+ const mapInstance = Object.values(mapl).pop();
89
+ if (!mapInstance)
90
+ return;
91
+ setSearchTerm(result.place_name);
92
+ setShowResults(false);
93
+ // Fly to the location
94
+ if (result.bbox) {
95
+ // Fit to bounding box if available
96
+ mapInstance.fitBounds([
97
+ [result.bbox[1], result.bbox[0]], // southwest
98
+ [result.bbox[3], result.bbox[2]], // northeast
99
+ ], {
100
+ padding: 50,
101
+ duration: 1500,
102
+ });
103
+ }
104
+ else {
105
+ // Fly to center point
106
+ mapInstance.flyTo({
107
+ center: result.center,
108
+ zoom: 12,
109
+ duration: 1500,
110
+ });
111
+ }
112
+ };
113
+ const handleClear = () => {
114
+ setSearchTerm("");
115
+ setResults([]);
116
+ setShowResults(false);
117
+ if (searchTimeoutRef.current) {
118
+ clearTimeout(searchTimeoutRef.current);
119
+ }
120
+ };
121
+ return ((0, jsx_runtime_1.jsx)("div", { className: "absolute top-4 left-1/2 transform -translate-x-1/2 z-30 w-full max-w-md px-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "relative", ref: resultsRef, children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)(core_1.SearchInput, { type: "search", placeholder: "Search for a location...", value: searchTerm, onChange: handleInputChange, className: "w-full shadow-lg" }), isSearching && ((0, jsx_runtime_1.jsx)("div", { className: "absolute right-3 top-1/2 transform -translate-y-1/2", children: (0, jsx_runtime_1.jsxs)("svg", { className: "animate-spin h-5 w-5 text-gray-400", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), (0, jsx_runtime_1.jsx)("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }) })), searchTerm && !isSearching && ((0, jsx_runtime_1.jsx)("button", { onClick: handleClear, className: "absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600", type: "button", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-5 w-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) }) }))] }), showResults && results.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "absolute top-full left-0 right-0 mt-1 bg-white rounded-md shadow-lg border border-gray-200 max-h-64 overflow-y-auto z-50", children: results.map((result, index) => ((0, jsx_runtime_1.jsx)("button", { onClick: () => handleSelectResult(result), className: "w-full text-left px-4 py-3 hover:bg-gray-50 border-b border-gray-100 last:border-b-0 transition-colors", type: "button", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-2", children: [(0, jsx_runtime_1.jsxs)("svg", { className: "w-5 h-5 text-gray-400 mt-0.5 shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" }), (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M15 11a3 3 0 11-6 0 3 3 0 016 0z" })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 min-w-0", children: (0, jsx_runtime_1.jsx)("p", { className: "text-sm font-medium text-gray-800 truncate", children: result.place_name }) })] }) }, index))) })), showResults && results.length === 0 && searchTerm && !isSearching && ((0, jsx_runtime_1.jsx)("div", { className: "absolute top-full left-0 right-0 mt-1 bg-white rounded-md shadow-lg border border-gray-200 p-4 z-50", children: (0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-gray-500 text-center", children: ["No results found for \"", searchTerm, "\""] }) }))] }) }));
122
+ }
@@ -0,0 +1,11 @@
1
+ import { AttributeOption } from "./types";
2
+ interface AttributeSelectorProps {
3
+ layerId: string;
4
+ attributes: AttributeOption[];
5
+ selectedAttribute?: string;
6
+ onSelect: (attributeKey?: string) => void;
7
+ label?: string;
8
+ }
9
+ export default function AttributeSelector({ layerId, attributes, selectedAttribute, onSelect, label, }: AttributeSelectorProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=attribute-selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribute-selector.d.ts","sourceRoot":"","sources":["../../../src/components/map-comparison/attribute-selector.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C,UAAU,sBAAsB;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EACxC,OAAO,EACP,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,KAA0B,GAC3B,EAAE,sBAAsB,2CA0BxB"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = AttributeSelector;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ function AttributeSelector({ layerId, attributes, selectedAttribute, onSelect, label = "Select Attribute", }) {
6
+ if (attributes.length === 0) {
7
+ return ((0, jsx_runtime_1.jsx)("div", { className: "text-sm text-gray-500", children: "No attributes available for this layer" }));
8
+ }
9
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-sm font-medium text-gray-700", children: label }), (0, jsx_runtime_1.jsxs)("select", { value: selectedAttribute || "", onChange: (e) => onSelect(e.target.value || undefined), className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm", children: [(0, jsx_runtime_1.jsx)("option", { value: "", children: "Default (All Attributes)" }), attributes.map((attr) => ((0, jsx_runtime_1.jsxs)("option", { value: attr.key, children: [attr.label, " (", attr.type, ")"] }, attr.key)))] })] }));
10
+ }
@@ -0,0 +1,2 @@
1
+ export default function ComparisonPanel(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=comparison-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparison-panel.d.ts","sourceRoot":"","sources":["../../../src/components/map-comparison/comparison-panel.tsx"],"names":[],"mappings":"AAOA,MAAM,CAAC,OAAO,UAAU,eAAe,4CAyQtC"}
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.default = ComparisonPanel;
8
+ const jsx_runtime_1 = require("react/jsx-runtime");
9
+ const react_1 = require("react");
10
+ const use_map_comparison_1 = require("./use-map-comparison");
11
+ const attribute_selector_1 = __importDefault(require("./attribute-selector"));
12
+ function ComparisonPanel() {
13
+ const { isOpen, setIsOpen, config, availableLayers, getLayerAttributes, addLayer, removeLayer, updateLayerAttribute, setMode, toggleSyncView, toggleStats, clearComparison, isLayerInComparison, } = (0, use_map_comparison_1.useMapComparison)();
14
+ const [selectedLayerId, setSelectedLayerId] = (0, react_1.useState)("");
15
+ const [selectedAttribute, setSelectedAttribute] = (0, react_1.useState)("");
16
+ if (!isOpen) {
17
+ return ((0, jsx_runtime_1.jsxs)("button", { onClick: () => setIsOpen(true), className: "fixed bottom-4 left-4 z-50 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg shadow-lg flex items-center gap-2 font-medium", children: [(0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" }), (0, jsx_runtime_1.jsx)("polyline", { points: "3.27 6.96 12 12.01 20.73 6.96" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "22.08", x2: "12", y2: "12" })] }), "Map Comparison"] }));
18
+ }
19
+ const handleAddLayer = () => {
20
+ if (!selectedLayerId)
21
+ return;
22
+ const attributes = getLayerAttributes(selectedLayerId);
23
+ const attributeKey = selectedAttribute || undefined;
24
+ addLayer(selectedLayerId, attributeKey);
25
+ setSelectedLayerId("");
26
+ setSelectedAttribute("");
27
+ };
28
+ const selectedLayerAttributes = selectedLayerId
29
+ ? getLayerAttributes(selectedLayerId)
30
+ : [];
31
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "fixed bottom-4 left-4 z-50 w-96 bg-white rounded-lg shadow-2xl border border-gray-200 max-h-[80vh] overflow-y-auto", children: [(0, jsx_runtime_1.jsxs)("div", { className: "sticky top-0 bg-blue-600 text-white p-4 rounded-t-lg flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold", children: "Map Comparison" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setIsOpen(false), className: "text-white hover:text-gray-200", children: (0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-sm font-medium text-gray-700", children: "Comparison Mode" }), (0, jsx_runtime_1.jsx)("div", { className: "flex gap-2", children: ["side-by-side", "overlay", "attribute"].map((mode) => ((0, jsx_runtime_1.jsx)("button", { onClick: () => setMode(mode), className: `px-3 py-1 rounded-md text-sm font-medium transition-colors ${config.mode === mode
32
+ ? "bg-blue-600 text-white"
33
+ : "bg-gray-100 text-gray-700 hover:bg-gray-200"}`, children: mode
34
+ .split("-")
35
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
36
+ .join(" ") }, mode))) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-t pt-4", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-sm font-semibold text-gray-700 mb-3", children: "Add Layer to Compare" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-sm font-medium text-gray-700", children: "Select Layer" }), (0, jsx_runtime_1.jsxs)("select", { value: selectedLayerId, onChange: (e) => {
37
+ setSelectedLayerId(e.target.value);
38
+ setSelectedAttribute("");
39
+ }, className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm", children: [(0, jsx_runtime_1.jsx)("option", { value: "", children: "Choose a layer..." }), availableLayers
40
+ .filter((l) => !isLayerInComparison(l.id))
41
+ .map((layer) => ((0, jsx_runtime_1.jsx)("option", { value: layer.id, children: layer.title }, layer.id)))] })] }), selectedLayerId && ((0, jsx_runtime_1.jsx)(attribute_selector_1.default, { layerId: selectedLayerId, attributes: selectedLayerAttributes, selectedAttribute: selectedAttribute, onSelect: setSelectedAttribute, label: "Select Attribute (Optional)" })), (0, jsx_runtime_1.jsx)("button", { onClick: handleAddLayer, disabled: !selectedLayerId, className: "w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed text-white rounded-md text-sm font-medium transition-colors", children: "Add to Comparison" })] })] }), config.layers.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "border-t pt-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-3", children: [(0, jsx_runtime_1.jsxs)("h4", { className: "text-sm font-semibold text-gray-700", children: ["Comparison Layers (", config.layers.length, ")"] }), (0, jsx_runtime_1.jsx)("button", { onClick: clearComparison, className: "text-xs text-red-600 hover:text-red-700", children: "Clear All" })] }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-2", children: config.layers.map((compLayer) => {
42
+ const attributes = getLayerAttributes(compLayer.layerId);
43
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "p-3 bg-gray-50 rounded-md border border-gray-200", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-start mb-2", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm font-medium text-gray-800", children: compLayer.layer.title }), compLayer.attributeLabel && ((0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-gray-600 mt-1", children: ["Attribute: ", compLayer.attributeLabel] }))] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => removeLayer(compLayer.layerId), className: "text-red-600 hover:text-red-700 ml-2", children: (0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }), attributes.length > 0 && ((0, jsx_runtime_1.jsx)(attribute_selector_1.default, { layerId: compLayer.layerId, attributes: attributes, selectedAttribute: compLayer.attributeKey, onSelect: (attrKey) => updateLayerAttribute(compLayer.layerId, attrKey), label: "Change Attribute" }))] }, compLayer.layerId));
44
+ }) })] })), config.layers.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "border-t pt-4 space-y-2", children: [(0, jsx_runtime_1.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: config.syncView, onChange: toggleSyncView, className: "h-4 w-4 accent-blue-600" }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-gray-700", children: "Sync Map Views" })] }), (0, jsx_runtime_1.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: config.showStats, onChange: toggleStats, className: "h-4 w-4 accent-blue-600" }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-gray-700", children: "Show Statistics" })] })] }))] })] }));
45
+ }
@@ -0,0 +1,2 @@
1
+ export default function ComparisonStats(): import("react/jsx-runtime").JSX.Element | null;
2
+ //# sourceMappingURL=comparison-stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparison-stats.d.ts","sourceRoot":"","sources":["../../../src/components/map-comparison/comparison-stats.tsx"],"names":[],"mappings":"AAMA,MAAM,CAAC,OAAO,UAAU,eAAe,mDAuGtC"}
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.default = ComparisonStats;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const react_1 = require("react");
7
+ const use_map_comparison_1 = require("./use-map-comparison");
8
+ function ComparisonStats() {
9
+ const { config } = (0, use_map_comparison_1.useMapComparison)();
10
+ // Calculate basic statistics for each layer
11
+ const stats = (0, react_1.useMemo)(() => {
12
+ return config.layers.map((compLayer) => {
13
+ // This is a placeholder - in a real implementation, you would:
14
+ // 1. Query the layer data for the selected attribute
15
+ // 2. Calculate min, max, avg, unique values, etc.
16
+ // 3. For now, we'll show basic layer info
17
+ const stats = {
18
+ layerId: compLayer.layerId,
19
+ attributeKey: compLayer.attributeKey,
20
+ totalFeatures: undefined, // Would need to query layer
21
+ minValue: undefined,
22
+ maxValue: undefined,
23
+ avgValue: undefined,
24
+ uniqueValues: undefined,
25
+ };
26
+ return stats;
27
+ });
28
+ }, [config.layers]);
29
+ if (config.layers.length === 0)
30
+ return null;
31
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "absolute top-4 right-4 z-50 bg-white rounded-lg shadow-lg border border-gray-200 p-4 max-w-sm", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-3", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-sm font-semibold text-gray-800", children: "Comparison Statistics" }), (0, jsx_runtime_1.jsx)("button", { className: "text-gray-400 hover:text-gray-600", children: (0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: config.layers.map((compLayer, index) => {
32
+ const layerStats = stats[index];
33
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "p-3 bg-gray-50 rounded-md border border-gray-200", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-sm font-medium text-gray-800 mb-2", children: compLayer.layer.title }), compLayer.attributeLabel && ((0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-gray-600 mb-2", children: ["Attribute: ", compLayer.attributeLabel] })), (0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-gray-500 space-y-1", children: [layerStats.totalFeatures !== undefined && ((0, jsx_runtime_1.jsxs)("div", { children: ["Total Features: ", layerStats.totalFeatures.toLocaleString()] })), layerStats.minValue !== undefined && ((0, jsx_runtime_1.jsxs)("div", { children: ["Min: ", layerStats.minValue] })), layerStats.maxValue !== undefined && ((0, jsx_runtime_1.jsxs)("div", { children: ["Max: ", layerStats.maxValue] })), layerStats.avgValue !== undefined && ((0, jsx_runtime_1.jsxs)("div", { children: ["Average: ", layerStats.avgValue.toFixed(2)] })), layerStats.uniqueValues !== undefined && ((0, jsx_runtime_1.jsxs)("div", { children: ["Unique Values: ", layerStats.uniqueValues] })), !layerStats.totalFeatures && ((0, jsx_runtime_1.jsx)("div", { className: "text-gray-400 italic", children: "Statistics calculation not implemented" }))] })] }, compLayer.layerId));
34
+ }) }), config.mode === "attribute" && ((0, jsx_runtime_1.jsx)("div", { className: "mt-3 pt-3 border-t border-gray-200", children: (0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-gray-600", children: [(0, jsx_runtime_1.jsx)("strong", { children: "Attribute Comparison Mode:" }), " Comparing different attributes across layers. Use this to analyze how different attributes relate to each other."] }) }))] }));
35
+ }
@@ -0,0 +1,2 @@
1
+ export default function ComparisonView(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=comparison-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparison-view.d.ts","sourceRoot":"","sources":["../../../src/components/map-comparison/comparison-view.tsx"],"names":[],"mappings":"AAkBA,MAAM,CAAC,OAAO,UAAU,cAAc,4CA0KrC"}
@@ -0,0 +1,152 @@
1
+ "use client";
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.default = ComparisonView;
41
+ const jsx_runtime_1 = require("react/jsx-runtime");
42
+ const react_1 = require("react");
43
+ const maplibre_1 = __importStar(require("react-map-gl/maplibre"));
44
+ const map_common_1 = require("@metastringfoundation/map-common");
45
+ const use_map_comparison_1 = require("./use-map-comparison");
46
+ const layers_1 = require("../map/layers");
47
+ const popup_1 = __importDefault(require("../map/popup"));
48
+ const use_layers_1 = __importDefault(require("../../hooks/use-layers"));
49
+ const comparison_stats_1 = __importDefault(require("./comparison-stats"));
50
+ const NavControl = maplibre_1.NavigationControl;
51
+ function ComparisonView() {
52
+ const { config } = (0, use_map_comparison_1.useMapComparison)();
53
+ const { mp, layer } = (0, use_layers_1.default)();
54
+ const [coordsByPane, setCoordsByPane] = (0, react_1.useState)({});
55
+ const [viewStates, setViewStates] = (0, react_1.useState)({});
56
+ const initialViewState = (0, react_1.useMemo)(() => mp.defaultViewState ?? map_common_1.defaultViewState, [mp.defaultViewState]);
57
+ // Initialize view states
58
+ (0, react_1.useEffect)(() => {
59
+ if (config.layers.length > 0) {
60
+ const newViewStates = {};
61
+ config.layers.forEach((compLayer) => {
62
+ if (!viewStates[compLayer.layerId]) {
63
+ newViewStates[compLayer.layerId] = initialViewState;
64
+ }
65
+ });
66
+ if (Object.keys(newViewStates).length > 0) {
67
+ setViewStates((prev) => ({ ...prev, ...newViewStates }));
68
+ }
69
+ }
70
+ }, [config.layers, initialViewState]);
71
+ // Sync view states if enabled
72
+ const handleViewStateChange = (layerId, viewState) => {
73
+ if (config.syncView && config.layers.length > 1) {
74
+ // Sync all maps to the same view state
75
+ const syncedViewStates = {};
76
+ config.layers.forEach((l) => {
77
+ syncedViewStates[l.layerId] = viewState;
78
+ });
79
+ setViewStates((prev) => ({ ...prev, ...syncedViewStates }));
80
+ }
81
+ else {
82
+ // Update only the specific map
83
+ setViewStates((prev) => ({ ...prev, [layerId]: viewState }));
84
+ }
85
+ };
86
+ const onMouseMove = (layerId) => (e) => {
87
+ if (!e.lngLat)
88
+ return;
89
+ setCoordsByPane((prev) => ({
90
+ ...prev,
91
+ [layerId]: e.lngLat,
92
+ }));
93
+ };
94
+ if (config.layers.length === 0) {
95
+ return ((0, jsx_runtime_1.jsx)("div", { className: "w-full h-screen flex items-center justify-center bg-gray-100", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-gray-500 text-lg mb-2", children: "No layers selected for comparison" }), (0, jsx_runtime_1.jsx)("p", { className: "text-gray-400 text-sm", children: "Add layers from the comparison panel to get started" })] }) }));
96
+ }
97
+ // Prepare layers with attribute/style modifications
98
+ const preparedLayers = (0, react_1.useMemo)(() => {
99
+ return config.layers.map((compLayer) => {
100
+ const baseLayer = { ...compLayer.layer };
101
+ // If attribute-based comparison, modify the layer to show specific attribute
102
+ if (compLayer.attributeKey && compLayer.attributeKey.startsWith("style_")) {
103
+ const styleIndex = parseInt(compLayer.attributeKey.replace("style_", ""));
104
+ if (baseLayer.data) {
105
+ baseLayer.data = {
106
+ ...baseLayer.data,
107
+ styleIndex: styleIndex,
108
+ };
109
+ }
110
+ }
111
+ return {
112
+ ...baseLayer,
113
+ id: `compare-${compLayer.layerId}`,
114
+ };
115
+ });
116
+ }, [config.layers]);
117
+ // Render based on mode
118
+ if (config.mode === "overlay") {
119
+ // Overlay mode: stack all layers on a single map
120
+ const overlayViewState = viewStates[config.layers[0]?.layerId] || initialViewState;
121
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full h-screen relative", children: [config.showStats && (0, jsx_runtime_1.jsx)(comparison_stats_1.default, {}), (0, jsx_runtime_1.jsxs)(maplibre_1.default, { id: "comparison-overlay", initialViewState: overlayViewState, style: { width: "100%", height: "100%" }, mapStyle: layer.mapStyle, onMove: (e) => {
122
+ if (config.layers[0]) {
123
+ handleViewStateChange(config.layers[0].layerId, e.viewState);
124
+ }
125
+ }, children: [(0, jsx_runtime_1.jsx)(NavControl, { position: "top-right", showZoom: true, showCompass: true }), preparedLayers.map((l, index) => {
126
+ const beforeId = index > 0 ? preparedLayers[index - 1].id : undefined;
127
+ return (0, jsx_runtime_1.jsx)(layers_1.MapLayer, { layer: l, beforeId: beforeId }, l.id);
128
+ }), (0, jsx_runtime_1.jsx)(popup_1.default, { coordinates: coordsByPane["overlay"] })] })] }));
129
+ }
130
+ // Side-by-side or attribute mode: show multiple maps
131
+ const layout = (0, react_1.useMemo)(() => {
132
+ const count = config.layers.length;
133
+ if (count === 1)
134
+ return { cols: 1, rows: 1 };
135
+ if (count === 2)
136
+ return { cols: 2, rows: 1 };
137
+ if (count === 3)
138
+ return { cols: 2, rows: 2 };
139
+ return { cols: 2, rows: Math.ceil(count / 2) };
140
+ }, [config.layers.length]);
141
+ const renderMap = (compLayer, index) => {
142
+ const preparedLayer = preparedLayers[index];
143
+ const viewState = viewStates[compLayer.layerId] || initialViewState;
144
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "relative w-full h-full", children: [(0, jsx_runtime_1.jsxs)("div", { className: "absolute top-2 left-2 z-10 bg-black/70 text-white px-3 py-1 rounded-md text-sm font-medium", children: [compLayer.layer.title, compLayer.attributeLabel && ((0, jsx_runtime_1.jsxs)("span", { className: "ml-2 text-xs text-gray-300", children: ["(", compLayer.attributeLabel, ")"] }))] }), (0, jsx_runtime_1.jsxs)(maplibre_1.default, { id: `compare-${compLayer.layerId}`, initialViewState: viewState, style: { position: "absolute", inset: 0 }, mapStyle: layer.mapStyle, onMouseMove: onMouseMove(compLayer.layerId), onMove: (e) => handleViewStateChange(compLayer.layerId, e.viewState), children: [(0, jsx_runtime_1.jsx)(NavControl, { position: "top-right", showZoom: true, showCompass: true }), (0, jsx_runtime_1.jsx)(layers_1.MapLayer, { layer: preparedLayer }), (0, jsx_runtime_1.jsx)(popup_1.default, { coordinates: coordsByPane[compLayer.layerId] })] }, config.syncView ? `sync-${JSON.stringify(viewState)}` : compLayer.layerId)] }, compLayer.layerId));
145
+ };
146
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full h-screen relative", children: [config.showStats && (0, jsx_runtime_1.jsx)(comparison_stats_1.default, {}), (0, jsx_runtime_1.jsx)("div", { style: {
147
+ display: "grid",
148
+ gridTemplateColumns: `repeat(${layout.cols}, 1fr)`,
149
+ gridTemplateRows: `repeat(${layout.rows}, ${100 / layout.rows}vh)`,
150
+ height: "100vh",
151
+ }, children: config.layers.map((compLayer, index) => renderMap(compLayer, index)) })] }));
152
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Map Comparison Wrapper Component
3
+ *
4
+ * This component works within the existing LayersProvider context
5
+ * Use this when you already have MapProvider and LayersProvider set up
6
+ */
7
+ export default function ComparisonWrapper(): import("react/jsx-runtime").JSX.Element;
8
+ //# sourceMappingURL=comparison-wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparison-wrapper.d.ts","sourceRoot":"","sources":["../../../src/components/map-comparison/comparison-wrapper.tsx"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,4CAcxC"}
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.default = ComparisonWrapper;
8
+ const jsx_runtime_1 = require("react/jsx-runtime");
9
+ const react_1 = require("react");
10
+ const comparison_panel_1 = __importDefault(require("./comparison-panel"));
11
+ const comparison_view_1 = __importDefault(require("./comparison-view"));
12
+ const use_map_comparison_1 = require("./use-map-comparison");
13
+ /**
14
+ * Map Comparison Wrapper Component
15
+ *
16
+ * This component works within the existing LayersProvider context
17
+ * Use this when you already have MapProvider and LayersProvider set up
18
+ */
19
+ function ComparisonWrapper() {
20
+ const { setIsOpen } = (0, use_map_comparison_1.useMapComparison)();
21
+ // Auto-open the comparison panel when comparison mode is activated
22
+ (0, react_1.useEffect)(() => {
23
+ setIsOpen(true);
24
+ }, [setIsOpen]);
25
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full h-screen relative", children: [(0, jsx_runtime_1.jsx)(comparison_panel_1.default, {}), (0, jsx_runtime_1.jsx)(comparison_view_1.default, {})] }));
26
+ }
@@ -0,0 +1,3 @@
1
+ declare const MapComparison: () => import("react/jsx-runtime").JSX.Element;
2
+ export default MapComparison;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/map-comparison/index.tsx"],"names":[],"mappings":"AAsJA,QAAA,MAAM,aAAa,+CAoQlB,CAAC;AAEF,eAAe,aAAa,CAAC"}