|
7 | 7 | dropTargetForElements,
|
8 | 8 | type ElementDropTargetGetFeedbackArgs,
|
9 | 9 | } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
10 |
| - import { dropTargetForExternal } from "@atlaskit/pragmatic-drag-and-drop/external/adapter"; |
| 10 | + import { |
| 11 | + dropTargetForExternal, |
| 12 | + type ExternalDropTargetGetFeedbackArgs, |
| 13 | + } from "@atlaskit/pragmatic-drag-and-drop/external/adapter"; |
11 | 14 | import { DEV } from "esm-env";
|
12 | 15 | import { SvelteSet } from "svelte/reactivity";
|
13 | 16 | import { isControlOrMeta, noop, truePredicate } from "$lib/helpers.js";
|
|
19 | 22 | type DefaultTFolder,
|
20 | 23 | } from "$lib/tree.svelte.js";
|
21 | 24 | import { setTreeContext } from "./context.js";
|
| 25 | + import { DragData } from "./data.js"; |
22 | 26 | import type {
|
23 | 27 | TreeCopyToClipboardMethodOptions,
|
24 | 28 | TreeProps,
|
|
72 | 76 | onRemove = noop,
|
73 | 77 | onDragEnter = noop,
|
74 | 78 | onDragLeave = noop,
|
| 79 | + canDrag = truePredicate, |
75 | 80 | onDrag = noop,
|
| 81 | + canDrop = truePredicate, |
76 | 82 | onDrop = noop,
|
77 | 83 | ...rest
|
78 | 84 | }: TreeProps<TFile, TFolder, TTree> = $props();
|
|
570 | 576 | return true;
|
571 | 577 | }
|
572 | 578 |
|
573 |
| - function getDragData(itemId: string) { |
574 |
| - return { itemId }; |
575 |
| - } |
576 |
| -
|
577 |
| - function getItemFromDragData(data: Record<string, unknown>) { |
578 |
| - const itemId = data.itemId; |
579 |
| - if (typeof itemId !== "string") { |
580 |
| - return; |
581 |
| - } |
582 |
| - return getItem(itemId); |
583 |
| - } |
584 |
| -
|
585 | 579 | function getDropDestination(item: TreeItemState<TFile, TFolder>) {
|
586 | 580 | switch (item.node.type) {
|
587 | 581 | case "file": {
|
|
593 | 587 | }
|
594 | 588 | }
|
595 | 589 |
|
596 |
| - function canDrop(item: TreeItemState<TFile, TFolder>, args: ElementDropTargetGetFeedbackArgs) { |
| 590 | + function canDropElementOnItem( |
| 591 | + item: TreeItemState<TFile, TFolder>, |
| 592 | + args: ElementDropTargetGetFeedbackArgs, |
| 593 | + ) { |
597 | 594 | if (item.disabled) {
|
598 | 595 | return false;
|
599 | 596 | }
|
600 | 597 |
|
601 |
| - const source = getItemFromDragData(args.source.data); |
602 |
| - if (source === undefined) { |
| 598 | + const dragData = args.source.data; |
| 599 | + if (!(dragData instanceof DragData)) { |
603 | 600 | return false;
|
604 | 601 | }
|
| 602 | + const source = dragData.item(); |
605 | 603 |
|
606 | 604 | if (item === source) {
|
607 | 605 | // Dropping an item on itself is not allowed.
|
|
627 | 625 | }
|
628 | 626 | }
|
629 | 627 |
|
630 |
| - return true; |
| 628 | + return canDrop({ |
| 629 | + type: "item", |
| 630 | + source, |
| 631 | + input: args.input, |
| 632 | + destination: dropDestinationItem?.node ?? root, |
| 633 | + }); |
| 634 | + } |
| 635 | +
|
| 636 | + function canDropExternalOnItem( |
| 637 | + item: TreeItemState<TFile, TFolder>, |
| 638 | + args: ExternalDropTargetGetFeedbackArgs, |
| 639 | + ) { |
| 640 | + if (item.disabled) { |
| 641 | + return false; |
| 642 | + } |
| 643 | +
|
| 644 | + return canDrop({ |
| 645 | + type: "external", |
| 646 | + input: args.input, |
| 647 | + items: args.source.items, |
| 648 | + destination: getDropDestination(item), |
| 649 | + }); |
631 | 650 | }
|
632 | 651 |
|
633 | 652 | function getDropDestinationFromLocation(location: DragLocation) {
|
|
637 | 656 | return root;
|
638 | 657 | }
|
639 | 658 | case "treeitem": {
|
640 |
| - const dropTargetItem = getItemFromDragData(dropTarget.data); |
641 |
| - if (dropTargetItem === undefined) { |
| 659 | + const dropData = dropTarget.data; |
| 660 | + if (!(dropData instanceof DragData)) { |
642 | 661 | return;
|
643 | 662 | }
|
644 |
| - return getDropDestination(dropTargetItem); |
| 663 | + return getDropDestination(dropData.item()); |
645 | 664 | }
|
646 | 665 | }
|
647 | 666 | }
|
|
953 | 972 | selectedIds.add(item.node.id);
|
954 | 973 | }
|
955 | 974 | },
|
956 |
| - getDragData, |
957 |
| - getItemFromDragData, |
958 | 975 | getDropDestination,
|
959 |
| - canDrag: (item) => !item.disabled, |
960 |
| - canDrop: (item, args) => { |
| 976 | + canDrag: (item, args) => { |
| 977 | + if (item.disabled) { |
| 978 | + return false; |
| 979 | + } |
| 980 | +
|
| 981 | + return canDrag({ |
| 982 | + input: args.input, |
| 983 | + source: item, |
| 984 | + }); |
| 985 | + }, |
| 986 | + canDropElement: (item, args) => { |
961 | 987 | // If an item cannot be dropped on, we need to notify the root drop target
|
962 | 988 | // that it cannot be dropped on as well.
|
963 |
| - const result = canDrop(item, args); |
| 989 | + const result = canDropElementOnItem(item, args); |
| 990 | + (args.input as any).__canDrop = result; |
| 991 | + return result; |
| 992 | + }, |
| 993 | + canDropExternal: (item, args) => { |
| 994 | + const result = canDropExternalOnItem(item, args); |
964 | 995 | (args.input as any).__canDrop = result;
|
965 | 996 | return result;
|
966 | 997 | },
|
|
980 | 1011 | $effect(() => {
|
981 | 1012 | return dropTargetForElements({
|
982 | 1013 | element: ref!,
|
983 |
| - canDrop: (args) => (args.input as any).__canDrop !== false, |
| 1014 | + canDrop: (args) => { |
| 1015 | + // Check if an item prevented the drop. |
| 1016 | + if ((args.input as any).__canDrop === false) { |
| 1017 | + return false; |
| 1018 | + } |
| 1019 | +
|
| 1020 | + const dragData = args.source.data; |
| 1021 | + if (!(dragData instanceof DragData)) { |
| 1022 | + return false; |
| 1023 | + } |
| 1024 | + const source = dragData.item(); |
| 1025 | +
|
| 1026 | + return canDrop({ |
| 1027 | + type: "item", |
| 1028 | + input: args.input, |
| 1029 | + source, |
| 1030 | + destination: root, |
| 1031 | + }); |
| 1032 | + }, |
984 | 1033 | onDragEnter: (args) => {
|
985 |
| - const source = getItemFromDragData(args.source.data); |
986 |
| - if (source === undefined) { |
987 |
| - return; |
| 1034 | + const dragData = args.source.data; |
| 1035 | + if (!(dragData instanceof DragData)) { |
| 1036 | + return false; |
988 | 1037 | }
|
| 1038 | + const source = dragData.item(); |
989 | 1039 |
|
990 | 1040 | onDragEnter({
|
991 | 1041 | type: "item",
|
|
995 | 1045 | });
|
996 | 1046 | },
|
997 | 1047 | onDragLeave: (args) => {
|
998 |
| - const source = getItemFromDragData(args.source.data); |
999 |
| - if (source === undefined) { |
1000 |
| - return; |
| 1048 | + const dragData = args.source.data; |
| 1049 | + if (!(dragData instanceof DragData)) { |
| 1050 | + return false; |
1001 | 1051 | }
|
| 1052 | + const source = dragData.item(); |
1002 | 1053 |
|
1003 | 1054 | onDragLeave({
|
1004 | 1055 | type: "item",
|
|
1008 | 1059 | });
|
1009 | 1060 | },
|
1010 | 1061 | onDrag: (args) => {
|
1011 |
| - const source = getItemFromDragData(args.source.data); |
1012 |
| - if (source === undefined) { |
1013 |
| - return; |
| 1062 | + const dragData = args.source.data; |
| 1063 | + if (!(dragData instanceof DragData)) { |
| 1064 | + return false; |
1014 | 1065 | }
|
| 1066 | + const source = dragData.item(); |
1015 | 1067 |
|
1016 | 1068 | const location = args.location.current;
|
1017 | 1069 | const dropDestination = getDropDestinationFromLocation(location);
|
|
1027 | 1079 | });
|
1028 | 1080 | },
|
1029 | 1081 | onDrop: async (args) => {
|
1030 |
| - const source = getItemFromDragData(args.source.data); |
1031 |
| - if (source === undefined) { |
1032 |
| - return; |
| 1082 | + const dragData = args.source.data; |
| 1083 | + if (!(dragData instanceof DragData)) { |
| 1084 | + return false; |
1033 | 1085 | }
|
| 1086 | + const source = dragData.item(); |
1034 | 1087 |
|
1035 | 1088 | const location = args.location.current;
|
1036 | 1089 | const dropDestination = getDropDestinationFromLocation(location);
|
|
1060 | 1113 | $effect(() => {
|
1061 | 1114 | return dropTargetForExternal({
|
1062 | 1115 | element: ref!,
|
| 1116 | + canDrop: (args) => { |
| 1117 | + // Check if an item prevented the drop. |
| 1118 | + if ((args.input as any).__canDrop === false) { |
| 1119 | + return false; |
| 1120 | + } |
| 1121 | +
|
| 1122 | + return canDrop({ |
| 1123 | + type: "external", |
| 1124 | + input: args.input, |
| 1125 | + items: args.source.items, |
| 1126 | + destination: root, |
| 1127 | + }); |
| 1128 | + }, |
1063 | 1129 | onDragEnter: (args) => {
|
1064 | 1130 | onDragEnter({
|
1065 | 1131 | type: "external",
|
|
0 commit comments