Repository: adobe/react-spectrum
File: packages/react-aria-components/src/useDragAndDrop.tsx (TypeScript)

Code before:
  DraggableCollectionStateOptions,
  DroppableCollectionState,
  DroppableCollectionStateOptions,
  useDraggableCollectionState,
  useDroppableCollectionState
} from 'react-stately';
import {isVirtualDragging} from '@react-aria/dnd';
import {JSX, useMemo} from 'react';

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

interface DragHooks {
  useDraggableCollectionState?: (props: DraggableCollectionStateOpts) => DraggableCollectionState,
  useDraggableCollection?: (props: DraggableCollectionOptions, state: DraggableCollectionState, ref: RefObject<HTMLElement | null>) => void,
  useDraggableItem?: (props: DraggableItemProps, state: DraggableCollectionState) => DraggableItemResult,
  DragPreview?: typeof DragPreview,
  renderDragPreview?: (items: DragItem[]) => JSX.Element,
  isVirtualDragging?: () => boolean
}

interface DropHooks {
  useDroppableCollectionState?: (props: DroppableCollectionStateOptions) => DroppableCollectionState,
  useDroppableCollection?: (props: DroppableCollectionOptions, state: DroppableCollectionState, ref: RefObject<HTMLElement | null>) => DroppableCollectionResult,
  useDroppableItem?: (options: DroppableItemOptions, state: DroppableCollectionState, ref: RefObject<HTMLElement | null>) => DroppableItemResult,
  useDropIndicator?: (props: AriaDropIndicatorProps, state: DroppableCollectionState, ref: RefObject<HTMLElement | null>) => DropIndicatorAria,
  renderDropIndicator?: (target: DropTarget, keys: Set<Key>, draggedKey?: Key) => JSX.Element,
  dropTargetDelegate?: DropTargetDelegate,
  ListDropTargetDelegate: typeof ListDropTargetDelegate
}

export type DragAndDropHooks = DragHooks & DropHooks

export interface DragAndDrop {
  /** Drag and drop hooks for the collection element.  */
  dragAndDropHooks: DragAndDropHooks
}

export interface DragAndDropOptions extends Omit<DraggableCollectionProps, 'preview' | 'getItems'>, DroppableCollectionProps {
  /**
   * A function that returns the items being dragged. If not specified, we assume that the collection is not draggable.
   * @default () => []
   */
  getItems?: (keys: Set<Key>) => 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.
   */
  renderDragPreview?: (items: DragItem[]) => JSX.Element,
  /**
   * A function that renders a drop indicator element between two items in a collection.
   * This should render a `<DropIndicator>` element. If this function is not provided, a

Review comment (suggestion):
I think the API is fine, its consistent with things like `renderPreview`. One small nit would be to perhaps make `keys` optional instead since we won't have access to keys/draggedKeys if the user is dropping from Finder for example 

Code after:
  DraggableCollectionStateOptions,
  DroppableCollectionState,
  DroppableCollectionStateOptions,
  useDraggableCollectionState,
  useDroppableCollectionState
} from 'react-stately';
import {isVirtualDragging} from '@react-aria/dnd';
import {JSX, useMemo} from 'react';

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

interface DragHooks {
  useDraggableCollectionState?: (props: DraggableCollectionStateOpts) => DraggableCollectionState,
  useDraggableCollection?: (props: DraggableCollectionOptions, state: DraggableCollectionState, ref: RefObject<HTMLElement | null>) => void,
  useDraggableItem?: (props: DraggableItemProps, state: DraggableCollectionState) => DraggableItemResult,
  DragPreview?: typeof DragPreview,
  renderDragPreview?: (items: DragItem[]) => JSX.Element,
  isVirtualDragging?: () => boolean
}

interface DropHooks {
  useDroppableCollectionState?: (props: DroppableCollectionStateOptions) => DroppableCollectionState,
  useDroppableCollection?: (props: DroppableCollectionOptions, state: DroppableCollectionState, ref: RefObject<HTMLElement | null>) => DroppableCollectionResult,
  useDroppableItem?: (options: DroppableItemOptions, state: DroppableCollectionState, ref: RefObject<HTMLElement | null>) => DroppableItemResult,
  useDropIndicator?: (props: AriaDropIndicatorProps, state: DroppableCollectionState, ref: RefObject<HTMLElement | null>) => DropIndicatorAria,
  renderDropIndicator?: (target: DropTarget, keys?: Set<Key>, draggedKey?: Key) => JSX.Element,
  dropTargetDelegate?: DropTargetDelegate,
  ListDropTargetDelegate: typeof ListDropTargetDelegate
}

export type DragAndDropHooks = DragHooks & DropHooks

export interface DragAndDrop {
  /** Drag and drop hooks for the collection element.  */
  dragAndDropHooks: DragAndDropHooks
}

export interface DragAndDropOptions extends Omit<DraggableCollectionProps, 'preview' | 'getItems'>, DroppableCollectionProps {
  /**
   * A function that returns the items being dragged. If not specified, we assume that the collection is not draggable.
   * @default () => []
   */
  getItems?: (keys: Set<Key>) => 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.
   */
  renderDragPreview?: (items: DragItem[]) => JSX.Element,
  /**
   * A function that renders a drop indicator element between two items in a collection.
   * This should render a `<DropIndicator>` element. If this function is not provided, a