feat(ui): use @invoke-ai/ui hooks for modifiers, global menu state

This commit is contained in:
psychedelicious 2024-01-20 20:27:55 +11:00
parent 53cf518390
commit e96ad41729
11 changed files with 12 additions and 106 deletions

View File

@ -1,7 +1,7 @@
import { PropsWithChildren, memo, useEffect } from 'react';
import { modelChanged } from '../src/features/parameters/store/generationSlice';
import { useAppDispatch } from '../src/app/store/storeHooks';
import { useGlobalModifiersInit } from '../src/common/hooks/useGlobalModifiers';
import { useGlobalModifiersInit } from '@invoke-ai/ui';
/**
* Initializes some state for storybook. Must be in a different component
* so that it is run inside the redux context.

View File

@ -1,4 +1,4 @@
import { Box } from '@invoke-ai/ui';
import { Box, useGlobalModifiersInit } from '@invoke-ai/ui';
import { useSocketIO } from 'app/hooks/useSocketIO';
import { useLogger } from 'app/logging/useLogger';
import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted';
@ -8,7 +8,6 @@ import ImageUploadOverlay from 'common/components/ImageUploadOverlay';
import { useClearStorage } from 'common/hooks/useClearStorage';
import { useFullscreenDropzone } from 'common/hooks/useFullscreenDropzone';
import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
import { useGlobalModifiersInit } from 'common/hooks/useGlobalModifiers';
import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal';
import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal';
import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';

View File

@ -1,36 +0,0 @@
import { atom } from 'nanostores';
import { useCallback, useEffect } from 'react';
type CB = () => void;
const $onCloseCallbacks = atom<CB[]>([]);
/**
* The reactflow background element somehow prevents the chakra `useOutsideClick()` hook from working.
* With a menu open, clicking on the reactflow background element doesn't close the menu.
*
* Reactflow does provide an `onPaneClick` to handle clicks on the background element, but it is not
* straightforward to programatically close all menus.
*
* This hook provides a way to close all menus by calling `onCloseGlobal()`. Menus that want to be closed
* in this way should register themselves by passing a callback to `useGlobalMenuCloseTrigger()`.
*/
export const useGlobalMenuClose = (onClose?: CB) => {
useEffect(() => {
if (!onClose) {
return;
}
$onCloseCallbacks.set([...$onCloseCallbacks.get(), onClose]);
return () => {
$onCloseCallbacks.set(
$onCloseCallbacks.get().filter((c) => c !== onClose)
);
};
}, [onClose]);
const onCloseGlobal = useCallback(() => {
$onCloseCallbacks.get().forEach((cb) => cb());
}, []);
return { onCloseGlobal };
};

View File

@ -1,52 +0,0 @@
import { atom } from 'nanostores';
import { useCallback, useEffect } from 'react';
export const $shift = atom(false);
export const $ctrl = atom(false);
export const $meta = atom(false);
export const $alt = atom(false);
const $subscribers = atom(0);
const listener = (e: KeyboardEvent) => {
$shift.set(e.shiftKey);
$ctrl.set(e.ctrlKey);
$alt.set(e.altKey);
$meta.set(e.metaKey);
};
export const useGlobalModifiersInit = () => {
useEffect(() => {
$subscribers.set($subscribers.get() + 1);
if ($subscribers.get() === 1) {
window.addEventListener('keydown', listener);
window.addEventListener('keyup', listener);
}
return () => {
$subscribers.set(Math.max($subscribers.get() - 1, 0));
if ($subscribers.get() > 0) {
return;
}
window.removeEventListener('keydown', listener);
window.removeEventListener('keyup', listener);
};
}, []);
};
export const useGlobalModifiersSetters = () => {
const setShift = useCallback((shift: boolean) => {
$shift.set(shift);
}, []);
const setCtrl = useCallback((ctrl: boolean) => {
$ctrl.set(ctrl);
}, []);
const setAlt = useCallback((alt: boolean) => {
$alt.set(alt);
}, []);
const setMeta = useCallback((meta: boolean) => {
$meta.set(meta);
}, []);
return { setShift, setCtrl, setAlt, setMeta };
};

View File

