diff --git a/packages/@react-spectrum/dnd/src/useDragAndDrop.ts b/packages/@react-spectrum/dnd/src/useDragAndDrop.ts index e69e3c73702..fa3a30fb8ac 100644 --- a/packages/@react-spectrum/dnd/src/useDragAndDrop.ts +++ b/packages/@react-spectrum/dnd/src/useDragAndDrop.ts @@ -39,10 +39,10 @@ import { } from '@react-stately/dnd'; import {JSX, useMemo} from 'react'; -interface DraggableCollectionStateOpts extends Omit {} +interface DraggableCollectionStateOpts extends Omit, 'getItems'> {} -interface DragHooks { - useDraggableCollectionState?: (props: DraggableCollectionStateOpts) => DraggableCollectionState, +interface DragHooks { + useDraggableCollectionState?: (props: DraggableCollectionStateOpts) => DraggableCollectionState, useDraggableCollection?: (props: DraggableCollectionOptions, state: DraggableCollectionState, ref: RefObject) => void, useDraggableItem?: (props: DraggableItemProps, state: DraggableCollectionState) => DraggableItemResult, DragPreview?: typeof DragPreview @@ -55,17 +55,17 @@ interface DropHooks { useDropIndicator?: (props: DropIndicatorProps, state: DroppableCollectionState, ref: RefObject) => DropIndicatorAria } -export interface DragAndDropHooks { +export interface DragAndDropHooks { /** Drag and drop hooks for the collection element. */ - dragAndDropHooks: DragHooks & DropHooks & {isVirtualDragging?: () => boolean, renderPreview?: (keys: Set, draggedKey: Key) => JSX.Element} + dragAndDropHooks: DragHooks & DropHooks & {isVirtualDragging?: () => boolean, renderPreview?: (keys: Set, draggedKey: Key) => JSX.Element} } -export interface DragAndDropOptions extends Omit, Omit { +export interface DragAndDropOptions extends Omit, Omit { /** * A function that returns the items being dragged. If not specified, we assume that the collection is not draggable. * @default () => [] */ - getItems?: (keys: Set) => DragItem[], + getItems?: (keys: Set, items: T[]) => DragItem[], /** Provide a custom drag preview. `draggedKey` represents the key of the item the user actually dragged. */ renderPreview?: (keys: Set, draggedKey: Key) => JSX.Element } @@ -73,7 +73,7 @@ export interface DragAndDropOptions extends Omit(options: DragAndDropOptions): DragAndDropHooks { let dragAndDropHooks = useMemo(() => { let { onDrop, @@ -90,7 +90,7 @@ export function useDragAndDrop(options: DragAndDropOptions): DragAndDropHooks { let hooks = {} as DragHooks & DropHooks & {isVirtualDragging?: () => boolean, renderPreview?: (keys: Set, draggedKey: Key) => JSX.Element}; if (isDraggable) { - hooks.useDraggableCollectionState = function useDraggableCollectionStateOverride(props: DraggableCollectionStateOpts) { + hooks.useDraggableCollectionState = function useDraggableCollectionStateOverride(props: DraggableCollectionStateOpts) { return useDraggableCollectionState({...props, ...options, getItems: options.getItems!}); }; hooks.useDraggableCollection = useDraggableCollection; diff --git a/packages/@react-spectrum/list/src/ListView.tsx b/packages/@react-spectrum/list/src/ListView.tsx index 9481f98a410..c34b366d268 100644 --- a/packages/@react-spectrum/list/src/ListView.tsx +++ b/packages/@react-spectrum/list/src/ListView.tsx @@ -59,14 +59,14 @@ export interface SpectrumListViewProps extends Omit, 'ke /** * The drag and drop hooks returned by `useDragAndDrop` used to enable drag and drop behavior for the ListView. */ - dragAndDropHooks?: DragAndDropHooks['dragAndDropHooks'] + dragAndDropHooks?: DragAndDropHooks>['dragAndDropHooks'] } interface ListViewContextValue { state: ListState, dragState: DraggableCollectionState | null, dropState: DroppableCollectionState | null, - dragAndDropHooks?: DragAndDropHooks['dragAndDropHooks'], + dragAndDropHooks?: DragAndDropHooks['dragAndDropHooks'], onAction?: (key: Key) => void, isListDraggable: boolean, isListDroppable: boolean, diff --git a/packages/@react-spectrum/list/stories/ListViewDnDExamples.tsx b/packages/@react-spectrum/list/stories/ListViewDnDExamples.tsx index 23f4227ac4c..3df3fe23339 100644 --- a/packages/@react-spectrum/list/stories/ListViewDnDExamples.tsx +++ b/packages/@react-spectrum/list/stories/ListViewDnDExamples.tsx @@ -16,8 +16,7 @@ import {useListData} from '@react-stately/data'; export function DragExample(props: {listViewProps: SpectrumListViewProps, dragHookOptions: DragAndDropOptions, getAllowedDropOperationsAction?: () => void}): JSX.Element { let {listViewProps, dragHookOptions} = props; - let getItems = (keys) => [...keys].map(key => { - let item = items.find(item => item.key === key); + let getItems = (keys, items) => items.map(item => { return { 'text/plain': item.name }; diff --git a/packages/@react-spectrum/table/src/TableViewBase.tsx b/packages/@react-spectrum/table/src/TableViewBase.tsx index 038742935f2..5934d217e19 100644 --- a/packages/@react-spectrum/table/src/TableViewBase.tsx +++ b/packages/@react-spectrum/table/src/TableViewBase.tsx @@ -110,7 +110,7 @@ export interface TableContextValue { state: TableState | TreeGridState, dragState: DraggableCollectionState | null, dropState: DroppableCollectionState | null, - dragAndDropHooks?: DragAndDropHooks['dragAndDropHooks'], + dragAndDropHooks?: DragAndDropHooks['dragAndDropHooks'], isTableDraggable: boolean, isTableDroppable: boolean, layout: TableViewLayout, diff --git a/packages/@react-spectrum/table/src/TableViewWrapper.tsx b/packages/@react-spectrum/table/src/TableViewWrapper.tsx index 5b02ba82dbc..2787307ecfe 100644 --- a/packages/@react-spectrum/table/src/TableViewWrapper.tsx +++ b/packages/@react-spectrum/table/src/TableViewWrapper.tsx @@ -59,7 +59,7 @@ export interface SpectrumTableProps extends TableProps, SpectrumSelectionP * The drag and drop hooks returned by `useDragAndDrop` used to enable drag and drop behavior for the TableView. * @version beta */ - dragAndDropHooks?: DragAndDropHooks['dragAndDropHooks'], + dragAndDropHooks?: DragAndDropHooks>['dragAndDropHooks'], /** * Whether the TableView should support expandable rows. Requires the feature flag to be enabled first, see https://react-spectrum.adobe.com/react-spectrum/TableView.html#expandable-rows. * @version alpha diff --git a/packages/@react-stately/dnd/src/useDraggableCollectionState.ts b/packages/@react-stately/dnd/src/useDraggableCollectionState.ts index 5114fbe22a6..b3e733989f2 100644 --- a/packages/@react-stately/dnd/src/useDraggableCollectionState.ts +++ b/packages/@react-stately/dnd/src/useDraggableCollectionState.ts @@ -14,7 +14,7 @@ import {Collection, DraggableCollectionEndEvent, DraggableCollectionProps, DragI import {MultipleSelectionManager} from '@react-stately/selection'; import {useRef, useState} from 'react'; -export interface DraggableCollectionStateOptions extends DraggableCollectionProps { +export interface DraggableCollectionStateOptions extends DraggableCollectionProps { /** A collection of items. */ collection: Collection>, /** An interface for reading and updating multiple selection state. */ @@ -55,7 +55,7 @@ export interface DraggableCollectionState { /** * Manages state for a draggable collection. */ -export function useDraggableCollectionState(props: DraggableCollectionStateOptions): DraggableCollectionState { +export function useDraggableCollectionState(props: DraggableCollectionStateOptions): DraggableCollectionState { let { getItems, isDisabled, @@ -118,7 +118,16 @@ export function useDraggableCollectionState(props: DraggableCollectionStateOptio }, getKeysForDrag: getKeys, getItems(key) { - return getItems(getKeys(key)); + let keys = getKeys(key); + let items: any[] = []; + for (let key of keys) { + let value = collection.getItem(key)?.value; + if (value != null) { + items.push(value); + } + } + + return getItems(getKeys(key), items); }, isDisabled, preview, diff --git a/packages/@react-types/shared/src/dnd.d.ts b/packages/@react-types/shared/src/dnd.d.ts index 1798ea4fe25..22a57ccfc66 100644 --- a/packages/@react-types/shared/src/dnd.d.ts +++ b/packages/@react-types/shared/src/dnd.d.ts @@ -277,7 +277,7 @@ export interface DraggableCollectionEndEvent extends DragEndEvent { export type DragPreviewRenderer = (items: DragItem[], callback: (node: HTMLElement | null, x?: number, y?: number) => void) => void; -export interface DraggableCollectionProps { +export interface DraggableCollectionProps { /** Handler that is called when a drag operation is started. */ onDragStart?: (e: DraggableCollectionStartEvent) => void, /** Handler that is called when the drag is moved. */ @@ -285,7 +285,7 @@ export interface DraggableCollectionProps { /** Handler that is called when the drag operation is ended, either as a result of a drop or a cancellation. */ onDragEnd?: (e: DraggableCollectionEndEvent) => void, /** A function that returns the items being dragged. */ - getItems: (keys: Set) => DragItem[], + getItems: (keys: Set, items: T[]) => DragItem[], /** The ref of the element that will be rendered as the drag preview while dragging. */ preview?: RefObject, /** Function that returns the drop operations that are allowed for the dragged items. If not provided, all drop operations are allowed. */ diff --git a/packages/react-aria-components/src/GridList.tsx b/packages/react-aria-components/src/GridList.tsx index 9cb34f49795..e77938a12a9 100644 --- a/packages/react-aria-components/src/GridList.tsx +++ b/packages/react-aria-components/src/GridList.tsx @@ -68,7 +68,7 @@ export interface GridListProps extends Omit, 'children'> */ selectionBehavior?: SelectionBehavior, /** The drag and drop hooks returned by `useDragAndDrop` used to enable drag and drop behavior for the GridList. */ - dragAndDropHooks?: DragAndDropHooks, + dragAndDropHooks?: DragAndDropHooks>, /** Provides content to display when there are no items in the list. */ renderEmptyState?: (props: GridListRenderProps) => ReactNode, /** diff --git a/packages/react-aria-components/src/ListBox.tsx b/packages/react-aria-components/src/ListBox.tsx index 01a9862f1c0..1fda5a3206b 100644 --- a/packages/react-aria-components/src/ListBox.tsx +++ b/packages/react-aria-components/src/ListBox.tsx @@ -64,7 +64,7 @@ export interface ListBoxProps extends Omit, 'children' | */ selectionBehavior?: SelectionBehavior, /** The drag and drop hooks returned by `useDragAndDrop` used to enable drag and drop behavior for the ListBox. */ - dragAndDropHooks?: DragAndDropHooks, + dragAndDropHooks?: DragAndDropHooks>, /** Provides content to display when there are no items in the list. */ renderEmptyState?: (props: ListBoxRenderProps) => ReactNode, /** diff --git a/packages/react-aria-components/src/Tree.tsx b/packages/react-aria-components/src/Tree.tsx index 1deea65fc38..41ae85143a5 100644 --- a/packages/react-aria-components/src/Tree.tsx +++ b/packages/react-aria-components/src/Tree.tsx @@ -148,7 +148,7 @@ export interface TreeProps extends Omit, 'children'>, Multip */ disabledBehavior?: DisabledBehavior, /** The drag and drop hooks returned by `useDragAndDrop` used to enable drag and drop behavior for the Tree. */ - dragAndDropHooks?: DragAndDropHooks + dragAndDropHooks?: DragAndDropHooks> } diff --git a/packages/react-aria-components/src/useDragAndDrop.tsx b/packages/react-aria-components/src/useDragAndDrop.tsx index a9e286152b0..319868dc470 100644 --- a/packages/react-aria-components/src/useDragAndDrop.tsx +++ b/packages/react-aria-components/src/useDragAndDrop.tsx @@ -43,10 +43,10 @@ import { import {isVirtualDragging} from '@react-aria/dnd'; import {JSX, useMemo} from 'react'; -interface DraggableCollectionStateOpts extends Omit {} +interface DraggableCollectionStateOpts extends Omit, 'getItems'> {} -interface DragHooks { - useDraggableCollectionState?: (props: DraggableCollectionStateOpts) => DraggableCollectionState, +interface DragHooks { + useDraggableCollectionState?: (props: DraggableCollectionStateOpts) => DraggableCollectionState, useDraggableCollection?: (props: DraggableCollectionOptions, state: DraggableCollectionState, ref: RefObject) => void, useDraggableItem?: (props: DraggableItemProps, state: DraggableCollectionState) => DraggableItemResult, DragPreview?: typeof DragPreview, @@ -64,19 +64,19 @@ interface DropHooks { ListDropTargetDelegate: typeof ListDropTargetDelegate } -export type DragAndDropHooks = DragHooks & DropHooks +export type DragAndDropHooks = DragHooks & DropHooks -export interface DragAndDrop { +export interface DragAndDrop { /** Drag and drop hooks for the collection element. */ - dragAndDropHooks: DragAndDropHooks + dragAndDropHooks: DragAndDropHooks } -export interface DragAndDropOptions extends Omit, DroppableCollectionProps { +export interface DragAndDropOptions extends Omit, DroppableCollectionProps { /** * A function that returns the items being dragged. If not specified, we assume that the collection is not draggable. * @default () => [] */ - getItems?: (keys: Set) => DragItem[], + getItems?: (keys: Set, items: T[]) => DragItem[], /** * A function that renders a drag preview, which is shown under the user's cursor while dragging. * By default, a copy of the dragged element is rendered. @@ -97,7 +97,7 @@ export interface DragAndDropOptions extends Omit(options: DragAndDropOptions): DragAndDrop { let dragAndDropHooks = useMemo(() => { let { onDrop, diff --git a/packages/react-aria-components/stories/ListBox.stories.tsx b/packages/react-aria-components/stories/ListBox.stories.tsx index d3ffaf1a281..c65bc18e2f4 100644 --- a/packages/react-aria-components/stories/ListBox.stories.tsx +++ b/packages/react-aria-components/stories/ListBox.stories.tsx @@ -148,8 +148,8 @@ export const ListBoxDnd: AlbumListBoxStory = (props) => { initialItems: albums }); - let {dragAndDropHooks} = useDragAndDrop({ - getItems: (keys) => [...keys].map(key => ({'text/plain': list.getItem(key)?.title ?? ''})), + let {dragAndDropHooks} = useDragAndDrop({ + getItems: (keys, items) => items.map(item => ({'text/plain': item.title ?? ''})), onReorder(e) { if (e.target.dropPosition === 'before') { list.moveBefore(e.target.key, e.keys);