| 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', |
| |
| '&[data-dnd-state="idle"]': { |
| pointerEvents: 'none', |
| }, |
| } satisfies SystemStyleObject; |
|
|
| type Props<T extends AnyDndTarget> = { |
| dndTarget: T; |
| dndTargetData: ReturnType<T['getData']>; |
| label: string; |
| isDisabled?: boolean; |
| }; |
|
|
| export const DndDropTarget = memo(<T extends AnyDndTarget>(props: Props<T>) => { |
| const { dndTarget, dndTargetData, label, isDisabled } = props; |
| const [dndState, setDndState] = useState<DndTargetState>('idle'); |
| const ref = useRef<HTMLDivElement>(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 }) => { |
| |
| |
| |
| 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 }) => { |
| |
| |
| |
| 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 ( |
| <Box ref={ref} sx={sx} data-dnd-state={dndState}> |
| <DndDropOverlay dndState={dndState} label={label} /> |
| </Box> |
| ); |
| }); |
|
|
| DndDropTarget.displayName = 'DndDropTarget'; |
|
|