vgapp 1.4.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,8 +12,10 @@ const NAME_KEY = "vg.nestable";
12
12
 
13
13
  const SELECTOR_DATA_TOGGLE = '[data-vg-toggle="nestable"]';
14
14
 
15
- const CLASS_ITEM_DRAGGING = "is-dragging";
16
- const CLASS_ITEM_GHOST = "is-drag-ghost";
15
+ const CLASS_ITEM_DRAGGING = "is-dragging";
16
+ const CLASS_ITEM_GHOST = "is-drag-ghost";
17
+ const CLASS_DISABLED = "is-disabled";
18
+ const CLASS_ITEM_DISABLED = "is-drag-disabled";
17
19
  const CLASS_PLACEHOLDER = "vg-nestable-placeholder";
18
20
  const CLASS_PLACEHOLDER_HIDDEN = "vg-nestable-placeholder-hidden";
19
21
  const CLASS_DRAG_ELEMENT = "vg-nestable-drag-element";
@@ -22,9 +24,13 @@ const CLASS_INNER = "vg-nestable-inner";
22
24
  const CLASS_HANDLE = "vg-nestable-handle";
23
25
  const CLASS_HANDLE_ICON = "vg-nestable-handle-icon";
24
26
  const CLASS_COLLAPSE_TOGGLE = "vg-nestable-collapse-toggle";
25
- const CLASS_DROP_TARGET = "is-drop-target";
26
- const CLASS_DROP_DENIED = "is-drop-denied";
27
- const CLASS_LIVE_REGION = "vg-nestable-live";
27
+ const CLASS_DROP_TARGET = "is-drop-target";
28
+ const CLASS_DROP_DENIED = "is-drop-denied";
29
+ const CLASS_DROP_BEFORE = "is-drop-before";
30
+ const CLASS_DROP_ATTACHABLE = "is-drop-attachable";
31
+ const CLASS_DROP_INSIDE = "is-drop-inside";
32
+ const CLASS_DROP_AFTER = "is-drop-after";
33
+ const CLASS_LIVE_REGION = "vg-nestable-live";
28
34
 
29
35
  const EVENT_KEY_START = `${NAME_KEY}.start`;
30
36
  const EVENT_KEY_CHANGE = `${NAME_KEY}.change`;
