fix: fixed scrolling behavior inside editor when plan editor window is opened

ref: N25B-412
This commit is contained in:
JGerla
2026-01-05 15:53:20 +01:00
parent 149b82cb66
commit 111400bd82
4 changed files with 227 additions and 205 deletions

View File

@@ -48,7 +48,8 @@ const selector = (state: FlowState) => ({
undo: state.undo, undo: state.undo,
redo: state.redo, redo: state.redo,
beginBatchAction: state.beginBatchAction, beginBatchAction: state.beginBatchAction,
endBatchAction: state.endBatchAction endBatchAction: state.endBatchAction,
scrollable: state.scrollable
}); });
// --| define ReactFlow editor |-- // --| define ReactFlow editor |--
@@ -72,7 +73,8 @@ const VisProgUI = () => {
undo, undo,
redo, redo,
beginBatchAction, beginBatchAction,
endBatchAction endBatchAction,
scrollable
} = useFlowStore(useShallow(selector)); // instructs the editor to use the corresponding functions from the FlowStore } = useFlowStore(useShallow(selector)); // instructs the editor to use the corresponding functions from the FlowStore
// adds ctrl+z and ctrl+y support to respectively undo and redo actions // adds ctrl+z and ctrl+y support to respectively undo and redo actions
@@ -101,6 +103,7 @@ const VisProgUI = () => {
onConnect={onConnect} onConnect={onConnect}
onNodeDragStart={beginBatchAction} onNodeDragStart={beginBatchAction}
onNodeDragStop={endBatchAction} onNodeDragStop={endBatchAction}
preventScrolling={scrollable}
snapToGrid snapToGrid
fitView fitView
proOptions={{hideAttribution: true}} proOptions={{hideAttribution: true}}

View File

@@ -72,6 +72,15 @@ const useFlowStore = create<FlowState>(UndoRedo((set, get) => ({
nodes: initialNodes, nodes: initialNodes,
edges: initialEdges, edges: initialEdges,
edgeReconnectSuccessful: true, edgeReconnectSuccessful: true,
scrollable: true,
/**
* handles changing the scrollable state of the editor,
* this is used to control if scrolling is captured by the editor
* or if it's available to other components within the reactFlowProvider
* @param {boolean} val - the desired state
*/
setScrollable: (val) => set({scrollable: val}),
/** /**
* Handles changes to nodes triggered by ReactFlow. * Handles changes to nodes triggered by ReactFlow.

View File

@@ -23,6 +23,10 @@ export type FlowState = {
nodes: Node[]; nodes: Node[];
edges: Edge[]; edges: Edge[];
edgeReconnectSuccessful: boolean; edgeReconnectSuccessful: boolean;
scrollable: boolean;
/** Handler for managing scrollable state */
setScrollable: (value: boolean) => void;
/** Handler for changes to nodes triggered by ReactFlow */ /** Handler for changes to nodes triggered by ReactFlow */
onNodesChange: OnNodesChange; onNodesChange: OnNodesChange;

View File

@@ -1,4 +1,5 @@
import {useRef, useState} from "react"; import {useRef, useState} from "react";
import useFlowStore from "../VisProgStores.tsx";
import styles from './PlanEditor.module.css'; import styles from './PlanEditor.module.css';
import { GetActionValue, type Action, type ActionTypes, type Plan } from "../components/Plan"; import { GetActionValue, type Action, type ActionTypes, type Plan } from "../components/Plan";
import { defaultPlan } from "../components/Plan.default"; import { defaultPlan } from "../components/Plan.default";
@@ -21,14 +22,17 @@ export default function PlanEditorDialog({
const [draftPlan, setDraftPlan] = useState<Plan | null>(null); const [draftPlan, setDraftPlan] = useState<Plan | null>(null);
const [newActionType, setNewActionType] = useState<ActionTypes>("speech"); const [newActionType, setNewActionType] = useState<ActionTypes>("speech");
const [newActionValue, setNewActionValue] = useState(""); const [newActionValue, setNewActionValue] = useState("");
const { setScrollable } = useFlowStore();
//Button Actions //Button Actions
const openCreate = () => { const openCreate = () => {
setScrollable(false);
setDraftPlan({...structuredClone(defaultPlan), id: crypto.randomUUID()}); setDraftPlan({...structuredClone(defaultPlan), id: crypto.randomUUID()});
dialogRef.current?.showModal(); dialogRef.current?.showModal();
}; };
const openCreateWithDescription = () => { const openCreateWithDescription = () => {
setScrollable(false);
setDraftPlan({...structuredClone(defaultPlan), id: crypto.randomUUID(), name: description!}); setDraftPlan({...structuredClone(defaultPlan), id: crypto.randomUUID(), name: description!});
setNewActionType("llm") setNewActionType("llm")
setNewActionValue(description!) setNewActionValue(description!)
@@ -36,12 +40,14 @@ export default function PlanEditorDialog({
} }
const openEdit = () => { const openEdit = () => {
setScrollable(false);
if (!plan) return; if (!plan) return;
setDraftPlan(structuredClone(plan)); setDraftPlan(structuredClone(plan));
dialogRef.current?.showModal(); dialogRef.current?.showModal();
}; };
const close = () => { const close = () => {
setScrollable(true);
dialogRef.current?.close(); dialogRef.current?.close();
setDraftPlan(null); setDraftPlan(null);
}; };
@@ -75,7 +81,7 @@ export default function PlanEditorDialog({
<dialog <dialog
ref={dialogRef} ref={dialogRef}
className={`${styles.planDialog}`} className={`${styles.planDialog}`}
onWheel={(e) => e.stopPropagation()} //onWheel={(e) => e.stopPropagation()}
data-testid={"PlanEditorDialogTestID"} data-testid={"PlanEditorDialogTestID"}
> >
<form method="dialog" className="flex-col gap-md"> <form method="dialog" className="flex-col gap-md">