primevue 4.3.9 → 4.4.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.
Files changed (101) hide show
  1. package/autocomplete/AutoComplete.vue +19 -4
  2. package/autocomplete/BaseAutoComplete.vue +4 -0
  3. package/autocomplete/index.d.ts +20 -0
  4. package/autocomplete/index.mjs +35 -8
  5. package/autocomplete/index.mjs.map +1 -1
  6. package/autocomplete/style/index.d.ts +4 -0
  7. package/autocomplete/style/index.mjs +3 -1
  8. package/autocomplete/style/index.mjs.map +1 -1
  9. package/cascadeselect/CascadeSelect.vue +1 -1
  10. package/cascadeselect/index.mjs +1 -1
  11. package/cascadeselect/index.mjs.map +1 -1
  12. package/checkbox/Checkbox.vue +15 -2
  13. package/checkbox/index.mjs +14 -2
  14. package/checkbox/index.mjs.map +1 -1
  15. package/colorpicker/ColorPicker.vue +3 -4
  16. package/colorpicker/index.mjs +3 -3
  17. package/colorpicker/index.mjs.map +1 -1
  18. package/confirmdialog/ConfirmDialog.vue +1 -1
  19. package/confirmdialog/index.d.ts +5 -0
  20. package/confirmdialog/index.mjs +3 -2
  21. package/confirmdialog/index.mjs.map +1 -1
  22. package/datatable/ColumnFilter.vue +1 -1
  23. package/datatable/DataTable.vue +2 -2
  24. package/datatable/HeaderCheckbox.vue +3 -3
  25. package/datatable/index.mjs +13 -4
  26. package/datatable/index.mjs.map +1 -1
  27. package/datepicker/BaseDatePicker.vue +8 -0
  28. package/datepicker/DatePicker.vue +225 -105
  29. package/datepicker/index.d.ts +43 -2
  30. package/datepicker/index.mjs +303 -186
  31. package/datepicker/index.mjs.map +1 -1
  32. package/datepicker/style/index.d.ts +4 -0
  33. package/datepicker/style/index.mjs +5 -2
  34. package/datepicker/style/index.mjs.map +1 -1
  35. package/drawer/BaseDrawer.vue +4 -0
  36. package/drawer/Drawer.vue +5 -5
  37. package/drawer/index.d.ts +5 -0
  38. package/drawer/index.mjs +11 -7
  39. package/drawer/index.mjs.map +1 -1
  40. package/editor/Editor.vue +5 -1
  41. package/editor/index.mjs +5 -0
  42. package/editor/index.mjs.map +1 -1
  43. package/image/index.d.ts +5 -11
  44. package/inputmask/InputMask.vue +1 -2
  45. package/inputmask/index.mjs +1 -1
  46. package/inputmask/index.mjs.map +1 -1
  47. package/inputnumber/BaseInputNumber.vue +4 -0
  48. package/inputnumber/InputNumber.vue +30 -5
  49. package/inputnumber/index.d.ts +20 -0
  50. package/inputnumber/index.mjs +45 -7
  51. package/inputnumber/index.mjs.map +1 -1
  52. package/inputnumber/style/index.mjs +1 -0
  53. package/inputnumber/style/index.mjs.map +1 -1
  54. package/inputotp/InputOtp.vue +7 -3
  55. package/inputotp/index.mjs +6 -3
  56. package/inputotp/index.mjs.map +1 -1
  57. package/listbox/Listbox.vue +1 -1
  58. package/listbox/index.mjs +1 -1
  59. package/listbox/index.mjs.map +1 -1
  60. package/menu/Menu.vue +2 -2
  61. package/menu/index.mjs +1 -1
  62. package/menu/index.mjs.map +1 -1
  63. package/multiselect/MultiSelect.vue +10 -6
  64. package/multiselect/index.mjs +15 -11
  65. package/multiselect/index.mjs.map +1 -1
  66. package/package.json +5 -5
  67. package/panel/Panel.vue +1 -1
  68. package/panel/index.d.ts +4 -0
  69. package/panel/index.mjs +2 -1
  70. package/panel/index.mjs.map +1 -1
  71. package/password/BasePassword.vue +4 -0
  72. package/password/Password.vue +14 -2
  73. package/password/index.d.ts +20 -0
  74. package/password/index.mjs +26 -3
  75. package/password/index.mjs.map +1 -1
  76. package/password/style/index.d.ts +4 -0
  77. package/password/style/index.mjs +1 -0
  78. package/password/style/index.mjs.map +1 -1
  79. package/select/Select.vue +2 -1
  80. package/select/index.mjs +2 -1
  81. package/select/index.mjs.map +1 -1
  82. package/speeddial/SpeedDial.vue +1 -1
  83. package/speeddial/index.mjs +1 -1
  84. package/speeddial/index.mjs.map +1 -1
  85. package/splitbutton/SplitButton.vue +1 -1
  86. package/splitbutton/index.mjs +1 -1
  87. package/splitbutton/index.mjs.map +1 -1
  88. package/tree/BaseTree.vue +20 -0
  89. package/tree/Tree.vue +236 -4
  90. package/tree/TreeNode.vue +295 -3
  91. package/tree/index.d.ts +140 -0
  92. package/tree/index.mjs +637 -27
  93. package/tree/index.mjs.map +1 -1
  94. package/tree/style/index.mjs +9 -4
  95. package/tree/style/index.mjs.map +1 -1
  96. package/treenode/index.d.ts +12 -0
  97. package/treeselect/TreeSelect.vue +3 -2
  98. package/treeselect/index.mjs +6 -5
  99. package/treeselect/index.mjs.map +1 -1
  100. package/umd/primevue.min.js +1 -1
  101. package/web-types.json +1 -1
