mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): move viewport state to nanostores
This commit is contained in:
parent
6cf5b402c6
commit
7f78fe7a36
@ -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;
|
||||||
|
@ -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(() => {
|
||||||
|
@ -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,
|
||||||
|
@ -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';
|
||||||
|
Loading…
Reference in New Issue
Block a user