maplibre-gl-layer-control 0.16.0 → 0.17.1

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.mjs CHANGED
@@ -689,6 +689,7 @@ class LayerControl {
689
689
  __publicField(this, "minPanelWidth");
690
690
  __publicField(this, "maxPanelWidth");
691
691
  __publicField(this, "initialPanelWidth");
692
+ /** Explicit max panel height; null means fill available vertical space */
692
693
  __publicField(this, "maxPanelHeight");
693
694
  __publicField(this, "showStyleEditor");
694
695
  __publicField(this, "showOpacitySlider");
@@ -701,13 +702,6 @@ class LayerControl {
701
702
  __publicField(this, "nativeLayerGroups", /* @__PURE__ */ new Map());
702
703
  __publicField(this, "basemapStyleUrl", null);
703
704
  __publicField(this, "basemapLayerIds", null);
704
- __publicField(this, "widthSliderEl", null);
705
- __publicField(this, "widthThumbEl", null);
706
- __publicField(this, "widthValueEl", null);
707
- __publicField(this, "isWidthSliderActive", false);
708
- __publicField(this, "widthDragRectWidth", null);
709
- __publicField(this, "widthDragStartX", null);
710
- __publicField(this, "widthDragStartWidth", null);
711
705
  __publicField(this, "widthFrame", null);
712
706
  // Exact-opacity input popup
713
707
  __publicField(this, "opacityInputEl", null);
@@ -733,9 +727,9 @@ class LayerControl {
733
727
  __publicField(this, "backgroundPresetStorageKey");
734
728
  __publicField(this, "onBackgroundPresetsChange");
735
729
  this.minPanelWidth = options.panelMinWidth || 240;
736
- this.maxPanelWidth = options.panelMaxWidth || 420;
730
+ this.maxPanelWidth = options.panelMaxWidth || 960;
737
731
  this.initialPanelWidth = options.panelWidth || 350;
738
- this.maxPanelHeight = options.panelMaxHeight || 600;
732
+ this.maxPanelHeight = options.panelMaxHeight ?? null;
739
733
  this.showStyleEditor = options.showStyleEditor !== false;
740
734
  this.showOpacitySlider = options.showOpacitySlider !== false;
741
735
  this.showLayerSymbol = options.showLayerSymbol !== false;
@@ -816,7 +810,6 @@ class LayerControl {
816
810
  this.contextMenuEl = this.createContextMenu();
817
811
  this.mapContainer.appendChild(this.contextMenuEl);
818
812
  }
819
- this.updateWidthDisplay();
820
813
  this.setupEventListeners();
821
814
  if (this.basemapStyleUrl && !this.basemapLayerIds) {
822
815
  this.fetchBasemapStyle().then(() => {
@@ -1216,7 +1209,9 @@ class LayerControl {
1216
1209
  const panel = document.createElement("div");
1217
1210
  panel.className = "layer-control-panel";
1218
1211
  panel.style.width = `${this.state.panelWidth}px`;
1219
- panel.style.maxHeight = `${this.maxPanelHeight}px`;
1212
+ if (this.maxPanelHeight != null) {
1213
+ panel.style.maxHeight = `${this.maxPanelHeight}px`;
1214
+ }
1220
1215
  if (!this.state.collapsed) {
1221
1216
  panel.classList.add("expanded");
1222
1217
  }
@@ -1383,6 +1378,15 @@ class LayerControl {
1383
1378
  this.panel.style.right = `${buttonRight}px`;
1384
1379
  break;
1385
1380
  }
1381
+ const edgeMargin = 8;
1382
+ const isTopAnchored = position === "top-left" || position === "top-right";
1383
+ const occupiedFromEdge = isTopAnchored ? buttonTop + buttonRect.height + panelGap : buttonBottom + buttonRect.height + panelGap;
1384
+ const availableHeight = Math.max(
1385
+ 120,
1386
+ Math.round(mapRect.height - occupiedFromEdge - edgeMargin)
1387
+ );
1388
+ const maxHeight = this.maxPanelHeight != null ? Math.min(this.maxPanelHeight, availableHeight) : availableHeight;
1389
+ this.panel.style.maxHeight = `${maxHeight}px`;
1386
1390
  }
1387
1391
  /**
1388
1392
  * Create action buttons for Show All / Hide All
@@ -1431,7 +1435,8 @@ class LayerControl {
1431
1435
  });
1432
1436
  }
1433
1437
  /**
1434
- * Create the panel header with title and width control
1438
+ * Create the panel header with the title. Panel width is adjusted by
1439
+ * dragging either edge of the panel (see createResizeHandle).
1435
1440
  */
1436
1441
  createPanelHeader() {
1437
1442
  const header = document.createElement("div");
@@ -1440,135 +1445,8 @@ class LayerControl {
1440
1445
  title.className = "layer-control-panel-title";
1441
1446
  title.textContent = "Layers";
1442
1447
  header.appendChild(title);
1443
- const widthControl = this.createWidthControl();
1444
- header.appendChild(widthControl);
1445
1448
  return header;
1446
1449
  }
1447
- /**
1448
- * Create the width control slider
1449
- */
1450
- createWidthControl() {
1451
- const widthControl = document.createElement("label");
1452
- widthControl.className = "layer-control-width-control";
1453
- widthControl.title = "Adjust layer panel width";
1454
- const widthLabel = document.createElement("span");
1455
- widthLabel.textContent = "Width";
1456
- widthControl.appendChild(widthLabel);
1457
- const widthSlider = document.createElement("div");
1458
- widthSlider.className = "layer-control-width-slider";
1459
- widthSlider.setAttribute("role", "slider");
1460
- widthSlider.setAttribute("aria-valuemin", String(this.minPanelWidth));
1461
- widthSlider.setAttribute("aria-valuemax", String(this.maxPanelWidth));
1462
- widthSlider.setAttribute("aria-valuenow", String(this.state.panelWidth));
1463
- widthSlider.setAttribute("aria-valuestep", "10");
1464
- widthSlider.setAttribute("aria-label", "Layer panel width");
1465
- widthSlider.tabIndex = 0;
1466
- const widthTrack = document.createElement("div");
1467
- widthTrack.className = "layer-control-width-track";
1468
- const widthThumb = document.createElement("div");
1469
- widthThumb.className = "layer-control-width-thumb";
1470
- widthSlider.appendChild(widthTrack);
1471
- widthSlider.appendChild(widthThumb);
1472
- this.widthSliderEl = widthSlider;
1473
- this.widthThumbEl = widthThumb;
1474
- const widthValue = document.createElement("span");
1475
- widthValue.className = "layer-control-width-value";
1476
- this.widthValueEl = widthValue;
1477
- widthControl.appendChild(widthSlider);
1478
- widthControl.appendChild(widthValue);
1479
- this.updateWidthDisplay();
1480
- this.setupWidthSliderEvents(widthSlider);
1481
- return widthControl;
1482
- }
1483
- /**
1484
- * Setup event listeners for width slider
1485
- */
1486
- setupWidthSliderEvents(widthSlider) {
1487
- widthSlider.addEventListener("pointerdown", (event) => {
1488
- event.preventDefault();
1489
- const rect = widthSlider.getBoundingClientRect();
1490
- this.widthDragRectWidth = rect.width || 1;
1491
- this.widthDragStartX = event.clientX;
1492
- this.widthDragStartWidth = this.state.panelWidth;
1493
- this.isWidthSliderActive = true;
1494
- widthSlider.setPointerCapture(event.pointerId);
1495
- this.updateWidthFromPointer(event, true);
1496
- });
1497
- widthSlider.addEventListener("pointermove", (event) => {
1498
- if (!this.isWidthSliderActive) return;
1499
- this.updateWidthFromPointer(event);
1500
- });
1501
- const endPointerDrag = (event) => {
1502
- if (!this.isWidthSliderActive) return;
1503
- if (event.pointerId !== void 0) {
1504
- try {
1505
- widthSlider.releasePointerCapture(event.pointerId);
1506
- } catch (error) {
1507
- }
1508
- }
1509
- this.isWidthSliderActive = false;
1510
- this.widthDragRectWidth = null;
1511
- this.widthDragStartX = null;
1512
- this.widthDragStartWidth = null;
1513
- this.updateWidthDisplay();
1514
- };
1515
- widthSlider.addEventListener("pointerup", endPointerDrag);
1516
- widthSlider.addEventListener("pointercancel", endPointerDrag);
1517
- widthSlider.addEventListener("lostpointercapture", endPointerDrag);
1518
- widthSlider.addEventListener("keydown", (event) => {
1519
- let handled = true;
1520
- const step = event.shiftKey ? 20 : 10;
1521
- switch (event.key) {
1522
- case "ArrowLeft":
1523
- case "ArrowDown":
1524
- this.applyPanelWidth(this.state.panelWidth - step, true);
1525
- break;
1526
- case "ArrowRight":
1527
- case "ArrowUp":
1528
- this.applyPanelWidth(this.state.panelWidth + step, true);
1529
- break;
1530
- case "Home":
1531
- this.applyPanelWidth(this.minPanelWidth, true);
1532
- break;
1533
- case "End":
1534
- this.applyPanelWidth(this.maxPanelWidth, true);
1535
- break;
1536
- case "PageUp":
1537
- this.applyPanelWidth(this.state.panelWidth + 50, true);
1538
- break;
1539
- case "PageDown":
1540
- this.applyPanelWidth(this.state.panelWidth - 50, true);
1541
- break;
1542
- default:
1543
- handled = false;
1544
- }
1545
- if (handled) {
1546
- event.preventDefault();
1547
- this.updateWidthDisplay();
1548
- }
1549
- });
1550
- }
1551
- /**
1552
- * Update panel width from pointer event
1553
- */
1554
- updateWidthFromPointer(event, resetBaseline = false) {
1555
- if (!this.widthSliderEl) return;
1556
- const sliderWidth = this.widthDragRectWidth || this.widthSliderEl.getBoundingClientRect().width || 1;
1557
- const widthRange = this.maxPanelWidth - this.minPanelWidth;
1558
- let width;
1559
- if (resetBaseline) {
1560
- const rect = this.widthSliderEl.getBoundingClientRect();
1561
- const relative = rect.width > 0 ? (event.clientX - rect.left) / rect.width : 0;
1562
- const clampedRatio = Math.min(1, Math.max(0, relative));
1563
- width = this.minPanelWidth + clampedRatio * widthRange;
1564
- this.widthDragStartWidth = width;
1565
- this.widthDragStartX = event.clientX;
1566
- } else {
1567
- const delta = event.clientX - (this.widthDragStartX || event.clientX);
1568
- width = (this.widthDragStartWidth || this.state.panelWidth) + delta / sliderWidth * widthRange;
1569
- }
1570
- this.applyPanelWidth(width, this.isWidthSliderActive);
1571
- }
1572
1450
  /**
1573
1451
  * Apply panel width (clamped to min/max)
1574
1452
  */
@@ -1580,7 +1458,6 @@ class LayerControl {
1580
1458
  this.state.panelWidth = clamped;
1581
1459
  const px = `${clamped}px`;
1582
1460
  this.panel.style.width = px;
1583
- this.updateWidthDisplay();
1584
1461
  };
1585
1462
  if (immediate) {
1586
1463
  applyWidth();
@@ -1594,34 +1471,6 @@ class LayerControl {
1594
1471
  this.widthFrame = null;
1595
1472
  });
1596
1473
  }
1597
- /**
1598
- * Update width display (value label and thumb position)
1599
- */
1600
- updateWidthDisplay() {
1601
- if (this.widthValueEl) {
1602
- this.widthValueEl.textContent = `${this.state.panelWidth}px`;
1603
- }
1604
- if (this.widthSliderEl) {
1605
- this.widthSliderEl.setAttribute(
1606
- "aria-valuenow",
1607
- String(this.state.panelWidth)
1608
- );
1609
- const ratio = (this.state.panelWidth - this.minPanelWidth) / (this.maxPanelWidth - this.minPanelWidth || 1);
1610
- if (this.widthThumbEl) {
1611
- const sliderWidth = this.widthSliderEl.clientWidth;
1612
- if (sliderWidth === 0) {
1613
- requestAnimationFrame(() => this.updateWidthDisplay());
1614
- return;
1615
- }
1616
- const thumbWidth = this.widthThumbEl.offsetWidth || 14;
1617
- const padding = 16;
1618
- const available = Math.max(0, sliderWidth - padding - thumbWidth);
1619
- const clampedRatio = Math.min(1, Math.max(0, ratio));
1620
- const leftPx = 8 + available * clampedRatio;
1621
- this.widthThumbEl.style.left = `${leftPx}px`;
1622
- }
1623
- }
1624
- }
1625
1474
  /**
1626
1475
  * Setup main event listeners
1627
1476
  */
@@ -1720,7 +1569,21 @@ class LayerControl {
1720
1569
  const existingItems = this.panel.querySelectorAll(".layer-control-item");
1721
1570
  existingItems.forEach((item) => item.remove());
1722
1571
  this.styleEditors.clear();
1723
- Object.entries(this.state.layerStates).forEach(([layerId, state]) => {
1572
+ const orderedLayerIds = this.getUserLayerIdsInMapOrder();
1573
+ const captured = new Set(orderedLayerIds);
1574
+ for (const layerId of Object.keys(this.state.layerStates)) {
1575
+ if (layerId !== "Background" && !captured.has(layerId)) {
1576
+ orderedLayerIds.push(layerId);
1577
+ }
1578
+ }
1579
+ if (this.state.layerStates["Background"]) {
1580
+ orderedLayerIds.push("Background");
1581
+ }
1582
+ orderedLayerIds.forEach((layerId) => {
1583
+ const state = this.state.layerStates[layerId];
1584
+ if (!state) {
1585
+ return;
1586
+ }
1724
1587
  if (this.targetLayers.length === 0 || this.targetLayers.includes(layerId)) {
1725
1588
  this.addLayerItem(layerId, state);
1726
1589
  }
@@ -2501,7 +2364,8 @@ class LayerControl {
2501
2364
  const styleLayers = this.map.getStyle().layers || [];
2502
2365
  return styleLayers.filter((layer) => {
2503
2366
  if (this.isUserAddedLayer(layer.id)) return false;
2504
- if (this.excludeDrawnLayers && this.isDrawnLayer(layer.id)) return false;
2367
+ if (this.excludeDrawnLayers && this.isDrawnLayer(layer.id))
2368
+ return false;
2505
2369
  if (this.isExcludedByPattern(layer.id)) return false;
2506
2370
  return true;
2507
2371
  }).map((layer) => layer.id);
@@ -3877,22 +3741,33 @@ class LayerControl {
3877
3741
  const style = this.map.getStyle();
3878
3742
  if (!(style == null ? void 0 : style.layers)) return [];
3879
3743
  const mapLayerIds = style.layers.map((l) => l.id);
3744
+ const indexById = new Map(mapLayerIds.map((id, i) => [id, i]));
3880
3745
  const userLayerIds = Object.keys(this.state.layerStates).filter(
3881
3746
  (id) => id !== "Background"
3882
3747
  );
3883
- const mapLibreLayers = userLayerIds.filter(
3884
- (id) => mapLayerIds.includes(id)
3885
- );
3886
- const customLayers = userLayerIds.filter(
3887
- (id) => {
3888
- var _a;
3889
- return ((_a = this.state.layerStates[id]) == null ? void 0 : _a.isCustomLayer) && !mapLayerIds.includes(id);
3748
+ const mapIndexOf = (id) => {
3749
+ var _a;
3750
+ const direct = indexById.get(id);
3751
+ if (direct !== void 0) return direct;
3752
+ const nativeIds = (_a = this.customLayerRegistry) == null ? void 0 : _a.getNativeLayerIds(id);
3753
+ if (nativeIds && nativeIds.length > 0) {
3754
+ let best = -1;
3755
+ for (const nativeId of nativeIds) {
3756
+ const idx = indexById.get(nativeId);
3757
+ if (idx !== void 0 && idx > best) best = idx;
3758
+ }
3759
+ if (best !== -1) return best;
3890
3760
  }
3891
- );
3892
- const sortedMapLibreLayers = mapLibreLayers.sort(
3893
- (a, b) => mapLayerIds.indexOf(b) - mapLayerIds.indexOf(a)
3894
- );
3895
- return [...customLayers, ...sortedMapLibreLayers];
3761
+ return Number.POSITIVE_INFINITY;
3762
+ };
3763
+ return userLayerIds.map((id, insertionIndex) => ({
3764
+ id,
3765
+ insertionIndex,
3766
+ mapIndex: mapIndexOf(id)
3767
+ })).sort((a, b) => {
3768
+ if (a.mapIndex !== b.mapIndex) return a.mapIndex > b.mapIndex ? -1 : 1;
3769
+ return a.insertionIndex - b.insertionIndex;
3770
+ }).map((entry) => entry.id);
3896
3771
  }
3897
3772
  /**
3898
3773
  * Check if a layer is a MapLibre layer (not a custom layer)
@@ -4318,18 +4193,17 @@ class LayerControl {
4318
4193
  uiLayerIds.push(layerId);
4319
4194
  }
4320
4195
  });
4321
- const reversedIds = [...uiLayerIds].reverse();
4322
4196
  const style = this.map.getStyle();
4323
4197
  const mapLibreLayerIds = new Set(((_a = style == null ? void 0 : style.layers) == null ? void 0 : _a.map((l) => l.id)) || []);
4324
- for (let i = 0; i < reversedIds.length; i++) {
4325
- const layerId = reversedIds[i];
4198
+ for (let i = 0; i < uiLayerIds.length; i++) {
4199
+ const layerId = uiLayerIds[i];
4326
4200
  if (!mapLibreLayerIds.has(layerId)) {
4327
4201
  continue;
4328
4202
  }
4329
4203
  let beforeId = void 0;
4330
4204
  for (let j = i - 1; j >= 0; j--) {
4331
- if (mapLibreLayerIds.has(reversedIds[j])) {
4332
- beforeId = reversedIds[j];
4205
+ if (mapLibreLayerIds.has(uiLayerIds[j])) {
4206
+ beforeId = uiLayerIds[j];
4333
4207
  break;
4334
4208
  }
4335
4209
  }