adobe/react-spectrum

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

Open

#8,162 建立於 2025年4月29日

在 GitHub 查看
 (4 留言) (0 反應) (0 負責人)TypeScript (1,500 fork)auto 404
enhancementhelp wanted

倉庫指標

Star
 (15,634 star)
PR 合併指標
 (PR 指標待抓取)

描述

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

貢獻者指南