Skip to content

Commit

Permalink
refactor: replace touch events with pointer events for drag-and-drop …
Browse files Browse the repository at this point in the history
…functionality
  • Loading branch information
Spikeysanju committed Nov 10, 2024
1 parent eea99a6 commit 2ceccdc
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 39 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ Thumbs.db
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

# .github
.github/copilot-instructions.md
52 changes: 38 additions & 14 deletions src/lib/actions/draggable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import { dndState } from '$lib/stores/dnd.svelte.js';
import type { DragDropOptions, DragDropState } from '$lib/types/index.js';

export function draggable<T>(node: HTMLElement, options: DragDropOptions<T>) {
function handleDragStart(event: DragEvent | TouchEvent) {

function handleDragStart(event: DragEvent) {
if (options.disabled) return;

dndState.isDragging = true;
dndState.draggedItem = options.dragData;
dndState.sourceContainer = options.container;
dndState.targetContainer = null;

if (event instanceof DragEvent && event.dataTransfer) {
if (event.dataTransfer) {
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setData('text/plain', JSON.stringify(options.dragData));
}
Expand All @@ -20,7 +19,7 @@ export function draggable<T>(node: HTMLElement, options: DragDropOptions<T>) {
options.callbacks?.onDragStart?.(dndState as DragDropState<T>);
}

function handleDragEnd(event: DragEvent | TouchEvent) {
function handleDragEnd() {
node.classList.remove('dragging');
options.callbacks?.onDragEnd?.(dndState as DragDropState<T>);

Expand All @@ -31,21 +30,45 @@ export function draggable<T>(node: HTMLElement, options: DragDropOptions<T>) {
dndState.targetContainer = null;
}

function handleTouchStart(event: TouchEvent) {
event.preventDefault();
handleDragStart(event);
function handlePointerDown(event: PointerEvent) {
if (options.disabled) return;

dndState.isDragging = true;
dndState.draggedItem = options.dragData;
dndState.sourceContainer = options.container;
dndState.targetContainer = null;

node.setPointerCapture(event.pointerId);
node.classList.add('dragging');
options.callbacks?.onDragStart?.(dndState as DragDropState<T>);
}

function handlePointerMove(event: PointerEvent) {
if (!dndState.isDragging) return;

// Optional: Update visual feedback or position
}

function handleTouchEnd(event: TouchEvent) {
event.preventDefault();
handleDragEnd(event);
function handlePointerUp(event: PointerEvent) {
if (!dndState.isDragging) return;

node.releasePointerCapture(event.pointerId);
node.classList.remove('dragging');
options.callbacks?.onDragEnd?.(dndState as DragDropState<T>);

// Reset state
dndState.isDragging = false;
dndState.draggedItem = null;
dndState.sourceContainer = '';
dndState.targetContainer = null;
}

node.draggable = !options.disabled;
node.addEventListener('dragstart', handleDragStart);
node.addEventListener('dragend', handleDragEnd);
node.addEventListener('touchstart', handleTouchStart);
node.addEventListener('touchend', handleTouchEnd);
node.addEventListener('pointerdown', handlePointerDown);
node.addEventListener('pointermove', handlePointerMove);
node.addEventListener('pointerup', handlePointerUp);

return {
update(newOptions: DragDropOptions<T>) {
Expand All @@ -56,8 +79,9 @@ export function draggable<T>(node: HTMLElement, options: DragDropOptions<T>) {
destroy() {
node.removeEventListener('dragstart', handleDragStart);
node.removeEventListener('dragend', handleDragEnd);
node.removeEventListener('touchstart', handleTouchStart);
node.removeEventListener('touchend', handleTouchEnd);
node.removeEventListener('pointerdown', handlePointerDown);
node.removeEventListener('pointermove', handlePointerMove);
node.removeEventListener('pointerup', handlePointerUp);
}
};
}
53 changes: 34 additions & 19 deletions src/lib/actions/droppable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import { dndState } from '$lib/stores/dnd.svelte.js';
import type { DragDropOptions, DragDropState } from '$lib/types/index.js';

export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
let touchTimeout: number | null = null;

function handleDragEnter(event: DragEvent | TouchEvent) {

function handleDragEnter(event: DragEvent) {
if (options.disabled) return;
event.preventDefault();

Expand All @@ -14,7 +11,7 @@ export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
options.callbacks?.onDragEnter?.(dndState as DragDropState<T>);
}

function handleDragLeave(event: DragEvent | TouchEvent) {
function handleDragLeave(event: DragEvent) {
if (options.disabled) return;

const target = event.target as HTMLElement;
Expand All @@ -25,26 +22,25 @@ export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
}
}

function handleDragOver(event: DragEvent | TouchEvent) {
function handleDragOver(event: DragEvent) {
if (options.disabled) return;
event.preventDefault();

if (event instanceof DragEvent && event.dataTransfer) {
if (event.dataTransfer) {
event.dataTransfer.dropEffect = 'move';
}

options.callbacks?.onDragOver?.(dndState as DragDropState<T>);
}

async function handleDrop(event: DragEvent | TouchEvent) {
async function handleDrop(event: DragEvent) {
if (options.disabled) return;
event.preventDefault();

node.classList.remove('drag-over');

try {

if (event instanceof DragEvent && event.dataTransfer) {
if (event.dataTransfer) {
const dragData = JSON.parse(event.dataTransfer.getData('text/plain')) as T;
dndState.draggedItem = dragData;
}
Expand All @@ -55,21 +51,37 @@ export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
}
}

function handleTouchMove(event: TouchEvent) {
if (touchTimeout) {
clearTimeout(touchTimeout);
}
function handlePointerOver(event: PointerEvent) {
if (options.disabled || !dndState.isDragging) return;

touchTimeout = window.setTimeout(() => {
handleDragOver(event);
}, 100);
dndState.targetContainer = options.container;
node.classList.add('drag-over');
options.callbacks?.onDragEnter?.(dndState as DragDropState<T>);
}

function handlePointerOut(event: PointerEvent) {
if (options.disabled || !dndState.isDragging) return;

dndState.targetContainer = null;
node.classList.remove('drag-over');
options.callbacks?.onDragLeave?.(dndState as DragDropState<T>);
}

function handlePointerUp(event: PointerEvent) {
if (options.disabled || !dndState.isDragging) return;

node.classList.remove('drag-over');
options.callbacks?.onDrop?.(dndState as DragDropState<T>);
}

node.addEventListener('dragenter', handleDragEnter);
node.addEventListener('dragleave', handleDragLeave);
node.addEventListener('dragover', handleDragOver);
node.addEventListener('drop', handleDrop);
node.addEventListener('touchmove', handleTouchMove);

node.addEventListener('pointerover', handlePointerOver);
node.addEventListener('pointerout', handlePointerOut);
node.addEventListener('pointerup', handlePointerUp);

return {
update(newOptions: DragDropOptions<T>) {
Expand All @@ -81,7 +93,10 @@ export function droppable<T>(node: HTMLElement, options: DragDropOptions<T>) {
node.removeEventListener('dragleave', handleDragLeave);
node.removeEventListener('dragover', handleDragOver);
node.removeEventListener('drop', handleDrop);
node.removeEventListener('touchmove', handleTouchMove);

node.removeEventListener('pointerover', handlePointerOver);
node.removeEventListener('pointerout', handlePointerOut);
node.removeEventListener('pointerup', handlePointerUp);
}
};
}
7 changes: 1 addition & 6 deletions src/lib/styles/dnd.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,11 @@
border: 2px dashed #9e9e9e;
}

/* Visual feedback for touch interactions */
.svelte-dnd-touch-feedback {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-color: #2196f3;
}

/* Media queries for responsive design */
@media (max-width: 600px) {
.svelte-dnd-draggable {
width: 100%;
touch-action: none; /* Prevents scrolling during drag */
}

.svelte-dnd-droppable {
Expand Down

0 comments on commit 2ceccdc

Please sign in to comment.