@mintplayer/ng-bootstrap 20.6.0 → 20.6.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.
@@ -1341,6 +1341,28 @@ class MintDockManagerElement extends HTMLElement {
1341
1341
  this.startDragPointerTracking();
1342
1342
  event.dataTransfer.effectAllowed = 'move';
1343
1343
  event.dataTransfer.setData('text/plain', pane);
1344
+ // Preferred UX: if the dragged tab is the only one in its stack,
1345
+ // immediately convert to a floating window unless it is already the
1346
+ // only pane in a floating window (this case is handled by reuse logic).
1347
+ if (this.dragState && this.dragState.floatingIndex !== null && this.dragState.floatingIndex < 0) {
1348
+ const loc = this.resolveStackLocation(this.dragState.sourcePath);
1349
+ if (loc && Array.isArray(loc.node.panes) && loc.node.panes.length === 1) {
1350
+ let shouldConvert = false;
1351
+ if (loc.context === "docked") {
1352
+ shouldConvert = true;
1353
+ }
1354
+ else if (loc.context === "floating") {
1355
+ const floating = this.floatingLayouts[loc.index];
1356
+ const totalPanes = floating && floating.root ? this.countPanesInTree(floating.root) : 0;
1357
+ shouldConvert = totalPanes > 1; // not the only pane in this floating window
1358
+ }
1359
+ if (shouldConvert) {
1360
+ const startX = Number.isFinite(event.clientX) ? event.clientX : (this.dragState.startClientX ?? 0);
1361
+ const startY = Number.isFinite(event.clientY) ? event.clientY : (this.dragState.startClientY ?? 0);
1362
+ this.convertPendingTabDragToFloating(startX, startY);
1363
+ }
1364
+ }
1365
+ }
1344
1366
  }
