From 106d40bd299126067908bc978d4ad2374e7c7510 Mon Sep 17 00:00:00 2001 From: Bengt Date: Mon, 11 Nov 2024 14:15:38 +0100 Subject: [PATCH 1/3] git ignored pnpm-lock.yaml --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8e23bac..61b3b83 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,8 @@ vite.config.js.timestamp-* vite.config.ts.timestamp-* # .github -.github/copilot-instructions.md \ No newline at end of file +.github/copilot-instructions.md + +# pnpm + +pnpm-lock.yaml \ No newline at end of file From 25cfa65c827d6884cb4062b61ae2b631d0dbd46e Mon Sep 17 00:00:00 2001 From: Bengt Date: Mon, 11 Nov 2024 14:25:15 +0100 Subject: [PATCH 2/3] feat: added ability to use custom classes --- src/lib/actions/draggable.ts | 12 ++- src/lib/actions/droppable.ts | 16 ++-- src/lib/types/index.ts | 6 ++ src/routes/custom-classes/+page.svelte | 110 +++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 10 deletions(-) create mode 100644 src/routes/custom-classes/+page.svelte diff --git a/src/lib/actions/draggable.ts b/src/lib/actions/draggable.ts index c11e05c..ad370ef 100644 --- a/src/lib/actions/draggable.ts +++ b/src/lib/actions/draggable.ts @@ -1,7 +1,11 @@ import { dndState } from '$lib/stores/dnd.svelte.js'; import type { DragDropOptions, DragDropState } from '$lib/types/index.js'; +const DEFAULT_DRAGGING_CLASS = 'dragging'; + export function draggable(node: HTMLElement, options: DragDropOptions) { + const draggingClass = (options.attributes?.draggingClass || DEFAULT_DRAGGING_CLASS).split(' '); + function handleDragStart(event: DragEvent) { if (options.disabled) return; @@ -15,12 +19,12 @@ export function draggable(node: HTMLElement, options: DragDropOptions) { event.dataTransfer.setData('text/plain', JSON.stringify(options.dragData)); } - node.classList.add('dragging'); + node.classList.add(...draggingClass); options.callbacks?.onDragStart?.(dndState as DragDropState); } function handleDragEnd() { - node.classList.remove('dragging'); + node.classList.remove(...draggingClass); options.callbacks?.onDragEnd?.(dndState as DragDropState); // Reset state @@ -39,7 +43,7 @@ export function draggable(node: HTMLElement, options: DragDropOptions) { dndState.targetContainer = null; node.setPointerCapture(event.pointerId); - node.classList.add('dragging'); + node.classList.add(...draggingClass); options.callbacks?.onDragStart?.(dndState as DragDropState); } @@ -53,7 +57,7 @@ export function draggable(node: HTMLElement, options: DragDropOptions) { if (!dndState.isDragging) return; node.releasePointerCapture(event.pointerId); - node.classList.remove('dragging'); + node.classList.remove(...draggingClass); options.callbacks?.onDragEnd?.(dndState as DragDropState); // Reset state diff --git a/src/lib/actions/droppable.ts b/src/lib/actions/droppable.ts index adfed61..610d262 100644 --- a/src/lib/actions/droppable.ts +++ b/src/lib/actions/droppable.ts @@ -1,13 +1,17 @@ import { dndState } from '$lib/stores/dnd.svelte.js'; import type { DragDropOptions, DragDropState } from '$lib/types/index.js'; +const DEFAULT_DRAG_OVER_CLASS = 'drag-over'; + export function droppable(node: HTMLElement, options: DragDropOptions) { + const dragOverClass = (options.attributes?.draggingClass || DEFAULT_DRAG_OVER_CLASS).split(' '); + function handleDragEnter(event: DragEvent) { if (options.disabled) return; event.preventDefault(); dndState.targetContainer = options.container; - node.classList.add('drag-over'); + node.classList.add(...dragOverClass); options.callbacks?.onDragEnter?.(dndState as DragDropState); } @@ -17,7 +21,7 @@ export function droppable(node: HTMLElement, options: DragDropOptions) { const target = event.target as HTMLElement; if (!node.contains(target)) { dndState.targetContainer = null; - node.classList.remove('drag-over'); + node.classList.remove(...dragOverClass); options.callbacks?.onDragLeave?.(dndState as DragDropState); } } @@ -37,7 +41,7 @@ export function droppable(node: HTMLElement, options: DragDropOptions) { if (options.disabled) return; event.preventDefault(); - node.classList.remove('drag-over'); + node.classList.remove(...dragOverClass); try { if (event.dataTransfer) { @@ -55,7 +59,7 @@ export function droppable(node: HTMLElement, options: DragDropOptions) { if (options.disabled || !dndState.isDragging) return; dndState.targetContainer = options.container; - node.classList.add('drag-over'); + node.classList.add(...dragOverClass); options.callbacks?.onDragEnter?.(dndState as DragDropState); } @@ -63,14 +67,14 @@ export function droppable(node: HTMLElement, options: DragDropOptions) { if (options.disabled || !dndState.isDragging) return; dndState.targetContainer = null; - node.classList.remove('drag-over'); + node.classList.remove(...dragOverClass); options.callbacks?.onDragLeave?.(dndState as DragDropState); } function handlePointerUp(event: PointerEvent) { if (options.disabled || !dndState.isDragging) return; - node.classList.remove('drag-over'); + node.classList.remove(...dragOverClass); options.callbacks?.onDrop?.(dndState as DragDropState); } diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts index 324aa7e..8514e02 100644 --- a/src/lib/types/index.ts +++ b/src/lib/types/index.ts @@ -14,9 +14,15 @@ export interface DragDropCallbacks { onDragEnd?: (state: DragDropState) => void; } +export interface DragDropAttributes { + draggingClass?: string; + dragOverClass?: string; +} + export interface DragDropOptions { dragData?: T; container: string; disabled?: boolean; callbacks?: DragDropCallbacks; + attributes?: DragDropAttributes; } diff --git a/src/routes/custom-classes/+page.svelte b/src/routes/custom-classes/+page.svelte new file mode 100644 index 0000000..2ded538 --- /dev/null +++ b/src/routes/custom-classes/+page.svelte @@ -0,0 +1,110 @@ + + +
+
+