@@ -45,17 +51,19 @@ class VGNestable extends BaseModule {
45
51
  constructor(element, params = {}) {
46
52
  super(element, params);
47
53
 
48
- this._params = this._getParams(element, mergeDeepObject({
49
- listselector: ".vg-nestable-list", // Root/nested list for dnd.
54
+ this._params = this._getParams(element, mergeDeepObject({
55
+ disabled: false, // Disable all drag-and-drop for this tree.
56
+ disabledattribute: "data-disabled", // Lock attribute for an item or nested list.
57
+ listselector: ".vg-nestable-list", // Root/nested list for dnd.
50
58
  itemselector: ".vg-nestable-item", // Sortable item selector.
51
59
  handleselector: ".vg-nestable-handle", // Drag handle selector.
52
60
  idattribute: "data-id", // Item id attribute used by serialize().
53
61
  childlistclass: "vg-nestable-list", // Class for auto-created child list.
54
62
  handleicon: '', // иконка для хендлера
55
- indent: 50, // X offset (px), after which item moves into child level.
63
+ indent: 18, // Small horizontal gesture (px) that moves the item under the previous sibling.
56
64
  maxdepth: 6, // Maximum nesting depth.
57
65
  moveaxis: "default", // Drag direction: default | vertical | horizontal.
58
- hoverthreshold: 0, // Vertical threshold (0..0.5) around hovered item center.
66
+ hoverthreshold: 0.25, // Half-height of the central child-drop zone (0.05..0.45).
59
67
  neighborchangethreshold: 0, // Percentage (0..49) of entering adjacent item before position changes.
60
68
  showplaceholder: true, // Show placeholder during drag.
61
69
  group: "",
@@ -101,8 +109,10 @@ class VGNestable extends BaseModule {
101
109
  this._isDragging = false;
102
110
  this._startSnapshot = "";
103
111
  this._sourceInstance = this;
104
- this._lastDropInstance = this;
105
- this._activeDropList = null;
112
+ this._lastDropInstance = this;
113
+ this._activeDropList = null;
114
+ this._activeDropItem = null;
115
+ this._dragBaseDepth = 1;
106
116
 
107
117
  this._mouse = {
108
118
  startX: 0,
@@ -255,8 +265,9 @@ class VGNestable extends BaseModule {
255
265
  ) || null;
256
266
  }
257
267
 
258
- _canAcceptItem(item, sourceInstance) {
259
- const accept = this._params?.accept;
268
+ _canAcceptItem(item, sourceInstance) {
269
+ if (this._isTreeDisabled()) return false;
270
+ const accept = this._params?.accept;
260
271
  if (typeof accept !== "function") return true;
261
272
  try {
262
273
  return !!accept(item, sourceInstance, this);
@@ -266,14 +277,21 @@ class VGNestable extends BaseModule {
266
277
  }
267
278
  }
268
279
 
269
- refresh() {
270
- this._getItems().forEach((item) => {
271
- const handle = this._ensureItemLayout(item);
272
-
273
- if (handle) {
274
- handle.style.cursor = "grab";
275
- handle.style.userSelect = "none";
276
- handle.style.touchAction = "none";
280
+ refresh() {
281
+ const treeDisabled = this._isTreeDisabled();
282
+ this._element.classList.toggle(CLASS_DISABLED, treeDisabled);
283
+ this._element.setAttribute("aria-disabled", treeDisabled ? "true" : "false");
284
+
285
+ this._getItems().forEach((item) => {
286
+ const handle = this._ensureItemLayout(item);
287
+ const dragDisabled = this._isItemDragDisabled(item);
288
+ item.classList.toggle(CLASS_ITEM_DISABLED, dragDisabled);
289
+
290
+ if (handle) {
291
+ handle.style.cursor = dragDisabled ? "not-allowed" : "grab";
292
+ handle.style.userSelect = "none";
293
+ handle.style.touchAction = "none";
294
+ handle.setAttribute("aria-disabled", dragDisabled ? "true" : "false");
277
295
 
278
296
  if (!["BUTTON", "A", "INPUT"].includes(handle.tagName)) {
279
297
  handle.setAttribute("role", "button");
@@ -798,9 +816,12 @@ class VGNestable extends BaseModule {
798
816
  return !!(handle && item.contains(handle));
799
817
  }
800
818
 
801
- _startKeyboardDrag(item) {
802
- if (!item || this._keyboardDraggedItem) {
803
- return;
819
+ _startKeyboardDrag(item) {
820
+ if (!item || this._keyboardDraggedItem || this._isItemDragDisabled(item)) {
821
+ if (item && this._isItemDragDisabled(item)) {
822
+ this._announce("This item cannot be moved.");
823
+ }
824
+ return;
804
825
  }
805
826
 
806
827
  this._keyboardDraggedItem = item;
@@ -895,15 +916,19 @@ class VGNestable extends BaseModule {
895
916
  return true;
896
917
  }
897
918
 
898
- _indentKeyboard(item) {
919
+ _indentKeyboard(item) {
899
920
  const parentCandidate = this._getPreviousItem(item);
900
921
  if (!parentCandidate || parentCandidate === item || item.contains(parentCandidate)) {
901
922
  this._announce("Cannot nest here.");
902
923
  return false;
903
924
  }
904
925
 
905
- const childList = this._getOrCreateChildList(parentCandidate);
906
- if (this._isDepthExceeded(childList, item)) {
926
+ const childList = this._getOrCreateChildList(parentCandidate);
927
+ if (this._isListDisabled(childList)) {
928
+ this._announce("This group cannot be changed.");
929
+ return false;
930
+ }
931
+ if (this._isDepthExceeded(childList, item)) {
907
932
  this._announce("Maximum nesting depth reached.");
908
933
  return false;
909
934
  }
@@ -949,15 +974,18 @@ class VGNestable extends BaseModule {
949
974
  return "Picked up item. Use arrow keys to move, Enter or Space to drop, Escape to cancel.";
950
975
  }
951
976
 
952
- _startInteraction(target, clientX, clientY, event) {
977
+ _startInteraction(target, clientX, clientY, event) {
953
978
  if (this._keyboardDraggedItem) {
954
979
  this._clearKeyboardDragState();
955
980
  }
956
981
 
957
982
  const item = target?.closest?.(this._params.itemselector);
958
- if (!item || !this._rootList.contains(item)) {
959
- return;
960
- }
983
+ if (!item || !this._rootList.contains(item)) {
984
+ return;
985
+ }
986
+ if (this._isItemDragDisabled(item)) {
987
+ return;
988
+ }
961
989
 
962
990
  const handleSelector = this._params.handleselector;
963
991
  if (handleSelector) {
@@ -1011,29 +1039,41 @@ class VGNestable extends BaseModule {
1011
1039
  this._moveDragElement(this._mouse.x, this._mouse.y);
1012
1040
 
1013
1041
  const pointerTarget = this._getPointerTarget(this._mouse.x, this._mouse.y);
1014
- if (!pointerTarget) {
1015
- this._setDropListState(null);
1016
- return;
1017
- }
1018
-
1019
- if (pointerTarget.closest(`.${CLASS_PLACEHOLDER}`)) {
1020
- return;
1021
- }
1042
+ if (!pointerTarget) {
1043
+ this._setDropListState(null);
1044
+ this._setDropItemState(null);
1045
+ return;
1046
+ }
1047
+
1048
+ const pointerPlaceholder = pointerTarget.closest(`.${CLASS_PLACEHOLDER}`);
1049
+ if (pointerPlaceholder) {
1050
+ const targetInstance = this._findOwnerInstanceByElement(pointerPlaceholder) || this._currentTargetInstance || this;
1051
+ this._tryIndentFromPlaceholder(this._mouse.x, targetInstance);
1052
+ return;
1053
+ }
1022
1054
 
1023
1055
  const targetInstance = this._findOwnerInstanceByElement(pointerTarget) || this;
1024
1056
  const hoveredItem = pointerTarget.closest(targetInstance._params.itemselector);
1025
- const list = this._resolveDropList(pointerTarget, hoveredItem, targetInstance);
1026
- if (!list || !targetInstance._rootList.contains(list)) {
1027
- this._setDropListState(null);
1028
- return;
1029
- }
1030
-
1031
- if (!targetInstance._canAcceptItem(this._draggedItem, this._sourceInstance)) {
1032
- this._setDropListState(list, true);
1033
- return;
1034
- }
1035
-
1036
- const mode = this._resolveMode(this._mouse.x, this._mouse.y, hoveredItem, targetInstance._params);
1057
+ const list = this._resolveDropList(pointerTarget, hoveredItem, targetInstance);
1058
+ if (!list || !targetInstance._rootList.contains(list)) {
1059
+ this._setDropListState(null);
1060
+ this._setDropItemState(null);
1061
+ return;
1062
+ }
1063
+ const mode = this._resolveMode(this._mouse.x, this._mouse.y, hoveredItem, targetInstance._params);
1064
+ if (targetInstance._isListDisabled(list)) {
1065
+ this._setDropListState(list, true);
1066
+ this._setDropItemState(hoveredItem, mode, true);
1067
+ return;
1068
+ }
1069
+
1070
+ if (!targetInstance._canAcceptItem(this._draggedItem, this._sourceInstance)) {
1071
+ this._setDropListState(list, true);
1072
+ this._setDropItemState(hoveredItem, mode, true);
1073
+ return;
1074
+ }
1075
+
1076
+ this._setDropItemState(hoveredItem, mode);
1037
1077
  this._emit("move", {
1038
1078
  item: this._draggedItem,
1039
1079
  hoveredItem,
@@ -1044,9 +1084,9 @@ class VGNestable extends BaseModule {
1044
1084
  y: this._mouse.y
1045
1085
  }
1046
1086
  });
1047
- if (mode === "keep") {
1048
- this._setDropListState(list);
1049
- return;
1087
+ if (mode === "keep") {
1088
+ this._setDropListState(list);
1089
+ return;
1050
1090
  }
1051
1091
 
1052
1092
  if (mode === "child") {
@@ -1071,16 +1111,18 @@ class VGNestable extends BaseModule {
1071
1111
  }
1072
1112
  }
1073
1113
 
1074
- if (!parentCandidate) {
1075
- this._setDropListState(null);
1076
- return;
1077
- }
1114
+ if (!parentCandidate) {
1115
+ this._setDropListState(null);
1116
+ this._setDropItemState(null);
1117
+ return;
1118
+ }
1078
1119
 
1079
1120
  const childList = targetInstance._getOrCreateChildList(parentCandidate);
1080
- if (targetInstance._isDepthExceeded(childList, this._draggedItem)) {
1081
- this._setDropListState(childList, true);
1082
- return;
1083
- }
1121
+ if (targetInstance._isDepthExceeded(childList, this._draggedItem)) {
1122
+ this._setDropListState(childList, true);
1123
+ this._setDropItemState(parentCandidate, mode, true);
1124
+ return;
1125
+ }
1084
1126
 
1085
1127
  this._placePlaceholder(childList, null);
1086
1128
  this._setDropListState(childList);
@@ -1090,16 +1132,18 @@ class VGNestable extends BaseModule {
1090
1132
  }
1091
1133
 
1092
1134
  if (hoveredItem) {
1093
- if (hoveredItem === this._draggedItem || this._draggedItem.contains(hoveredItem)) {
1094
- this._setDropListState(null);
1095
- return;
1096
- }
1135
+ if (hoveredItem === this._draggedItem || this._draggedItem.contains(hoveredItem)) {
1136
+ this._setDropListState(null);
1137
+ this._setDropItemState(null);
1138
+ return;
1139
+ }
1097
1140
 
1098
1141
  const targetList = hoveredItem.parentElement;
1099
- if (targetInstance._isDepthExceeded(targetList, this._draggedItem)) {
1100
- this._setDropListState(targetList, true);
1101
- return;
1102
- }
1142
+ if (targetInstance._isDepthExceeded(targetList, this._draggedItem)) {
1143
+ this._setDropListState(targetList, true);
1144
+ this._setDropItemState(hoveredItem, mode, true);
1145
+ return;
1146
+ }
1103
1147
 
1104
1148
  if (mode === "before") {
1105
1149
  this._placePlaceholder(targetList, hoveredItem);
@@ -1240,9 +1284,10 @@ class VGNestable extends BaseModule {
1240
1284
 
1241
1285
  this._isDragging = true;
1242
1286
  this._startSnapshot = JSON.stringify(this.serialize());
1243
- this._sourceInstance = this;
1244
- this._sourceRoot = this._rootList;
1245
- this._currentTargetInstance = this;
1287
+ this._sourceInstance = this;
1288
+ this._sourceRoot = this._rootList;
1289
+ this._dragBaseDepth = this._getListDepth(this._draggedItem.parentElement);
1290
+ this._currentTargetInstance = this;
1246
1291
  this._lastDropInstance = this;
1247
1292
 
1248
1293
  this._placeholder = this._createPlaceholder(this._draggedItem);
@@ -1336,66 +1381,201 @@ class VGNestable extends BaseModule {
1336
1381
  return targetInstance._rootList;
1337
1382
  }
1338
1383
 
1339
- _resolveMode(pointerX, pointerY, hoveredItem, params = this._params) {
1340
- if (!hoveredItem) {
1341
- return "append";
1342
- }
1343
-
1344
- const rect = hoveredItem.getBoundingClientRect();
1345
- const offsetY = pointerY - rect.top;
1346
- // Use the dragged item's original left edge as baseline, not the pointer-down X.
1347
- // This makes "shift right to nest" work reliably regardless of where inside the handle the user grabbed.
1348
- const baseX = Number.isFinite(this._mouse.startItemX) ? this._mouse.startItemX : this._mouse.startX;
1349
- const offsetX = pointerX - baseX;
1350
- const indentValue = parseFloat(params.indent);
1351
- const indent = Number.isFinite(indentValue) ? indentValue : 0;
1352
- const moveAxis = this._getMoveAxis(params);
1353
- const allowVertical = moveAxis !== "horizontal";
1354
- const allowHorizontal = moveAxis !== "vertical";
1355
- const neighborThresholdPercent = Math.max(
1356
- 0,
1357
- Math.min(49, Number(params.neighborchangethreshold || 0))
1358
- );
1359
-
1360
- if (neighborThresholdPercent > 0) {
1361
- const edgeRatio = neighborThresholdPercent / 100;
1362
- const topBorder = rect.height * edgeRatio;
1363
- const bottomBorder = rect.height * (1 - edgeRatio);
1364
-
1365
- if (allowHorizontal && offsetX > indent) {
1366
- return "child";
1367
- }
1368
-
1369
- if (allowVertical && offsetY <= topBorder) {
1370
- return "before";
1371
- }
1372
-
1373
- if (allowVertical && offsetY >= bottomBorder) {
1374
- return "after";
1375
- }
1376
-
1377
- return "keep";
1378
- }
1379
-
1380
- const threshold = Math.min(
1381
- 0.45,
1382
- Math.max(0.05, Number(params.hoverthreshold || 0.18))
1383
- );
1384
-
1385
- if (allowHorizontal && offsetX > indent) {
1386
- return "child";
1387
- }
1388
-
1389
- if (allowVertical && offsetY < rect.height * (0.5 - threshold)) {
1390
- return "before";
1391
- }
1392
-
1393
- if (allowVertical && offsetY > rect.height * (0.5 + threshold)) {
1394
- return "after";
1395
- }
1396
-
1397
- return "keep";
1398
- }
1384
+ _resolveMode(pointerX, pointerY, hoveredItem, params = this._params) {
1385
+ if (!hoveredItem) {
1386
+ return "append";
1387
+ }
1388
+
1389
+ const rect = this._getItemDropRect(hoveredItem);
1390
+ const offsetY = pointerY - rect.top;
1391
+ // Measure indentation against the hovered row. Nested lists and wide subtrees must not
1392
+ // change the pointer target geometry or force a large horizontal mouse gesture.
1393
+ const offsetX = pointerX - rect.left;
1394
+ const indentValue = parseFloat(params.indent);
1395
+ const indent = Number.isFinite(indentValue) ? indentValue : 0;
1396
+ const grabOffsetX = Math.max(0, Number(this._mouse.grabOffsetX) || 0);
1397
+ const nestTriggerX = grabOffsetX + indent;
1398
+ const moveAxis = this._getMoveAxis(params);
1399
+ const allowVertical = moveAxis !== "horizontal";
1400
+ const allowHorizontal = moveAxis !== "vertical";
1401
+ const neighborThresholdPercent = Math.max(
1402
+ 0,
1403
+ Math.min(49, Number(params.neighborchangethreshold || 0))
1404
+ );
1405
+
1406
+ if (neighborThresholdPercent > 0) {
1407
+ const edgeRatio = neighborThresholdPercent / 100;
1408
+ const topBorder = rect.height * edgeRatio;
1409
+ const bottomBorder = rect.height * (1 - edgeRatio);
1410
+
1411
+ if (allowHorizontal && offsetX > nestTriggerX && offsetY > topBorder && offsetY < bottomBorder) {
1412
+ return "child";
1413
+ }
1414
+
1415
+ if (allowVertical && offsetY <= topBorder) {
1416
+ return "before";
1417
+ }
1418
+
1419
+ if (allowVertical && offsetY >= bottomBorder) {
1420
+ return "after";
1421
+ }
1422
+
1423
+ return "keep";
1424
+ }
1425
+
1426
+ const threshold = Math.min(
1427
+ 0.45,
1428
+ Math.max(0.05, Number(params.hoverthreshold || 0.25))
1429
+ );
1430
+
1431
+ if (
1432
+ allowHorizontal &&
1433
+ offsetX > nestTriggerX &&
1434
+ offsetY >= rect.height * (0.5 - threshold) &&
1435
+ offsetY <= rect.height * (0.5 + threshold)
1436
+ ) {
1437
+ return "child";
1438
+ }
1439
+
1440
+ if (allowVertical && offsetY < rect.height * (0.5 - threshold)) {
1441
+ return "before";
1442
+ }
1443
+
1444
+ if (allowVertical && offsetY > rect.height * (0.5 + threshold)) {
1445
+ return "after";
1446
+ }
1447
+
1448
+ return "keep";
1449
+ }
1450
+
1451
+ _getItemDropRect(item) {
1452
+ const inner = item?.querySelector?.(`:scope > .${CLASS_INNER}`);
1453
+ return (inner || item).getBoundingClientRect();
1454
+ }
1455
+
1456
+ _tryIndentFromPlaceholder(pointerX, targetInstance = this) {
1457
+ if (!this._placeholder || this._getMoveAxis(targetInstance._params) === "vertical") {
1458
+ return false;
1459
+ }
1460
+
1461
+ if (
1462
+ !targetInstance._canAcceptItem(this._draggedItem, this._sourceInstance) ||
1463
+ targetInstance._isListDisabled(this._placeholder.parentElement)
1464
+ ) {
1465
+ this._setDropListState(this._placeholder.parentElement, true);
1466
+ this._setDropItemState(null);
1467
+ return false;
1468
+ }
1469
+
1470
+ const indentValue = parseFloat(targetInstance._params.indent);
1471
+ const indent = Number.isFinite(indentValue) ? Math.max(1, indentValue) : 18;
1472
+ const horizontalDistance = Math.max(0, pointerX - this._mouse.startX);
1473
+ const requestedDepth = this._dragBaseDepth + Math.floor(horizontalDistance / indent);
1474
+ let currentList = this._placeholder.parentElement;
1475
+ let currentDepth = targetInstance._getListDepth(currentList);
1476
+ let parentCandidate = null;
1477
+
1478
+ // Moving left promotes the placeholder one level at a time.
1479
+ while (currentDepth > requestedDepth) {
1480
+ const currentParent = currentList.closest(targetInstance._params.itemselector);
1481
+ const parentList = currentParent?.parentElement;
1482
+ if (!currentParent || !parentList) {
1483
+ break;
1484
+ }
1485
+ this._placePlaceholder(parentList, currentParent.nextSibling);
1486
+ currentList = parentList;
1487
+ currentDepth = targetInstance._getListDepth(currentList);
1488
+ }
1489
+
1490
+ // Every additional horizontal step nests under the previous item on that level.
1491
+ while (currentDepth < requestedDepth) {
1492
+ parentCandidate = targetInstance._getPreviousItem(this._placeholder);
1493
+ while (parentCandidate && (parentCandidate === this._draggedItem || this._draggedItem.contains(parentCandidate))) {
1494
+ parentCandidate = targetInstance._getPreviousItem(parentCandidate);
1495
+ }
1496
+ if (!parentCandidate) {
1497
+ break;
1498
+ }
1499
+
1500
+ const childList = targetInstance._getOrCreateChildList(parentCandidate);
1501
+ if (targetInstance._isListDisabled(childList)) {
1502
+ this._setDropListState(childList, true);
1503
+ this._setDropItemState(parentCandidate, "child", true);
1504
+ return false;
1505
+ }
1506
+ if (targetInstance._isDepthExceeded(childList, this._draggedItem)) {
1507
+ this._setDropListState(childList, true);
1508
+ this._setDropItemState(parentCandidate, "child", true);
1509
+ return false;
1510
+ }
1511
+
1512
+ this._placePlaceholder(childList, null);
1513
+ currentList = childList;
1514
+ currentDepth = targetInstance._getListDepth(currentList);
1515
+ }
1516
+
1517
+ const currentParent = currentList.closest(targetInstance._params.itemselector);
1518
+ const nextCandidate = targetInstance._getPreviousItem(this._placeholder);
1519
+ const stepProgress = (horizontalDistance % indent) / indent;
1520
+ if (nextCandidate && nextCandidate !== this._draggedItem && stepProgress >= 0.35) {
1521
+ this._setDropItemState(nextCandidate, "attachable");
1522
+ parentCandidate = nextCandidate;
1523
+ } else if (currentParent) {
1524
+ this._setDropItemState(currentParent, "child");
1525
+ parentCandidate = currentParent;
1526
+ } else if (nextCandidate && nextCandidate !== this._draggedItem) {
1527
+ this._setDropItemState(nextCandidate, "attachable");
1528
+ parentCandidate = nextCandidate;
1529
+ } else {
1530
+ this._setDropItemState(null);
1531
+ }
1532
+
1533
+ this._setDropListState(currentList);
1534
+ this._currentTargetInstance = targetInstance;
1535
+ this._lastDropInstance = targetInstance;
1536
+ this._emit("move", {
1537
+ item: this._draggedItem,
1538
+ hoveredItem: parentCandidate,
1539
+ mode: currentDepth > this._dragBaseDepth ? "child" : "keep",
1540
+ targetInstance,
1541
+ mouse: { x: this._mouse.x, y: this._mouse.y }
1542
+ });
1543
+ return currentDepth > this._dragBaseDepth;
1544
+ }
1545
+
1546
+ _hasDisabledAttribute(element) {
1547
+ if (!element || !this._params.disabledattribute) {
1548
+ return false;
1549
+ }
1550
+ const value = element.getAttribute(this._params.disabledattribute);
1551
+ return value !== null && normalizeData(value === "" ? "true" : value) === true;
1552
+ }
1553
+
1554
+ _isTreeDisabled() {
1555
+ return normalizeData(this._params.disabled) === true || this._hasDisabledAttribute(this._element);
1556
+ }
1557
+
1558
+ _isListDisabled(list) {
1559
+ if (this._isTreeDisabled()) {
1560
+ return true;
1561
+ }
1562
+
1563
+ let currentList = list;
1564
+ while (currentList && this._rootList.contains(currentList)) {
1565
+ if (currentList.matches(this._params.listselector) && this._hasDisabledAttribute(currentList)) {
1566
+ return true;
1567
+ }
1568
+ if (currentList === this._rootList) {
1569
+ break;
1570
+ }
1571
+ currentList = currentList.parentElement?.closest(this._params.listselector) || null;
1572
+ }
1573
+ return false;
1574
+ }
1575
+
1576
+ _isItemDragDisabled(item) {
1577
+ return this._isTreeDisabled() || this._hasDisabledAttribute(item) || this._isListDisabled(item?.parentElement);
1578
+ }
1399
1579
 
1400
1580
  _getPreviousItem(item) {
1401
1581
  let sibling = item?.previousElementSibling || null;
@@ -1560,7 +1740,7 @@ _resolveMode(pointerX, pointerY, hoveredItem, params = this._params) {
1560
1740
  }
1561
1741
  }
1562
1742
 
1563
- _setDropListState(list, denied = false) {
1743
+ _setDropListState(list, denied = false) {
1564
1744
  if (this._activeDropList && this._activeDropList !== list) {
1565
1745
  this._activeDropList.classList.remove(CLASS_DROP_TARGET, CLASS_DROP_DENIED);
1566
1746
  }
@@ -1572,11 +1752,47 @@ _resolveMode(pointerX, pointerY, hoveredItem, params = this._params) {
1572
1752
 
1573
1753
  list.classList.add(denied ? CLASS_DROP_DENIED : CLASS_DROP_TARGET);
1574
1754
  list.classList.remove(denied ? CLASS_DROP_TARGET : CLASS_DROP_DENIED);
1575
- this._activeDropList = list;
1576
- }
1577
-
1578
- _clearDragState() {
1579
- this._setDropListState(null);
1755
+ this._activeDropList = list;
1756
+ }
1757
+
1758
+ _setDropItemState(item, mode = "", denied = false) {
1759
+ const stateClasses = [
1760
+ CLASS_DROP_BEFORE,
1761
+ CLASS_DROP_ATTACHABLE,
1762
+ CLASS_DROP_INSIDE,
1763
+ CLASS_DROP_AFTER,
1764
+ CLASS_DROP_DENIED
1765
+ ];
1766
+
1767
+ if (this._activeDropItem && this._activeDropItem !== item) {
1768
+ this._activeDropItem.classList.remove(...stateClasses);
1769
+ }
1770
+
1771
+ if (!item || !["before", "attachable", "child", "after"].includes(mode)) {
1772
+ if (this._activeDropItem) {
1773
+ this._activeDropItem.classList.remove(...stateClasses);
1774
+ }
1775
+ this._activeDropItem = null;
1776
+ return;
1777
+ }
1778
+
1779
+ item.classList.remove(...stateClasses);
1780
+ const modeClass = {
1781
+ before: CLASS_DROP_BEFORE,
1782
+ attachable: CLASS_DROP_ATTACHABLE,
1783
+ child: CLASS_DROP_INSIDE,
1784
+ after: CLASS_DROP_AFTER
1785
+ };
1786
+ item.classList.add(modeClass[mode]);
1787
+ if (denied) {
1788
+ item.classList.add(CLASS_DROP_DENIED);
1789
+ }
1790
+ this._activeDropItem = item;
1791
+ }
1792
+
1793
+ _clearDragState() {
1794
+ this._setDropListState(null);
1795
+ this._setDropItemState(null);
1580
1796
 
1581
1797
  if (this._draggedItem) {
1582
1798
  this._draggedItem.classList.remove(CLASS_ITEM_DRAGGING);
@@ -1609,8 +1825,9 @@ _resolveMode(pointerX, pointerY, hoveredItem, params = this._params) {
1609
1825
  this._currentTargetInstance = this;
1610
1826
  this._lastDropInstance = this;
1611
1827
  this._activePointerId = null;
1612
- this._activeTouchId = null;
1613
- }
1828
+ this._activeTouchId = null;
1829
+ this._dragBaseDepth = 1;
1830
+ }
1614
1831
 
1615
1832
  _ensureLiveRegion() {
1616
1833
  if (!this._element || this._liveRegion) {
@@ -11,9 +11,16 @@ $nestable-map: (
11
11
  list-nested-border-left: 1px dashed rgba(0, 0, 0, .12),
12
12
 
13
13
  item-margin: .35rem 0,
14
- item-transition: opacity .15s ease,
15
- item-dragging-opacity: .85,
16
- item-ghost-opacity: .3,
14
+ item-transition: opacity .15s ease,
15
+ item-dragging-opacity: .85,
16
+ item-ghost-opacity: .3,
17
+ item-drop-line: #0d6efd,
18
+ item-drop-attachable-outline: 1px dashed rgba(13, 110, 253, .55),
19
+ item-drop-inside-bg: rgba(13, 110, 253, .1),
20
+ item-drop-inside-border: rgba(13, 110, 253, .72),
21
+ item-drop-denied: #dc3545,
22
+ item-disabled-bg: rgba(0, 0, 0, .025),
23
+ item-disabled-handle-color: rgba(0, 0, 0, .28),
17
24
 
18
25
  inner-gap: .5rem,
19
26
  inner-min-height: 40px,
@@ -27,7 +34,7 @@ $nestable-map: (
27
34
  handle-bg: rgba(0, 0, 0, .03),
28
35
  handle-border-radius: .35rem,
29
36
  handle-cursor: grab,
30
- handle-active-cursor: grabbing,
37
+ handle-active-cursor: grabbing,
31
38
 
32
39
  toggle-size: 1.85rem,
33
40
  toggle-border: 1px solid rgba(0, 0, 0, .12),
@@ -54,7 +61,7 @@ $nestable-map: (
54
61
  placeholder-margin: .35rem 0,
55
62
  placeholder-min-height: 40px,
56
63
 
57
- drag-element-opacity: .92,
58
- drag-element-transform: rotate(.5deg),
59
- drag-element-shadow: 0 8px 22px rgba(0, 0, 0, .18)
60
- );
64
+ drag-element-opacity: 1,
65
+ drag-element-transform: scale(1.01),
66
+ drag-element-shadow: 0 12px 30px rgba(0, 0, 0, .2)
67
+ );