mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Fixes bug causing gallery to close on context menu open
This commit is contained in:
parent
76e7e82f5e
commit
b6dd5b664c
@ -1,25 +1,37 @@
|
||||
import { RefObject, useEffect } from 'react';
|
||||
import { RefObject, useEffect, useRef } from 'react';
|
||||
import { Rect } from 'react-konva';
|
||||
|
||||
const useClickOutsideWatcher = (
|
||||
ref: RefObject<HTMLElement>,
|
||||
callback: () => void,
|
||||
req = true
|
||||
) => {
|
||||
const watchers: {
|
||||
ref: RefObject<HTMLElement>;
|
||||
enable: boolean;
|
||||
callback: () => void;
|
||||
}[] = [];
|
||||
|
||||
const useClickOutsideWatcher = () => {
|
||||
useEffect(() => {
|
||||
function handleClickOutside(e: MouseEvent) {
|
||||
if (ref.current && !ref.current.contains(e.target as Node)) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
if (req) {
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
watchers.forEach(({ ref, enable, callback }) => {
|
||||
if (enable && ref.current && !ref.current.contains(e.target as Node)) {
|
||||
console.log('callback');
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => {
|
||||
if (req) {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
}
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, [ref, req, callback]);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
addWatcher: (watcher: {
|
||||
ref: RefObject<HTMLElement>;
|
||||
callback: () => void;
|
||||
enable: boolean;
|
||||
}) => {
|
||||
watchers.push(watcher);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default useClickOutsideWatcher;
|
||||
|
@ -7,7 +7,10 @@ import {
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||
import { setCurrentImage } from 'features/gallery/store/gallerySlice';
|
||||
import {
|
||||
setCurrentImage,
|
||||
setShouldHoldGalleryOpen,
|
||||
} from 'features/gallery/store/gallerySlice';
|
||||
import { FaCheck, FaTrashAlt } from 'react-icons/fa';
|
||||
import DeleteImageModal from './DeleteImageModal';
|
||||
import { memo, useState } from 'react';
|
||||
@ -153,10 +156,9 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
|
||||
return (
|
||||
<ContextMenu.Root
|
||||
// onOpenChange={(open: boolean) => {
|
||||
// dispatch(setShouldHoldGalleryOpen(open));
|
||||
// dispatch(setShouldShowGallery(true));
|
||||
// }}
|
||||
onOpenChange={(open: boolean) => {
|
||||
dispatch(setShouldHoldGalleryOpen(open));
|
||||
}}
|
||||
>
|
||||
<ContextMenu.Trigger>
|
||||
<Box
|
||||
@ -204,6 +206,9 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
<ContextMenu.Content
|
||||
className="hoverable-image-context-menu"
|
||||
sticky={'always'}
|
||||
onInteractOutside={(e) => {
|
||||
e.detail.originalEvent.preventDefault();
|
||||
}}
|
||||
>
|
||||
<ContextMenu.Item
|
||||
onClickCapture={handleUsePrompt}
|
||||
|
@ -3,6 +3,7 @@ import { NumberSize, Resizable } from 're-resizable';
|
||||
|
||||
import {
|
||||
ChangeEvent,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
@ -39,7 +40,6 @@ import { BiReset } from 'react-icons/bi';
|
||||
import IAICheckbox from 'common/components/IAICheckbox';
|
||||
import { setDoesCanvasNeedScaling } from 'features/canvas/store/canvasSlice';
|
||||
import _ from 'lodash';
|
||||
import useClickOutsideWatcher from 'common/hooks/useClickOutsideWatcher';
|
||||
|
||||
const GALLERY_SHOW_BUTTONS_MIN_WIDTH = 320;
|
||||
|
||||
@ -124,15 +124,15 @@ export default function ImageGallery() {
|
||||
shouldPinGallery && dispatch(setDoesCanvasNeedScaling(true));
|
||||
};
|
||||
|
||||
const handleCloseGallery = () => {
|
||||
const handleCloseGallery = useCallback(() => {
|
||||
dispatch(setShouldShowGallery(false));
|
||||
dispatch(setShouldHoldGalleryOpen(false));
|
||||
dispatch(
|
||||
setGalleryScrollPosition(
|
||||
galleryContainerRef.current ? galleryContainerRef.current.scrollTop : 0
|
||||
)
|
||||
);
|
||||
dispatch(setShouldHoldGalleryOpen(false));
|
||||
};
|
||||
}, [dispatch]);
|
||||
|
||||
const handleClickLoadMore = () => {
|
||||
dispatch(requestImages(currentCategory));
|
||||
@ -144,6 +144,7 @@ export default function ImageGallery() {
|
||||
};
|
||||
|
||||
const setCloseGalleryTimer = () => {
|
||||
if (shouldHoldGalleryOpen) return;
|
||||
timeoutIdRef.current = window.setTimeout(() => handleCloseGallery(), 500);
|
||||
};
|
||||
|
||||
@ -273,12 +274,25 @@ export default function ImageGallery() {
|
||||
setShouldShowButtons(galleryWidth >= 280);
|
||||
}, [galleryWidth]);
|
||||
|
||||
useClickOutsideWatcher(galleryRef, handleCloseGallery, !shouldPinGallery);
|
||||
useEffect(() => {
|
||||
function handleClickOutside(e: MouseEvent) {
|
||||
if (
|
||||
galleryRef.current &&
|
||||
!galleryRef.current.contains(e.target as Node)
|
||||
) {
|
||||
handleCloseGallery();
|
||||
}
|
||||
}
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, [handleCloseGallery]);
|
||||
|
||||
return (
|
||||
<CSSTransition
|
||||
nodeRef={galleryRef}
|
||||
in={shouldShowGallery || (shouldHoldGalleryOpen && !shouldPinGallery)}
|
||||
in={shouldShowGallery || shouldHoldGalleryOpen}
|
||||
unmountOnExit
|
||||
timeout={200}
|
||||
classNames="image-gallery-wrapper"
|
||||
@ -288,6 +302,7 @@ export default function ImageGallery() {
|
||||
style={{ zIndex: shouldPinGallery ? 1 : 100 }}
|
||||
data-pinned={shouldPinGallery}
|
||||
ref={galleryRef}
|
||||
// onMouseLeave={setCloseGalleryTimer}
|
||||
onMouseLeave={!shouldPinGallery ? setCloseGalleryTimer : undefined}
|
||||
onMouseEnter={!shouldPinGallery ? cancelCloseGalleryTimer : undefined}
|
||||
onMouseOver={!shouldPinGallery ? cancelCloseGalleryTimer : undefined}
|
||||
|
@ -1,12 +1,11 @@
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import _ from 'lodash';
|
||||
import { MouseEvent, ReactNode, useCallback, useRef } from 'react';
|
||||
import React, { ReactNode, useCallback, useEffect, useRef } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs';
|
||||
import { CSSTransition } from 'react-transition-group';
|
||||
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
||||
import useClickOutsideWatcher from 'common/hooks/useClickOutsideWatcher';
|
||||
import {
|
||||
OptionsState,
|
||||
setOptionsPanelScrollPosition,
|
||||
@ -101,15 +100,8 @@ const InvokeOptionsPanel = (props: Props) => {
|
||||
);
|
||||
dispatch(setShouldShowOptionsPanel(false));
|
||||
dispatch(setShouldHoldOptionsPanelOpen(false));
|
||||
// dispatch(setDoesCanvasNeedScaling(true));
|
||||
}, [dispatch, shouldPinOptionsPanel]);
|
||||
|
||||
useClickOutsideWatcher(
|
||||
optionsPanelRef,
|
||||
handleCloseOptionsPanel,
|
||||
!shouldPinOptionsPanel
|
||||
);
|
||||
|
||||
const setCloseOptionsPanelTimer = () => {
|
||||
timeoutIdRef.current = window.setTimeout(
|
||||
() => handleCloseOptionsPanel(),
|
||||
@ -126,6 +118,21 @@ const InvokeOptionsPanel = (props: Props) => {
|
||||
dispatch(setDoesCanvasNeedScaling(true));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
function handleClickOutside(e: MouseEvent) {
|
||||
if (
|
||||
optionsPanelRef.current &&
|
||||
!optionsPanelRef.current.contains(e.target as Node)
|
||||
) {
|
||||
handleCloseOptionsPanel();
|
||||
}
|
||||
}
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, [handleCloseOptionsPanel]);
|
||||
|
||||
return (
|
||||
<CSSTransition
|
||||
nodeRef={optionsPanelRef}
|
||||
@ -153,7 +160,7 @@ const InvokeOptionsPanel = (props: Props) => {
|
||||
<div
|
||||
className="options-panel"
|
||||
ref={optionsPanelContainerRef}
|
||||
onMouseLeave={(e: MouseEvent<HTMLDivElement>) => {
|
||||
onMouseLeave={(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (e.target !== optionsPanelContainerRef.current) {
|
||||
cancelCloseOptionsPanelTimer();
|
||||
} else {
|
||||
|
@ -6,9 +6,7 @@ import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
||||
import NodesWIP from 'common/components/WorkInProgress/NodesWIP';
|
||||
import { PostProcessingWIP } from 'common/components/WorkInProgress/PostProcessingWIP';
|
||||
import ImageToImageIcon from 'common/icons/ImageToImageIcon';
|
||||
import InpaintIcon from 'common/icons/InpaintIcon';
|
||||
import NodesIcon from 'common/icons/NodesIcon';
|
||||
import OutpaintIcon from 'common/icons/OutpaintIcon';
|
||||
import PostprocessingIcon from 'common/icons/PostprocessingIcon';
|
||||
import TextToImageIcon from 'common/icons/TextToImageIcon';
|
||||
import {
|
||||
|
Loading…
Reference in New Issue
Block a user