@biodiv-platform/naksha-maplibre-draw 5.0.6 → 5.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -20,6 +20,7 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
 
21
21
  // src/components/map.tsx
22
22
  import maplibregl2 from "maplibre-gl";
23
+ import { useRef, useState as useState2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
23
24
 
24
25
  // src/components/setup-draw.tsx
25
26
  import {
@@ -34,6 +35,9 @@ import {
34
35
  TerraDrawRectangleMode
35
36
  } from "terra-draw";
36
37
  import { TerraDrawMapLibreGLAdapter } from "terra-draw-maplibre-gl-adapter";
38
+ import { tw } from "twind";
39
+ import React from "react";
40
+ import { jsx } from "react/jsx-runtime";
37
41
  function setupDraw(map) {
38
42
  return new TerraDraw({
39
43
  tracked: true,
@@ -124,9 +128,50 @@ function setupDraw(map) {
124
128
  ]
125
129
  });
126
130
  }
127
-
128
- // src/components/map.tsx
129
- import { useRef, useState as useState2, useEffect as useEffect2, useCallback } from "react";
131
+ var ensureModeProperty = (features) => {
132
+ return features.map((feature) => {
133
+ var _a, _b;
134
+ if ((_a = feature.properties) == null ? void 0 : _a.mode)
135
+ return feature;
136
+ const type = (_b = feature.geometry) == null ? void 0 : _b.type;
137
+ const mode = type === "Point" ? "point" : type === "Polygon" ? "polygon" : type === "LineString" ? "linestring" : "unknown";
138
+ return __spreadProps(__spreadValues({}, feature), {
139
+ properties: __spreadProps(__spreadValues({}, feature.properties), { mode })
140
+ });
141
+ });
142
+ };
143
+ var IconButton = React.forwardRef(
144
+ (props, ref) => /* @__PURE__ */ jsx("button", __spreadValues({
145
+ ref,
146
+ type: "button",
147
+ className: tw`h-8 px-3 py-2 rounded-md focus:outline-none cursor-pointer text-md flex align-middle items-center gap-2 bg-gray-100 hover:bg-gray-200 text-gray-700 disabled:cursor-not-allowed disabled:bg-gray-100! disabled:opacity-50`
148
+ }, props))
149
+ );
150
+ var MapStyleSwitcher = ({
151
+ currentStyleIdx,
152
+ onStyleChange,
153
+ mapStyles
154
+ }) => /* @__PURE__ */ jsx("div", {
155
+ style: {
156
+ position: "absolute",
157
+ left: 12,
158
+ bottom: 12,
159
+ background: "rgba(255,255,255,0.95)",
160
+ padding: "8px",
161
+ borderRadius: "6px",
162
+ zIndex: 1e3,
163
+ boxShadow: "0 2px 4px rgba(0,0,0,0.2)"
164
+ },
165
+ children: /* @__PURE__ */ jsx("select", {
166
+ value: currentStyleIdx,
167
+ onChange: (e) => onStyleChange(Number(e.target.value)),
168
+ style: { fontSize: 14, padding: "4px" },
169
+ children: mapStyles.map((style, idx) => /* @__PURE__ */ jsx("option", {
170
+ value: idx,
171
+ children: style.text || `Style ${idx + 1}`
172
+ }, style.key || idx))
173
+ })
174
+ });
130
175
 
131
176
  // src/components/setup-maplibre.tsx
132
177
  import maplibregl from "maplibre-gl";
@@ -155,8 +200,97 @@ function setupMaplibreMap({
155
200
  });
156
201
  }
157
202
 
203
+ // src/components/map-buttons/map-buttons.tsx
204
+ import { useEffect, useState, useCallback, useMemo } from "react";
205
+
158
206
  // src/components/icon-buttons/icons.tsx
159
- import { jsx, jsxs } from "react/jsx-runtime";
207
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
208
+ var PencilOpenIcon = () => /* @__PURE__ */ jsxs("svg", {
209
+ xmlns: "http://www.w3.org/2000/svg",
210
+ width: "24",
211
+ height: "24",
212
+ viewBox: "0 0 24 24",
213
+ fill: "none",
214
+ stroke: "currentColor",
215
+ strokeWidth: "1.5",
216
+ strokeLinecap: "round",
217
+ strokeLinejoin: "round",
218
+ children: [
219
+ /* @__PURE__ */ jsx2("path", {
220
+ d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
221
+ }),
222
+ /* @__PURE__ */ jsx2("path", {
223
+ d: "m15 5 4 4"
224
+ })
225
+ ]
226
+ });
227
+ var PencilCloseIcon = () => /* @__PURE__ */ jsxs("svg", {
228
+ xmlns: "http://www.w3.org/2000/svg",
229
+ width: "24",
230
+ height: "24",
231
+ viewBox: "0 0 24 24",
232
+ fill: "none",
233
+ stroke: "currentColor",
234
+ strokeWidth: "1.5",
235
+ strokeLinecap: "round",
236
+ strokeLinejoin: "round",
237
+ children: [
238
+ /* @__PURE__ */ jsx2("path", {
239
+ d: "m10 10-6.157 6.162a2 2 0 0 0-.5.833l-1.322 4.36a.5.5 0 0 0 .622.624l4.358-1.323a2 2 0 0 0 .83-.5L14 13.982"
240
+ }),
241
+ /* @__PURE__ */ jsx2("path", {
242
+ d: "m12.829 7.172 4.359-4.346a1 1 0 1 1 3.986 3.986l-4.353 4.353"
243
+ }),
244
+ /* @__PURE__ */ jsx2("path", {
245
+ d: "m15 5 4 4"
246
+ }),
247
+ /* @__PURE__ */ jsx2("path", {
248
+ d: "m2 2 20 20"
249
+ })
250
+ ]
251
+ });
252
+ var LocateIcon = () => /* @__PURE__ */ jsxs("svg", {
253
+ xmlns: "http://www.w3.org/2000/svg",
254
+ width: "24",
255
+ height: "24",
256
+ viewBox: "0 0 24 24",
257
+ fill: "none",
258
+ stroke: "currentColor",
259
+ strokeWidth: "1.5",
260
+ strokeLinecap: "round",
261
+ strokeLinejoin: "round",
262
+ children: [
263
+ /* @__PURE__ */ jsx2("line", {
264
+ x1: "2",
265
+ x2: "5",
266
+ y1: "12",
267
+ y2: "12"
268
+ }),
269
+ /* @__PURE__ */ jsx2("line", {
270
+ x1: "19",
271
+ x2: "22",
272
+ y1: "12",
273
+ y2: "12"
274
+ }),
275
+ /* @__PURE__ */ jsx2("line", {
276
+ x1: "12",
277
+ x2: "12",
278
+ y1: "2",
279
+ y2: "5"
280
+ }),
281
+ /* @__PURE__ */ jsx2("line", {
282
+ x1: "12",
283
+ x2: "12",
284
+ y1: "19",
285
+ y2: "22"
286
+ }),
287
+ /* @__PURE__ */ jsx2("circle", {
288
+ cx: "12",
289
+ cy: "12",
290
+ r: "7"
291
+ })
292
+ ]
293
+ });
160
294
  var SelectIcon = () => /* @__PURE__ */ jsxs("svg", {
161
295
  xmlns: "http://www.w3.org/2000/svg",
162
296
  width: "24",
@@ -168,10 +302,10 @@ var SelectIcon = () => /* @__PURE__ */ jsxs("svg", {
168
302
  strokeLinecap: "round",
169
303
  strokeLinejoin: "round",
170
304
  children: [
171
- /* @__PURE__ */ jsx("path", {
305
+ /* @__PURE__ */ jsx2("path", {
172
306
  d: "M12.586 12.586 19 19"
173
307
  }),
174
- /* @__PURE__ */ jsx("path", {
308
+ /* @__PURE__ */ jsx2("path", {
175
309
  d: "M3.688 3.037a.497.497 0 0 0-.651.651l6.5 15.999a.501.501 0 0 0 .947-.062l1.569-6.083a2 2 0 0 1 1.448-1.479l6.124-1.579a.5.5 0 0 0 .063-.947z"
176
310
  })
177
311
  ]
@@ -187,150 +321,143 @@ var PointIcon = () => /* @__PURE__ */ jsxs("svg", {
187
321
  strokeLinecap: "round",
188
322
  strokeLinejoin: "round",
189
323
  children: [
190
- /* @__PURE__ */ jsx("path", {
324
+ /* @__PURE__ */ jsx2("path", {
191
325
  d: "M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"
192
326
  }),
193
- /* @__PURE__ */ jsx("circle", {
327
+ /* @__PURE__ */ jsx2("circle", {
194
328
  cx: "12",
195
329
  cy: "10",
196
330
  r: "3"
197
331
  })
198
332
  ]
199
333
  });
200
- var LineIcon = () => /* @__PURE__ */ jsx("svg", {
334
+ var LineIcon = () => /* @__PURE__ */ jsx2("svg", {
201
335
  width: "16",
202
336
  height: "16",
203
337
  viewBox: "0 0 24 24",
204
338
  fill: "none",
205
339
  stroke: "currentColor",
206
340
  strokeWidth: "2",
207
- children: /* @__PURE__ */ jsx("line", {
341
+ children: /* @__PURE__ */ jsx2("line", {
208
342
  x1: "4",
209
343
  y1: "20",
210
344
  x2: "20",
211
345
  y2: "4"
212
346
  })
213
347
  });
214
- var PolygonIcon = () => /* @__PURE__ */ jsx("svg", {
348
+ var PolygonIcon = () => /* @__PURE__ */ jsx2("svg", {
215
349
  width: "16",
216
350
  height: "16",
217
351
  viewBox: "0 0 24 24",
218
352
  fill: "none",
219
353
  stroke: "currentColor",
220
354
  strokeWidth: "2",
221
- children: /* @__PURE__ */ jsx("polygon", {
355
+ children: /* @__PURE__ */ jsx2("polygon", {
222
356
  points: "12,2 22,8 18,22 6,22 2,8"
223
357
  })
224
358
  });
225
- var DeleteIcon = () => /* @__PURE__ */ jsx("svg", {
359
+ var RectangleIcon = () => /* @__PURE__ */ jsx2("svg", {
226
360
  width: "16",
227
361
  height: "16",
228
362
  viewBox: "0 0 24 24",
229
363
  fill: "none",
230
364
  stroke: "currentColor",
231
365
  strokeWidth: "2",
232
- children: /* @__PURE__ */ jsx("path", {
366
+ children: /* @__PURE__ */ jsx2("rect", {
367
+ x: "4",
368
+ y: "4",
369
+ width: "16",
370
+ height: "16"
371
+ })
372
+ });
373
+ var CircleIcon = () => /* @__PURE__ */ jsx2("svg", {
374
+ width: "16",
375
+ height: "16",
376
+ viewBox: "0 0 24 24",
377
+ fill: "none",
378
+ stroke: "currentColor",
379
+ strokeWidth: "2",
380
+ children: /* @__PURE__ */ jsx2("circle", {
381
+ cx: "12",
382
+ cy: "12",
383
+ r: "10"
384
+ })
385
+ });
386
+ var FreeHandIcon = () => /* @__PURE__ */ jsx2("svg", {
387
+ width: "16",
388
+ height: "16",
389
+ viewBox: "0 0 24 24",
390
+ fill: "none",
391
+ stroke: "currentColor",
392
+ strokeWidth: "2",
393
+ children: /* @__PURE__ */ jsx2("path", {
394
+ d: "M3 16c1-3 4-5 7-4 3 1 5 3 7 2 2-1 3-4 1-6-1-2-4-2-6-1"
395
+ })
396
+ });
397
+ var DeleteIcon = () => /* @__PURE__ */ jsx2("svg", {
398
+ width: "16",
399
+ height: "16",
400
+ viewBox: "0 0 24 24",
401
+ fill: "none",
402
+ stroke: "currentColor",
403
+ strokeWidth: "2",
404
+ children: /* @__PURE__ */ jsx2("path", {
233
405
  d: "M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
234
406
  })
235
407
  });
236
408
 
237
- // src/components/map-button/MapButton.tsx
238
- import { jsx as jsx2 } from "react/jsx-runtime";
409
+ // src/components/map-button/map-button.tsx
410
+ import { jsx as jsx3 } from "react/jsx-runtime";
411
+ var BUTTON_STYLE = {
412
+ display: "flex",
413
+ justifyContent: "center",
414
+ alignItems: "center",
415
+ width: 30,
416
+ height: 30,
417
+ padding: 0,
418
+ borderRadius: 4
419
+ };
239
420
  var MapButton = ({
240
421
  mode,
241
422
  currentMode,
242
- changeMode,
423
+ onClick,
243
424
  icon,
244
- tooltip
245
- }) => {
246
- return /* @__PURE__ */ jsx2("button", {
247
- onClick: () => changeMode(mode),
248
- title: tooltip,
249
- style: {
250
- display: "flex",
251
- justifyContent: "center",
252
- alignItems: "center",
253
- width: "30px",
254
- height: "30px",
255
- padding: "0",
256
- borderRadius: "4px",
257
- backgroundColor: currentMode === mode ? "#02cf87" : "#f0f0f0",
258
- cursor: "pointer"
259
- },
260
- children: icon
261
- });
262
- };
263
- var MapButton_default = MapButton;
425
+ tooltip,
426
+ disabled
427
+ }) => /* @__PURE__ */ jsx3(IconButton, {
428
+ type: "button",
429
+ title: tooltip,
430
+ disabled,
431
+ onClick: () => !disabled && onClick(mode != null ? mode : ""),
432
+ style: __spreadProps(__spreadValues({}, BUTTON_STYLE), {
433
+ backgroundColor: disabled ? "#d3d3d3" : currentMode === mode ? "#02cf87" : "#f0f0f0",
434
+ cursor: disabled ? "not-allowed" : "pointer",
435
+ opacity: disabled ? 0.6 : 1
436
+ }),
437
+ children: icon
438
+ });
439
+ var map_button_default = MapButton;
264
440
 
265
- // src/components/map-buttons/MapButtons.tsx
266
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
267
- var MapButtons = ({
441
+ // src/components/map-buttons/map-buttons.tsx
442
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
443
+ function MapButtons({
268
444
  mode,
269
- changeMode
270
- }) => {
271
- return /* @__PURE__ */ jsxs2("div", {
272
- style: {
273
- position: "absolute",
274
- top: "10px",
275
- left: "10px",
276
- display: "flex",
277
- flexDirection: "column",
278
- gap: "6px",
279
- zIndex: 1e3,
280
- backgroundColor: "rgba(255, 255, 255, 0.9)",
281
- padding: "8px",
282
- borderRadius: "6px",
283
- boxShadow: "0 2px 6px rgba(0,0,0,0.2)"
284
- },
285
- children: [
286
- /* @__PURE__ */ jsx3(MapButton_default, {
287
- mode: "select",
288
- icon: /* @__PURE__ */ jsx3(SelectIcon, {}),
289
- currentMode: mode,
290
- changeMode,
291
- tooltip: "Select"
292
- }),
293
- /* @__PURE__ */ jsx3(MapButton_default, {
294
- mode: "point",
295
- icon: /* @__PURE__ */ jsx3(PointIcon, {}),
296
- currentMode: mode,
297
- changeMode,
298
- tooltip: "Point"
299
- }),
300
- /* @__PURE__ */ jsx3(MapButton_default, {
301
- mode: "linestring",
302
- icon: /* @__PURE__ */ jsx3(LineIcon, {}),
303
- currentMode: mode,
304
- changeMode,
305
- tooltip: "Line"
306
- }),
307
- /* @__PURE__ */ jsx3(MapButton_default, {
308
- mode: "polygon",
309
- icon: /* @__PURE__ */ jsx3(PolygonIcon, {}),
310
- currentMode: mode,
311
- changeMode,
312
- tooltip: "Polygon"
313
- })
314
- ]
315
- });
316
- };
317
- var MapButtons_default = MapButtons;
318
-
319
- // src/components/icon-buttons/ClearButton.tsx
320
- import { useState, useEffect } from "react";
321
- import { jsx as jsx4 } from "react/jsx-runtime";
322
- var ClearButton = ({
445
+ setMode,
446
+ onClick,
323
447
  draw,
324
- onFeaturesChange
325
- }) => {
448
+ onFeaturesChange,
449
+ isMultiple = true,
450
+ autoFocus
451
+ }) {
452
+ const [expanded, setExpanded] = useState(false);
326
453
  const [hasFeatures, setHasFeatures] = useState(false);
454
+ const updateHasFeatures = useCallback(
455
+ () => setHasFeatures(draw.getSnapshot().length > 0),
456
+ [draw]
457
+ );
327
458
  useEffect(() => {
328
459
  if (!draw)
329
460
  return;
330
- const updateHasFeatures = () => {
331
- const snapshot = draw.getSnapshot();
332
- setHasFeatures(snapshot.length > 0);
333
- };
334
461
  draw.on("finish", updateHasFeatures);
335
462
  draw.on("change", updateHasFeatures);
336
463
  updateHasFeatures();
@@ -338,128 +465,242 @@ var ClearButton = ({
338
465
  draw.off("finish", updateHasFeatures);
339
466
  draw.off("change", updateHasFeatures);
340
467
  };
341
- }, [draw]);
342
- const handleClear = () => {
343
- if (!draw)
468
+ }, [draw, updateHasFeatures]);
469
+ const handleGeolocation = useCallback(() => {
470
+ if (!("geolocation" in navigator)) {
471
+ alert("Geolocation is not supported in this browser.");
344
472
  return;
473
+ }
474
+ navigator.geolocation.getCurrentPosition(
475
+ (pos) => {
476
+ const coords = [
477
+ pos.coords.longitude,
478
+ pos.coords.latitude
479
+ ];
480
+ const pt = {
481
+ type: "Feature",
482
+ geometry: { type: "Point", coordinates: coords },
483
+ properties: { mode: "point", source: "geolocation" }
484
+ };
485
+ if (!isMultiple)
486
+ draw.clear();
487
+ draw.addFeatures([pt]);
488
+ onFeaturesChange == null ? void 0 : onFeaturesChange(draw.getSnapshot());
489
+ autoFocus == null ? void 0 : autoFocus([pt]);
490
+ },
491
+ (error) => {
492
+ alert("Error getting geolocation");
493
+ console.error(error);
494
+ }
495
+ );
496
+ setMode("current-location");
497
+ }, [draw, isMultiple, onFeaturesChange, autoFocus]);
498
+ const handleClear = useCallback(() => {
345
499
  draw.clear();
346
500
  setHasFeatures(false);
347
- if (onFeaturesChange)
348
- onFeaturesChange([]);
349
- };
350
- return /* @__PURE__ */ jsx4("button", {
351
- onClick: handleClear,
352
- title: "Clear all features",
353
- disabled: !hasFeatures,
501
+ setMode("static");
502
+ onFeaturesChange == null ? void 0 : onFeaturesChange([]);
503
+ }, [draw, onFeaturesChange]);
504
+ const buttons = useMemo(
505
+ () => [
506
+ {
507
+ icon: /* @__PURE__ */ jsx4(LocateIcon, {}),
508
+ mode: "current-location",
509
+ onClick: handleGeolocation,
510
+ tooltip: "Use current location"
511
+ },
512
+ {
513
+ icon: /* @__PURE__ */ jsx4(SelectIcon, {}),
514
+ mode: "select",
515
+ onClick,
516
+ tooltip: "Select"
517
+ },
518
+ {
519
+ icon: /* @__PURE__ */ jsx4(PointIcon, {}),
520
+ mode: "point",
521
+ onClick,
522
+ tooltip: "Point"
523
+ },
524
+ {
525
+ icon: /* @__PURE__ */ jsx4(LineIcon, {}),
526
+ mode: "linestring",
527
+ onClick,
528
+ tooltip: "Linestring"
529
+ },
530
+ {
531
+ icon: /* @__PURE__ */ jsx4(PolygonIcon, {}),
532
+ mode: "polygon",
533
+ onClick,
534
+ tooltip: "Polygon"
535
+ },
536
+ {
537
+ icon: /* @__PURE__ */ jsx4(RectangleIcon, {}),
538
+ mode: "rectangle",
539
+ onClick,
540
+ tooltip: "Reactangle"
541
+ },
542
+ {
543
+ icon: /* @__PURE__ */ jsx4(CircleIcon, {}),
544
+ mode: "circle",
545
+ onClick,
546
+ tooltip: "Circle"
547
+ },
548
+ {
549
+ icon: /* @__PURE__ */ jsx4(FreeHandIcon, {}),
550
+ mode: "freehand",
551
+ onClick,
552
+ tooltip: "Freehand"
553
+ },
554
+ {
555
+ icon: /* @__PURE__ */ jsx4(DeleteIcon, {}),
556
+ mode: "clear",
557
+ onClick: handleClear,
558
+ tooltip: "Clear all features",
559
+ disabled: !hasFeatures
560
+ }
561
+ ],
562
+ [onClick, handleGeolocation, handleClear, hasFeatures]
563
+ );
564
+ return /* @__PURE__ */ jsxs2("div", {
354
565
  style: {
566
+ position: "absolute",
567
+ top: 10,
568
+ left: 10,
355
569
  display: "flex",
356
- justifyContent: "center",
357
- alignItems: "center",
358
- width: "30px",
359
- height: "30px",
360
- padding: "0",
361
- borderRadius: "4px",
362
- backgroundColor: hasFeatures ? "#f0f0f0" : "#e0e0e0",
363
- cursor: hasFeatures ? "pointer" : "not-allowed"
570
+ flexDirection: "column",
571
+ gap: 6,
572
+ zIndex: 1e3,
573
+ backgroundColor: "rgba(255,255,255,0.9)",
574
+ padding: 8,
575
+ borderRadius: 6,
576
+ boxShadow: "0 2px 6px rgba(0,0,0,0.2)"
364
577
  },
365
- children: /* @__PURE__ */ jsx4(DeleteIcon, {})
578
+ children: [
579
+ /* @__PURE__ */ jsx4(IconButton, {
580
+ onClick: () => setExpanded((v) => !v),
581
+ style: {
582
+ display: "flex",
583
+ justifyContent: "center",
584
+ alignItems: "center",
585
+ width: 30,
586
+ height: 30,
587
+ padding: 0,
588
+ borderRadius: 4,
589
+ backgroundColor: "#d3d3d3"
590
+ },
591
+ title: "Expand or collapse tools",
592
+ children: expanded ? /* @__PURE__ */ jsx4(PencilCloseIcon, {}) : /* @__PURE__ */ jsx4(PencilOpenIcon, {})
593
+ }),
594
+ expanded && /* @__PURE__ */ jsx4("div", {
595
+ style: { display: "flex", flexDirection: "column", gap: 6 },
596
+ children: buttons.map((btn, i) => /* @__PURE__ */ jsx4(map_button_default, {
597
+ icon: btn.icon,
598
+ mode: btn.mode,
599
+ currentMode: mode,
600
+ onClick: btn.onClick,
601
+ tooltip: btn.tooltip,
602
+ disabled: btn.disabled
603
+ }, i))
604
+ })
605
+ ]
366
606
  });
367
- };
368
- var ClearButton_default = ClearButton;
607
+ }
608
+ var map_buttons_default = MapButtons;
369
609
 
370
610
  // src/components/map.tsx
371
- import { defaultMapStyles } from "@biodiv-platform/naksha-commons";
372
611
  import bbox from "@turf/bbox";
373
- import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
374
- var ensureModeProperty = (features) => {
375
- return features.map((feature) => {
376
- var _a, _b;
377
- if ((_a = feature.properties) == null ? void 0 : _a.mode)
378
- return feature;
379
- const geometryType = (_b = feature.geometry) == null ? void 0 : _b.type;
380
- const mode = geometryType === "Point" ? "point" : geometryType === "Polygon" ? "polygon" : geometryType === "LineString" ? "linestring" : "unknown";
381
- return __spreadProps(__spreadValues({}, feature), {
382
- properties: __spreadProps(__spreadValues({}, feature.properties), { mode })
383
- });
384
- });
385
- };
612
+ import { defaultMapStyles } from "@biodiv-platform/naksha-commons";
613
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
386
614
  var Map = (props) => {
615
+ var _a;
616
+ console.info("Rendering Naksha Maplibre Draw Map Component");
387
617
  const mapRef = useRef(null);
388
618
  const [map, setMap] = useState2();
389
619
  const [mode, setMode] = useState2("static");
390
620
  const [draw, setDraw] = useState2();
391
- const mapStyle = defaultMapStyles[(props == null ? void 0 : props.mapStyle) || 0].style;
392
- const { isMultiple = true } = props;
621
+ const { isMultiple = true, features = [], onFeaturesChange } = props;
622
+ const [selectedMapStyleIdx, setSelectedMapStyleIdx] = useState2(
623
+ (props == null ? void 0 : props.mapStyle) || 0
624
+ );
625
+ const mapTile = props.mapStyles ? props.mapStyles : defaultMapStyles;
626
+ const mapStyle = (_a = mapTile[selectedMapStyleIdx]) == null ? void 0 : _a.style;
627
+ const autoFocus = useCallback2(
628
+ (features2) => {
629
+ if (!(features2 == null ? void 0 : features2.length) || !map)
630
+ return;
631
+ const _bbox = bbox({ type: "FeatureCollection", features: features2 });
632
+ map.fitBounds(_bbox, {
633
+ padding: 40,
634
+ duration: 1e3,
635
+ maxZoom: 15
636
+ });
637
+ },
638
+ [map]
639
+ );
640
+ const mapStyleConfig = mapTile[selectedMapStyleIdx];
393
641
  useEffect2(() => {
394
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
642
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
395
643
  const maplibreMap = setupMaplibreMap({
396
644
  containerId: "maplibre-map",
397
- latitude: (_b = (_a = props.defaultViewState) == null ? void 0 : _a.latitude) != null ? _b : 0,
645
+ latitude: (_b = (_a2 = props.defaultViewState) == null ? void 0 : _a2.latitude) != null ? _b : 0,
398
646
  longitude: (_d = (_c = props.defaultViewState) == null ? void 0 : _c.longitude) != null ? _d : 0,
399
647
  zoom: (_f = (_e = props.defaultViewState) == null ? void 0 : _e.zoom) != null ? _f : 0,
400
648
  pitch: (_h = (_g = props.defaultViewState) == null ? void 0 : _g.pitch) != null ? _h : 0,
401
649
  bearing: (_j = (_i = props.defaultViewState) == null ? void 0 : _i.bearing) != null ? _j : 0,
402
650
  mapstyle: mapStyle
403
651
  });
652
+ if ("maxZoom" in mapStyleConfig && mapStyleConfig.maxZoom) {
653
+ maplibreMap.setMaxZoom(mapStyleConfig.maxZoom);
654
+ }
404
655
  const navControl = new maplibregl2.NavigationControl({
405
656
  showCompass: true,
406
657
  showZoom: true,
407
658
  visualizePitch: true
408
659
  });
660
+ const fullscreen = new maplibregl2.FullscreenControl({});
409
661
  maplibreMap.addControl(navControl, "bottom-right");
662
+ maplibreMap.addControl(fullscreen, "bottom-right");
410
663
  maplibreMap.once("style.load", () => setMap(maplibreMap));
411
664
  return () => {
412
- if (navControl && maplibreMap) {
413
- maplibreMap.removeControl(navControl);
414
- }
665
+ maplibreMap.removeControl(navControl);
415
666
  };
416
- }, []);
417
- const autoFocus = useCallback(
418
- (features) => {
419
- if (!(features == null ? void 0 : features.length) || !map)
420
- return;
421
- const _bbox = bbox({
422
- type: "FeatureCollection",
423
- features
424
- });
425
- map.fitBounds(_bbox, { padding: 40, duration: 1e3 });
426
- },
427
- [map]
667
+ }, [mapStyle, props.defaultViewState]);
668
+ const filterUserFeatures = (features2) => features2.filter(
669
+ (f) => f.geometry.type !== "Point" || f.properties.mode !== "static" && f.properties.mode !== "select"
428
670
  );
429
671
  useEffect2(() => {
430
- var _a;
431
672
  if (!map)
432
673
  return;
433
674
  const terraDraw = setupDraw(map);
434
675
  terraDraw.start();
435
676
  setDraw(terraDraw);
436
677
  const handleChange = () => {
437
- var _a2;
438
- const snapshot = terraDraw.getSnapshot();
439
- let filteredFeatures = snapshot;
440
- if (!isMultiple && snapshot.length > 1) {
441
- const latestFeature = snapshot[snapshot.length - 1];
442
- filteredFeatures = [latestFeature];
443
- const featuresToRemove = snapshot.slice(0, -1);
444
- const featureIds = featuresToRemove.map((f) => f.id).filter((id) => id !== void 0);
445
- if (featureIds.length > 0) {
446
- terraDraw.removeFeatures(featureIds);
678
+ let snapshot = terraDraw.getSnapshot();
679
+ let userFeatures = filterUserFeatures(snapshot);
680
+ if (!isMultiple && userFeatures.length > 1) {
681
+ const lastFeature = userFeatures.at(-1);
682
+ const toRemove = userFeatures.slice(0, -1).map((f) => f.id).filter((id) => Boolean(id));
683
+ if (toRemove.length > 0) {
684
+ try {
685
+ terraDraw.removeFeatures(toRemove);
686
+ } catch (e) {
687
+ console.warn("removeFeatures failed", e);
688
+ }
447
689
  }
690
+ userFeatures = [lastFeature];
448
691
  }
449
- (_a2 = props.onFeaturesChange) == null ? void 0 : _a2.call(props, snapshot);
450
- autoFocus(filteredFeatures);
692
+ onFeaturesChange == null ? void 0 : onFeaturesChange(userFeatures);
693
+ autoFocus(userFeatures);
694
+ setMode("static");
451
695
  };
452
696
  terraDraw.on("finish", handleChange);
453
- if ((_a = props.features) == null ? void 0 : _a.length) {
697
+ if (features.length) {
454
698
  setTimeout(() => {
455
699
  if (terraDraw.getSnapshot().length === 0) {
456
- const featuresWithMode = ensureModeProperty(props.features);
457
- let initialFeatures = featuresWithMode;
458
- if (!isMultiple && featuresWithMode.length > 1) {
459
- initialFeatures = [featuresWithMode[featuresWithMode.length - 1]];
460
- }
461
- terraDraw.addFeatures(initialFeatures);
462
- autoFocus(initialFeatures);
700
+ let withMode = ensureModeProperty(features);
701
+ let initial = !isMultiple && withMode.length > 1 ? [withMode.at(-1)] : withMode;
702
+ terraDraw.addFeatures(initial);
703
+ autoFocus(initial);
463
704
  }
464
705
  });
465
706
  }
@@ -467,45 +708,37 @@ var Map = (props) => {
467
708
  terraDraw.off("finish", handleChange);
468
709
  terraDraw.stop();
469
710
  };
470
- }, [map, isMultiple, autoFocus]);
471
- const changeMode = useCallback(
711
+ }, [map, isMultiple, autoFocus, features, onFeaturesChange]);
712
+ const changeMode = useCallback2(
472
713
  (newMode) => {
473
714
  draw == null ? void 0 : draw.setMode(newMode);
474
715
  setMode(newMode);
475
716
  },
476
717
  [draw]
477
718
  );
478
- return /* @__PURE__ */ jsx5("div", {
719
+ const handleStyleChange = (idx) => {
720
+ setSelectedMapStyleIdx(idx);
721
+ };
722
+ return /* @__PURE__ */ jsxs3("div", {
479
723
  ref: mapRef,
480
724
  id: "maplibre-map",
481
- style: { width: "100%", height: "100%" },
482
- children: draw && /* @__PURE__ */ jsxs3(Fragment, {
483
- children: [
484
- /* @__PURE__ */ jsx5(MapButtons_default, {
485
- mode,
486
- changeMode
487
- }),
488
- /* @__PURE__ */ jsx5("div", {
489
- style: {
490
- position: "absolute",
491
- top: "180px",
492
- left: "10px",
493
- display: "flex",
494
- flexDirection: "column",
495
- gap: "6px",
496
- zIndex: 1e3,
497
- backgroundColor: "rgba(255, 255, 255, 0.9)",
498
- padding: "8px",
499
- borderRadius: "6px",
500
- boxShadow: "0 2px 6px rgba(0,0,0,0.2)"
501
- },
502
- children: /* @__PURE__ */ jsx5(ClearButton_default, {
503
- draw,
504
- onFeaturesChange: props.onFeaturesChange
505
- })
506
- })
507
- ]
508
- })
725
+ style: { width: "100%", height: "100%", position: "relative" },
726
+ children: [
727
+ /* @__PURE__ */ jsx5(MapStyleSwitcher, {
728
+ currentStyleIdx: selectedMapStyleIdx,
729
+ onStyleChange: handleStyleChange,
730
+ mapStyles: mapTile
731
+ }),
732
+ draw && /* @__PURE__ */ jsx5(map_buttons_default, {
733
+ mode,
734
+ setMode,
735
+ onClick: changeMode,
736
+ draw,
737
+ onFeaturesChange,
738
+ isMultiple,
739
+ autoFocus
740
+ })
741
+ ]
509
742
  });
510
743
  };
511
744
  var map_default = Map;