adobe/react-spectrum

Custom getKeysForDrag bug - Drag and drop selected items seperatly with GridList

Open

#8.162 aberto em 29 de abr. de 2025

Ver no GitHub
 (4 comments) (0 reactions) (0 assignees)TypeScript (1.500 forks)auto 404
enhancementhelp wanted

Métricas do repositório

Stars
 (15.634 stars)
Métricas de merge de PR
 (Métricas PR pendentes)

Description

Provide a general summary of the issue here

The documentation says that getKeysForDrag returns the selected items. I want to overwrite this function to drag and drop selected items separately. Even though I overwrite it, drag and drop don't work as expected.

https://github.com/user-attachments/assets/4bf6bc62-f29e-4146-9482-a7b8a3c147f7

Overwriting getKeysForDrag, full example in "Steps to reproduce"

  dragAndDropHooks.useDraggableCollectionState =
    function useDraggableCollectionStateOverride(
      props: DraggableCollectionStateOpts
    ) {
      const draggableHook = useDraggableCollectionState({
        ...props,
        ...options,
      } as DraggableCollectionStateOptions);
      draggableHook.getKeysForDrag = function (key: string) {
        return new Set([key]); //Just the clicked item be a key for drag
      };
      return draggableHook;
    };

🤔 Expected Behavior?

Items of a GridList to be reordered (drag and drop) separately

😯 Current Behavior

All the selected keys are dragged

💁 Possible Solution

I'm not sure, I didn't realize looking at the source code where onReorder evaluates the event.keys

🔦 Context

No response

🖥️ Steps to Reproduce

Repository

You can just clone and run this repository:
https://github.com/JonRC/react-aria-grid-list-bug

Code

Here is the code used in the repository below if you want reproduce by your own

/* eslint-disable @typescript-eslint/no-empty-object-type */
import {
  DraggableCollectionStateOptions,
  useDraggableCollectionState,
  useListData,
} from "react-stately";
import {
  GridList,
  GridListItem,
  useDragAndDrop,
  Checkbox as AriaCheckbox,
  CheckboxProps,
  DragAndDropOptions,
} from "react-aria-components";
import { useMemo } from "react";

interface DraggableCollectionStateOpts
  extends Omit<DraggableCollectionStateOptions, "getItems"> {}

function App() {
  const list = useListData({
    initialItems: [
      { id: 1, name: "Adobe Photoshop" },
      { id: 2, name: "Adobe XD" },
      { id: 3, name: "Adobe Dreamweaver" },
      { id: 4, name: "Adobe InDesign" },
      { id: 5, name: "Adobe Connect" },
    ],
  });

  const options = useMemo<DragAndDropOptions>(
    () => ({
      getItems: (keys) =>
        [...keys].map((key) => ({
          "text/plain": list.getItem(key)?.name ?? "",
        })),
      onReorder(e) {
        if (e.target.dropPosition === "before") {
          list.moveBefore(e.target.key, e.keys);
        } else if (e.target.dropPosition === "after") {
          list.moveAfter(e.target.key, e.keys);
        }
      },
    }),
    [list]
  );

  const { dragAndDropHooks } = useDragAndDrop(options);

  dragAndDropHooks.useDraggableCollectionState =
    function useDraggableCollectionStateOverride(
      props: DraggableCollectionStateOpts
    ) {
      const draggableHook = useDraggableCollectionState({
        ...props,
        ...options,
      } as DraggableCollectionStateOptions);
      draggableHook.getKeysForDrag = function (key: string) {
        return new Set([key]); //Just the clicked item be a key for drag
      };
      return draggableHook;
    };

  return (
    <GridList
      aria-label="Reorderable list"
      selectionMode="multiple"
      items={list.items}
      dragAndDropHooks={dragAndDropHooks}
      style={{ marginLeft: "100px" }}
    >
      {(item) => (
        <GridListItem style={{ display: "flex" }}>
          {() => (
            <>
              <Checkbox slot="selection" />
              {item.name}
            </>
          )}
        </GridListItem>
      )}
    </GridList>
  );
}

export function Checkbox(props: CheckboxProps) {
  return (
    <AriaCheckbox {...props} style={{ display: "flex" }}>
      {({ isSelected, isIndeterminate }) => (
        <>
          <div>{isIndeterminate ? "[ ]" : isSelected ? "[x]" : "[ ]"}</div>
          {props.children}
        </>
      )}
    </AriaCheckbox>
  );
}

export default App;

Version

"react-aria-components": "^1.8.0"

What browsers are you seeing the problem on?

Chrome

If other, please specify.

No response

What operating system are you using?

Linux, Ubuntu

🧢 Your Company/Team

No response

🕷 Tracking Issue

No response

Guia do colaborador