package/tree/Tree.vue CHANGED
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :class="cx('root')" :data-p="containerDataP" v-bind="ptmi('root')">
2
+ <div :class="cx('root')" @dragover="onDragOver" @dragenter="onDragEnter" @dragleave="onDragLeave" @drop="onDrop" :data-p="containerDataP" v-bind="ptmi('root')">
3
3
  <template v-if="loading && loadingMode === 'mask'">
4
4
  <div :class="cx('mask')" v-bind="ptm('mask')">
5
5
  <slot name="loadingicon" :class="cx('loadingIcon')">
@@ -19,11 +19,12 @@
19
19
  </IconField>
20
20
  <div :class="cx('wrapper')" :style="{ maxHeight: scrollHeight }" :data-p="wrapperDataP" v-bind="ptm('wrapper')">
21
21
  <slot name="header" :value="value" :expandedKeys="expandedKeys" :selectionKeys="selectionKeys" />
22
- <ul :class="cx('rootChildren')" role="tree" :aria-labelledby="ariaLabelledby" :aria-label="ariaLabel" v-bind="ptm('rootChildren')">
22
+ <ul v-if="!empty" :class="cx('rootChildren')" role="tree" :aria-labelledby="ariaLabelledby" :aria-label="ariaLabel" v-bind="ptm('rootChildren')">
23
23
  <TreeNode
24
24
  v-for="(node, index) of valueToRender"
25
25
  :key="node.key"
26
26
  :node="node"
27
+ :rootNodes="valueToRender"
27
28
  :templates="$slots"
28
29
  :level="level + 1"
29
30
  :index="index"
@@ -34,10 +35,23 @@
34
35
  :selectionKeys="selectionKeys"
35
36
  @checkbox-change="onCheckboxChange"
36
37
  :loadingMode="loadingMode"
38
+ :draggableNodes="draggableNodes"
39
+ :droppableNodes="droppableNodes"
40
+ :draggableScope="draggableScope"
41
+ :validateDrop="validateDrop"
42
+ @node-drop="onNodeDrop"
43
+ @node-dragenter="onNodeDragEnter"
44
+ @node-dragleave="onNodeDragLeave"
45
+ @value-change="onValueChanged"
37
46
  :unstyled="unstyled"
38
47
  :pt="pt"
39
48
  ></TreeNode>
40
49
  </ul>
