From 53a3dc52bc448e112b73128fe8dda3aeacf42a13 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 16 May 2025 12:00:39 +1000 Subject: [PATCH] feat(ui): viewer is a modal (wip) --- .../src/app/components/GlobalHookIsolator.tsx | 8 +++ .../app/components/GlobalModalIsolator.tsx | 2 + .../components/CanvasDropArea.tsx | 6 -- .../components/CanvasMainPanelContent.tsx | 2 - .../components/CanvasRightPanel.tsx | 17 +---- .../NewSessionConfirmationAlertDialog.tsx | 9 +-- .../components/Tool/ToolBboxButton.tsx | 6 +- .../components/Tool/ToolBrushButton.tsx | 6 +- .../components/Tool/ToolBrushWidth.tsx | 10 ++- .../components/Tool/ToolColorPickerButton.tsx | 6 +- .../components/Tool/ToolEraserButton.tsx | 6 +- .../components/Tool/ToolEraserWidth.tsx | 10 ++- .../components/Tool/ToolFillColorPicker.tsx | 6 +- .../components/Tool/ToolMoveButton.tsx | 6 +- .../components/Tool/ToolRectButton.tsx | 6 +- .../components/Tool/ToolViewButton.tsx | 6 +- .../Toolbar/CanvasToolbarResetViewButton.tsx | 26 ++++---- .../hooks/useCanvasDeleteLayerHotkey.ts | 7 +- .../hooks/useCanvasEntityQuickSwitchHotkey.ts | 5 +- .../hooks/useCanvasResetLayerHotkey.ts | 6 +- .../hooks/useCanvasUndoRedoHotkeys.tsx | 10 ++- .../controlLayers/hooks/useEntityFilter.ts | 5 +- .../hooks/useEntitySegmentAnything.ts | 5 +- .../controlLayers/hooks/useEntityTransform.ts | 8 +-- .../web/src/features/dnd/DndImage.tsx | 4 ++ .../components/ImageViewer/ImageViewer.tsx | 65 ++++++++++++------- .../components/ImageViewer/useImageViewer.ts | 3 +- .../FloatingParametersPanelButtons.tsx | 4 +- 28 files changed, 114 insertions(+), 146 deletions(-) diff --git a/invokeai/frontend/web/src/app/components/GlobalHookIsolator.tsx b/invokeai/frontend/web/src/app/components/GlobalHookIsolator.tsx index 5dfcdcab5b..4be48fcd2c 100644 --- a/invokeai/frontend/web/src/app/components/GlobalHookIsolator.tsx +++ b/invokeai/frontend/web/src/app/components/GlobalHookIsolator.tsx @@ -10,9 +10,11 @@ import type { PartialAppConfig } from 'app/types/invokeai'; import { useFocusRegionWatcher } from 'common/hooks/focus'; import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys'; import { useDynamicPromptsWatcher } from 'features/dynamicPrompts/hooks/useDynamicPromptsWatcher'; +import { toggleImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useStarterModelsToast } from 'features/modelManagerV2/hooks/useStarterModelsToast'; import { useWorkflowBuilderWatcher } from 'features/nodes/components/sidePanel/workflow/IsolatedWorkflowBuilderWatcher'; import { useReadinessWatcher } from 'features/queue/store/readiness'; +import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { configChanged } from 'features/system/store/configSlice'; import { selectLanguage } from 'features/system/store/systemSelectors'; import i18n from 'i18n'; @@ -61,6 +63,12 @@ export const GlobalHookIsolator = memo( useWorkflowBuilderWatcher(); useDynamicPromptsWatcher(); + useRegisteredHotkeys({ + id: 'toggleViewer', + category: 'viewer', + callback: toggleImageViewer, + }); + return null; } ); diff --git a/invokeai/frontend/web/src/app/components/GlobalModalIsolator.tsx b/invokeai/frontend/web/src/app/components/GlobalModalIsolator.tsx index da982d105f..ae83f0c5c2 100644 --- a/invokeai/frontend/web/src/app/components/GlobalModalIsolator.tsx +++ b/invokeai/frontend/web/src/app/components/GlobalModalIsolator.tsx @@ -11,6 +11,7 @@ import { FullscreenDropzone } from 'features/dnd/FullscreenDropzone'; import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal'; import DeleteBoardModal from 'features/gallery/components/Boards/DeleteBoardModal'; import { ImageContextMenu } from 'features/gallery/components/ImageContextMenu/ImageContextMenu'; +import { ImageViewerModal } from 'features/gallery/components/ImageViewer/ImageViewer'; import { ShareWorkflowModal } from 'features/nodes/components/sidePanel/workflow/WorkflowLibrary/ShareWorkflowModal'; import { WorkflowLibraryModal } from 'features/nodes/components/sidePanel/workflow/WorkflowLibrary/WorkflowLibraryModal'; import { CancelAllExceptCurrentQueueItemConfirmationAlertDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog'; @@ -58,6 +59,7 @@ export const GlobalModalIsolator = memo(() => { + ); }); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasDropArea.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasDropArea.tsx index e988ecce68..adf21bd318 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasDropArea.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasDropArea.tsx @@ -2,7 +2,6 @@ import { Grid, GridItem } from '@invoke-ai/ui-library'; import { useCanvasIsBusy } from 'features/controlLayers/hooks/useCanvasIsBusy'; import { newCanvasEntityFromImageDndTarget } from 'features/dnd/dnd'; import { DndDropTarget } from 'features/dnd/DndDropTarget'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -19,13 +18,8 @@ const addGlobalReferenceImageFromImageDndTargetData = newCanvasEntityFromImageDn export const CanvasDropArea = memo(() => { const { t } = useTranslation(); - const imageViewer = useImageViewer(); const isBusy = useCanvasIsBusy(); - if (imageViewer.isOpen) { - return null; - } - return ( <> { - ); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasRightPanel.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasRightPanel.tsx index ac0c669005..c1bca93a26 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasRightPanel.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasRightPanel.tsx @@ -11,7 +11,6 @@ import { DndDropOverlay } from 'features/dnd/DndDropOverlay'; import type { DndTargetState } from 'features/dnd/types'; import GalleryPanelContent from 'features/gallery/components/GalleryPanelContent'; import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; -import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { selectActiveTabCanvasRightPanel } from 'features/ui/store/uiSelectors'; import { activeTabCanvasRightPanelChanged } from 'features/ui/store/uiSlice'; import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -32,11 +31,8 @@ export const CanvasRightPanel = memo(() => { }, [activeTab]); const onClickViewerToggleButton = useCallback(() => { - if (activeTab !== 'gallery') { - dispatch(activeTabCanvasRightPanelChanged('gallery')); - } - imageViewer.toggle(); - }, [imageViewer, activeTab, dispatch]); + imageViewer.open(); + }, [imageViewer]); const onChangeTab = useCallback( (index: number) => { @@ -49,20 +45,13 @@ export const CanvasRightPanel = memo(() => { [dispatch] ); - useRegisteredHotkeys({ - id: 'toggleViewer', - category: 'viewer', - callback: imageViewer.toggle, - dependencies: [imageViewer], - }); - return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/NewSessionConfirmationAlertDialog.tsx b/invokeai/frontend/web/src/features/controlLayers/components/NewSessionConfirmationAlertDialog.tsx index b365abb807..f57818964c 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/NewSessionConfirmationAlertDialog.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/NewSessionConfirmationAlertDialog.tsx @@ -3,7 +3,6 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAssertSingleton } from 'common/hooks/useAssertSingleton'; import { buildUseBoolean } from 'common/hooks/useBoolean'; import { newCanvasSessionRequested, newGallerySessionRequested } from 'features/controlLayers/store/actions'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { selectSystemShouldConfirmOnNewSession, shouldConfirmOnNewSessionToggled, @@ -17,15 +16,13 @@ const [useNewCanvasSessionDialog] = buildUseBoolean(false); export const useNewGallerySession = () => { const dispatch = useAppDispatch(); - const imageViewer = useImageViewer(); const shouldConfirmOnNewSession = useAppSelector(selectSystemShouldConfirmOnNewSession); const newSessionDialog = useNewGallerySessionDialog(); const newGallerySessionImmediate = useCallback(() => { dispatch(newGallerySessionRequested()); - imageViewer.open(); dispatch(activeTabCanvasRightPanelChanged('gallery')); - }, [dispatch, imageViewer]); + }, [dispatch]); const newGallerySessionWithDialog = useCallback(() => { if (shouldConfirmOnNewSession) { @@ -40,15 +37,13 @@ export const useNewGallerySession = () => { export const useNewCanvasSession = () => { const dispatch = useAppDispatch(); - const imageViewer = useImageViewer(); const shouldConfirmOnNewSession = useAppSelector(selectSystemShouldConfirmOnNewSession); const newSessionDialog = useNewCanvasSessionDialog(); const newCanvasSessionImmediate = useCallback(() => { dispatch(newCanvasSessionRequested()); - imageViewer.close(); dispatch(activeTabCanvasRightPanelChanged('layers')); - }, [dispatch, imageViewer]); + }, [dispatch]); const newCanvasSessionWithDialog = useCallback(() => { if (shouldConfirmOnNewSession) { diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBboxButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBboxButton.tsx index 4796092faf..30f5eb0c38 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBboxButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBboxButton.tsx @@ -1,6 +1,5 @@ import { IconButton, Tooltip } from '@invoke-ai/ui-library'; import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,14 +9,13 @@ export const ToolBboxButton = memo(() => { const { t } = useTranslation(); const selectBbox = useSelectTool('bbox'); const isSelected = useToolIsSelected('bbox'); - const imageViewer = useImageViewer(); useRegisteredHotkeys({ id: 'selectBboxTool', category: 'canvas', callback: selectBbox, - options: { enabled: !isSelected && !imageViewer.isOpen }, - dependencies: [selectBbox, isSelected, imageViewer.isOpen], + options: { enabled: !isSelected }, + dependencies: [selectBbox, isSelected], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBrushButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBrushButton.tsx index d9afdb18f5..1f3f2a0044 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBrushButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBrushButton.tsx @@ -1,6 +1,5 @@ import { IconButton, Tooltip } from '@invoke-ai/ui-library'; import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,14 +9,13 @@ export const ToolBrushButton = memo(() => { const { t } = useTranslation(); const isSelected = useToolIsSelected('brush'); const selectBrush = useSelectTool('brush'); - const imageViewer = useImageViewer(); useRegisteredHotkeys({ id: 'selectBrushTool', category: 'canvas', callback: selectBrush, - options: { enabled: !isSelected && !imageViewer.isOpen }, - dependencies: [isSelected, selectBrush, imageViewer.isOpen], + options: { enabled: !isSelected }, + dependencies: [isSelected, selectBrush], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBrushWidth.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBrushWidth.tsx index a8dcb12c71..6d14493d50 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBrushWidth.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolBrushWidth.tsx @@ -16,7 +16,6 @@ import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useToolIsSelected } from 'features/controlLayers/components/Tool/hooks'; import { selectCanvasSettingsSlice, settingsBrushWidthChanged } from 'features/controlLayers/store/canvasSettingsSlice'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { clamp } from 'lodash-es'; import type { KeyboardEvent } from 'react'; @@ -69,7 +68,6 @@ const sliderDefaultValue = mapRawValueToSliderValue(50); export const ToolBrushWidth = memo(() => { const dispatch = useAppDispatch(); const { t } = useTranslation(); - const imageViewer = useImageViewer(); const isSelected = useToolIsSelected('brush'); const width = useAppSelector(selectBrushWidth); const [localValue, setLocalValue] = useState(width); @@ -133,15 +131,15 @@ export const ToolBrushWidth = memo(() => { id: 'decrementToolWidth', category: 'canvas', callback: decrement, - options: { enabled: isSelected && !imageViewer.isOpen }, - dependencies: [decrement, isSelected, imageViewer.isOpen], + options: { enabled: isSelected }, + dependencies: [decrement, isSelected], }); useRegisteredHotkeys({ id: 'incrementToolWidth', category: 'canvas', callback: increment, - options: { enabled: isSelected && !imageViewer.isOpen }, - dependencies: [increment, isSelected, imageViewer.isOpen], + options: { enabled: isSelected }, + dependencies: [increment, isSelected], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolColorPickerButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolColorPickerButton.tsx index 1f48b2ee72..a8c590163e 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolColorPickerButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolColorPickerButton.tsx @@ -1,6 +1,5 @@ import { IconButton, Tooltip } from '@invoke-ai/ui-library'; import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,14 +9,13 @@ export const ToolColorPickerButton = memo(() => { const { t } = useTranslation(); const isSelected = useToolIsSelected('colorPicker'); const selectColorPicker = useSelectTool('colorPicker'); - const imageViewer = useImageViewer(); useRegisteredHotkeys({ id: 'selectColorPickerTool', category: 'canvas', callback: selectColorPicker, - options: { enabled: !isSelected && !imageViewer.isOpen }, - dependencies: [selectColorPicker, isSelected, imageViewer.isOpen], + options: { enabled: !isSelected }, + dependencies: [selectColorPicker, isSelected], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolEraserButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolEraserButton.tsx index 8257523367..f9de6cc4aa 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolEraserButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolEraserButton.tsx @@ -1,6 +1,5 @@ import { IconButton, Tooltip } from '@invoke-ai/ui-library'; import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,14 +9,13 @@ export const ToolEraserButton = memo(() => { const { t } = useTranslation(); const isSelected = useToolIsSelected('eraser'); const selectEraser = useSelectTool('eraser'); - const imageViewer = useImageViewer(); useRegisteredHotkeys({ id: 'selectEraserTool', category: 'canvas', callback: selectEraser, - options: { enabled: !isSelected && !imageViewer.isOpen }, - dependencies: [isSelected, selectEraser, imageViewer.isOpen], + options: { enabled: !isSelected }, + dependencies: [isSelected, selectEraser], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolEraserWidth.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolEraserWidth.tsx index 1bcdd69297..a0821c8776 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolEraserWidth.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolEraserWidth.tsx @@ -19,7 +19,6 @@ import { selectCanvasSettingsSlice, settingsEraserWidthChanged, } from 'features/controlLayers/store/canvasSettingsSlice'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { clamp } from 'lodash-es'; import type { KeyboardEvent } from 'react'; @@ -72,7 +71,6 @@ const sliderDefaultValue = mapRawValueToSliderValue(50); export const ToolEraserWidth = memo(() => { const dispatch = useAppDispatch(); const { t } = useTranslation(); - const imageViewer = useImageViewer(); const isSelected = useToolIsSelected('eraser'); const width = useAppSelector(selectEraserWidth); const [localValue, setLocalValue] = useState(width); @@ -136,15 +134,15 @@ export const ToolEraserWidth = memo(() => { id: 'decrementToolWidth', category: 'canvas', callback: decrement, - options: { enabled: isSelected && !imageViewer.isOpen }, - dependencies: [decrement, isSelected, imageViewer.isOpen], + options: { enabled: isSelected }, + dependencies: [decrement, isSelected], }); useRegisteredHotkeys({ id: 'incrementToolWidth', category: 'canvas', callback: increment, - options: { enabled: isSelected && !imageViewer.isOpen }, - dependencies: [increment, isSelected, imageViewer.isOpen], + options: { enabled: isSelected }, + dependencies: [increment, isSelected], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx index 7d1b4bdd0e..8b3de75e72 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx @@ -14,7 +14,6 @@ import RgbaColorPicker from 'common/components/ColorPicker/RgbaColorPicker'; import { rgbaColorToString } from 'common/util/colorCodeTransformers'; import { selectCanvasSettingsSlice, settingsColorChanged } from 'features/controlLayers/store/canvasSettingsSlice'; import type { RgbaColor } from 'features/controlLayers/store/types'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -31,14 +30,13 @@ export const ToolColorPicker = memo(() => { }, [dispatch] ); - const imageViewer = useImageViewer(); useRegisteredHotkeys({ id: 'setFillToWhite', category: 'canvas', callback: () => dispatch(settingsColorChanged({ r: 255, g: 255, b: 255, a: 1 })), - options: { preventDefault: true, enabled: !imageViewer.isOpen }, - dependencies: [dispatch, imageViewer.isOpen], + options: { preventDefault: true }, + dependencies: [dispatch], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolMoveButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolMoveButton.tsx index 63cbbbce8f..cd842e64b6 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolMoveButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolMoveButton.tsx @@ -1,6 +1,5 @@ import { IconButton, Tooltip } from '@invoke-ai/ui-library'; import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,14 +9,13 @@ export const ToolMoveButton = memo(() => { const { t } = useTranslation(); const isSelected = useToolIsSelected('move'); const selectMove = useSelectTool('move'); - const imageViewer = useImageViewer(); useRegisteredHotkeys({ id: 'selectMoveTool', category: 'canvas', callback: selectMove, - options: { enabled: !isSelected && !imageViewer.isOpen }, - dependencies: [isSelected, selectMove, imageViewer.isOpen], + options: { enabled: !isSelected }, + dependencies: [isSelected, selectMove], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolRectButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolRectButton.tsx index 6e9251c1ef..9302939088 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolRectButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolRectButton.tsx @@ -1,6 +1,5 @@ import { IconButton, Tooltip } from '@invoke-ai/ui-library'; import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,14 +9,13 @@ export const ToolRectButton = memo(() => { const { t } = useTranslation(); const isSelected = useToolIsSelected('rect'); const selectRect = useSelectTool('rect'); - const imageViewer = useImageViewer(); useRegisteredHotkeys({ id: 'selectRectTool', category: 'canvas', callback: selectRect, - options: { enabled: !isSelected && !imageViewer.isOpen }, - dependencies: [isSelected, selectRect, imageViewer.isOpen], + options: { enabled: !isSelected }, + dependencies: [isSelected, selectRect], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolViewButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolViewButton.tsx index f58e66b91c..f16c055fcf 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolViewButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolViewButton.tsx @@ -1,6 +1,5 @@ import { IconButton, Tooltip } from '@invoke-ai/ui-library'; import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,14 +9,13 @@ export const ToolViewButton = memo(() => { const { t } = useTranslation(); const isSelected = useToolIsSelected('view'); const selectView = useSelectTool('view'); - const imageViewer = useImageViewer(); useRegisteredHotkeys({ id: 'selectViewTool', category: 'canvas', callback: selectView, - options: { enabled: !isSelected && !imageViewer.isOpen }, - dependencies: [selectView, isSelected, imageViewer.isOpen], + options: { enabled: !isSelected }, + dependencies: [selectView, isSelected], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarResetViewButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarResetViewButton.tsx index 88aae8a2ba..547575cff2 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarResetViewButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarResetViewButton.tsx @@ -1,7 +1,6 @@ import { IconButton } from '@invoke-ai/ui-library'; import { useIsRegionFocused } from 'common/hooks/focus'; import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -11,49 +10,48 @@ export const CanvasToolbarResetViewButton = memo(() => { const { t } = useTranslation(); const canvasManager = useCanvasManager(); const isCanvasFocused = useIsRegionFocused('canvas'); - const imageViewer = useImageViewer(); useRegisteredHotkeys({ id: 'fitLayersToCanvas', category: 'canvas', callback: canvasManager.stage.fitLayersToStage, - options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true }, - dependencies: [isCanvasFocused, imageViewer.isOpen], + options: { enabled: isCanvasFocused, preventDefault: true }, + dependencies: [isCanvasFocused], }); useRegisteredHotkeys({ id: 'fitBboxToCanvas', category: 'canvas', callback: canvasManager.stage.fitBboxToStage, - options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true }, - dependencies: [isCanvasFocused, imageViewer.isOpen], + options: { enabled: isCanvasFocused, preventDefault: true }, + dependencies: [isCanvasFocused], }); useRegisteredHotkeys({ id: 'setZoomTo100Percent', category: 'canvas', callback: () => canvasManager.stage.setScale(1), - options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true }, - dependencies: [isCanvasFocused, imageViewer.isOpen], + options: { enabled: isCanvasFocused, preventDefault: true }, + dependencies: [isCanvasFocused], }); useRegisteredHotkeys({ id: 'setZoomTo200Percent', category: 'canvas', callback: () => canvasManager.stage.setScale(2), - options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true }, - dependencies: [isCanvasFocused, imageViewer.isOpen], + options: { enabled: isCanvasFocused, preventDefault: true }, + dependencies: [isCanvasFocused], }); useRegisteredHotkeys({ id: 'setZoomTo400Percent', category: 'canvas', callback: () => canvasManager.stage.setScale(4), - options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true }, - dependencies: [isCanvasFocused, imageViewer.isOpen], + options: { enabled: isCanvasFocused, preventDefault: true }, + dependencies: [isCanvasFocused], }); useRegisteredHotkeys({ id: 'setZoomTo800Percent', category: 'canvas', callback: () => canvasManager.stage.setScale(8), - options: { enabled: isCanvasFocused && !imageViewer.isOpen, preventDefault: true }, - dependencies: [isCanvasFocused, imageViewer.isOpen], + options: { enabled: isCanvasFocused, preventDefault: true }, + dependencies: [isCanvasFocused], }); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasDeleteLayerHotkey.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasDeleteLayerHotkey.ts index 98d9222bd7..11ac1b6897 100644 --- a/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasDeleteLayerHotkey.ts +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasDeleteLayerHotkey.ts @@ -3,7 +3,6 @@ import { useAssertSingleton } from 'common/hooks/useAssertSingleton'; import { useCanvasIsBusy } from 'features/controlLayers/hooks/useCanvasIsBusy'; import { entityDeleted } from 'features/controlLayers/store/canvasSlice'; import { selectSelectedEntityIdentifier } from 'features/controlLayers/store/selectors'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { selectActiveTab, selectActiveTabCanvasRightPanel } from 'features/ui/store/uiSelectors'; import { useCallback, useMemo } from 'react'; @@ -16,8 +15,6 @@ export function useCanvasDeleteLayerHotkey() { const canvasRightPanelTab = useAppSelector(selectActiveTabCanvasRightPanel); const appTab = useAppSelector(selectActiveTab); - const imageViewer = useImageViewer(); - const deleteSelectedLayer = useCallback(() => { if (selectedEntityIdentifier === null) { return; @@ -34,7 +31,7 @@ export function useCanvasDeleteLayerHotkey() { id: 'deleteSelected', category: 'canvas', callback: deleteSelectedLayer, - options: { enabled: isDeleteEnabled && !imageViewer.isOpen }, - dependencies: [isDeleteEnabled, deleteSelectedLayer, imageViewer.isOpen], + options: { enabled: isDeleteEnabled }, + dependencies: [isDeleteEnabled, deleteSelectedLayer], }); } diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasEntityQuickSwitchHotkey.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasEntityQuickSwitchHotkey.ts index 10b51c585f..f8ee66c289 100644 --- a/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasEntityQuickSwitchHotkey.ts +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasEntityQuickSwitchHotkey.ts @@ -5,7 +5,6 @@ import { selectSelectedEntityIdentifier, } from 'features/controlLayers/store/selectors'; import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { useCallback, useEffect, useState } from 'react'; @@ -15,7 +14,6 @@ export const useCanvasEntityQuickSwitchHotkey = () => { const [current, setCurrent] = useState(null); const selected = useAppSelector(selectSelectedEntityIdentifier); const bookmarked = useAppSelector(selectBookmarkedEntityIdentifier); - const imageViewer = useImageViewer(); // Update prev and current when selected entity changes useEffect(() => { @@ -49,7 +47,6 @@ export const useCanvasEntityQuickSwitchHotkey = () => { id: 'quickSwitch', category: 'canvas', callback: onQuickSwitch, - options: { enabled: !imageViewer.isOpen }, - dependencies: [onQuickSwitch, imageViewer.isOpen], + dependencies: [onQuickSwitch], }); }; diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasResetLayerHotkey.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasResetLayerHotkey.ts index cfa648eb9f..b62d2d7dfd 100644 --- a/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasResetLayerHotkey.ts +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasResetLayerHotkey.ts @@ -6,7 +6,6 @@ import { useEntityIsLocked } from 'features/controlLayers/hooks/useEntityIsLocke import { entityReset } from 'features/controlLayers/store/canvasSlice'; import { selectSelectedEntityIdentifier } from 'features/controlLayers/store/selectors'; import { isMaskEntityIdentifier } from 'features/controlLayers/store/types'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { useCallback, useMemo } from 'react'; @@ -17,7 +16,6 @@ export function useCanvasResetLayerHotkey() { const isBusy = useCanvasIsBusy(); const adapter = useEntityAdapterSafe(entityIdentifier); const isLocked = useEntityIsLocked(entityIdentifier); - const imageViewer = useImageViewer(); const resetSelectedLayer = useCallback(() => { if (entityIdentifier === null || adapter === null) { @@ -36,7 +34,7 @@ export function useCanvasResetLayerHotkey() { id: 'resetSelected', category: 'canvas', callback: resetSelectedLayer, - options: { enabled: isResetAllowed && !isBusy && !isLocked && !imageViewer.isOpen }, - dependencies: [isResetAllowed, isBusy, isLocked, resetSelectedLayer, imageViewer.isOpen], + options: { enabled: isResetAllowed && !isBusy && !isLocked }, + dependencies: [isResetAllowed, isBusy, isLocked, resetSelectedLayer], }); } diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasUndoRedoHotkeys.tsx b/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasUndoRedoHotkeys.tsx index c5b1c03023..9e90a197e6 100644 --- a/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasUndoRedoHotkeys.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasUndoRedoHotkeys.tsx @@ -3,7 +3,6 @@ import { useAssertSingleton } from 'common/hooks/useAssertSingleton'; import { useCanvasIsBusy } from 'features/controlLayers/hooks/useCanvasIsBusy'; import { canvasRedo, canvasUndo } from 'features/controlLayers/store/canvasSlice'; import { selectCanvasMayRedo, selectCanvasMayUndo } from 'features/controlLayers/store/selectors'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { useCallback } from 'react'; import { useDispatch } from 'react-redux'; @@ -12,7 +11,6 @@ export const useCanvasUndoRedoHotkeys = () => { useAssertSingleton('useCanvasUndoRedo'); const dispatch = useDispatch(); const isBusy = useCanvasIsBusy(); - const imageViewer = useImageViewer(); const mayUndo = useAppSelector(selectCanvasMayUndo); const handleUndo = useCallback(() => { @@ -22,8 +20,8 @@ export const useCanvasUndoRedoHotkeys = () => { id: 'undo', category: 'canvas', callback: handleUndo, - options: { enabled: mayUndo && !isBusy && !imageViewer.isOpen, preventDefault: true }, - dependencies: [mayUndo, isBusy, handleUndo, imageViewer.isOpen], + options: { enabled: mayUndo && !isBusy, preventDefault: true }, + dependencies: [mayUndo, isBusy, handleUndo], }); const mayRedo = useAppSelector(selectCanvasMayRedo); @@ -34,7 +32,7 @@ export const useCanvasUndoRedoHotkeys = () => { id: 'redo', category: 'canvas', callback: handleRedo, - options: { enabled: mayRedo && !isBusy && !imageViewer.isOpen, preventDefault: true }, - dependencies: [mayRedo, handleRedo, isBusy, imageViewer.isOpen], + options: { enabled: mayRedo && !isBusy, preventDefault: true }, + dependencies: [mayRedo, handleRedo, isBusy], }); }; diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityFilter.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityFilter.ts index c86aa92dc2..e3da064b51 100644 --- a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityFilter.ts +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityFilter.ts @@ -5,13 +5,11 @@ import { useEntityIsEmpty } from 'features/controlLayers/hooks/useEntityIsEmpty' import { useEntityIsLocked } from 'features/controlLayers/hooks/useEntityIsLocked'; import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'; import { isFilterableEntityIdentifier } from 'features/controlLayers/store/types'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useCallback, useMemo } from 'react'; export const useEntityFilter = (entityIdentifier: CanvasEntityIdentifier | null) => { const canvasManager = useCanvasManager(); const adapter = useEntityAdapterSafe(entityIdentifier); - const imageViewer = useImageViewer(); const isBusy = useCanvasIsBusy(); const isLocked = useEntityIsLocked(entityIdentifier); const isEmpty = useEntityIsEmpty(entityIdentifier); @@ -52,9 +50,8 @@ export const useEntityFilter = (entityIdentifier: CanvasEntityIdentifier | null) if (!adapter) { return; } - imageViewer.close(); adapter.filterer.start(); - }, [isDisabled, entityIdentifier, canvasManager, imageViewer]); + }, [isDisabled, entityIdentifier, canvasManager]); return { isDisabled, start } as const; }; diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntitySegmentAnything.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntitySegmentAnything.ts index 0893f02119..2959bb9b96 100644 --- a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntitySegmentAnything.ts +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntitySegmentAnything.ts @@ -5,13 +5,11 @@ import { useEntityIsEmpty } from 'features/controlLayers/hooks/useEntityIsEmpty' import { useEntityIsLocked } from 'features/controlLayers/hooks/useEntityIsLocked'; import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'; import { isSegmentableEntityIdentifier } from 'features/controlLayers/store/types'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useCallback, useMemo } from 'react'; export const useEntitySegmentAnything = (entityIdentifier: CanvasEntityIdentifier | null) => { const canvasManager = useCanvasManager(); const adapter = useEntityAdapterSafe(entityIdentifier); - const imageViewer = useImageViewer(); const isBusy = useCanvasIsBusy(); const isLocked = useEntityIsLocked(entityIdentifier); const isEmpty = useEntityIsEmpty(entityIdentifier); @@ -52,9 +50,8 @@ export const useEntitySegmentAnything = (entityIdentifier: CanvasEntityIdentifie if (!adapter) { return; } - imageViewer.close(); adapter.segmentAnything.start(); - }, [isDisabled, entityIdentifier, canvasManager, imageViewer]); + }, [isDisabled, entityIdentifier, canvasManager]); return { isDisabled, start } as const; }; diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTransform.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTransform.ts index 5b7e3fbc74..624cb4395d 100644 --- a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTransform.ts +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTransform.ts @@ -5,13 +5,11 @@ import { useEntityIsEmpty } from 'features/controlLayers/hooks/useEntityIsEmpty' import { useEntityIsLocked } from 'features/controlLayers/hooks/useEntityIsLocked'; import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'; import { isTransformableEntityIdentifier } from 'features/controlLayers/store/types'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useCallback, useMemo } from 'react'; export const useEntityTransform = (entityIdentifier: CanvasEntityIdentifier | null) => { const canvasManager = useCanvasManager(); const adapter = useEntityAdapterSafe(entityIdentifier); - const imageViewer = useImageViewer(); const isBusy = useCanvasIsBusy(); const isLocked = useEntityIsLocked(entityIdentifier); const isEmpty = useEntityIsEmpty(entityIdentifier); @@ -52,9 +50,8 @@ export const useEntityTransform = (entityIdentifier: CanvasEntityIdentifier | nu if (!adapter) { return; } - imageViewer.close(); await adapter.transformer.startTransform(); - }, [isDisabled, entityIdentifier, canvasManager, imageViewer]); + }, [isDisabled, entityIdentifier, canvasManager]); const fitToBbox = useCallback(async () => { if (isDisabled) { @@ -70,11 +67,10 @@ export const useEntityTransform = (entityIdentifier: CanvasEntityIdentifier | nu if (!adapter) { return; } - imageViewer.close(); await adapter.transformer.startTransform({ silent: true }); adapter.transformer.fitToBboxContain(); await adapter.transformer.applyTransform(); - }, [canvasManager, entityIdentifier, imageViewer, isDisabled]); + }, [canvasManager, entityIdentifier, isDisabled]); return { isDisabled, start, fitToBbox } as const; }; diff --git a/invokeai/frontend/web/src/features/dnd/DndImage.tsx b/invokeai/frontend/web/src/features/dnd/DndImage.tsx index 533bc2bd4c..5e7042cde7 100644 --- a/invokeai/frontend/web/src/features/dnd/DndImage.tsx +++ b/invokeai/frontend/web/src/features/dnd/DndImage.tsx @@ -8,6 +8,7 @@ import type { DndDragPreviewSingleImageState } from 'features/dnd/DndDragPreview import { createSingleImageDragPreview, setSingleImageDragPreview } from 'features/dnd/DndDragPreviewSingleImage'; import { firefoxDndFix } from 'features/dnd/util'; import { useImageContextMenu } from 'features/gallery/components/ImageContextMenu/ImageContextMenu'; +import { $imageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { memo, useEffect, useState } from 'react'; import type { ImageDTO } from 'services/api/types'; @@ -47,6 +48,9 @@ export const DndImage = memo(({ imageDTO, asThumbnail, ...rest }: DndImage.Props getInitialData: () => singleImageDndSource.getData({ imageDTO }, imageDTO.image_name), onDragStart: () => { setIsDragging(true); + if ($imageViewer.get()) { + $imageViewer.set(false); + } }, onDrop: () => { setIsDragging(false); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx index 5f080d1ab6..4264196bca 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx @@ -1,4 +1,4 @@ -import { Box, IconButton, type SystemStyleObject } from '@invoke-ai/ui-library'; +import { Box, IconButton, type SystemStyleObject, useOutsideClick } from '@invoke-ai/ui-library'; import { useAppSelector } from 'app/store/storeHooks'; import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper'; import { useAssertSingleton } from 'common/hooks/useAssertSingleton'; @@ -9,7 +9,7 @@ import { ImageComparisonDroppable } from 'features/gallery/components/ImageViewe import { ViewerToolbar } from 'features/gallery/components/ImageViewer/ViewerToolbar'; import { selectHasImageToCompare } from 'features/gallery/store/gallerySelectors'; import type { ReactNode } from 'react'; -import { memo } from 'react'; +import { memo, useRef } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; import { PiXBold } from 'react-icons/pi'; @@ -43,7 +43,7 @@ export const ImageViewer = memo(({ closeButton }: Props) => { const [containerRef, containerDims] = useMeasure(); return ( - + {hasImageToCompare && } {!hasImageToCompare && } @@ -57,17 +57,50 @@ export const ImageViewer = memo(({ closeButton }: Props) => { ImageViewer.displayName = 'ImageViewer'; -export const GatedImageViewer = memo(() => { +const imageViewerContainerSx: SystemStyleObject = { + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + left: 0, + transition: 'opacity 0.15s ease', + opacity: 1, + pointerEvents: 'auto', + '&[data-hidden="true"]': { + opacity: 0, + pointerEvents: 'none', + }, + backdropFilter: 'blur(10px) brightness(70%)', +}; + +const imageViewerModalSx: SystemStyleObject = { + position: 'absolute', + bg: 'base.800', + borderRadius: 'base', + top: 16, + right: 16, + bottom: 16, + left: 16, +}; + +export const ImageViewerModal = memo(() => { + const ref = useRef(null); const imageViewer = useImageViewer(); + useOutsideClick({ + ref, + handler: imageViewer.close, + }); - if (!imageViewer.isOpen) { - return null; - } - - return } />; + return ( + + + } /> + + + ); }); -GatedImageViewer.displayName = 'GatedImageViewer'; +ImageViewerModal.displayName = 'GatedImageViewer'; const ImageViewerCloseButton = memo(() => { const { t } = useTranslation(); @@ -87,15 +120,3 @@ const ImageViewerCloseButton = memo(() => { }); ImageViewerCloseButton.displayName = 'ImageViewerCloseButton'; - -const GatedImageViewerCloseButton = memo(() => { - const imageViewer = useImageViewer(); - - if (!imageViewer.isOpen) { - return null; - } - - return ; -}); - -GatedImageViewerCloseButton.displayName = 'GatedImageViewerCloseButton'; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/useImageViewer.ts b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/useImageViewer.ts index 854326450f..038c5ee607 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/useImageViewer.ts +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/useImageViewer.ts @@ -27,9 +27,10 @@ import type { ImageDTO } from 'services/api/types'; * TODO(psyche): Figure out a better way to do handle this... */ let didCloseImageViewer = false; -const api = buildUseBoolean(true); +const api = buildUseBoolean(false); const useImageViewerState = api[0]; export const $imageViewer = api[1]; +export const toggleImageViewer = () => $imageViewer.set(!$imageViewer.get()); export const useImageViewer = () => { const dispatch = useAppDispatch(); diff --git a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx index a731d40ad9..61a118881e 100644 --- a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx +++ b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx @@ -2,7 +2,6 @@ import { ButtonGroup, Flex, Icon, IconButton, spinAnimation, Tooltip, useShiftMo import { useAppSelector } from 'app/store/storeHooks'; import { ToolChooser } from 'features/controlLayers/components/Tool/ToolChooser'; import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; import { useCancelAllExceptCurrentQueueItemDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog'; import { useClearQueueDialog } from 'features/queue/components/ClearQueueConfirmationAlertDialog'; import { InvokeButtonTooltip } from 'features/queue/components/InvokeButtonTooltip/InvokeButtonTooltip'; @@ -30,12 +29,11 @@ type Props = { const FloatingSidePanelButtons = ({ togglePanel }: Props) => { const { t } = useTranslation(); const tab = useAppSelector(selectActiveTab); - const imageViewer = useImageViewer(); const isCancelAndClearAllEnabled = useFeatureStatus('cancelAndClearAll'); return ( - {tab === 'canvas' && !imageViewer.isOpen && ( + {tab === 'canvas' && (