maplibre-gl-layer-control 0.1.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,1166 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
6
+ function getOpacityProperty(layerType) {
7
+ switch (layerType) {
8
+ case "fill":
9
+ return "fill-opacity";
10
+ case "line":
11
+ return "line-opacity";
12
+ case "circle":
13
+ return "circle-opacity";
14
+ case "symbol":
15
+ return ["icon-opacity", "text-opacity"];
16
+ case "raster":
17
+ return "raster-opacity";
18
+ case "background":
19
+ return "background-opacity";
20
+ default:
21
+ return `${layerType}-opacity`;
22
+ }
23
+ }
24
+ function getLayerOpacity(map, layerId, layerType) {
25
+ const opacityProp = getOpacityProperty(layerType);
26
+ if (Array.isArray(opacityProp)) {
27
+ const opacity2 = map.getPaintProperty(layerId, opacityProp[0]);
28
+ return opacity2 !== void 0 && opacity2 !== null ? opacity2 : 1;
29
+ }
30
+ const opacity = map.getPaintProperty(layerId, opacityProp);
31
+ return opacity !== void 0 && opacity !== null ? opacity : 1;
32
+ }
33
+ function setLayerOpacity(map, layerId, layerType, opacity) {
34
+ const opacityProp = getOpacityProperty(layerType);
35
+ if (Array.isArray(opacityProp)) {
36
+ opacityProp.forEach((prop) => {
37
+ map.setPaintProperty(layerId, prop, opacity);
38
+ });
39
+ } else {
40
+ map.setPaintProperty(layerId, opacityProp, opacity);
41
+ }
42
+ }
43
+ function isStyleableLayerType(layerType) {
44
+ return ["fill", "line", "circle", "symbol", "raster"].includes(layerType);
45
+ }
46
+ function getLayerType(map, layerId) {
47
+ try {
48
+ const layer = map.getLayer(layerId);
49
+ return layer ? layer.type : null;
50
+ } catch (error) {
51
+ console.warn(`Failed to get layer type for ${layerId}:`, error);
52
+ return null;
53
+ }
54
+ }
55
+ function clonePaintValue(value) {
56
+ if (Array.isArray(value)) {
57
+ return value.map((item) => clonePaintValue(item));
58
+ }
59
+ if (value && typeof value === "object") {
60
+ try {
61
+ return JSON.parse(JSON.stringify(value));
62
+ } catch (error) {
63
+ return value;
64
+ }
65
+ }
66
+ return value;
67
+ }
68
+ function cacheOriginalLayerStyle(map, layerId, originalStyles) {
69
+ var _a;
70
+ if (originalStyles.has(layerId)) {
71
+ return;
72
+ }
73
+ try {
74
+ const layer = map.getLayer(layerId);
75
+ if (!layer) {
76
+ return;
77
+ }
78
+ const paint = {};
79
+ const style = map.getStyle();
80
+ const layerDef = (_a = style.layers) == null ? void 0 : _a.find((l) => l.id === layerId);
81
+ if (layer.type === "raster") {
82
+ const rasterDefaults = {
83
+ "raster-opacity": 1,
84
+ "raster-brightness-min": 0,
85
+ "raster-brightness-max": 1,
86
+ "raster-saturation": 0,
87
+ "raster-contrast": 0,
88
+ "raster-hue-rotate": 0
89
+ };
90
+ Object.assign(paint, rasterDefaults);
91
+ if (layerDef && "paint" in layerDef && layerDef.paint) {
92
+ Object.entries(layerDef.paint).forEach(([prop, value]) => {
93
+ if (prop.startsWith("raster-")) {
94
+ paint[prop] = clonePaintValue(value);
95
+ }
96
+ });
97
+ }
98
+ } else {
99
+ if (layerDef && "paint" in layerDef && layerDef.paint) {
100
+ Object.entries(layerDef.paint).forEach(([prop, value]) => {
101
+ paint[prop] = clonePaintValue(value);
102
+ });
103
+ }
104
+ }
105
+ originalStyles.set(layerId, { paint });
106
+ } catch (error) {
107
+ console.warn(`Failed to cache original style for ${layerId}:`, error);
108
+ }
109
+ }
110
+ function restoreOriginalStyle(map, layerId, originalStyles) {
111
+ const original = originalStyles.get(layerId);
112
+ if (!original) {
113
+ return {};
114
+ }
115
+ const applied = {};
116
+ Object.entries(original.paint).forEach(([property, value]) => {
117
+ try {
118
+ const restoredValue = clonePaintValue(value);
119
+ map.setPaintProperty(layerId, property, restoredValue);
120
+ applied[property] = restoredValue;
121
+ } catch (error) {
122
+ console.warn(`Failed to restore ${property} for ${layerId}:`, error);
123
+ }
124
+ });
125
+ return applied;
126
+ }
127
+ function rgbToHex(r, g, b) {
128
+ const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
129
+ const toHex = (v) => {
130
+ const hex = clamp2(v).toString(16);
131
+ return hex.length === 1 ? `0${hex}` : hex;
132
+ };
133
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
134
+ }
135
+ function normalizeColor(value) {
136
+ if (typeof value === "string") {
137
+ if (value.startsWith("#")) {
138
+ if (value.length === 4) {
139
+ const r = value[1];
140
+ const g = value[2];
141
+ const b = value[3];
142
+ return `#${r}${r}${g}${g}${b}${b}`;
143
+ }
144
+ return value;
145
+ }
146
+ if (value.startsWith("rgb")) {
147
+ const match = value.match(/\d+/g);
148
+ if (match && match.length >= 3) {
149
+ const [r, g, b] = match.map((num) => parseInt(num, 10));
150
+ return rgbToHex(r, g, b);
151
+ }
152
+ }
153
+ } else if (Array.isArray(value) && value.length >= 3) {
154
+ return rgbToHex(value[0], value[1], value[2]);
155
+ }
156
+ return "#3388ff";
157
+ }
158
+ function formatNumericValue(value, step) {
159
+ let decimals = 0;
160
+ if (step && Number(step) !== 1) {
161
+ const stepNumber = Number(step);
162
+ if (stepNumber > 0 && stepNumber < 1) {
163
+ decimals = Math.min(4, Math.ceil(Math.abs(Math.log10(stepNumber))));
164
+ }
165
+ }
166
+ return value.toFixed(decimals);
167
+ }
168
+ function clamp(value, min, max) {
169
+ return Math.max(min, Math.min(max, value));
170
+ }
171
+ class LayerControl {
172
+ constructor(options = {}) {
173
+ __publicField(this, "map");
174
+ __publicField(this, "container");
175
+ __publicField(this, "button");
176
+ __publicField(this, "panel");
177
+ // State management
178
+ __publicField(this, "state");
179
+ __publicField(this, "targetLayers");
180
+ __publicField(this, "styleEditors");
181
+ // Panel width management
182
+ __publicField(this, "minPanelWidth");
183
+ __publicField(this, "maxPanelWidth");
184
+ __publicField(this, "widthSliderEl", null);
185
+ __publicField(this, "widthThumbEl", null);
186
+ __publicField(this, "widthValueEl", null);
187
+ __publicField(this, "isWidthSliderActive", false);
188
+ __publicField(this, "widthDragRectWidth", null);
189
+ __publicField(this, "widthDragStartX", null);
190
+ __publicField(this, "widthDragStartWidth", null);
191
+ __publicField(this, "widthFrame", null);
192
+ this.minPanelWidth = options.panelMinWidth || 240;
193
+ this.maxPanelWidth = options.panelMaxWidth || 420;
194
+ this.state = {
195
+ collapsed: options.collapsed !== false,
196
+ panelWidth: options.panelWidth || 320,
197
+ activeStyleEditor: null,
198
+ layerStates: options.layerStates || {},
199
+ originalStyles: /* @__PURE__ */ new Map(),
200
+ userInteractingWithSlider: false
201
+ };
202
+ this.targetLayers = options.layers || Object.keys(this.state.layerStates);
203
+ this.styleEditors = /* @__PURE__ */ new Map();
204
+ }
205
+ /**
206
+ * Called when the control is added to the map
207
+ */
208
+ onAdd(map) {
209
+ this.map = map;
210
+ if (Object.keys(this.state.layerStates).length === 0) {
211
+ this.autoDetectLayers();
212
+ }
213
+ this.container = this.createContainer();
214
+ this.button = this.createToggleButton();
215
+ this.panel = this.createPanel();
216
+ this.container.appendChild(this.button);
217
+ this.container.appendChild(this.panel);
218
+ this.updateWidthDisplay();
219
+ this.setupEventListeners();
220
+ this.buildLayerItems();
221
+ return this.container;
222
+ }
223
+ /**
224
+ * Called when the control is removed from the map
225
+ */
226
+ onRemove() {
227
+ var _a;
228
+ (_a = this.container.parentNode) == null ? void 0 : _a.removeChild(this.container);
229
+ }
230
+ /**
231
+ * Auto-detect layers from the map and populate layerStates
232
+ */
233
+ autoDetectLayers() {
234
+ const style = this.map.getStyle();
235
+ if (!style || !style.layers) {
236
+ return;
237
+ }
238
+ const allLayerIds = style.layers.map((layer) => layer.id);
239
+ if (this.targetLayers.length === 0) {
240
+ allLayerIds.forEach((layerId) => {
241
+ const layer = this.map.getLayer(layerId);
242
+ if (!layer) return;
243
+ const visibility = this.map.getLayoutProperty(layerId, "visibility");
244
+ const isVisible = visibility !== "none";
245
+ const layerType = layer.type;
246
+ const opacity = getLayerOpacity(this.map, layerId, layerType);
247
+ const friendlyName = this.generateFriendlyName(layerId);
248
+ this.state.layerStates[layerId] = {
249
+ visible: isVisible,
250
+ opacity,
251
+ name: friendlyName
252
+ };
253
+ });
254
+ } else {
255
+ const userLayers = [];
256
+ const basemapLayers = [];
257
+ allLayerIds.forEach((layerId) => {
258
+ if (this.targetLayers.includes(layerId)) {
259
+ userLayers.push(layerId);
260
+ } else {
261
+ basemapLayers.push(layerId);
262
+ }
263
+ });
264
+ if (basemapLayers.length > 0) {
265
+ this.state.layerStates["Background"] = {
266
+ visible: true,
267
+ opacity: 1,
268
+ name: "Background"
269
+ };
270
+ }
271
+ userLayers.forEach((layerId) => {
272
+ const layer = this.map.getLayer(layerId);
273
+ if (!layer) return;
274
+ const visibility = this.map.getLayoutProperty(layerId, "visibility");
275
+ const isVisible = visibility !== "none";
276
+ const layerType = layer.type;
277
+ const opacity = getLayerOpacity(this.map, layerId, layerType);
278
+ const friendlyName = this.generateFriendlyName(layerId);
279
+ this.state.layerStates[layerId] = {
280
+ visible: isVisible,
281
+ opacity,
282
+ name: friendlyName
283
+ };
284
+ });
285
+ }
286
+ this.targetLayers = Object.keys(this.state.layerStates);
287
+ }
288
+ /**
289
+ * Generate a friendly display name from a layer ID
290
+ */
291
+ generateFriendlyName(layerId) {
292
+ let name = layerId.replace(/^(layer[-_]?|gl[-_]?)/, "");
293
+ name = name.replace(/[-_]/g, " ");
294
+ name = name.replace(/\b\w/g, (char) => char.toUpperCase());
295
+ return name || layerId;
296
+ }
297
+ /**
298
+ * Create the main container element
299
+ */
300
+ createContainer() {
301
+ const container = document.createElement("div");
302
+ container.className = "maplibregl-ctrl maplibregl-ctrl-group maplibregl-ctrl-layer-control";
303
+ return container;
304
+ }
305
+ /**
306
+ * Create the toggle button
307
+ */
308
+ createToggleButton() {
309
+ const button = document.createElement("button");
310
+ button.type = "button";
311
+ button.title = "Layer Control";
312
+ button.setAttribute("aria-label", "Layer Control");
313
+ const icon = document.createElement("span");
314
+ icon.className = "layer-control-icon";
315
+ icon.innerHTML = '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 3 3 8.25 12 13.5 21 8.25 12 3"></polygon><polyline points="3 12.75 12 18 21 12.75"></polyline><polyline points="3 17.25 12 22 21 17.25"></polyline></svg>';
316
+ button.appendChild(icon);
317
+ return button;
318
+ }
319
+ /**
320
+ * Create the panel element
321
+ */
322
+ createPanel() {
323
+ const panel = document.createElement("div");
324
+ panel.className = "layer-control-panel";
325
+ panel.style.width = `${this.state.panelWidth}px`;
326
+ if (!this.state.collapsed) {
327
+ panel.classList.add("expanded");
328
+ }
329
+ const header = this.createPanelHeader();
330
+ panel.appendChild(header);
331
+ return panel;
332
+ }
333
+ /**
334
+ * Create the panel header with title and width control
335
+ */
336
+ createPanelHeader() {
337
+ const header = document.createElement("div");
338
+ header.className = "layer-control-panel-header";
339
+ const title = document.createElement("span");
340
+ title.className = "layer-control-panel-title";
341
+ title.textContent = "Layers";
342
+ header.appendChild(title);
343
+ const widthControl = this.createWidthControl();
344
+ header.appendChild(widthControl);
345
+ return header;
346
+ }
347
+ /**
348
+ * Create the width control slider
349
+ */
350
+ createWidthControl() {
351
+ const widthControl = document.createElement("label");
352
+ widthControl.className = "layer-control-width-control";
353
+ widthControl.title = "Adjust layer panel width";
354
+ const widthLabel = document.createElement("span");
355
+ widthLabel.textContent = "Width";
356
+ widthControl.appendChild(widthLabel);
357
+ const widthSlider = document.createElement("div");
358
+ widthSlider.className = "layer-control-width-slider";
359
+ widthSlider.setAttribute("role", "slider");
360
+ widthSlider.setAttribute("aria-valuemin", String(this.minPanelWidth));
361
+ widthSlider.setAttribute("aria-valuemax", String(this.maxPanelWidth));
362
+ widthSlider.setAttribute("aria-valuenow", String(this.state.panelWidth));
363
+ widthSlider.setAttribute("aria-valuestep", "10");
364
+ widthSlider.setAttribute("aria-label", "Layer panel width");
365
+ widthSlider.tabIndex = 0;
366
+ const widthTrack = document.createElement("div");
367
+ widthTrack.className = "layer-control-width-track";
368
+ const widthThumb = document.createElement("div");
369
+ widthThumb.className = "layer-control-width-thumb";
370
+ widthSlider.appendChild(widthTrack);
371
+ widthSlider.appendChild(widthThumb);
372
+ this.widthSliderEl = widthSlider;
373
+ this.widthThumbEl = widthThumb;
374
+ const widthValue = document.createElement("span");
375
+ widthValue.className = "layer-control-width-value";
376
+ this.widthValueEl = widthValue;
377
+ widthControl.appendChild(widthSlider);
378
+ widthControl.appendChild(widthValue);
379
+ this.updateWidthDisplay();
380
+ this.setupWidthSliderEvents(widthSlider);
381
+ return widthControl;
382
+ }
383
+ /**
384
+ * Setup event listeners for width slider
385
+ */
386
+ setupWidthSliderEvents(widthSlider) {
387
+ widthSlider.addEventListener("pointerdown", (event) => {
388
+ event.preventDefault();
389
+ const rect = widthSlider.getBoundingClientRect();
390
+ this.widthDragRectWidth = rect.width || 1;
391
+ this.widthDragStartX = event.clientX;
392
+ this.widthDragStartWidth = this.state.panelWidth;
393
+ this.isWidthSliderActive = true;
394
+ widthSlider.setPointerCapture(event.pointerId);
395
+ this.updateWidthFromPointer(event, true);
396
+ });
397
+ widthSlider.addEventListener("pointermove", (event) => {
398
+ if (!this.isWidthSliderActive) return;
399
+ this.updateWidthFromPointer(event);
400
+ });
401
+ const endPointerDrag = (event) => {
402
+ if (!this.isWidthSliderActive) return;
403
+ if (event.pointerId !== void 0) {
404
+ try {
405
+ widthSlider.releasePointerCapture(event.pointerId);
406
+ } catch (error) {
407
+ }
408
+ }
409
+ this.isWidthSliderActive = false;
410
+ this.widthDragRectWidth = null;
411
+ this.widthDragStartX = null;
412
+ this.widthDragStartWidth = null;
413
+ this.updateWidthDisplay();
414
+ };
415
+ widthSlider.addEventListener("pointerup", endPointerDrag);
416
+ widthSlider.addEventListener("pointercancel", endPointerDrag);
417
+ widthSlider.addEventListener("lostpointercapture", endPointerDrag);
418
+ widthSlider.addEventListener("keydown", (event) => {
419
+ let handled = true;
420
+ const step = event.shiftKey ? 20 : 10;
421
+ switch (event.key) {
422
+ case "ArrowLeft":
423
+ case "ArrowDown":
424
+ this.applyPanelWidth(this.state.panelWidth - step, true);
425
+ break;
426
+ case "ArrowRight":
427
+ case "ArrowUp":
428
+ this.applyPanelWidth(this.state.panelWidth + step, true);
429
+ break;
430
+ case "Home":
431
+ this.applyPanelWidth(this.minPanelWidth, true);
432
+ break;
433
+ case "End":
434
+ this.applyPanelWidth(this.maxPanelWidth, true);
435
+ break;
436
+ case "PageUp":
437
+ this.applyPanelWidth(this.state.panelWidth + 50, true);
438
+ break;
439
+ case "PageDown":
440
+ this.applyPanelWidth(this.state.panelWidth - 50, true);
441
+ break;
442
+ default:
443
+ handled = false;
444
+ }
445
+ if (handled) {
446
+ event.preventDefault();
447
+ this.updateWidthDisplay();
448
+ }
449
+ });
450
+ }
451
+ /**
452
+ * Update panel width from pointer event
453
+ */
454
+ updateWidthFromPointer(event, resetBaseline = false) {
455
+ if (!this.widthSliderEl) return;
456
+ const sliderWidth = this.widthDragRectWidth || this.widthSliderEl.getBoundingClientRect().width || 1;
457
+ const widthRange = this.maxPanelWidth - this.minPanelWidth;
458
+ let width;
459
+ if (resetBaseline) {
460
+ const rect = this.widthSliderEl.getBoundingClientRect();
461
+ const relative = rect.width > 0 ? (event.clientX - rect.left) / rect.width : 0;
462
+ const clampedRatio = Math.min(1, Math.max(0, relative));
463
+ width = this.minPanelWidth + clampedRatio * widthRange;
464
+ this.widthDragStartWidth = width;
465
+ this.widthDragStartX = event.clientX;
466
+ } else {
467
+ const delta = event.clientX - (this.widthDragStartX || event.clientX);
468
+ width = (this.widthDragStartWidth || this.state.panelWidth) + delta / sliderWidth * widthRange;
469
+ }
470
+ this.applyPanelWidth(width, this.isWidthSliderActive);
471
+ }
472
+ /**
473
+ * Apply panel width (clamped to min/max)
474
+ */
475
+ applyPanelWidth(width, immediate = false) {
476
+ const clamped = Math.round(Math.min(this.maxPanelWidth, Math.max(this.minPanelWidth, width)));
477
+ const applyWidth = () => {
478
+ this.state.panelWidth = clamped;
479
+ const px = `${clamped}px`;
480
+ this.panel.style.width = px;
481
+ this.updateWidthDisplay();
482
+ };
483
+ if (immediate) {
484
+ applyWidth();
485
+ return;
486
+ }
487
+ if (this.widthFrame) {
488
+ cancelAnimationFrame(this.widthFrame);
489
+ }
490
+ this.widthFrame = requestAnimationFrame(() => {
491
+ applyWidth();
492
+ this.widthFrame = null;
493
+ });
494
+ }
495
+ /**
496
+ * Update width display (value label and thumb position)
497
+ */
498
+ updateWidthDisplay() {
499
+ if (this.widthValueEl) {
500
+ this.widthValueEl.textContent = `${this.state.panelWidth}px`;
501
+ }
502
+ if (this.widthSliderEl) {
503
+ this.widthSliderEl.setAttribute("aria-valuenow", String(this.state.panelWidth));
504
+ const ratio = (this.state.panelWidth - this.minPanelWidth) / (this.maxPanelWidth - this.minPanelWidth || 1);
505
+ if (this.widthThumbEl) {
506
+ const sliderWidth = this.widthSliderEl.clientWidth || 1;
507
+ const thumbWidth = this.widthThumbEl.offsetWidth || 14;
508
+ const padding = 16;
509
+ const available = Math.max(0, sliderWidth - padding - thumbWidth);
510
+ const clampedRatio = Math.min(1, Math.max(0, ratio));
511
+ const leftPx = 8 + available * clampedRatio;
512
+ this.widthThumbEl.style.left = `${leftPx}px`;
513
+ }
514
+ }
515
+ }
516
+ /**
517
+ * Setup main event listeners
518
+ */
519
+ setupEventListeners() {
520
+ this.button.addEventListener("click", () => this.toggle());
521
+ document.addEventListener("click", (e) => {
522
+ if (!this.container.contains(e.target)) {
523
+ this.collapse();
524
+ }
525
+ });
526
+ this.setupLayerChangeListeners();
527
+ }
528
+ /**
529
+ * Setup listeners for map layer changes
530
+ */
531
+ setupLayerChangeListeners() {
532
+ this.map.on("styledata", () => {
533
+ setTimeout(() => {
534
+ this.updateLayerStatesFromMap();
535
+ this.checkForNewLayers();
536
+ }, 100);
537
+ });
538
+ this.map.on("data", (e) => {
539
+ if (e.sourceDataType === "content") {
540
+ setTimeout(() => {
541
+ this.updateLayerStatesFromMap();
542
+ this.checkForNewLayers();
543
+ }, 100);
544
+ }
545
+ });
546
+ this.map.on("sourcedata", (e) => {
547
+ if (e.sourceDataType === "metadata") {
548
+ setTimeout(() => {
549
+ this.checkForNewLayers();
550
+ }, 150);
551
+ }
552
+ });
553
+ }
554
+ /**
555
+ * Toggle panel expanded/collapsed state
556
+ */
557
+ toggle() {
558
+ if (this.state.collapsed) {
559
+ this.expand();
560
+ } else {
561
+ this.collapse();
562
+ }
563
+ }
564
+ /**
565
+ * Expand the panel
566
+ */
567
+ expand() {
568
+ this.state.collapsed = false;
569
+ this.panel.classList.add("expanded");
570
+ }
571
+ /**
572
+ * Collapse the panel
573
+ */
574
+ collapse() {
575
+ this.state.collapsed = true;
576
+ this.panel.classList.remove("expanded");
577
+ }
578
+ /**
579
+ * Build layer items (called initially and when layers change)
580
+ */
581
+ buildLayerItems() {
582
+ const existingItems = this.panel.querySelectorAll(".layer-control-item");
583
+ existingItems.forEach((item) => item.remove());
584
+ this.styleEditors.clear();
585
+ Object.entries(this.state.layerStates).forEach(([layerId, state]) => {
586
+ if (this.targetLayers.length === 0 || this.targetLayers.includes(layerId)) {
587
+ this.addLayerItem(layerId, state);
588
+ }
589
+ });
590
+ }
591
+ /**
592
+ * Add a single layer item to the panel
593
+ */
594
+ addLayerItem(layerId, state) {
595
+ const item = document.createElement("div");
596
+ item.className = "layer-control-item";
597
+ item.setAttribute("data-layer-id", layerId);
598
+ const row = document.createElement("div");
599
+ row.className = "layer-control-row";
600
+ const checkbox = document.createElement("input");
601
+ checkbox.type = "checkbox";
602
+ checkbox.className = "layer-control-checkbox";
603
+ checkbox.checked = state.visible;
604
+ checkbox.addEventListener("change", () => {
605
+ this.toggleLayerVisibility(layerId, checkbox.checked);
606
+ });
607
+ const name = document.createElement("span");
608
+ name.className = "layer-control-name";
609
+ name.textContent = state.name || layerId;
610
+ name.title = state.name || layerId;
611
+ const opacity = document.createElement("input");
612
+ opacity.type = "range";
613
+ opacity.className = "layer-control-opacity";
614
+ opacity.min = "0";
615
+ opacity.max = "1";
616
+ opacity.step = "0.01";
617
+ opacity.value = String(state.opacity);
618
+ opacity.title = `Opacity: ${Math.round(state.opacity * 100)}%`;
619
+ opacity.addEventListener("mousedown", () => {
620
+ this.state.userInteractingWithSlider = true;
621
+ });
622
+ opacity.addEventListener("mouseup", () => {
623
+ this.state.userInteractingWithSlider = false;
624
+ });
625
+ opacity.addEventListener("input", () => {
626
+ this.changeLayerOpacity(layerId, parseFloat(opacity.value));
627
+ opacity.title = `Opacity: ${Math.round(parseFloat(opacity.value) * 100)}%`;
628
+ });
629
+ row.appendChild(checkbox);
630
+ row.appendChild(name);
631
+ row.appendChild(opacity);
632
+ if (layerId !== "Background") {
633
+ const styleButton = this.createStyleButton(layerId);
634
+ if (styleButton) {
635
+ row.appendChild(styleButton);
636
+ }
637
+ }
638
+ item.appendChild(row);
639
+ this.panel.appendChild(item);
640
+ }
641
+ /**
642
+ * Toggle layer visibility
643
+ */
644
+ toggleLayerVisibility(layerId, visible) {
645
+ if (layerId === "Background") {
646
+ this.toggleBackgroundVisibility(visible);
647
+ return;
648
+ }
649
+ if (this.state.layerStates[layerId]) {
650
+ this.state.layerStates[layerId].visible = visible;
651
+ }
652
+ this.map.setLayoutProperty(layerId, "visibility", visible ? "visible" : "none");
653
+ }
654
+ /**
655
+ * Change layer opacity
656
+ */
657
+ changeLayerOpacity(layerId, opacity) {
658
+ if (layerId === "Background") {
659
+ this.changeBackgroundOpacity(opacity);
660
+ return;
661
+ }
662
+ if (this.state.layerStates[layerId]) {
663
+ this.state.layerStates[layerId].opacity = opacity;
664
+ }
665
+ const layerType = getLayerType(this.map, layerId);
666
+ if (layerType) {
667
+ setLayerOpacity(this.map, layerId, layerType, opacity);
668
+ }
669
+ }
670
+ /**
671
+ * Check if a layer is a user-added layer (vs basemap layer)
672
+ */
673
+ isUserAddedLayer(layerId) {
674
+ return this.state.layerStates[layerId] !== void 0 && layerId !== "Background";
675
+ }
676
+ /**
677
+ * Toggle visibility for all background layers (basemap layers)
678
+ */
679
+ toggleBackgroundVisibility(visible) {
680
+ if (this.state.layerStates["Background"]) {
681
+ this.state.layerStates["Background"].visible = visible;
682
+ }
683
+ const styleLayers = this.map.getStyle().layers || [];
684
+ styleLayers.forEach((layer) => {
685
+ if (!this.isUserAddedLayer(layer.id)) {
686
+ this.map.setLayoutProperty(layer.id, "visibility", visible ? "visible" : "none");
687
+ }
688
+ });
689
+ }
690
+ /**
691
+ * Change opacity for all background layers (basemap layers)
692
+ */
693
+ changeBackgroundOpacity(opacity) {
694
+ if (this.state.layerStates["Background"]) {
695
+ this.state.layerStates["Background"].opacity = opacity;
696
+ }
697
+ const styleLayers = this.map.getStyle().layers || [];
698
+ styleLayers.forEach((styleLayer) => {
699
+ if (!this.isUserAddedLayer(styleLayer.id)) {
700
+ const layerType = getLayerType(this.map, styleLayer.id);
701
+ if (layerType) {
702
+ setLayerOpacity(this.map, styleLayer.id, layerType, opacity);
703
+ }
704
+ }
705
+ });
706
+ }
707
+ /**
708
+ * Create style button for a layer
709
+ */
710
+ createStyleButton(layerId) {
711
+ if (layerId === "Background") {
712
+ return null;
713
+ }
714
+ const button = document.createElement("button");
715
+ button.className = "layer-control-style-button";
716
+ button.innerHTML = "&#9881;";
717
+ button.title = "Edit layer style";
718
+ button.setAttribute("aria-label", `Edit style for ${layerId}`);
719
+ button.addEventListener("click", (e) => {
720
+ e.stopPropagation();
721
+ this.toggleStyleEditor(layerId);
722
+ });
723
+ return button;
724
+ }
725
+ /**
726
+ * Toggle style editor for a layer
727
+ */
728
+ toggleStyleEditor(layerId) {
729
+ if (this.state.activeStyleEditor === layerId) {
730
+ this.closeStyleEditor(layerId);
731
+ return;
732
+ }
733
+ if (this.state.activeStyleEditor) {
734
+ this.closeStyleEditor(this.state.activeStyleEditor);
735
+ }
736
+ this.openStyleEditor(layerId);
737
+ }
738
+ /**
739
+ * Open style editor for a layer
740
+ */
741
+ openStyleEditor(layerId) {
742
+ const itemEl = this.panel.querySelector(`[data-layer-id="${layerId}"]`);
743
+ if (!itemEl) return;
744
+ if (!this.state.originalStyles.has(layerId)) {
745
+ const layer = this.map.getLayer(layerId);
746
+ if (layer) {
747
+ cacheOriginalLayerStyle(this.map, layerId, this.state.originalStyles);
748
+ }
749
+ }
750
+ const editor = this.createStyleEditor(layerId);
751
+ if (!editor) return;
752
+ itemEl.appendChild(editor);
753
+ this.styleEditors.set(layerId, editor);
754
+ this.state.activeStyleEditor = layerId;
755
+ setTimeout(() => {
756
+ editor.scrollIntoView({ behavior: "smooth", block: "nearest" });
757
+ }, 50);
758
+ }
759
+ /**
760
+ * Close style editor for a layer
761
+ */
762
+ closeStyleEditor(layerId) {
763
+ const editor = this.styleEditors.get(layerId);
764
+ if (editor) {
765
+ editor.remove();
766
+ this.styleEditors.delete(layerId);
767
+ }
768
+ if (this.state.activeStyleEditor === layerId) {
769
+ this.state.activeStyleEditor = null;
770
+ }
771
+ }
772
+ /**
773
+ * Create style editor UI
774
+ */
775
+ createStyleEditor(layerId) {
776
+ const layer = this.map.getLayer(layerId);
777
+ if (!layer) return null;
778
+ const editor = document.createElement("div");
779
+ editor.className = "layer-control-style-editor";
780
+ const header = document.createElement("div");
781
+ header.className = "style-editor-header";
782
+ const title = document.createElement("span");
783
+ title.className = "style-editor-title";
784
+ title.textContent = "Edit Style";
785
+ const closeBtn = document.createElement("button");
786
+ closeBtn.className = "style-editor-close";
787
+ closeBtn.innerHTML = "&times;";
788
+ closeBtn.title = "Close";
789
+ closeBtn.addEventListener("click", (e) => {
790
+ e.stopPropagation();
791
+ this.closeStyleEditor(layerId);
792
+ });
793
+ header.appendChild(title);
794
+ header.appendChild(closeBtn);
795
+ const controls = document.createElement("div");
796
+ controls.className = "style-editor-controls";
797
+ const layerType = layer.type;
798
+ this.addStyleControlsForLayerType(controls, layerId, layerType);
799
+ const actions = document.createElement("div");
800
+ actions.className = "style-editor-actions";
801
+ const resetBtn = document.createElement("button");
802
+ resetBtn.className = "style-editor-button style-editor-button-reset";
803
+ resetBtn.textContent = "Reset";
804
+ resetBtn.addEventListener("click", (e) => {
805
+ e.stopPropagation();
806
+ this.resetLayerStyle(layerId);
807
+ });
808
+ const closeActionBtn = document.createElement("button");
809
+ closeActionBtn.className = "style-editor-button style-editor-button-close";
810
+ closeActionBtn.textContent = "Close";
811
+ closeActionBtn.addEventListener("click", (e) => {
812
+ e.stopPropagation();
813
+ this.closeStyleEditor(layerId);
814
+ });
815
+ actions.appendChild(resetBtn);
816
+ actions.appendChild(closeActionBtn);
817
+ editor.appendChild(header);
818
+ editor.appendChild(controls);
819
+ editor.appendChild(actions);
820
+ return editor;
821
+ }
822
+ /**
823
+ * Add style controls based on layer type
824
+ */
825
+ addStyleControlsForLayerType(container, layerId, layerType) {
826
+ switch (layerType) {
827
+ case "fill":
828
+ this.addFillControls(container, layerId);
829
+ break;
830
+ case "line":
831
+ this.addLineControls(container, layerId);
832
+ break;
833
+ case "circle":
834
+ this.addCircleControls(container, layerId);
835
+ break;
836
+ case "raster":
837
+ this.addRasterControls(container, layerId);
838
+ break;
839
+ case "symbol":
840
+ this.addSymbolControls(container, layerId);
841
+ break;
842
+ default:
843
+ container.textContent = `Style controls for ${layerType} layers not yet implemented.`;
844
+ }
845
+ }
846
+ /**
847
+ * Add controls for fill layers
848
+ */
849
+ addFillControls(container, layerId) {
850
+ var _a;
851
+ const style = this.map.getStyle();
852
+ const layer = (_a = style.layers) == null ? void 0 : _a.find((l) => l.id === layerId);
853
+ let fillColor = void 0;
854
+ if (layer && "paint" in layer && layer.paint && "fill-color" in layer.paint) {
855
+ fillColor = layer.paint["fill-color"];
856
+ }
857
+ if (!fillColor) {
858
+ fillColor = this.map.getPaintProperty(layerId, "fill-color");
859
+ }
860
+ this.createColorControl(container, layerId, "fill-color", "Fill Color", normalizeColor(fillColor || "#088"));
861
+ const fillOpacity = this.map.getPaintProperty(layerId, "fill-opacity");
862
+ if (fillOpacity !== void 0 && typeof fillOpacity === "number") {
863
+ this.createSliderControl(container, layerId, "fill-opacity", "Fill Opacity", fillOpacity, 0, 1, 0.05);
864
+ }
865
+ const outlineColor = this.map.getPaintProperty(layerId, "fill-outline-color");
866
+ if (outlineColor !== void 0) {
867
+ this.createColorControl(container, layerId, "fill-outline-color", "Outline Color", normalizeColor(outlineColor));
868
+ }
869
+ }
870
+ /**
871
+ * Add controls for line layers
872
+ */
873
+ addLineControls(container, layerId) {
874
+ var _a;
875
+ const style = this.map.getStyle();
876
+ const layer = (_a = style.layers) == null ? void 0 : _a.find((l) => l.id === layerId);
877
+ let lineColor = void 0;
878
+ if (layer && "paint" in layer && layer.paint && "line-color" in layer.paint) {
879
+ lineColor = layer.paint["line-color"];
880
+ }
881
+ if (!lineColor) {
882
+ lineColor = this.map.getPaintProperty(layerId, "line-color");
883
+ }
884
+ this.createColorControl(container, layerId, "line-color", "Line Color", normalizeColor(lineColor || "#000"));
885
+ const lineWidth = this.map.getPaintProperty(layerId, "line-width");
886
+ this.createSliderControl(container, layerId, "line-width", "Line Width", typeof lineWidth === "number" ? lineWidth : 1, 0, 20, 0.5);
887
+ const lineOpacity = this.map.getPaintProperty(layerId, "line-opacity");
888
+ if (lineOpacity !== void 0 && typeof lineOpacity === "number") {
889
+ this.createSliderControl(container, layerId, "line-opacity", "Line Opacity", lineOpacity, 0, 1, 0.05);
890
+ }
891
+ const lineBlur = this.map.getPaintProperty(layerId, "line-blur");
892
+ if (lineBlur !== void 0 && typeof lineBlur === "number") {
893
+ this.createSliderControl(container, layerId, "line-blur", "Line Blur", lineBlur, 0, 5, 0.1);
894
+ }
895
+ }
896
+ /**
897
+ * Add controls for circle layers
898
+ */
899
+ addCircleControls(container, layerId) {
900
+ var _a;
901
+ const style = this.map.getStyle();
902
+ const layer = (_a = style.layers) == null ? void 0 : _a.find((l) => l.id === layerId);
903
+ let circleColor = void 0;
904
+ if (layer && "paint" in layer && layer.paint && "circle-color" in layer.paint) {
905
+ circleColor = layer.paint["circle-color"];
906
+ }
907
+ if (!circleColor) {
908
+ circleColor = this.map.getPaintProperty(layerId, "circle-color");
909
+ }
910
+ this.createColorControl(container, layerId, "circle-color", "Circle Color", normalizeColor(circleColor || "#000"));
911
+ const circleRadius = this.map.getPaintProperty(layerId, "circle-radius");
912
+ this.createSliderControl(container, layerId, "circle-radius", "Radius", typeof circleRadius === "number" ? circleRadius : 5, 0, 40, 0.5);
913
+ const circleOpacity = this.map.getPaintProperty(layerId, "circle-opacity");
914
+ if (circleOpacity !== void 0 && typeof circleOpacity === "number") {
915
+ this.createSliderControl(container, layerId, "circle-opacity", "Opacity", circleOpacity, 0, 1, 0.05);
916
+ }
917
+ const strokeColor = this.map.getPaintProperty(layerId, "circle-stroke-color");
918
+ if (strokeColor !== void 0) {
919
+ this.createColorControl(container, layerId, "circle-stroke-color", "Stroke Color", normalizeColor(strokeColor));
920
+ }
921
+ const strokeWidth = this.map.getPaintProperty(layerId, "circle-stroke-width");
922
+ if (strokeWidth !== void 0 && typeof strokeWidth === "number") {
923
+ this.createSliderControl(container, layerId, "circle-stroke-width", "Stroke Width", strokeWidth, 0, 10, 0.1);
924
+ }
925
+ }
926
+ /**
927
+ * Add controls for raster layers
928
+ */
929
+ addRasterControls(container, layerId) {
930
+ const rasterOpacity = this.map.getPaintProperty(layerId, "raster-opacity");
931
+ this.createSliderControl(container, layerId, "raster-opacity", "Opacity", typeof rasterOpacity === "number" ? rasterOpacity : 1, 0, 1, 0.05);
932
+ const brightnessMin = this.map.getPaintProperty(layerId, "raster-brightness-min");
933
+ this.createSliderControl(container, layerId, "raster-brightness-min", "Brightness Min", typeof brightnessMin === "number" ? brightnessMin : 0, -1, 1, 0.05);
934
+ const brightnessMax = this.map.getPaintProperty(layerId, "raster-brightness-max");
935
+ this.createSliderControl(container, layerId, "raster-brightness-max", "Brightness Max", typeof brightnessMax === "number" ? brightnessMax : 1, -1, 1, 0.05);
936
+ const saturation = this.map.getPaintProperty(layerId, "raster-saturation");
937
+ this.createSliderControl(container, layerId, "raster-saturation", "Saturation", typeof saturation === "number" ? saturation : 0, -1, 1, 0.05);
938
+ const contrast = this.map.getPaintProperty(layerId, "raster-contrast");
939
+ this.createSliderControl(container, layerId, "raster-contrast", "Contrast", typeof contrast === "number" ? contrast : 0, -1, 1, 0.05);
940
+ const hueRotate = this.map.getPaintProperty(layerId, "raster-hue-rotate");
941
+ this.createSliderControl(container, layerId, "raster-hue-rotate", "Hue Rotate", typeof hueRotate === "number" ? hueRotate : 0, 0, 360, 5);
942
+ }
943
+ /**
944
+ * Add controls for symbol layers
945
+ */
946
+ addSymbolControls(container, layerId) {
947
+ const textColor = this.map.getPaintProperty(layerId, "text-color");
948
+ if (textColor !== void 0) {
949
+ this.createColorControl(container, layerId, "text-color", "Text Color", normalizeColor(textColor));
950
+ }
951
+ const textOpacity = this.map.getPaintProperty(layerId, "text-opacity");
952
+ if (textOpacity !== void 0 && typeof textOpacity === "number") {
953
+ this.createSliderControl(container, layerId, "text-opacity", "Text Opacity", textOpacity, 0, 1, 0.05);
954
+ }
955
+ const iconOpacity = this.map.getPaintProperty(layerId, "icon-opacity");
956
+ if (iconOpacity !== void 0 && typeof iconOpacity === "number") {
957
+ this.createSliderControl(container, layerId, "icon-opacity", "Icon Opacity", iconOpacity, 0, 1, 0.05);
958
+ }
959
+ }
960
+ /**
961
+ * Create a color control
962
+ */
963
+ createColorControl(container, layerId, property, label, initialValue) {
964
+ const controlGroup = document.createElement("div");
965
+ controlGroup.className = "style-control-group";
966
+ const labelEl = document.createElement("label");
967
+ labelEl.className = "style-control-label";
968
+ labelEl.textContent = label;
969
+ const inputWrapper = document.createElement("div");
970
+ inputWrapper.className = "style-control-color-group";
971
+ const colorInput = document.createElement("input");
972
+ colorInput.type = "color";
973
+ colorInput.className = "style-control-color-picker";
974
+ colorInput.value = initialValue;
975
+ colorInput.dataset.property = property;
976
+ const hexDisplay = document.createElement("input");
977
+ hexDisplay.type = "text";
978
+ hexDisplay.className = "style-control-color-value";
979
+ hexDisplay.value = initialValue;
980
+ hexDisplay.readOnly = true;
981
+ colorInput.addEventListener("input", () => {
982
+ const color = colorInput.value;
983
+ hexDisplay.value = color;
984
+ this.map.setPaintProperty(layerId, property, color);
985
+ });
986
+ inputWrapper.appendChild(colorInput);
987
+ inputWrapper.appendChild(hexDisplay);
988
+ controlGroup.appendChild(labelEl);
989
+ controlGroup.appendChild(inputWrapper);
990
+ container.appendChild(controlGroup);
991
+ }
992
+ /**
993
+ * Create a slider control
994
+ */
995
+ createSliderControl(container, layerId, property, label, initialValue, min, max, step) {
996
+ const controlGroup = document.createElement("div");
997
+ controlGroup.className = "style-control-group";
998
+ const labelEl = document.createElement("label");
999
+ labelEl.className = "style-control-label";
1000
+ labelEl.textContent = label;
1001
+ const inputWrapper = document.createElement("div");
1002
+ inputWrapper.className = "style-control-input-wrapper";
1003
+ const slider = document.createElement("input");
1004
+ slider.type = "range";
1005
+ slider.className = "style-control-slider";
1006
+ slider.min = String(min);
1007
+ slider.max = String(max);
1008
+ slider.step = String(step);
1009
+ slider.value = String(initialValue);
1010
+ slider.dataset.property = property;
1011
+ const valueDisplay = document.createElement("span");
1012
+ valueDisplay.className = "style-control-value";
1013
+ valueDisplay.textContent = formatNumericValue(initialValue, step);
1014
+ slider.addEventListener("input", () => {
1015
+ const value = parseFloat(slider.value);
1016
+ valueDisplay.textContent = formatNumericValue(value, step);
1017
+ this.map.setPaintProperty(layerId, property, value);
1018
+ });
1019
+ inputWrapper.appendChild(slider);
1020
+ inputWrapper.appendChild(valueDisplay);
1021
+ controlGroup.appendChild(labelEl);
1022
+ controlGroup.appendChild(inputWrapper);
1023
+ container.appendChild(controlGroup);
1024
+ }
1025
+ /**
1026
+ * Reset layer style to original
1027
+ */
1028
+ resetLayerStyle(layerId) {
1029
+ const originalStyle = this.state.originalStyles.get(layerId);
1030
+ if (!originalStyle) return;
1031
+ restoreOriginalStyle(this.map, layerId, this.state.originalStyles);
1032
+ const editor = this.styleEditors.get(layerId);
1033
+ if (editor) {
1034
+ const sliders = editor.querySelectorAll(".style-control-slider");
1035
+ sliders.forEach((slider) => {
1036
+ var _a;
1037
+ const property = slider.dataset.property;
1038
+ if (property) {
1039
+ const value = this.map.getPaintProperty(layerId, property);
1040
+ if (value !== void 0 && typeof value === "number") {
1041
+ slider.value = String(value);
1042
+ const valueDisplay = (_a = slider.parentElement) == null ? void 0 : _a.querySelector(".style-control-value");
1043
+ if (valueDisplay) {
1044
+ const step = parseFloat(slider.step);
1045
+ valueDisplay.textContent = formatNumericValue(value, step);
1046
+ }
1047
+ }
1048
+ }
1049
+ });
1050
+ const colorPickers = editor.querySelectorAll(".style-control-color-picker");
1051
+ colorPickers.forEach((picker) => {
1052
+ var _a;
1053
+ const property = picker.dataset.property;
1054
+ if (property) {
1055
+ const value = this.map.getPaintProperty(layerId, property);
1056
+ if (value !== void 0) {
1057
+ const hexColor = normalizeColor(value);
1058
+ picker.value = hexColor;
1059
+ const hexDisplay = (_a = picker.parentElement) == null ? void 0 : _a.querySelector(".style-control-color-value");
1060
+ if (hexDisplay) {
1061
+ hexDisplay.textContent = hexColor;
1062
+ }
1063
+ }
1064
+ }
1065
+ });
1066
+ }
1067
+ }
1068
+ /**
1069
+ * Update layer states from map (sync UI with map)
1070
+ */
1071
+ updateLayerStatesFromMap() {
1072
+ if (this.state.userInteractingWithSlider) {
1073
+ return;
1074
+ }
1075
+ Object.keys(this.state.layerStates).forEach((layerId) => {
1076
+ try {
1077
+ const layer = this.map.getLayer(layerId);
1078
+ if (!layer) return;
1079
+ const visibility = this.map.getLayoutProperty(layerId, "visibility");
1080
+ const isVisible = visibility !== "none";
1081
+ const layerType = layer.type;
1082
+ const opacity = getLayerOpacity(this.map, layerId, layerType);
1083
+ if (this.state.layerStates[layerId]) {
1084
+ this.state.layerStates[layerId].visible = isVisible;
1085
+ this.state.layerStates[layerId].opacity = opacity;
1086
+ }
1087
+ this.updateUIForLayer(layerId, isVisible, opacity);
1088
+ } catch (error) {
1089
+ console.warn(`Failed to update state for layer ${layerId}:`, error);
1090
+ }
1091
+ });
1092
+ }
1093
+ /**
1094
+ * Update UI elements for a specific layer
1095
+ */
1096
+ updateUIForLayer(layerId, visible, opacity) {
1097
+ const layerItems = this.panel.querySelectorAll(".layer-control-item");
1098
+ layerItems.forEach((item) => {
1099
+ if (item.dataset.layerId === layerId) {
1100
+ const checkbox = item.querySelector(".layer-control-checkbox");
1101
+ const opacitySlider = item.querySelector(".layer-control-opacity");
1102
+ if (checkbox) {
1103
+ checkbox.checked = visible;
1104
+ }
1105
+ if (opacitySlider) {
1106
+ opacitySlider.value = String(opacity);
1107
+ opacitySlider.title = `Opacity: ${Math.round(opacity * 100)}%`;
1108
+ }
1109
+ }
1110
+ });
1111
+ }
1112
+ /**
1113
+ * Check for new layers and add them to the control
1114
+ */
1115
+ checkForNewLayers() {
1116
+ try {
1117
+ const style = this.map.getStyle();
1118
+ if (!style || !style.layers) {
1119
+ return;
1120
+ }
1121
+ const currentMapLayers = style.layers.map((layer) => layer.id).filter((id) => {
1122
+ if (this.targetLayers.length > 0) {
1123
+ return this.targetLayers.includes(id);
1124
+ }
1125
+ return true;
1126
+ });
1127
+ const newLayers = [];
1128
+ currentMapLayers.forEach((layerId) => {
1129
+ if (layerId !== "Background" && !this.state.layerStates[layerId]) {
1130
+ const layer = this.map.getLayer(layerId);
1131
+ if (layer) {
1132
+ newLayers.push(layerId);
1133
+ }
1134
+ }
1135
+ });
1136
+ if (newLayers.length > 0) {
1137
+ newLayers.forEach((layerId) => {
1138
+ const layer = this.map.getLayer(layerId);
1139
+ if (!layer) return;
1140
+ const layerType = layer.type;
1141
+ const opacity = getLayerOpacity(this.map, layerId, layerType);
1142
+ const visibility = this.map.getLayoutProperty(layerId, "visibility");
1143
+ const isVisible = visibility !== "none";
1144
+ this.state.layerStates[layerId] = {
1145
+ visible: isVisible,
1146
+ opacity,
1147
+ name: layerId.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase())
1148
+ };
1149
+ this.addLayerItem(layerId, this.state.layerStates[layerId]);
1150
+ });
1151
+ }
1152
+ } catch (error) {
1153
+ console.warn("Failed to check for new layers:", error);
1154
+ }
1155
+ }
1156
+ }
1157
+ exports.LayerControl = LayerControl;
1158
+ exports.clamp = clamp;
1159
+ exports.formatNumericValue = formatNumericValue;
1160
+ exports.getLayerOpacity = getLayerOpacity;
1161
+ exports.getLayerType = getLayerType;
1162
+ exports.isStyleableLayerType = isStyleableLayerType;
1163
+ exports.normalizeColor = normalizeColor;
1164
+ exports.rgbToHex = rgbToHex;
1165
+ exports.setLayerOpacity = setLayerOpacity;
1166
+ //# sourceMappingURL=index.cjs.map