Sortable List

+

Drag and drop items to reorder them in the list.

+
+ +
+
+
+ {#each items as item, index (item.id)} +
+
+

+ {item.title} +

+ + {item.priority} + +
+

+ {item.description} +

+
+ {/each} +
+
+
+
+ + From bbb2460abf4cd8b0a48ef639ddb08de4283112b0 Mon Sep 17 00:00:00 2001 From: Bengt Date: Mon, 11 Nov 2024 16:33:42 +0100 Subject: [PATCH 3/3] fix: removing the classes from the container after not dragging over anymore --- src/lib/actions/droppable.ts | 19 ++++++++++++++----- src/lib/stores/dnd.svelte.ts | 3 ++- src/lib/types/index.ts | 1 + src/routes/custom-classes/+page.svelte | 4 ++-- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/lib/actions/droppable.ts b/src/lib/actions/droppable.ts index 610d262..9511600 100644 --- a/src/lib/actions/droppable.ts +++ b/src/lib/actions/droppable.ts @@ -10,7 +10,11 @@ export function droppable(node: HTMLElement, options: DragDropOptions) { if (options.disabled) return; event.preventDefault(); + const target = event.target as HTMLElement; + dndState.targetContainer = options.container; + dndState.targetElement = target; + node.classList.add(...dragOverClass); options.callbacks?.onDragEnter?.(dndState as DragDropState); } @@ -19,11 +23,16 @@ export function droppable(node: HTMLElement, options: DragDropOptions) { if (options.disabled) return; const target = event.target as HTMLElement; - if (!node.contains(target)) { - dndState.targetContainer = null; - node.classList.remove(...dragOverClass); - options.callbacks?.onDragLeave?.(dndState as DragDropState); - } + + // check if element is still being dragged over + if (!dndState.targetElement?.isSameNode(target)) return; + + node.classList.remove(...dragOverClass); + + options.callbacks?.onDragLeave?.(dndState as DragDropState); + + dndState.targetContainer = null; + dndState.targetElement = null; } function handleDragOver(event: DragEvent) { diff --git a/src/lib/stores/dnd.svelte.ts b/src/lib/stores/dnd.svelte.ts index 4bb7456..fcc6d7b 100644 --- a/src/lib/stores/dnd.svelte.ts +++ b/src/lib/stores/dnd.svelte.ts @@ -5,5 +5,6 @@ export const dndState = $state({ isDragging: false, draggedItem: null, sourceContainer: '', - targetContainer: null + targetContainer: null, + targetElement: null }); diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts index 8514e02..7c9a610 100644 --- a/src/lib/types/index.ts +++ b/src/lib/types/index.ts @@ -3,6 +3,7 @@ export interface DragDropState { draggedItem: T; sourceContainer: string; targetContainer: string | null; + targetElement: HTMLElement | null; } export interface DragDropCallbacks { diff --git a/src/routes/custom-classes/+page.svelte b/src/routes/custom-classes/+page.svelte index 2ded538..7521f18 100644 --- a/src/routes/custom-classes/+page.svelte +++ b/src/routes/custom-classes/+page.svelte @@ -67,8 +67,8 @@ container: index.toString(), callbacks: { onDrop: handleDrop }, attributes: { - draggingClass: 'custom-dragging ring-1 ring-blue-500', - dragOverClass: 'custom-drag-over ring-1 ring-red-500' + draggingClass: 'border border-blue-500', + dragOverClass: 'border border-red-500' } }} animate:flip={{ duration: 200 }}