Skip to content

Pass dataTransfer through in onDrop #6835

@alecmev

Description

@alecmev
Contributor

Provide a general summary of the feature here

I use DropZone in a form, and would like to have an easy way to set the associated input's files property. Currently I have to construct my own FileList, but the original dataTransfer is right there, just discarded:

if (typeof options.onDrop === 'function') {
let dropOperation = DROP_EFFECT_TO_DROP_OPERATION[state.dropEffect];
let items = readFromDataTransfer(e.dataTransfer);
let rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
let event: DropEvent = {
type: 'drop',
x: e.clientX - rect.x,
y: e.clientY - rect.y,
items,
dropOperation
};
options.onDrop(event);
}

🤔 Expected Behavior?

I wish I could just do this:

<DropZone
  onDrop={(event) => {
    ok(inputRef.current);
    inputRef.current.files = event.dataTransfer.files;
  }}
>
  <FileTrigger
    ref={inputRef}
    allowsMultiple
  >
    <Button>Select files</Button>
  </FileTrigger>
  <span>Drop files here</span>
</DropZone>

😯 Current Behavior

Currently I have to do this:

<DropZone
  onDrop={async (event) => {
    const dataTransfer = new DataTransfer();
    const files = await Promise.all(
      event.items
        .filter((x) => x.kind === 'file')
        .map(async (x) => x.getFile()),
    );
    for (const file of files) dataTransfer.items.add(file);
    ok(inputRef.current);
    inputRef.current.files = dataTransfer.files;
  }}
>
  <FileTrigger
    ref={inputRef}
    allowsMultiple
  >
    <Button>Select files</Button>
  </FileTrigger>
  <span>Drop files here</span>
</DropZone>

Activity

LFDanLu

LFDanLu commented on Aug 6, 2024

@LFDanLu
Member

@devongovett I don't recall if we had a reason behind discarding the original dataTransfer other than the various inconsistencies that are handled in readFromDataTransfer.

snowystinger

snowystinger commented on Aug 7, 2024

@snowystinger
Member

Possibly related, our decision to split our current FileTrigger away from forms, #5751

alecmev

alecmev commented on Aug 7, 2024

@alecmev
ContributorAuthor

FileTrigger is just an example, it can be a raw <input type="file" />.

devongovett

devongovett commented on Aug 7, 2024

@devongovett
Member

The problem is that there isn't always a DataTransfer available for all types of drops. For example, dnd using the keyboard is custom and does not use native dnd.

alecmev

alecmev commented on Aug 8, 2024

@alecmev
ContributorAuthor

Okay, I understand. I guess it doesn't make sense to expose the whole dataTransfer, maybe just dataTransfer.files would be acceptable? Looks like onKeyboardDrop can only produce text items:

if (typeof this.currentDropTarget.onDrop === 'function') {
let items: DropItem[] = this.dragTarget.items.map(item => ({
kind: 'text',
types: new Set(Object.keys(item)),
getText: (type: string) => Promise.resolve(item[type])
}));
let rect = this.currentDropTarget.element.getBoundingClientRect();
this.currentDropTarget.onDrop({
type: 'drop',
x: rect.left + (rect.width / 2),
y: rect.top + (rect.height / 2),
items,
dropOperation: this.dropOperation
}, item?.target);
}

So it doesn't even need to be synthesized there, just omit files. Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @devongovett@snowystinger@alecmev@LFDanLu

        Issue actions

          Pass `dataTransfer` through in `onDrop` · Issue #6835 · adobe/react-spectrum