import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine'; import { dropTargetForElements, monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; import type { SystemStyleObject } from '@invoke-ai/ui-library'; import { Box } from '@invoke-ai/ui-library'; import { getStore } from 'app/store/nanostores/store'; import { useAppDispatch } from 'app/store/storeHooks'; import type { AnyDndTarget } from 'features/dnd/dnd'; import { DndDropOverlay } from 'features/dnd/DndDropOverlay'; import type { DndTargetState } from 'features/dnd/types'; import { memo, useEffect, useRef, useState } from 'react'; const sx = { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, w: 'full', h: 'full', pointerEvents: 'auto', // We must disable pointer events when idle to prevent the overlay from blocking clicks '&[data-dnd-state="idle"]': { pointerEvents: 'none', }, } satisfies SystemStyleObject; type Props = { dndTarget: T; dndTargetData: ReturnType; label: string; isDisabled?: boolean; }; export const DndDropTarget = memo((props: Props) => { const { dndTarget, dndTargetData, label, isDisabled } = props; const [dndState, setDndState] = useState('idle'); const ref = useRef(null); const dispatch = useAppDispatch(); useEffect(() => { const element = ref.current; if (!element) { return; } if (isDisabled) { return; } const { dispatch, getState } = getStore(); return combine( dropTargetForElements({ element, canDrop: ({ source }) => { // TS cannot infer `dndTargetData` but we've just checked it. // TODO(psyche): Figure out how to satisfy TS. /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ const arg = { sourceData: source.data, targetData: dndTargetData, dispatch, getState } as any; return dndTarget.isValid(arg); }, onDragEnter: () => { setDndState('over'); }, onDragLeave: () => { setDndState('potential'); }, getData: () => dndTargetData, }), monitorForElements({ canMonitor: ({ source }) => { // TS cannot infer `dndTargetData` but we've just checked it. // TODO(psyche): Figure out how to satisfy TS. /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ const arg = { sourceData: source.data, targetData: dndTargetData, dispatch, getState } as any; return dndTarget.isValid(arg); }, onDragStart: () => { setDndState('potential'); }, onDrop: () => { setDndState('idle'); }, }) ); }, [dispatch, isDisabled, dndTarget, dndTargetData]); return ( ); }); DndDropTarget.displayName = 'DndDropTarget';