mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-23 01:22:12 +03:00
Turn drag & drop into a Svelte action
There are lots of things that different drop zones have in common, so this commit abstracts that away.
This commit is contained in:
parent
ebe1124ee4
commit
d2f57f7797
@ -7,7 +7,7 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body
|
<body
|
||||||
class="h-full w-full select-none bg-light-200 font-sans text-base text-light-800 antialiased dark:bg-dark-900 dark:text-light-300"
|
class="h-full w-full cursor-default select-none bg-light-200 font-sans text-base text-light-800 antialiased dark:bg-dark-900 dark:text-light-300"
|
||||||
style="height: 100vh"
|
style="height: 100vh"
|
||||||
>
|
>
|
||||||
%sveltekit.body%
|
%sveltekit.body%
|
||||||
|
@ -325,41 +325,13 @@ input[type='checkbox'].large {
|
|||||||
.drag-zone-marker {
|
.drag-zone-marker {
|
||||||
@apply border-green-450 bg-green-200 dark:bg-green-470;
|
@apply border-green-450 bg-green-200 dark:bg-green-470;
|
||||||
}
|
}
|
||||||
.drag-zone-active.drag-zone-hover .drag-zone-marker,
|
.drag-zone-active.drag-zone-hover .drag-zone-marker {
|
||||||
.drag-zone-active + #new-branch-dz.drag-zone-hover .drag-zone-marker {
|
@apply border-green-500 bg-green-300 dark:bg-green-460;
|
||||||
@apply bg-green-300 dark:bg-green-460;
|
|
||||||
}
|
}
|
||||||
.drag-zone-hover {
|
.drag-zone-active .no-changes,
|
||||||
@apply border-green-500;
|
.drag-zone-active .call-to-action {
|
||||||
}
|
|
||||||
.drag-zone-active .no-changes {
|
|
||||||
@apply hidden;
|
@apply hidden;
|
||||||
}
|
}
|
||||||
.drag-zone-active .drag-zone-marker {
|
.drag-zone-active .drag-zone-marker {
|
||||||
@apply block;
|
@apply block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* drag & drop ugly stuff */
|
|
||||||
#new-branch-dz.new-branch-active {
|
|
||||||
@apply visible flex;
|
|
||||||
}
|
|
||||||
.drag-zone-active + #new-branch-dz .call-to-action {
|
|
||||||
@apply hidden;
|
|
||||||
}
|
|
||||||
.drag-zone-active + #new-branch-dz .drag-zone-marker {
|
|
||||||
@apply block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drag-zone-hover + #new-branch-dz .call-to-action {
|
|
||||||
@apply hidden;
|
|
||||||
}
|
|
||||||
.drag-zone-hover + #new-branch-dz .drag-zone-marker {
|
|
||||||
@apply block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#new-branch-dz.drag-zone-hover .call-to-action {
|
|
||||||
@apply hidden;
|
|
||||||
}
|
|
||||||
#new-branch-dz.drag-zone-hover .drag-zone-marker {
|
|
||||||
@apply block bg-green-300 dark:bg-green-460;
|
|
||||||
}
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import type { VirtualBranchOperations } from './vbranches';
|
import type { VirtualBranchOperations } from './vbranches';
|
||||||
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
|
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
|
||||||
import { setContext } from 'svelte';
|
import { setContext } from 'svelte';
|
||||||
|
import { dzHighlight } from './dropZone';
|
||||||
|
|
||||||
export let projectId: string;
|
export let projectId: string;
|
||||||
export let projectPath: string;
|
export let projectPath: string;
|
||||||
@ -19,7 +20,7 @@
|
|||||||
let priorPosition = 0;
|
let priorPosition = 0;
|
||||||
let dropPosition = 0;
|
let dropPosition = 0;
|
||||||
|
|
||||||
const hoverClass = 'drag-zone-hover';
|
const dzType = 'text/branch';
|
||||||
|
|
||||||
function handleEmpty() {
|
function handleEmpty() {
|
||||||
const emptyIndex = branches.findIndex((item) => !item.files || item.files.length == 0);
|
const emptyIndex = branches.findIndex((item) => !item.files || item.files.length == 0);
|
||||||
@ -34,23 +35,8 @@
|
|||||||
bind:this={dropZone}
|
bind:this={dropZone}
|
||||||
id="branch-lanes"
|
id="branch-lanes"
|
||||||
class="flex max-w-full flex-shrink flex-grow snap-x items-start overflow-x-auto overflow-y-hidden bg-light-200 px-2 dark:bg-dark-1000"
|
class="flex max-w-full flex-shrink flex-grow snap-x items-start overflow-x-auto overflow-y-hidden bg-light-200 px-2 dark:bg-dark-1000"
|
||||||
on:dragenter={(e) => {
|
use:dzHighlight={{ type: dzType }}
|
||||||
if (!e.dataTransfer?.types.includes('text/branch')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dropZone.classList.add(hoverClass);
|
|
||||||
}}
|
|
||||||
on:dragend={(e) => {
|
|
||||||
if (!e.dataTransfer?.types.includes('text/branch')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dropZone.classList.remove(hoverClass);
|
|
||||||
}}
|
|
||||||
on:dragover={(e) => {
|
on:dragover={(e) => {
|
||||||
if (!e.dataTransfer?.types.includes('text/branch')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault(); // Only when text/branch
|
|
||||||
const children = [...e.currentTarget.children];
|
const children = [...e.currentTarget.children];
|
||||||
dropPosition = 0;
|
dropPosition = 0;
|
||||||
for (let i = 0; i < children.length; i++) {
|
for (let i = 0; i < children.length; i++) {
|
||||||
@ -69,7 +55,6 @@
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
on:drop={(e) => {
|
on:drop={(e) => {
|
||||||
dropZone.classList.remove(hoverClass);
|
|
||||||
if (priorPosition != dropPosition) {
|
if (priorPosition != dropPosition) {
|
||||||
const el = branches.splice(priorPosition, 1);
|
const el = branches.splice(priorPosition, 1);
|
||||||
branches.splice(dropPosition, 0, ...el);
|
branches.splice(dropPosition, 0, ...el);
|
||||||
@ -85,7 +70,7 @@
|
|||||||
<Lane
|
<Lane
|
||||||
on:dragstart={(e) => {
|
on:dragstart={(e) => {
|
||||||
if (!e.dataTransfer) return;
|
if (!e.dataTransfer) return;
|
||||||
e.dataTransfer.setData('text/branch', id);
|
e.dataTransfer.setData(dzType, id);
|
||||||
dragged = e.currentTarget;
|
dragged = e.currentTarget;
|
||||||
priorPosition = Array.from(dropZone.children).indexOf(dragged);
|
priorPosition = Array.from(dropZone.children).indexOf(dragged);
|
||||||
}}
|
}}
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
<script lang="ts" context="module">
|
|
||||||
const zones = new Set<HTMLDivElement>();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Commit, File, Hunk } from '$lib/api/ipc/vbranches';
|
import type { Commit, File, Hunk } from '$lib/api/ipc/vbranches';
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
@ -15,6 +11,7 @@
|
|||||||
import type { VirtualBranchOperations } from './vbranches';
|
import type { VirtualBranchOperations } from './vbranches';
|
||||||
import PopupMenu from '../../../lib/components/PopupMenu/PopupMenu.svelte';
|
import PopupMenu from '../../../lib/components/PopupMenu/PopupMenu.svelte';
|
||||||
import PopupMenuItem from '../../../lib/components/PopupMenu/PopupMenuItem.svelte';
|
import PopupMenuItem from '../../../lib/components/PopupMenu/PopupMenuItem.svelte';
|
||||||
|
import { dzHighlight } from './dropZone';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
empty: never;
|
empty: never;
|
||||||
@ -40,15 +37,9 @@
|
|||||||
let isPushing = false;
|
let isPushing = false;
|
||||||
let popupMenu: PopupMenu;
|
let popupMenu: PopupMenu;
|
||||||
let meatballButton: HTMLButtonElement;
|
let meatballButton: HTMLButtonElement;
|
||||||
let dropZone: HTMLDivElement;
|
|
||||||
|
|
||||||
const hoverClass = 'drag-zone-hover';
|
const hoverClass = 'drag-zone-hover';
|
||||||
const hunkType = 'text/hunk';
|
const dzType = 'text/hunk';
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
zones.add(dropZone);
|
|
||||||
return () => zones.delete(dropZone);
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateBranchOwnership() {
|
function updateBranchOwnership() {
|
||||||
const ownership = files
|
const ownership = files
|
||||||
@ -134,37 +125,17 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
draggable="true"
|
draggable="true"
|
||||||
bind:this={dropZone}
|
|
||||||
class="flex max-h-full min-w-[24rem] max-w-[120ch] shrink-0 snap-center flex-col overflow-y-auto bg-light-200 py-2 px-3 transition-width dark:bg-dark-1000 dark:text-dark-100"
|
|
||||||
class:w-full={maximized}
|
class:w-full={maximized}
|
||||||
class:w-96={!maximized}
|
class:w-96={!maximized}
|
||||||
|
class="flex max-h-full min-w-[24rem] max-w-[120ch] shrink-0 cursor-grabbing snap-center flex-col overflow-y-auto bg-light-200 py-2 px-3 transition-width dark:bg-dark-1000 dark:text-dark-100"
|
||||||
|
use:dzHighlight={{ type: dzType, hover: hoverClass, active: 'drag-zone-active' }}
|
||||||
on:dragstart
|
on:dragstart
|
||||||
on:dragenter={(e) => {
|
on:dragend
|
||||||
if (!e.dataTransfer?.types.includes(hunkType)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dropZone.classList.add(hoverClass);
|
|
||||||
}}
|
|
||||||
on:dragleave|stopPropagation={(e) => {
|
|
||||||
if (!e.dataTransfer?.types.includes(hunkType)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!isChildOf(e.target, dropZone)) {
|
|
||||||
dropZone.classList.remove(hoverClass);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
on:dragover|stopPropagation={(e) => {
|
|
||||||
if (e.dataTransfer?.types.includes(hunkType)) e.preventDefault();
|
|
||||||
}}
|
|
||||||
on:dragend={(e) => {
|
|
||||||
dropZone.classList.remove(hoverClass);
|
|
||||||
}}
|
|
||||||
on:drop|stopPropagation={(e) => {
|
on:drop|stopPropagation={(e) => {
|
||||||
if (!e.dataTransfer) {
|
if (!e.dataTransfer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dropZone.classList.remove(hoverClass);
|
const data = e.dataTransfer.getData(dzType);
|
||||||
const data = e.dataTransfer.getData(hunkType);
|
|
||||||
const ownership = files
|
const ownership = files
|
||||||
.map((file) => file.id + ':' + file.hunks.map((hunk) => hunk.id).join(','))
|
.map((file) => file.id + ':' + file.hunks.map((hunk) => hunk.id).join(','))
|
||||||
.join('\n');
|
.join('\n');
|
||||||
@ -251,23 +222,12 @@
|
|||||||
filepath={file.path}
|
filepath={file.path}
|
||||||
expanded={file.expanded}
|
expanded={file.expanded}
|
||||||
hunks={file.hunks}
|
hunks={file.hunks}
|
||||||
|
{dzType}
|
||||||
{maximized}
|
{maximized}
|
||||||
on:update={(e) => {
|
|
||||||
handleFileUpdate(file.id, e.detail);
|
|
||||||
}}
|
|
||||||
on:expanded={(e) => {
|
on:expanded={(e) => {
|
||||||
setExpandedWithCache(file, e.detail);
|
setExpandedWithCache(file, e.detail);
|
||||||
expandFromCache();
|
expandFromCache();
|
||||||
}}
|
}}
|
||||||
on:drag={(e) => {
|
|
||||||
zones.forEach((zone) => {
|
|
||||||
if (zone != dropZone) {
|
|
||||||
e.detail
|
|
||||||
? zone.classList.add('drag-zone-active')
|
|
||||||
: zone.classList.remove('drag-zone-active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
{projectPath}
|
{projectPath}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
import PopupMenuItem from '$lib/components/PopupMenu/PopupMenuItem.svelte';
|
import PopupMenuItem from '$lib/components/PopupMenu/PopupMenuItem.svelte';
|
||||||
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
|
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
|
import { dzTrigger } from './dropZone';
|
||||||
|
|
||||||
const userSettings = getContext<SettingsStore>(SETTINGS_CONTEXT);
|
const userSettings = getContext<SettingsStore>(SETTINGS_CONTEXT);
|
||||||
|
|
||||||
@ -18,11 +19,10 @@
|
|||||||
export let filepath: string;
|
export let filepath: string;
|
||||||
export let hunks: Hunk[];
|
export let hunks: Hunk[];
|
||||||
export let maximized: boolean;
|
export let maximized: boolean;
|
||||||
|
export let dzType: string;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
expanded: boolean;
|
expanded: boolean;
|
||||||
update: Hunk[];
|
|
||||||
drag: boolean;
|
|
||||||
}>();
|
}>();
|
||||||
export let expanded: boolean | undefined;
|
export let expanded: boolean | undefined;
|
||||||
|
|
||||||
@ -49,19 +49,16 @@
|
|||||||
function getFirstLineNumber(diff: string): number {
|
function getFirstLineNumber(diff: string): number {
|
||||||
return parseInt(diff.split('\n')[0].split('@@')[1].trim().split(' ')[0].split(',')[0].slice(1));
|
return parseInt(diff.split('\n')[0].split('@@')[1].trim().split(' ')[0].split(',')[0].slice(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAllHunksOwnership(): string {
|
||||||
|
return id + ':' + hunks.map((h) => h.id).join(',');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
draggable="true"
|
draggable="true"
|
||||||
on:dragstart|stopPropagation={(e) => {
|
use:dzTrigger={{ type: dzType }}
|
||||||
if (!e.dataTransfer) return;
|
on:dragstart={(e) => e.dataTransfer?.setData('text/hunk', getAllHunksOwnership())}
|
||||||
e.dataTransfer.setData('text/hunk', id + ':' + hunks.map((h) => h.id).join(','));
|
|
||||||
dispatch('drag', true);
|
|
||||||
return true;
|
|
||||||
}}
|
|
||||||
on:dragend|stopPropagation={(e) => {
|
|
||||||
dispatch('drag', false);
|
|
||||||
}}
|
|
||||||
class="changed-file flex w-full flex-col justify-center gap-2 rounded-lg border border-light-300 bg-light-50 text-light-900 dark:border-dark-400 dark:bg-dark-700 dark:text-light-300"
|
class="changed-file flex w-full flex-col justify-center gap-2 rounded-lg border border-light-300 bg-light-50 text-light-900 dark:border-dark-400 dark:bg-dark-700 dark:text-light-300"
|
||||||
>
|
>
|
||||||
<div class="items-cente flex px-2 pt-2">
|
<div class="items-cente flex px-2 pt-2">
|
||||||
@ -89,15 +86,8 @@
|
|||||||
{#each hunks || [] as hunk (hunk.id)}
|
{#each hunks || [] as hunk (hunk.id)}
|
||||||
<div
|
<div
|
||||||
draggable="true"
|
draggable="true"
|
||||||
on:dragstart|stopPropagation={(e) => {
|
use:dzTrigger={{ type: dzType }}
|
||||||
if (!e.dataTransfer) return;
|
on:dragstart={(e) => e.dataTransfer?.setData('text/hunk', id + ':' + hunk.id)}
|
||||||
e.dataTransfer.setData('text/hunk', id + ':' + hunk.id);
|
|
||||||
dispatch('drag', true);
|
|
||||||
return false;
|
|
||||||
}}
|
|
||||||
on:dragend|stopPropagation={(e) => {
|
|
||||||
dispatch('drag', false);
|
|
||||||
}}
|
|
||||||
on:contextmenu|preventDefault={(e) => popupMenu.openByMouse(e, hunk)}
|
on:contextmenu|preventDefault={(e) => popupMenu.openByMouse(e, hunk)}
|
||||||
class="changed-hunk flex w-full flex-col rounded-lg border border-light-200 bg-white dark:border-dark-400 dark:bg-dark-900"
|
class="changed-hunk flex w-full flex-col rounded-lg border border-light-200 bg-white dark:border-dark-400 dark:bg-dark-900"
|
||||||
>
|
>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Branch } from '$lib/api/ipc/vbranches';
|
import type { Branch } from '$lib/api/ipc/vbranches';
|
||||||
import { Button } from '$lib/components';
|
import { Button } from '$lib/components';
|
||||||
|
import { dzHighlight } from './dropZone';
|
||||||
import type { VirtualBranchOperations } from './vbranches';
|
import type { VirtualBranchOperations } from './vbranches';
|
||||||
|
|
||||||
export let virtualBranches: VirtualBranchOperations;
|
export let virtualBranches: VirtualBranchOperations;
|
||||||
@ -23,20 +24,11 @@
|
|||||||
id="new-branch-dz"
|
id="new-branch-dz"
|
||||||
class="h-42 ml-4 mt-16 flex w-[22.5rem] shrink-0 justify-center text-center text-light-800 dark:text-dark-100"
|
class="h-42 ml-4 mt-16 flex w-[22.5rem] shrink-0 justify-center text-center text-light-800 dark:text-dark-100"
|
||||||
bind:this={dropZone}
|
bind:this={dropZone}
|
||||||
on:dragover|stopPropagation={(e) => {
|
use:dzHighlight={{ type: 'text/hunk', hover: 'drag-zone-hover', active: 'drag-zone-active' }}
|
||||||
if (e.dataTransfer?.types.includes('text/hunk')) e.preventDefault();
|
|
||||||
dropZone.classList.add('drag-zone-hover');
|
|
||||||
}}
|
|
||||||
on:dragleave|stopPropagation={(e) => {
|
|
||||||
if (!isChildOf(e.target, dropZone)) {
|
|
||||||
dropZone.classList.remove('drag-zone-hover');
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
on:drop|stopPropagation={(e) => {
|
on:drop|stopPropagation={(e) => {
|
||||||
if (!e.dataTransfer) {
|
if (!e.dataTransfer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dropZone.classList.remove('drag-zone-hover');
|
|
||||||
const ownership = e.dataTransfer.getData('text/hunk');
|
const ownership = e.dataTransfer.getData('text/hunk');
|
||||||
virtualBranches.createBranch({ ownership });
|
virtualBranches.createBranch({ ownership });
|
||||||
}}
|
}}
|
||||||
|
@ -200,7 +200,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>{branch.ahead}/{branch.behind}</div>
|
<div>{branch.ahead}/{branch.behind}</div>
|
||||||
{#if !branch.mergeable}
|
{#if !branch.mergeable}
|
||||||
<div class="text-red-500 font-bold" title="Can't be merged">!</div>
|
<div class="font-bold text-red-500" title="Can't be merged">!</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if branch.lastCommitTs > 0}
|
{#if branch.lastCommitTs > 0}
|
||||||
|
123
src/routes/repo/[projectId]/dropZone.ts
Normal file
123
src/routes/repo/[projectId]/dropZone.ts
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
const zoneMap = new Map<string, Set<HTMLElement>>();
|
||||||
|
|
||||||
|
export interface DzOptions {
|
||||||
|
type: string;
|
||||||
|
hover: string;
|
||||||
|
active: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultOptions: DzOptions = {
|
||||||
|
hover: 'drag-zone-hover',
|
||||||
|
active: 'drag-zone-active',
|
||||||
|
type: 'default'
|
||||||
|
};
|
||||||
|
|
||||||
|
function inactivateZones(zones: Set<HTMLElement>, cssClass: string) {
|
||||||
|
zones?.forEach((zone) => {
|
||||||
|
zone.classList.remove(cssClass);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateZones(zones: Set<HTMLElement>, activeZone: HTMLElement, cssClass: string) {
|
||||||
|
zones?.forEach((zone) => {
|
||||||
|
if (zone !== activeZone && !isChildOf(activeZone, zone)) {
|
||||||
|
zone.classList.add(cssClass);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getZones(type: string): Set<HTMLElement> {
|
||||||
|
let zones = zoneMap.get(type);
|
||||||
|
if (!zones) {
|
||||||
|
zones = new Set([]);
|
||||||
|
zoneMap.set(type, zones);
|
||||||
|
}
|
||||||
|
return zones;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isChildOf(child: any, parent: HTMLElement): boolean {
|
||||||
|
if (parent === child) return false;
|
||||||
|
if (!child.parentElement) return false;
|
||||||
|
if (child.parentElement == parent) return true;
|
||||||
|
return isChildOf(child.parentElement, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dzTrigger(node: HTMLElement, opts: Partial<DzOptions> | undefined) {
|
||||||
|
const options = { ...defaultOptions, ...opts };
|
||||||
|
const zones = getZones(options.type);
|
||||||
|
|
||||||
|
function handleDragStart(e: DragEvent) {
|
||||||
|
activateZones(zones, node, options.active);
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
node.addEventListener('dragstart', handleDragStart);
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
node.removeEventListener('dragstart', handleDragStart);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dzHighlight(node: HTMLElement, opts: Partial<DzOptions> | undefined) {
|
||||||
|
const options = { ...defaultOptions, ...opts };
|
||||||
|
const zones = getZones(options.type);
|
||||||
|
zones.add(node);
|
||||||
|
|
||||||
|
function handleDragEnter(e: DragEvent) {
|
||||||
|
if (!e.dataTransfer?.types.includes(options.type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node.classList.add(options.hover);
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragLeave(e: DragEvent) {
|
||||||
|
if (!e.dataTransfer?.types.includes(options.type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isChildOf(e.target, node)) {
|
||||||
|
node.classList.remove(options.hover);
|
||||||
|
}
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragEnd(e: DragEvent) {
|
||||||
|
node.classList.remove(options.hover);
|
||||||
|
inactivateZones(zones, options.active);
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrop(e: DragEvent) {
|
||||||
|
if (!e.dataTransfer?.types.includes(options.type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node.classList.remove(options.hover);
|
||||||
|
inactivateZones(zones, options.active);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragOver(e: DragEvent) {
|
||||||
|
if (!e.dataTransfer?.types.includes(options.type)) {
|
||||||
|
e.stopImmediatePropagation(); // Stops event from reaching `on:dragover` on the element
|
||||||
|
}
|
||||||
|
if (e.dataTransfer?.types.includes(options.type)) e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
node.addEventListener('dragend', handleDragEnd);
|
||||||
|
node.addEventListener('dragenter', handleDragEnter);
|
||||||
|
node.addEventListener('dragleave', handleDragLeave);
|
||||||
|
node.addEventListener('dragover', handleDragOver);
|
||||||
|
node.addEventListener('drop', handleDrop);
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
node.removeEventListener('dragend', handleDragEnd);
|
||||||
|
node.removeEventListener('dragenter', handleDragEnter);
|
||||||
|
node.removeEventListener('dragleave', handleDragLeave);
|
||||||
|
node.removeEventListener('dragover', handleDragOver);
|
||||||
|
node.removeEventListener('drop', handleDrop);
|
||||||
|
zones?.delete(node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user