feat(ui): move viewport state to nanostores

This commit is contained in:
psychedelicious 2024-05-16 21:21:39 +10:00
parent 6cf5b402c6
commit 7f78fe7a36
4 changed files with 14 additions and 24 deletions

View File

@ -1,23 +1,21 @@
import type { Modifier } from '@dnd-kit/core'; import type { Modifier } from '@dnd-kit/core';
import { getEventCoordinates } from '@dnd-kit/utilities'; import { getEventCoordinates } from '@dnd-kit/utilities';
import { createSelector } from '@reduxjs/toolkit'; import { useStore } from '@nanostores/react';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectNodesSlice } from 'features/nodes/store/nodesSlice'; import { $viewport } from 'features/nodes/store/nodesSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useCallback } from 'react'; import { useCallback } from 'react';
const selectZoom = createSelector([selectNodesSlice, activeTabNameSelector], (nodes, activeTabName) =>
activeTabName === 'workflows' ? nodes.viewport.zoom : 1
);
/** /**
* Applies scaling to the drag transform (if on node editor tab) and centers it on cursor. * Applies scaling to the drag transform (if on node editor tab) and centers it on cursor.
*/ */
export const useScaledModifer = () => { export const useScaledModifer = () => {
const zoom = useAppSelector(selectZoom); const activeTabName = useAppSelector(activeTabNameSelector);
const workflowsViewport = useStore($viewport);
const modifier: Modifier = useCallback( const modifier: Modifier = useCallback(
({ activatorEvent, draggingNodeRect, transform }) => { ({ activatorEvent, draggingNodeRect, transform }) => {
if (draggingNodeRect && activatorEvent) { if (draggingNodeRect && activatorEvent) {
const zoom = activeTabName === 'workflows' ? workflowsViewport.zoom : 1;
const activatorCoordinates = getEventCoordinates(activatorEvent); const activatorCoordinates = getEventCoordinates(activatorEvent);
if (!activatorCoordinates) { if (!activatorCoordinates) {
@ -42,7 +40,7 @@ export const useScaledModifer = () => {
return transform; return transform;
}, },
[zoom] [activeTabName, workflowsViewport.zoom]
); );
return modifier; return modifier;

View File

@ -1,4 +1,5 @@
import { useGlobalMenuClose, useToken } from '@invoke-ai/ui-library'; import { useGlobalMenuClose, useToken } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useConnection } from 'features/nodes/hooks/useConnection'; import { useConnection } from 'features/nodes/hooks/useConnection';
import { useCopyPaste } from 'features/nodes/hooks/useCopyPaste'; import { useCopyPaste } from 'features/nodes/hooks/useCopyPaste';
@ -6,6 +7,7 @@ import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection'
import { useWorkflowWatcher } from 'features/nodes/hooks/useWorkflowWatcher'; import { useWorkflowWatcher } from 'features/nodes/hooks/useWorkflowWatcher';
import { import {
$cursorPos, $cursorPos,
$viewport,
connectionMade, connectionMade,
edgeAdded, edgeAdded,
edgeDeleted, edgeDeleted,
@ -16,7 +18,6 @@ import {
redo, redo,
selectedAll, selectedAll,
undo, undo,
viewportChanged,
} from 'features/nodes/store/nodesSlice'; } from 'features/nodes/store/nodesSlice';
import { $flow } from 'features/nodes/store/reactFlowInstance'; import { $flow } from 'features/nodes/store/reactFlowInstance';
import type { CSSProperties, MouseEvent } from 'react'; import type { CSSProperties, MouseEvent } from 'react';
@ -64,7 +65,7 @@ export const Flow = memo(() => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const nodes = useAppSelector((s) => s.nodes.present.nodes); const nodes = useAppSelector((s) => s.nodes.present.nodes);
const edges = useAppSelector((s) => s.nodes.present.edges); const edges = useAppSelector((s) => s.nodes.present.edges);
const viewport = useAppSelector((s) => s.nodes.present.viewport); const viewport = useStore($viewport);
const shouldSnapToGrid = useAppSelector((s) => s.workflowSettings.shouldSnapToGrid); const shouldSnapToGrid = useAppSelector((s) => s.workflowSettings.shouldSnapToGrid);
const selectionMode = useAppSelector((s) => s.workflowSettings.selectionMode); const selectionMode = useAppSelector((s) => s.workflowSettings.selectionMode);
const { onConnectStart, onConnect, onConnectEnd } = useConnection(); const { onConnectStart, onConnect, onConnectEnd } = useConnection();
@ -108,12 +109,9 @@ export const Flow = memo(() => {
[dispatch] [dispatch]
); );
const handleMoveEnd: OnMoveEnd = useCallback( const handleMoveEnd: OnMoveEnd = useCallback((e, viewport) => {
(e, viewport) => { $viewport.set(viewport);
dispatch(viewportChanged(viewport)); }, []);
},
[dispatch]
);
const { onCloseGlobal } = useGlobalMenuClose(); const { onCloseGlobal } = useGlobalMenuClose();
const handlePaneClick = useCallback(() => { const handlePaneClick = useCallback(() => {

View File

@ -75,7 +75,6 @@ const initialNodesState: NodesState = {
nodes: [], nodes: [],
edges: [], edges: [],
nodeExecutionStates: {}, nodeExecutionStates: {},
viewport: { x: 0, y: 0, zoom: 1 },
}; };
type FieldValueAction<T extends FieldValue> = PayloadAction<{ type FieldValueAction<T extends FieldValue> = PayloadAction<{
@ -410,9 +409,6 @@ export const nodesSlice = createSlice({
state.nodes = []; state.nodes = [];
state.edges = []; state.edges = [];
}, },
viewportChanged: (state, action: PayloadAction<Viewport>) => {
state.viewport = action.payload;
},
selectedAll: (state) => { selectedAll: (state) => {
state.nodes = applyNodeChanges( state.nodes = applyNodeChanges(
state.nodes.map((n) => ({ id: n.id, type: 'select', selected: true })), state.nodes.map((n) => ({ id: n.id, type: 'select', selected: true })),
@ -586,7 +582,6 @@ export const {
notesNodeValueChanged, notesNodeValueChanged,
selectedAll, selectedAll,
selectionPasted, selectionPasted,
viewportChanged,
edgeAdded, edgeAdded,
undo, undo,
redo, redo,
@ -598,6 +593,7 @@ export const $copiedNodes = atom<AnyNode[]>([]);
export const $copiedEdges = atom<InvocationNodeEdge[]>([]); export const $copiedEdges = atom<InvocationNodeEdge[]>([]);
export const $pendingConnection = atom<PendingConnection | null>(null); export const $pendingConnection = atom<PendingConnection | null>(null);
export const $isModifyingEdge = atom(false); export const $isModifyingEdge = atom(false);
export const $viewport = atom<Viewport>({ x: 0, y: 0, zoom: 1 });
export const $isAddNodePopoverOpen = atom(false); export const $isAddNodePopoverOpen = atom(false);
export const closeAddNodePopover = () => { export const closeAddNodePopover = () => {
$isAddNodePopoverOpen.set(false); $isAddNodePopoverOpen.set(false);
@ -638,7 +634,7 @@ const isSelectionAction = (action: UnknownAction) => {
return false; return false;
}; };
const individualGroupByMatcher = isAnyOf(nodesChanged, viewportChanged); const individualGroupByMatcher = isAnyOf(nodesChanged);
export const nodesUndoableConfig: UndoableOptions<NodesState, UnknownAction> = { export const nodesUndoableConfig: UndoableOptions<NodesState, UnknownAction> = {
limit: 64, limit: 64,

View File

@ -12,7 +12,6 @@ import type {
NodeExecutionState, NodeExecutionState,
} from 'features/nodes/types/invocation'; } from 'features/nodes/types/invocation';
import type { WorkflowV3 } from 'features/nodes/types/workflow'; import type { WorkflowV3 } from 'features/nodes/types/workflow';
import type { Viewport } from 'reactflow';
export type Templates = Record<string, InvocationTemplate>; export type Templates = Record<string, InvocationTemplate>;
@ -27,7 +26,6 @@ export type NodesState = {
nodes: AnyNode[]; nodes: AnyNode[];
edges: InvocationNodeEdge[]; edges: InvocationNodeEdge[];
nodeExecutionStates: Record<string, NodeExecutionState>; nodeExecutionStates: Record<string, NodeExecutionState>;
viewport: Viewport;
}; };
export type WorkflowMode = 'edit' | 'view'; export type WorkflowMode = 'edit' | 'view';