Skip to content

Commit 6e08a96

Browse files
authored
Merge pull request #6 from colecrouter/main
feat: add custom dragstart event and improve drag enter/leave handling
2 parents 0ba36d3 + badc252 commit 6e08a96

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

src/lib/actions/draggable.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ export function draggable<T>(node: HTMLElement, options: DragDropOptions<T>) {
2121

2222
node.classList.add(...draggingClass);
2323
options.callbacks?.onDragStart?.(dndState as DragDropState<T>);
24+
25+
// **Dispatch the custom event that bubbles up to the container**
26+
const customEvent = new CustomEvent('dragstart-on-container', { bubbles: true });
27+
node.dispatchEvent(customEvent);
2428
}
2529

2630
function handleDragEnd() {

src/lib/actions/droppable.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@ const DEFAULT_DRAG_OVER_CLASS = 'drag-over';
55

66
export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
77
const dragOverClass = (options.attributes?.draggingClass || DEFAULT_DRAG_OVER_CLASS).split(' ');
8+
let dragEnterCounter = 0; // Initialize the counter
89

910
function handleDragEnter(event: DragEvent) {
1011
if (options.disabled) return;
1112
event.preventDefault();
1213

13-
const target = event.target as HTMLElement;
14+
dragEnterCounter++;
1415

1516
dndState.targetContainer = options.container;
16-
dndState.targetElement = target;
17+
dndState.targetElement = event.target as HTMLElement;
18+
19+
if (dragEnterCounter === 0) return;
1720

1821
node.classList.add(...dragOverClass);
1922
options.callbacks?.onDragEnter?.(dndState as DragDropState<T>);
@@ -22,10 +25,10 @@ export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
2225
function handleDragLeave(event: DragEvent) {
2326
if (options.disabled) return;
2427

25-
const target = event.target as HTMLElement;
28+
dragEnterCounter--;
2629

2730
// check if element is still being dragged over
28-
if (!dndState.targetElement?.isSameNode(target)) return;
31+
if (dragEnterCounter > 0) return;
2932

3033
node.classList.remove(...dragOverClass);
3134

@@ -50,6 +53,7 @@ export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
5053
if (options.disabled) return;
5154
event.preventDefault();
5255

56+
dragEnterCounter = 0; // Reset the counter
5357
node.classList.remove(...dragOverClass);
5458

5559
try {
@@ -64,6 +68,14 @@ export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
6468
}
6569
}
6670

71+
function handleDragStartOnContainer(event: Event) {
72+
if (options.disabled) return;
73+
74+
// Reset the counter and remove the class
75+
dragEnterCounter = 0;
76+
node.classList.remove(...dragOverClass);
77+
}
78+
6779
function handlePointerOver(event: PointerEvent) {
6880
if (options.disabled || !dndState.isDragging) return;
6981

@@ -91,6 +103,7 @@ export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
91103
node.addEventListener('dragleave', handleDragLeave);
92104
node.addEventListener('dragover', handleDragOver);
93105
node.addEventListener('drop', handleDrop);
106+
node.addEventListener('dragstart-on-container', handleDragStartOnContainer);
94107

95108
node.addEventListener('pointerover', handlePointerOver);
96109
node.addEventListener('pointerout', handlePointerOut);
@@ -106,6 +119,7 @@ export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
106119
node.removeEventListener('dragleave', handleDragLeave);
107120
node.removeEventListener('dragover', handleDragOver);
108121
node.removeEventListener('drop', handleDrop);
122+
node.removeEventListener('dragstart-on-container', handleDragStartOnContainer);
109123

110124
node.removeEventListener('pointerover', handlePointerOver);
111125
node.removeEventListener('pointerout', handlePointerOut);

0 commit comments

Comments
 (0)