-
-
Notifications
You must be signed in to change notification settings - Fork 674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[experimental] Native file dragging plugin #1584
base: experimental
Are you sure you want to change the base?
Changes from 4 commits
9afc4d6
a188a86
ea8e2de
ed3faa3
39e9dfc
313af6a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@dnd-kit/abstract': minor | ||
'@dnd-kit/dom': minor | ||
--- | ||
|
||
feat: Add a plugin to allow dragging file from native file system |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,9 +67,9 @@ export class CollisionObserver< | |
collisionDetector?: CollisionDetector | ||
) { | ||
const {registry, dragOperation} = this.manager; | ||
const {source, shape, status} = dragOperation; | ||
const {source, status} = dragOperation; | ||
|
||
if (!status.initialized || !shape) { | ||
if (!status.initialized) { | ||
return DEFAULT_VALUE; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be collision detection algorithm's responsibility to check shape's availability. File draggable does not have a shape and would be filtered by the original code implementation |
||
} | ||
|
||
|
@@ -90,7 +90,6 @@ export class CollisionObserver< | |
continue; | ||
} | ||
|
||
entry.shape; | ||
yf-yang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const collision = untracked(() => | ||
detectCollision({ | ||
droppable: entry, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,13 +63,14 @@ | |
} | ||
}, | ||
"scripts": { | ||
"build": "bun build:utilities && bun build:core && bun build:sortable && bun build:modifiers && bun build:plugins", | ||
"build": "bun build:utilities && bun build:core && bun build:sortable && bun build:draggableFile && bun build:modifiers && bun build:plugins", | ||
"build:core": "tsup src/core/index.ts", | ||
"build:modifiers": "tsup --entry.modifiers src/modifiers/index.ts", | ||
"build:plugins": "tsup --entry.debug src/plugins/debug/index.ts --outDir ./plugins", | ||
"build:draggableFile": "tsup --entry.draggableFile src/plugins/draggableFile/index.ts --outDir ./plugins", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Didn't take times figuring out how to configure the command. Put it here for now |
||
"build:sortable": "tsup --entry.sortable src/sortable/index.ts", | ||
"build:utilities": "tsup --entry.utilities src/utilities/index.ts", | ||
"dev": "bun build:utilities --watch & bun build:core --watch & bun build:sortable --watch & bun build:modifiers --watch & bun build:plugins --watch", | ||
"dev": "bun build:utilities --watch & bun build:core --watch & bun build:sortable --watch & bun build:modifiers --watch & bun build:plugins --watch & bun build:draggableFile --watch", | ||
"lint": "TIMING=1 eslint src/**/*.ts* --fix", | ||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" | ||
}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import {batch, CleanupFunction} from '@dnd-kit/state'; | ||
import {Plugin} from '@dnd-kit/abstract'; | ||
import {Draggable, type DragDropManager} from '@dnd-kit/dom'; | ||
import {getDocument, Listeners} from '@dnd-kit/dom/utilities'; | ||
|
||
export const DraggableFileId = '$DRAGGABLE_FILE_GLOBALLY_UNIQUE_ID'; | ||
|
||
export class DraggableFile extends Plugin<DragDropManager> { | ||
private listeners = new Listeners(); | ||
|
||
private cleanup: Set<CleanupFunction> = new Set(); | ||
|
||
constructor(manager: DragDropManager) { | ||
super(manager); | ||
console.log('DraggableFile constructor'); | ||
|
||
const draggable = new Draggable({id: DraggableFileId}, manager); | ||
|
||
const unbind = this.listeners.bind(document.body, [ | ||
{type: 'dragenter', listener: this.handleDragEnter.bind(this)}, | ||
]); | ||
|
||
this.destroy = () => { | ||
this.cleanup.forEach((cleanup) => cleanup()); | ||
this.cleanup.clear(); | ||
unbind(); | ||
draggable.destroy(); | ||
}; | ||
} | ||
|
||
private handleDragEnter(event: DragEvent) { | ||
const isDraggingFile = (event.dataTransfer?.types ?? []).includes('Files'); | ||
if (this.disabled || event.relatedTarget || !isDraggingFile) { | ||
return; | ||
} | ||
event.preventDefault(); | ||
event.stopImmediatePropagation(); | ||
// console.log('handleDragEnter', event); | ||
|
||
batch(() => { | ||
this.manager.actions.setDragSource(DraggableFileId); | ||
this.manager.actions.start({ | ||
coordinates: {x: event.clientX, y: event.clientY}, | ||
event, | ||
}); | ||
}); | ||
|
||
const ownerDocument = getDocument(event.target); | ||
|
||
const unbindListeners = this.listeners.bind(ownerDocument, [ | ||
{type: 'dragover', listener: this.handleDragOver.bind(this)}, | ||
{type: 'dragleave', listener: this.handleDragLeave.bind(this)}, | ||
{type: 'drop', listener: this.handleDrop.bind(this)}, | ||
]); | ||
|
||
const cleanup = () => { | ||
setTimeout(unbindListeners); | ||
}; | ||
|
||
this.cleanup.add(cleanup); | ||
} | ||
|
||
private handleDragLeave(event: DragEvent) { | ||
if (event.relatedTarget) { | ||
return; | ||
} | ||
// Prevent the default behaviour of the event | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
|
||
// console.log('handleDragLeave', event); | ||
|
||
// End the drag and drop operation | ||
|
||
this.manager.actions.stop({canceled: true}); | ||
|
||
// Remove the pointer move and up event listeners | ||
this.cleanup.forEach((cleanup) => cleanup()); | ||
this.cleanup.clear(); | ||
} | ||
|
||
private handleDragOver(event: DragEvent) { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
|
||
// console.log('handleDragOver', event); | ||
|
||
this.manager.actions.move({to: {x: event.clientX, y: event.clientY}}); | ||
} | ||
|
||
private handleDrop(event: DragEvent) { | ||
// Prevent the default behaviour of the event | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
|
||
// End the drag and drop operation | ||
|
||
this.manager.actions.stop(); | ||
|
||
// Remove the pointer move and up event listeners | ||
this.cleanup.forEach((cleanup) => cleanup()); | ||
this.cleanup.clear(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export {DraggableFile, DraggableFileId} from './draggableFile.ts'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if it has a performance penalty (too many collisions recompute?)