50
+ <div v-else-if="empty && !$pcTreeSelect" :class="cx('emptyMessage')" v-bind="ptm('emptyMessage')">
51
+ <slot name="empty">
52
+ {{ emptyMessageText }}
53
+ </slot>
54
+ </div>
41
55
  <slot name="footer" :value="value" :expandedKeys="expandedKeys" :selectionKeys="selectionKeys" />
42
56
  </div>
43
57
  </div>
@@ -52,24 +66,65 @@ import IconField from 'primevue/iconfield';
52
66
  import InputIcon from 'primevue/inputicon';
53
67
  import InputText from 'primevue/inputtext';
54
68
  import BaseTree from './BaseTree.vue';
69
+ import { useTreeDragDropService } from './TreeDragDropService';
55
70
  import TreeNode from './TreeNode.vue';
56
71
 
57
72
  export default {
58
73
  name: 'Tree',
59
74
  extends: BaseTree,
60
75
  inheritAttrs: false,
61
- emits: ['node-expand', 'node-collapse', 'update:expandedKeys', 'update:selectionKeys', 'node-select', 'node-unselect', 'filter'],
76
+ emits: ['node-expand', 'node-collapse', 'update:expandedKeys', 'update:selectionKeys', 'node-select', 'node-unselect', 'filter', 'node-drop', 'node-dragenter', 'node-dragleave', 'update:value', 'drag-enter', 'drag-leave'],
62
77
  data() {
63
78
  return {
64
79
  d_expandedKeys: this.expandedKeys || {},
65
- filterValue: null
80
+ filterValue: null,
81
+ dragNode: null,
82
+ dragNodeSubNodes: null,
83
+ dragNodeIndex: null,
84
+ dragNodeScope: null,
85
+ dragHover: null
66
86
  };
67
87
  },
88
+ inject: {
89
+ $pcTreeSelect: { default: null }
90
+ },
91
+ dragDropService: null,
92
+ dragStartCleanup: null,
93
+ dragStopCleanup: null,
68
94
  watch: {
69
95
  expandedKeys(newValue) {
70
96
  this.d_expandedKeys = newValue;
71
97
  }
72
98
  },
99
+ mounted() {
100
+ if (this.droppableNodes) {
101
+ this.dragDropService = useTreeDragDropService();
102
+
103
+ this.dragStartCleanup = this.dragDropService.onDragStart((event) => {
104
+ this.dragNode = event.node;
105
+ this.dragNodeSubNodes = event.subNodes;
106
+ this.dragNodeIndex = event.index;
107
+ this.dragNodeScope = event.scope;
108
+ });
109
+
110
+ this.dragStopCleanup = this.dragDropService.onDragStop(() => {
111
+ this.dragNode = null;
112
+ this.dragNodeSubNodes = null;
113
+ this.dragNodeIndex = null;
114
+ this.dragNodeScope = null;
115
+ this.dragHover = false;
116
+ });
117
+ }
118
+ },
119
+ beforeUnmount() {
120
+ if (this.dragStartCleanup) {
121
+ this.dragStartCleanup();
122
+ }
123
+
124
+ if (this.dragStopCleanup) {
125
+ this.dragStopCleanup();
126
+ }
127
+ },
73
128
  methods: {
74
129
  onNodeToggle(node) {
75
130
  const key = node.key;
@@ -220,6 +275,177 @@ export default {
220
275
  }
221
276
 
222
277
  return matched;
278
+ },
279
+ onNodeDrop(event) {
280
+ this.$emit('node-drop', event);
281
+ },
282
+ onNodeDragEnter(event) {
283
+ this.$emit('node-dragenter', event);
284
+ },
285
+ onNodeDragLeave(event) {
286
+ this.$emit('node-dragleave', event);
287
+ },
288
+ onValueChanged(event) {
289
+ this.dragNodeSubNodes.splice(this.dragNodeIndex, 1);
290
+ this.$emit('update:value', event.nodes);
291
+ },
292
+ allowDrop(dragNode, dropNode, dragNodeScope) {
293
+ if (!dragNode) {
294
+ //prevent random html elements to be dragged
295
+ return false;
296
+ } else if (this.isValidDragScope(dragNodeScope)) {
297
+ let allow = true;
298
+
299
+ if (dropNode) {
300
+ if (dragNode === dropNode) {
301
+ allow = false;
302
+ } else {
303
+ let parent = dropNode.parent;
304
+
305
+ while (parent != null) {
306
+ if (parent === dragNode) {
307
+ allow = false;
308
+
309
+ break;
310
+ }
311
+
312
+ parent = parent.parent;
313
+ }
314
+ }
315
+ }
316
+
317
+ return allow;
318
+ } else {
319
+ return false;
320
+ }
321
+ },
322
+ allowNodeDrop(dropNode) {
323
+ return this.allowDrop(this.dragNode, dropNode, this.dragNodeScope);
324
+ },
325
+ hasCommonScope(dragScope, dropScope) {
326
+ if (dragScope === null && dropScope === null) {
327
+ return true;
328
+ } else if (dragScope === null || dropScope === null) {
329
+ return false;
330
+ }
331
+
332
+ if (typeof dropScope === 'string') {
333
+ if (typeof dragScope === 'string') {
334
+ return dragScope === dropScope;
335
+ } else if (Array.isArray(dragScope)) {
336
+ return dragScope.indexOf(dropScope) !== -1;
337
+ }
338
+ } else if (Array.isArray(dropScope)) {
339
+ if (typeof dragScope === 'string') {
340
+ return dropScope.indexOf(dragScope) !== -1;
341
+ } else if (Array.isArray(dragScope)) {
342
+ for (let ds of dragScope) {
343
+ if (dropScope.indexOf(ds) !== -1) {
344
+ return true;
345
+ }
346
+ }
347
+ return false;
348
+ }
349
+ }
350
+
351
+ return false;
352
+ },
353
+ isValidDragScope(dragScope) {
354
+ if (this.droppableScope === null) {
355
+ return true;
356
+ }
357
+
358
+ return this.hasCommonScope(dragScope, this.droppableScope);
359
+ },
360
+ isSameTreeScope(dragScope) {
361
+ return this.hasCommonScope(dragScope, this.draggableScope);
362
+ },
363
+ onDragOver(event) {
364
+ if (this.droppableNodes && this.allowDrop(this.dragNode, null, this.dragNodeScope)) {
365
+ event.dataTransfer.dropEffect = 'copy';
366
+ } else {
367
+ event.dataTransfer.dropEffect = 'none';
368
+ }
369
+
370
+ event.preventDefault();
371
+ },
372
+ onDragEnter(event) {
373
+ if (this.droppableNodes && this.allowDrop(this.dragNode, null, this.dragNodeScope)) {
374
+ this.dragHover = true;
375
+
376
+ this.$emit('drag-enter', {
377
+ originalEvent: event,
378
+ value: this.value,
379
+ dragNode: this.dragNode,
380
+ dragNodeScope: this.dragNodeScope
381
+ });
382
+ }
383
+ },
384
+ onDragLeave(event) {
385
+ if (this.droppableNodes) {
386
+ let rect = event.currentTarget.getBoundingClientRect();
387
+
388
+ if (event.x >= parseInt(rect.right) || event.x <= parseInt(rect.left) || event.y >= parseInt(rect.bottom) || event.y <= parseInt(rect.top)) {
389
+ this.dragHover = false;
390
+ }
391
+
392
+ this.$emit('drag-leave', {
393
+ originalEvent: event,
394
+ value: this.value,
395
+ dragNode: this.dragNode,
396
+ dragNodeScope: this.dragNodeScope
397
+ });
398
+ }
399
+ },
400
+ processTreeDrop(dragNode, dragNodeIndex) {
401
+ this.dragNodeSubNodes.splice(dragNodeIndex, 1);
402
+ const newValue = [...(this.value || []), dragNode];
403
+ this.$emit('update:value', newValue);
404
+
405
+ this.dragDropService.stopDrag({
406
+ node: dragNode
407
+ });
408
+ },
409
+ onDrop(event) {
410
+ if (this.droppableNodes) {
411
+ event.preventDefault();
412
+ let dragNode = this.dragNode;
413
+
414
+ if (this.allowDrop(dragNode, null, this.dragNodeScope)) {
415
+ let dragNodeIndex = this.dragNodeIndex;
416
+
417
+ if (this.isSameTreeScope(this.dragNodeScope)) {
418
+ this.dragDropService.stopDrag({
419
+ node: dragNode
420
+ });
421
+
422
+ return;
423
+ }
424
+
425
+ if (this.validateDrop) {
426
+ this.$emit('node-drop', {
427
+ originalEvent: event,
428
+ value: this.value,
429
+ dragNode: dragNode,
430
+ dropNode: null,
431
+ index: dragNodeIndex,
432
+ accept: () => {
433
+ this.processTreeDrop(dragNode, dragNodeIndex);
434
+ }
435
+ });
436
+ } else {
437
+ this.$emit('node-drop', {
438
+ originalEvent: event,
439
+ value: this.value,
440
+ dragNode: dragNode,
441
+ dropNode: null,
442
+ index: dragNodeIndex
443
+ });
444
+
445
+ this.processTreeDrop(dragNode, dragNodeIndex);
446
+ }
447
+ }
448
+ }
223
449
  }
224
450
  },
225
451
  computed: {
@@ -247,6 +473,12 @@ export default {
247
473
  if (this.filterValue && this.filterValue.trim().length > 0) return this.filteredValue;
248
474
  else return this.value;
249
475
  },
476
+ empty() {
477
+ return !this.valueToRender || this.valueToRender.length === 0;
478
+ },
479
+ emptyMessageText() {
480
+ return this.$primevue.config?.locale?.emptyMessage || '';
481
+ },
250
482
  containerDataP() {
251
483
  return cn({
252
484
  loading: this.loading,
package/tree/TreeNode.vue CHANGED
@@ -14,7 +14,23 @@
14
14
  @keydown="onKeyDown"
15
15
  v-bind="getPTOptions('node')"
16
16
  >
17
- <div :class="cx('nodeContent')" @click="onClick" @touchend="onTouchEnd" :style="node.style" v-bind="getPTOptions('nodeContent')" :data-p-selected="checkboxMode ? checked : selected" :data-p-selectable="selectable">
17
+ <div v-if="isPrevDropPointActive" :class="cx('dropPoint')" aria-hidden="true" />
18
+ <div
19
+ :class="cx('nodeContent')"
20
+ :style="node.style"
21
+ :draggable="isDraggable"
22
+ @click="onClick"
23
+ @touchend="onTouchEnd"
24
+ @dragstart="onNodeDragStart"
25
+ @dragover="onNodeDragOver"
26
+ @dragenter="onNodeDragEnter"
27
+ @dragleave="onNodeDragLeave"
28
+ @dragend="onNodeDragEnd"
29
+ @drop="onNodeDrop"
30
+ v-bind="getPTOptions('nodeContent')"
31
+ :data-p-selected="checkboxMode ? checked : selected"
32
+ :data-p-selectable="selectable"
33
+ >
18
34
  <button v-ripple type="button" :class="cx('nodeToggleButton')" @click="toggle" tabindex="-1" :data-p-leaf="leaf" v-bind="getPTOptions('nodeToggleButton')">
19
35
  <template v-if="node.loading && loadingMode === 'icon'">
20
36
  <!-- TODO: nodetogglericon deprecated since v4.0-->
@@ -50,11 +66,14 @@
50
66
  <template v-else>{{ label(node) }}</template>
51
67
  </span>
52
68
  </div>
69
+ <div v-if="isNextDropPointActive" :class="cx('dropPoint')" aria-hidden="true" />
53
70
  <ul v-if="hasChildren && expanded" :class="cx('nodeChildren')" role="group" v-bind="ptm('nodeChildren')">
54
71
  <TreeNode
55
72
  v-for="(childNode, index) of node.children"
56
73
  :key="childNode.key"
57
74
  :node="childNode"
75
+ :parentNode="node"
76
+ :rootNodes="rootNodes"
58
77
  :templates="templates"
59
78
  :level="level + 1"
60
79
  :index="index"
@@ -65,6 +84,14 @@
65
84
  :selectionMode="selectionMode"
66
85
  :selectionKeys="selectionKeys"
67
86
  @checkbox-change="propagateUp"
87
+ :draggableScope="draggableScope"
88
+ :draggableNodes="draggableNodes"
89
+ :droppableNodes="droppableNodes"
90
+ :validateDrop="validateDrop"
91
+ @node-drop="$emit('node-drop', $event)"
92
+ @node-dragenter="$emit('node-dragenter', $event)"
93
+ @node-dragleave="$emit('node-dragleave', $event)"
94
+ @value-change="$emit('value-change', $event)"
68
95
  :unstyled="unstyled"
69
96
  :pt="pt"
70
97
  />
@@ -73,7 +100,7 @@
73
100
  </template>
74
101
 
75
102
  <script>
76
- import { find, findSingle, getAttribute } from '@primeuix/utils/dom';
103
+ import { find, findSingle, getAttribute, getOuterHeight, getOuterWidth } from '@primeuix/utils';
77
104
  import BaseComponent from '@primevue/core/basecomponent';
78
105
  import CheckIcon from '@primevue/icons/check';
79
106
  import ChevronDownIcon from '@primevue/icons/chevrondown';
@@ -87,12 +114,20 @@ export default {
87
114
  name: 'TreeNode',
88
115
  hostName: 'Tree',
89
116
  extends: BaseComponent,
90
- emits: ['node-toggle', 'node-click', 'checkbox-change'],
117
+ emits: ['node-toggle', 'node-click', 'checkbox-change', 'node-drop', 'value-change', 'node-dragenter', 'node-dragleave'],
91
118
  props: {
92
119
  node: {
93
120
  type: null,
94
121
  default: null
95
122
  },
123
+ parentNode: {
124
+ type: null,
125
+ default: null
126
+ },
127
+ rootNodes: {
128
+ type: Array,
129
+ default: null
130
+ },
96
131
  expandedKeys: {
97
132
  type: null,
98
133
  default: null
@@ -117,10 +152,38 @@ export default {
117
152
  type: Number,
118
153
  default: null
119
154
  },
155
+ draggableScope: {
156
+ type: [String, Array],
157
+ default: null
158
+ },
159
+ draggableNodes: {
160
+ type: Boolean,
161
+ default: null
162
+ },
163
+ droppableNodes: {
164
+ type: Boolean,
165
+ default: null
166
+ },
167
+ validateDrop: {
168
+ type: Boolean,
169
+ default: false
170
+ },
120
171
  index: null
121
172
  },
122
173
  nodeTouched: false,
123
174
  toggleClicked: false,
175
+ inject: {
176
+ $pcTree: {
177
+ default: undefined
178
+ }
179
+ },
180
+ data() {
181
+ return {
182
+ isPrevDropPointHovered: false,
183
+ isNextDropPointHovered: false,
184
+ isNodeDropHovered: false
185
+ };
186
+ },
124
187
  mounted() {
125
188
  this.setAllNodesTabIndexes();
126
189
  },
@@ -288,6 +351,208 @@ export default {
288
351
  onTabKey() {
289
352
  this.setAllNodesTabIndexes();
290
353
  },
354
+ removeNodeFromTree(nodes, nodeToRemove) {
355
+ return nodes.reduce((acc, node) => {
356
+ if (node.key === nodeToRemove.key) {
357
+ return acc;
358
+ }
359
+ if (node.children && node.children.length > 0) {
360
+ const updatedChildren = this.removeNodeFromTree(node.children, nodeToRemove);
361
+ acc.push({ ...node, children: updatedChildren });
362
+ } else {
363
+ acc.push(node);
364
+ }
365
+
366
+ return acc;
367
+ }, []);
368
+ },
369
+ insertNodeInSiblings(nodes, targetKey, nodeToInsert, offset) {
370
+ const targetIndex = nodes.findIndex((n) => n.key === targetKey);
371
+
372
+ if (targetIndex !== -1) {
373
+ return nodes.toSpliced(targetIndex + offset, 0, nodeToInsert);
374
+ }
375
+
376
+ return nodes.map((node) => {
377
+ if (node.children && node.children.length > 0) {
378
+ return { ...node, children: this.insertNodeInSiblings(node.children, targetKey, nodeToInsert, offset) };
379
+ }
380
+
381
+ return node;
382
+ });
383
+ },
384
+ addNodeAsChild(nodes, parentKey, nodeToInsert) {
385
+ return nodes.map((node) => {
386
+ if (node.key === parentKey) {
387
+ return { ...node, children: [...(node.children || []), nodeToInsert] };
388
+ }
389
+
390
+ if (node.children && node.children.length > 0) {
391
+ return { ...node, children: this.addNodeAsChild(node.children, parentKey, nodeToInsert) };
392
+ }
393
+
394
+ return node;
395
+ });
396
+ },
397
+ insertNodeOnDrop() {
398
+ const { dragNode, dragNodeIndex, dragNodeSubNodes, dragDropService } = this.$pcTree;
399
+
400
+ if (!this.node || dragNodeIndex == null || !dragNode || !dragNodeSubNodes) {
401
+ return null;
402
+ }
403
+
404
+ const position = this.dropPosition;
405
+ let updatedNodes = this.removeNodeFromTree(this.rootNodes, dragNode);
406
+
407
+ if (position < 0) {
408
+ // insert before a Node
409
+ updatedNodes = this.insertNodeInSiblings(updatedNodes, this.node.key, dragNode, 0);
410
+ } else if (position > 0) {
411
+ // insert after a Node
412
+ updatedNodes = this.insertNodeInSiblings(updatedNodes, this.node.key, dragNode, 1);
413
+ } else {
414
+ // insert as child of a Node
415
+ updatedNodes = this.addNodeAsChild(updatedNodes, this.node.key, dragNode);
416
+ }
417
+
418
+ this.$emit('value-change', { nodes: updatedNodes });
419
+
420
+ dragDropService.stopDrag({
421
+ node: dragNode,
422
+ subNodes: updatedNodes,
423
+ index: dragNodeIndex
424
+ });
425
+
426
+ return updatedNodes;
427
+ },
428
+ onNodeDrop(event) {
429
+ if (this.isDroppable) {
430
+ event.preventDefault();
431
+ event.stopPropagation();
432
+
433
+ const { dragNode } = this.$pcTree;
434
+ const position = this.dropPosition;
435
+ const isValidDrop = position !== 0 || (position === 0 && this.isNodeDroppable);
436
+
437
+ if (isValidDrop) {
438
+ if (this.validateDrop) {
439
+ this.$emit('node-drop', {
440
+ originalEvent: event,
441
+ value: this.rootNodes,
442
+ dragNode: dragNode,
443
+ dropNode: this.node,
444
+ index: this.index,
445
+ accept: () => {
446
+ const updatedNodes = this.insertNodeOnDrop();
447
+
448
+ this.$emit('node-drop', {
449
+ originalEvent: event,
450
+ value: updatedNodes,
451
+ dragNode: dragNode,
452
+ dropNode: this.node,
453
+ index: this.index
454
+ });
455
+ }
456
+ });
457
+ } else {
458
+ const updatedNodes = this.insertNodeOnDrop();
459
+
460
+ this.$emit('node-drop', {
461
+ originalEvent: event,
462
+ value: updatedNodes,
463
+ dragNode: dragNode,
464
+ dropNode: this.node,
465
+ index: this.index
466
+ });
467
+ }
468
+ }
469
+
470
+ this.isPrevDropPointHovered = false;
471
+ this.isNextDropPointHovered = false;
472
+ this.isNodeDropHovered = false;
473
+ }
474
+ },
475
+ onNodeDragStart(event) {
476
+ if (this.isNodeDraggable) {
477
+ event.dataTransfer.effectAllowed = 'all';
478
+ event.dataTransfer.setData('text', 'data');
479
+
480
+ const target = event.currentTarget;
481
+ const dragEl = target.cloneNode(true);
482
+ const toggler = dragEl.querySelector('[data-pc-section="nodetogglebutton"]');
483
+ const checkbox = dragEl.querySelector('[data-pc-name="pcnodecheckbox"]');
484
+
485
+ target.setAttribute('data-p-dragging', 'true');
486
+ dragEl.style.width = getOuterWidth(target) + 'px';
487
+ dragEl.style.height = getOuterHeight(target) + 'px';
488
+ dragEl.setAttribute('data-pc-section', 'drag-image');
489
+ toggler.style.visibility = 'hidden';
490
+ checkbox?.remove();
491
+ document.body.appendChild(dragEl);
492
+ event.dataTransfer.setDragImage(dragEl, 0, 0);
493
+
494
+ setTimeout(() => document.body.removeChild(dragEl), 0);
495
+
496
+ this.$pcTree.dragDropService.startDrag({
497
+ node: this.node,
498
+ subNodes: this.subNodes,
499
+ index: this.index,
500
+ scope: this.draggableScope
501
+ });
502
+ } else {
503
+ event.preventDefault();
504
+ }
505
+ },
506
+ onNodeDragOver(event) {
507
+ if (this.isDroppable) {
508
+ event.dataTransfer.dropEffect = 'copy';
509
+ const nodeElement = event.currentTarget;
510
+ const rect = nodeElement.getBoundingClientRect();
511
+ const y = event.clientY - rect.top;
512
+
513
+ this.isPrevDropPointHovered = false;
514
+ this.isNextDropPointHovered = false;
515
+ this.isNodeDropHovered = false;
516
+
517
+ if (y < rect.height * 0.25) {
518
+ this.isPrevDropPointHovered = true;
519
+ } else if (y > rect.height * 0.75) {
520
+ this.isNextDropPointHovered = true;
521
+ } else if (this.isNodeDroppable) {
522
+ this.isNodeDropHovered = true;
523
+ }
524
+ } else {
525
+ event.dataTransfer.dropEffect = 'none';
526
+ }
527
+
528
+ if (this.droppableNodes) {
529
+ event.preventDefault();
530
+ event.stopPropagation();
531
+ }
532
+ },
533
+ onNodeDragEnter() {
534
+ this.$emit('node-dragenter', {
535
+ node: this.node
536
+ });
537
+ },
538
+ onNodeDragLeave() {
539
+ this.$emit('node-dragleave', {
540
+ node: this.node
541
+ });
542
+
543
+ this.isPrevDropPointHovered = false;
544
+ this.isNextDropPointHovered = false;
545
+ this.isNodeDropHovered = false;
546
+ },
547
+ onNodeDragEnd(event) {
548
+ event.currentTarget?.removeAttribute('data-p-dragging');
549
+
550
+ this.$pcTree.dragDropService.stopDrag({
551
+ node: this.node,
552
+ subNodes: this.subNodes,
553
+ index: this.index
554
+ });
555
+ },
291
556
  setAllNodesTabIndexes() {
292
557
  const nodes = find(this.$refs.currentNode.closest('[data-pc-section="rootchildren"]'), '[role="treeitem"]');
293
558
 
@@ -458,6 +723,33 @@ export default {
458
723
  },
459
724
  ariaSelected() {
460
725
  return this.checkboxMode ? this.checked : undefined;
726
+ },
727
+ isPrevDropPointActive() {
728
+ return this.isPrevDropPointHovered && this.isDroppable;
729
+ },
730
+ isNextDropPointActive() {
731
+ return this.isNextDropPointHovered && this.isDroppable;
732
+ },
733
+ dropPosition() {
734
+ return this.isPrevDropPointActive ? -1 : this.isNextDropPointActive ? 1 : 0;
735
+ },
736
+ subNodes() {
737
+ return this.parentNode ? this.parentNode.children : this.rootNodes;
738
+ },
739
+ isDraggable() {
740
+ return this.draggableNodes;
741
+ },
742
+ isDroppable() {
743
+ return this.droppableNodes && this.$pcTree.allowNodeDrop(this.node);
744
+ },
745
+ isNodeDraggable() {
746
+ return this.node?.draggable !== false && this.isDraggable;
747
+ },
748
+ isNodeDroppable() {
749
+ return this.node?.droppable !== false && this.isDroppable;
750
+ },
751
+ isNodeDropActive() {
752
+ return this.isNodeDropHovered && this.isNodeDroppable;
461
753
  }
462
754
  },
463
755
  components: {