perf(ui): fix issue w/ add node cmdk component (more fixed)

This commit is contained in:
psychedelicious
2025-02-15 23:48:10 +10:00
parent aae4fa3cca
commit cfb08f326e
5 changed files with 31 additions and 28 deletions

View File

@@ -19,13 +19,13 @@ import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import { useBuildNode } from 'features/nodes/hooks/useBuildNode';
import {
$addNodeCmdk,
$cursorPos,
$edgePendingUpdate,
$pendingConnection,
$templates,
edgesChanged,
nodesChanged,
useAddNodeCmdk,
} from 'features/nodes/store/nodesSlice';
import { selectNodesSlice } from 'features/nodes/store/selectors';
import { findUnoccupiedPosition } from 'features/nodes/store/util/findUnoccupiedPosition';
@@ -142,19 +142,25 @@ const cmdkRootSx: SystemStyleObject = {
export const AddNodeCmdk = memo(() => {
const { t } = useTranslation();
const addNodeCmdk = useAddNodeCmdk();
const inputRef = useRef<HTMLInputElement>(null);
const [searchTerm, setSearchTerm] = useState('');
const addNode = useAddNode();
const tab = useAppSelector(selectActiveTab);
const [debouncedSearchTerm] = useDebounce(searchTerm, 300);
const isOpen = useStore($addNodeCmdk);
const open = useCallback(() => {
$addNodeCmdk.set(true);
}, []);
const close = useCallback(() => {
$addNodeCmdk.set(false);
}, []);
useRegisteredHotkeys({
id: 'addNode',
category: 'workflows',
callback: addNodeCmdk.setTrue,
callback: open,
options: { enabled: tab === 'workflows', preventDefault: true },
dependencies: [addNodeCmdk.setTrue, tab],
dependencies: [open, tab],
});
const onChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
@@ -162,10 +168,10 @@ export const AddNodeCmdk = memo(() => {
}, []);
const onClose = useCallback(() => {
addNodeCmdk.setFalse();
close();
setSearchTerm('');
$pendingConnection.set(null);
}, [addNodeCmdk]);
}, [close]);
const onSelect = useCallback(
(value: string) => {
@@ -176,14 +182,7 @@ export const AddNodeCmdk = memo(() => {
);
return (
<Modal
isOpen={addNodeCmdk.isTrue}
onClose={onClose}
useInert={false}
initialFocusRef={inputRef}
size="xl"
isCentered
>
<Modal isOpen={isOpen} onClose={onClose} useInert={false} initialFocusRef={inputRef} size="xl" isCentered>
<ModalOverlay />
<ModalContent h="512" maxH="70%">
<ModalBody p={2} h="full" sx={cmdkRootSx}>

View File

@@ -1,19 +1,22 @@
import { IconButton } from '@invoke-ai/ui-library';
import { useAddNodeCmdk } from 'features/nodes/store/nodesSlice';
import { memo } from 'react';
import { $addNodeCmdk } from 'features/nodes/store/nodesSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiPlusBold } from 'react-icons/pi';
const AddNodeButton = () => {
const addNodeCmdk = useAddNodeCmdk();
const { t } = useTranslation();
const onClick = useCallback(() => {
$addNodeCmdk.set(true);
}, []);
return (
<IconButton
tooltip={t('nodes.addNodeToolTip')}
aria-label={t('nodes.addNode')}
icon={<PiPlusBold />}
onClick={addNodeCmdk.setTrue}
onClick={onClick}
pointerEvents="auto"
/>
);

View File

@@ -1,20 +1,23 @@
import { useStore } from '@nanostores/react';
import { useReactFlow } from '@xyflow/react';
import { $templates } from 'features/nodes/store/nodesSlice';
import { $flow } from 'features/nodes/store/reactFlowInstance';
import { NODE_WIDTH } from 'features/nodes/types/constants';
import type { AnyNode, InvocationTemplate } from 'features/nodes/types/invocation';
import { buildCurrentImageNode } from 'features/nodes/util/node/buildCurrentImageNode';
import { buildInvocationNode } from 'features/nodes/util/node/buildInvocationNode';
import { buildNotesNode } from 'features/nodes/util/node/buildNotesNode';
import { useCallback } from 'react';
import { assert } from 'tsafe';
export const useBuildNode = () => {
const templates = useStore($templates);
const { screenToFlowPosition } = useReactFlow();
return useCallback(
// string here is "any invocation type"
(type: string | 'current_image' | 'notes'): AnyNode => {
const flow = $flow.get();
assert(flow !== null);
let _x = window.innerWidth / 2;
let _y = window.innerHeight / 2;
@@ -26,7 +29,7 @@ export const useBuildNode = () => {
_y = rect.height / 2 - NODE_WIDTH / 2 + rect.top;
}
const position = screenToFlowPosition({
const position = flow.screenToFlowPosition({
x: _x,
y: _y,
});
@@ -45,6 +48,6 @@ export const useBuildNode = () => {
return buildInvocationNode(position, template);
},
[screenToFlowPosition, templates]
[templates]
);
};

View File

@@ -4,12 +4,12 @@ import { useUpdateNodeInternals } from '@xyflow/react';
import { useAppStore } from 'app/store/storeHooks';
import { $mouseOverNode } from 'features/nodes/hooks/useMouseOverNode';
import {
$addNodeCmdk,
$didUpdateEdge,
$edgePendingUpdate,
$pendingConnection,
$templates,
edgesChanged,
useAddNodeCmdk,
} from 'features/nodes/store/nodesSlice';
import { selectNodes, selectNodesSlice } from 'features/nodes/store/selectors';
import { getFirstValidConnection } from 'features/nodes/store/util/getFirstValidConnection';
@@ -22,7 +22,6 @@ export const useConnection = () => {
const store = useAppStore();
const templates = useStore($templates);
const updateNodeInternals = useUpdateNodeInternals();
const addNodeCmdk = useAddNodeCmdk();
const onConnectStart = useCallback<OnConnectStart>(
(event, { nodeId, handleId, handleType }) => {
@@ -109,9 +108,9 @@ export const useConnection = () => {
$pendingConnection.set(null);
} else {
// The mouse is not over a node - we should open the add node popover
addNodeCmdk.setTrue();
$addNodeCmdk.set(true);
}
}, [addNodeCmdk, store, templates, updateNodeInternals]);
}, [store, templates, updateNodeInternals]);
const api = useMemo(() => ({ onConnectStart, onConnect, onConnectEnd }), [onConnectStart, onConnect, onConnectEnd]);
return api;

View File

@@ -3,7 +3,6 @@ import { createSlice, isAnyOf } from '@reduxjs/toolkit';
import type { EdgeChange, NodeChange, Viewport, XYPosition } from '@xyflow/react';
import { applyEdgeChanges, applyNodeChanges, getConnectedEdges, getIncomers, getOutgoers } from '@xyflow/react';
import type { PersistConfig } from 'app/store/store';
import { buildUseBoolean } from 'common/hooks/useBoolean';
import { workflowLoaded } from 'features/nodes/store/actions';
import { SHARED_NODE_PROPERTIES } from 'features/nodes/types/constants';
import type {
@@ -541,7 +540,7 @@ export const $didUpdateEdge = atom(false);
export const $lastEdgeUpdateMouseEvent = atom<MouseEvent | null>(null);
export const $viewport = atom<Viewport>({ x: 0, y: 0, zoom: 1 });
export const [useAddNodeCmdk, $addNodeCmdk] = buildUseBoolean(false);
export const $addNodeCmdk = atom(false);
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
const migrateNodesState = (state: any): any => {