-
Notifications
You must be signed in to change notification settings - Fork 67
Expand file tree
/
Copy pathDraggable.tsx
More file actions
114 lines (105 loc) · 2.94 KB
/
Copy pathDraggable.tsx
File metadata and controls
114 lines (105 loc) · 2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { ObjectId } from "bson";
import {
DetailedHTMLProps,
ForwardedRef,
HTMLAttributes,
ReactHTML,
cloneElement,
createElement,
forwardRef,
isValidElement,
useState,
} from "react";
import {
UniqueIdentifier,
UseDraggableArguments,
useDraggable,
} from "@dnd-kit/core";
import { CSS } from "@dnd-kit/utilities";
import { useMergeRefs } from "@floating-ui/react";
import { Categories_Event } from "@core/types/event.types";
import { Task } from "@web/common/types/task.types";
import { Schema_GridEvent } from "@web/common/types/web.event.types";
export type DraggableDataType = Categories_Event | "task";
/**
* Data structure for draggable items in the application
* @property type - The type of item being dragged (event category or "task")
* @property event - The event data (required when type is a Categories_Event)
* @property task - The task data (required when type is "task")
* @property view - The view where the drag originated ("day" | "week" | "now")
* @property deleteTask - Optional function to delete a task (used when converting task to event)
*/
export interface DraggableDNDData {
type: DraggableDataType;
event?: Schema_GridEvent | null;
task?: Task | null;
view: "day" | "week" | "now";
deleteTask?: () => void;
}
export interface DNDChildProps
extends Pick<
ReturnType<typeof useDraggable>,
"over" | "listeners" | "isDragging"
> {
id: UniqueIdentifier;
setDisabled?: (disabled: boolean) => void;
}
function CompassDraggable(
props: DetailedHTMLProps<
{
dndProps: Omit<UseDraggableArguments, "id" | "data"> & {
id: UniqueIdentifier;
data: DraggableDNDData;
};
as: keyof ReactHTML;
asChild?: boolean;
} & HTMLAttributes<HTMLElement>,
HTMLElement
>,
_ref: ForwardedRef<HTMLElement | null>,
) {
const [disabled, setDisabled] = useState(!!props.dndProps.disabled);
const {
dndProps,
as,
asChild,
style,
onContextMenu,
children,
...elementProps
} = props;
const { setNodeRef, attributes, listeners, transform, isDragging, over } =
useDraggable({
...props.dndProps,
id: props.dndProps.id ?? new ObjectId().toString(),
disabled,
});
const ref = useMergeRefs([_ref, setNodeRef]);
const useChild = asChild && isValidElement(children);
return createElement(as ?? "div", {
...attributes,
...elementProps,
...(!useChild ? listeners : {}),
onContextMenu: isDragging ? undefined : onContextMenu,
style: {
...style,
...(isDragging
? { opacity: 0, transform: CSS.Translate.toString(transform) }
: {}),
},
ref,
children: useChild
? cloneElement(children, {
...children.props,
dndProps: {
over,
id: props.dndProps.id,
listeners,
isDragging,
setDisabled,
},
})
: props.children,
});
}
export const Draggable = forwardRef(CompassDraggable);