1345
1367
  preparePaneDragSource(path, pane, stackEl, event) {
1346
1368
  const location = this.resolveStackLocation(path);
@@ -1607,6 +1629,8 @@ class MintDockManagerElement extends HTMLElement {
1607
1629
  if (this.dropJoystick.dataset['visible'] !== 'true') {
1608
1630
  this.hideDropIndicator();
1609
1631
  }
1632
+ // Also ensure any in-header placeholder is cleared when not over a stack
1633
+ this.clearHeaderDragPlaceholder();
1610
1634
  return;
1611
1635
  }
1612
1636
  // If we moved to a different target stack, reset any sticky zone so
@@ -1617,7 +1641,7 @@ class MintDockManagerElement extends HTMLElement {
1617
1641
  }
1618
1642
  // Previous behavior hid the indicator and returned early here; instead,
1619
1643
  // allow the live-reorder branch below to handle in-header drags.
1620
- // While reordering within the same header, update order live and suppress joystick/indicator
1644
+ // While dragging within the same header, show a placeholder and suppress joystick/indicator
1621
1645
  if (this.dragState &&
1622
1646
  this.dragState.floatingIndex !== null &&
1623
1647
  this.dragState.floatingIndex < 0 &&
@@ -1628,16 +1652,12 @@ class MintDockManagerElement extends HTMLElement {
1628
1652
  if (inHeaderByBounds || inHeaderByHitTest) {
1629
1653
  const header = stack.querySelector('.dock-stack__header');
1630
1654
  if (header) {
1655
+ // Ensure placeholder exists and move it as the pointer moves
1656
+ this.ensureHeaderDragPlaceholder(header, this.dragState.pane);
1631
1657
  const idx = this.computeHeaderInsertIndex(header, clientX);
1632
1658
  if (this.dragState.liveReorderIndex !== idx) {
1633
- this.ensureHeaderDragPlaceholder(header, this.dragState.pane);
1634
1659
  this.updateHeaderDragPlaceholderPosition(header, idx);
1635
- const location = this.resolveStackLocation(path);
1636
- if (location) {
1637
- this.reorderPaneInLocationAtIndex(location, this.dragState.pane, idx);
1638
- this.render();
1639
- this.dispatchLayoutChanged();
1640
- }
1660
+ // Keep model reordering until drop; only move the placeholder now
1641
1661
  this.dragState.liveReorderIndex = idx;
1642
1662
  }
1643
1663
  }
@@ -1645,6 +1665,8 @@ class MintDockManagerElement extends HTMLElement {
1645
1665
  return;
1646
1666
  }
1647
1667
  }
1668
+ // Leaving the header: ensure any placeholder is removed immediately
1669
+ this.clearHeaderDragPlaceholder();
1648
1670
  const zoneHint = this.findDropZoneByPoint(clientX, clientY);
1649
1671
  const zone = this.computeDropZone(stack, { clientX, clientY }, zoneHint);
1650
1672
  this.showDropIndicator(stack, zone);
@@ -1687,11 +1709,14 @@ class MintDockManagerElement extends HTMLElement {
1687
1709
  placeholder.type = 'button';
1688
1710
  placeholder.classList.add('dock-tab');
1689
1711
  placeholder.dataset['placeholder'] = 'true';
1690
- placeholder.textContent = dragged.textContent ?? '';
1691
- // Hide the original dragged tab so it doesn't duplicate visually
1692
- dragged.style.visibility = 'hidden';
1693
- // Insert placeholder next to dragged initially
1694
- header.insertBefore(placeholder, dragged.nextSibling);
1712
+ // Keep the placeholder visually empty but reserving the same width
1713
+ placeholder.textContent = '';
1714
+ placeholder.setAttribute('aria-hidden', 'true');
1715
+ placeholder.style.width = `${dragged.offsetWidth}px`;
1716
+ // Hide the original dragged tab so it doesn't duplicate visually and free up its slot
1717
+ dragged.style.display = 'none';
1718
+ // Insert placeholder in the original position of the dragged tab
1719
+ header.insertBefore(placeholder, dragged);
1695
1720
  if (this.dragState) {
1696
1721
  this.dragState.placeholderHeader = header;
1697
1722
  this.dragState.placeholderEl = placeholder;
@@ -1703,8 +1728,9 @@ class MintDockManagerElement extends HTMLElement {
1703
1728
  if (!placeholder) {
1704
1729
  return;
1705
1730
  }
1731
+ const draggedPane = this.dragState?.pane ?? null;
1706
1732
  const tabs = Array.from(header.querySelectorAll('.dock-tab'))
1707
- .filter((t) => t !== placeholder);
1733
+ .filter((t) => t !== placeholder && (!draggedPane || t.dataset['pane'] !== draggedPane));
1708
1734
  const clampedTarget = Math.max(0, Math.min(targetIndex, tabs.length));
1709
1735
  const ref = tabs[clampedTarget] ?? null;
1710
1736
  header.insertBefore(placeholder, ref);
@@ -1718,7 +1744,7 @@ class MintDockManagerElement extends HTMLElement {
1718
1744
  ? (Array.from(header.querySelectorAll('.dock-tab')).find((t) => t.dataset['pane'] === this.dragState?.pane) ?? null)
1719
1745
  : null;
1720
1746
  if (dragged) {
1721
- dragged.style.visibility = '';
1747
+ dragged.style.display = '';
1722
1748
  }
1723
1749
  }
1724
1750
  if (ph && ph.parentElement) {
@@ -1872,20 +1898,41 @@ class MintDockManagerElement extends HTMLElement {
1872
1898
  this.dispatchLayoutChanged();
1873
1899
  }
1874
1900
  // Compute the intended tab insert index within a header based on pointer X
1901
+ // Adds a slight rightward bias and uses the placeholder rect (if present)
1902
+ // to ensure offsets are correct even when the dragged tab is display:none.
1875
1903
  computeHeaderInsertIndex(header, clientX) {
1876
- const tabs = Array.from(header.querySelectorAll('.dock-tab'))
1877
- .filter((t) => t.dataset['placeholder'] !== 'true');
1878
- if (tabs.length === 0) {
1904
+ const allTabs = Array.from(header.querySelectorAll('.dock-tab'));
1905
+ if (allTabs.length === 0) {
1879
1906
  return 0;
1880
1907
  }
1881
- for (let i = 0; i < tabs.length; i += 1) {
1882
- const rect = tabs[i].getBoundingClientRect();
1883
- const mid = rect.left + rect.width / 2;
1908
+ const draggedPane = this.dragState?.pane ?? null;
1909
+ const draggedEl = draggedPane
1910
+ ? (allTabs.find((t) => t.dataset['pane'] === draggedPane) ?? null)
1911
+ : null;
1912
+ const placeholderEl = header.querySelector('.dock-tab[data-placeholder="true"]');
1913
+ const targets = allTabs.filter((t) => t !== draggedEl && t !== placeholderEl);
1914
+ if (targets.length === 0) {
1915
+ return 0;
1916
+ }
1917
+ const rightBias = 12;
1918
+ const leftBias = 0;
1919
+ const baseRect = placeholderEl
1920
+ ? placeholderEl.getBoundingClientRect()
1921
+ : draggedEl
1922
+ ? draggedEl.getBoundingClientRect()
1923
+ : null;
1924
+ const rectValid = !!baseRect && Number.isFinite(baseRect.width) && baseRect.width > 0;
1925
+ const draggedCenter = rectValid && baseRect ? baseRect.left + baseRect.width / 2 : null;
1926
+ for (let i = 0; i < targets.length; i += 1) {
1927
+ const rect = targets[i].getBoundingClientRect();
1928
+ const baseMid = rect.left + rect.width / 2;
1929
+ const isRightOfDragged = draggedCenter !== null ? baseMid >= draggedCenter : false;
1930
+ const mid = isRightOfDragged ? baseMid + rightBias : baseMid - leftBias;
1884
1931
  if (clientX < mid) {
1885
1932
  return i;
1886
1933
  }
1887
1934
  }
1888
- return tabs.length; // insert at end
1935
+ return targets.length;
1889
1936
  }
1890
1937
  reorderPaneInLocationAtIndex(location, pane, targetIndex) {
1891
1938
  const panes = location.node.panes;