| import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine'; |
| import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; |
| import type { ImageProps, SystemStyleObject } from '@invoke-ai/ui-library'; |
| import { Image } from '@invoke-ai/ui-library'; |
| import { useAppStore } from 'app/store/nanostores/store'; |
| import { singleImageDndSource } from 'features/dnd/dnd'; |
| import type { DndDragPreviewSingleImageState } from 'features/dnd/DndDragPreviewSingleImage'; |
| import { createSingleImageDragPreview, setSingleImageDragPreview } from 'features/dnd/DndDragPreviewSingleImage'; |
| import { firefoxDndFix } from 'features/dnd/util'; |
| import { useImageContextMenu } from 'features/gallery/components/ImageContextMenu/ImageContextMenu'; |
| import { memo, useEffect, useState } from 'react'; |
| import type { ImageDTO } from 'services/api/types'; |
|
|
| const sx = { |
| objectFit: 'contain', |
| maxW: 'full', |
| maxH: 'full', |
| borderRadius: 'base', |
| cursor: 'grab', |
| '&[data-is-dragging=true]': { |
| opacity: 0.3, |
| }, |
| } satisfies SystemStyleObject; |
|
|
| type Props = ImageProps & { |
| imageDTO: ImageDTO; |
| asThumbnail?: boolean; |
| }; |
|
|
| export const DndImage = memo(({ imageDTO, asThumbnail, ...rest }: Props) => { |
| const store = useAppStore(); |
| const [isDragging, setIsDragging] = useState(false); |
| const [element, ref] = useState<HTMLImageElement | null>(null); |
| const [dragPreviewState, setDragPreviewState] = useState<DndDragPreviewSingleImageState | null>(null); |
|
|
| useEffect(() => { |
| if (!element) { |
| return; |
| } |
| return combine( |
| firefoxDndFix(element), |
| draggable({ |
| element, |
| getInitialData: () => singleImageDndSource.getData({ imageDTO }, imageDTO.image_name), |
| onDragStart: () => { |
| setIsDragging(true); |
| }, |
| onDrop: () => { |
| setIsDragging(false); |
| }, |
| onGenerateDragPreview: (args) => { |
| if (singleImageDndSource.typeGuard(args.source.data)) { |
| setSingleImageDragPreview({ |
| singleImageDndData: args.source.data, |
| onGenerateDragPreviewArgs: args, |
| setDragPreviewState, |
| }); |
| } |
| }, |
| }) |
| ); |
| }, [imageDTO, element, store]); |
|
|
| useImageContextMenu(imageDTO, element); |
|
|
| return ( |
| <> |
| <Image |
| role="button" |
| ref={ref} |
| src={asThumbnail ? imageDTO.thumbnail_url : imageDTO.image_url} |
| fallbackSrc={asThumbnail ? undefined : imageDTO.thumbnail_url} |
| w={imageDTO.width} |
| sx={sx} |
| data-is-dragging={isDragging} |
| {...rest} |
| /> |
| {dragPreviewState?.type === 'single-image' ? createSingleImageDragPreview(dragPreviewState) : null} |
| </> |
| ); |
| }); |
|
|
| DndImage.displayName = 'DndImage'; |
|
|