@ -1,6 +1,6 @@
import { useShiftModifier } from '@invoke-ai/ui';
import { useStore } from '@nanostores/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { $shift } from 'common/hooks/useGlobalModifiers';
import {
roundDownToMultiple,
roundDownToMultipleMin,
@ -54,7 +54,7 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
const optimalDimension = useAppSelector(selectOptimalDimension);
const transformerRef = useRef<Konva.Transformer>(null);
const shapeRef = useRef<Konva.Rect>(null);
const shift = useStore($shift);
const shift = useShiftModifier();
const tool = useStore($tool);
const isDrawing = useStore($isDrawing);
const isMovingBoundingBox = useStore($isMovingBoundingBox);

View File

@ -1,12 +1,11 @@
import type { SystemStyleObject } from '@invoke-ai/ui';
import { Box, Flex } from '@invoke-ai/ui';
import { Box, Flex, useShiftModifier } from '@invoke-ai/ui';
import { useStore } from '@nanostores/react';
import { $customStarUI } from 'app/store/nanostores/customStarUI';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIDndImage from 'common/components/IAIDndImage';
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
import IAIFillSkeleton from 'common/components/IAIFillSkeleton';
import { $shift } from 'common/hooks/useGlobalModifiers';
import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice';
import type {
GallerySelectionDraggableData,
@ -40,7 +39,7 @@ const GalleryImage = (props: HoverableImageProps) => {
const dispatch = useAppDispatch();
const { imageName } = props;
const { currentData: imageDTO } = useGetImageDTOQuery(imageName);
const shift = useStore($shift);
const shift = useShiftModifier()
const { t } = useTranslation();
const selectedBoardId = useAppSelector((s) => s.gallery.selectedBoardId);
const { handleClick, isSelected, areMultiplesSelected } =

View File

@ -1,6 +1,5 @@
import { useToken } from '@invoke-ai/ui';
import { useGlobalMenuClose, useToken } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useGlobalMenuClose } from 'common/hooks/useGlobalMenuClose';
import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection';
import { $mouseOverNode } from 'features/nodes/hooks/useMouseOverNode';
import { useWorkflowWatcher } from 'features/nodes/hooks/useWorkflowWatcher';

View File

@ -1,9 +1,8 @@
import type { ChakraProps } from '@invoke-ai/ui';
import { Box, useToken } from '@invoke-ai/ui';
import { Box, useGlobalMenuClose, useToken } from '@invoke-ai/ui';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import NodeSelectionOverlay from 'common/components/NodeSelectionOverlay';
import { useGlobalMenuClose } from 'common/hooks/useGlobalMenuClose';
import { useMouseOverNode } from 'features/nodes/hooks/useMouseOverNode';
import {
nodeExclusivelySelected,

View File

@ -1,7 +1,5 @@
import type { IconButtonProps } from '@invoke-ai/ui';
import { IconButton, useDisclosure } from '@invoke-ai/ui';
import { useStore } from '@nanostores/react';
import { $shift } from 'common/hooks/useGlobalModifiers';
import { IconButton, useDisclosure, useShiftModifier } from '@invoke-ai/ui';
import ClearQueueConfirmationAlertDialog from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { useCancelCurrentQueueItem } from 'features/queue/hooks/useCancelCurrentQueueItem';
import { useClearQueue } from 'features/queue/hooks/useClearQueue';
@ -59,7 +57,7 @@ const ClearSingleQueueItemIconButton = (props: ClearQueueButtonProps) => {
export const ClearQueueIconButton = (props: ClearQueueButtonProps) => {
// Show the single item clear button when shift is pressed
// Otherwise show the clear queue button
const shift = useStore($shift);
const shift = useShiftModifier()
const disclosure = useDisclosure();
return (

View File

@ -6,8 +6,8 @@ import {
MenuItem,
MenuList,
useDisclosure,
useGlobalMenuClose,
} from '@invoke-ai/ui';
import { useGlobalMenuClose } from 'common/hooks/useGlobalMenuClose';
import AboutModal from 'features/system/components/AboutModal/AboutModal';
import HotkeysModal from 'features/system/components/HotkeysModal/HotkeysModal';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';

View File

@ -5,8 +5,8 @@ import {
MenuDivider,
MenuList,
useDisclosure,
useGlobalMenuClose,
} from '@invoke-ai/ui';
import { useGlobalMenuClose } from 'common/hooks/useGlobalMenuClose';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import DownloadWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/DownloadWorkflowMenuItem';
import NewWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/NewWorkflowMenuItem';