Give the panel the canvas, and open a flow already fitted
Opening a node or the flow settings now takes the flowbar and the dock away, leaving the graph and the panel; they come back on close, leaving by the same slideUp they arrive with. The panel header names the flow before the node, `/heating/`, which is how messages are qualified everywhere else. Opening a flow already fitted, and pressing Fit to screen, disagreed: one used a 0.25 padding capped at 1x, the other xyflow's defaults, so the button visibly jumped and a small flow opened at 100% in an empty canvas. Both read one constant now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkmeRiyeYmVZqJVwuyHq9o
This commit is contained in:
co-authored by
Claude Opus 5
parent
2bc9f684e8
commit
bcdc90edbb
@@ -19,6 +19,7 @@ import {
|
||||
} from "@tanstack/react-query"
|
||||
import { useNavigate } from "@tanstack/react-router"
|
||||
import { Workflow } from "lucide-react"
|
||||
import { AnimatePresence } from "motion/react"
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||
|
||||
import {
|
||||
@@ -40,7 +41,7 @@ import useCustomToast from "@/hooks/useCustomToast"
|
||||
import { CommandPalette } from "./CommandPalette"
|
||||
import { bindingsKey, deriveEdges, portOf, qualify } from "./deriveEdges"
|
||||
import { EdgeInspector, type InspectedEdge } from "./EdgeInspector"
|
||||
import { FlowDock } from "./FlowDock"
|
||||
import { FIT_VIEW, FlowDock } from "./FlowDock"
|
||||
import { FlowNode, type FlowNodeData } from "./FlowNode"
|
||||
import { FlowPanel } from "./FlowPanel"
|
||||
import { FlowTabs } from "./FlowTabs"
|
||||
@@ -608,6 +609,10 @@ function FlowEditorInner({ flowName }: { flowName: string }) {
|
||||
)
|
||||
|
||||
const selected = definitions.find((node) => node.id === selectedId) ?? null
|
||||
// A panel is the view you are working in: the bars would only compete with
|
||||
// it, so they step aside until it closes. On a phone the panel covers them
|
||||
// anyway, and its own close button is the way back.
|
||||
const panelOpen = Boolean(selected) || flowPanelOpen
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -646,7 +651,7 @@ function FlowEditorInner({ flowName }: { flowName: string }) {
|
||||
edgeTypes={edgeTypes}
|
||||
proOptions={{ hideAttribution: true }}
|
||||
fitView
|
||||
fitViewOptions={{ maxZoom: 1, padding: 0.25 }}
|
||||
fitViewOptions={FIT_VIEW}
|
||||
minZoom={0.25}
|
||||
maxZoom={2}
|
||||
nodeDragThreshold={5}
|
||||
@@ -660,30 +665,34 @@ function FlowEditorInner({ flowName }: { flowName: string }) {
|
||||
<CanvasBackground />
|
||||
</ReactFlow>
|
||||
|
||||
{editorExpanded ? null : (
|
||||
<FlowTabs
|
||||
flows={flows.data}
|
||||
active={flowName}
|
||||
saving={saving.isPending}
|
||||
onEditFlow={() => {
|
||||
setSelectedId(null)
|
||||
setFlowPanelOpen(true)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<AnimatePresence>
|
||||
{panelOpen ? null : (
|
||||
<FlowTabs
|
||||
key="flow-tabs"
|
||||
flows={flows.data}
|
||||
active={flowName}
|
||||
saving={saving.isPending}
|
||||
onEditFlow={() => {
|
||||
setSelectedId(null)
|
||||
setFlowPanelOpen(true)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{editorExpanded ? null : (
|
||||
<FlowDock
|
||||
issues={issues}
|
||||
running={runMutation.isPending}
|
||||
onAddNode={() => setPaletteOpen(true)}
|
||||
onRun={() => {
|
||||
flush()
|
||||
runMutation.mutate()
|
||||
}}
|
||||
onFocusNode={focusNode}
|
||||
/>
|
||||
)}
|
||||
{panelOpen ? null : (
|
||||
<FlowDock
|
||||
key="flow-dock"
|
||||
issues={issues}
|
||||
running={runMutation.isPending}
|
||||
onAddNode={() => setPaletteOpen(true)}
|
||||
onRun={() => {
|
||||
flush()
|
||||
runMutation.mutate()
|
||||
}}
|
||||
onFocusNode={focusNode}
|
||||
/>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{definitions.length === 0 ? (
|
||||
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
||||
@@ -857,7 +866,11 @@ export function FlowEditor({ flowName }: { flowName: string }) {
|
||||
|
||||
return (
|
||||
<ReactFlowProvider>
|
||||
{/* Remounting per flow keeps canvas state from leaking between them. */}
|
||||
{/*
|
||||
* Remounting per flow keeps canvas state from leaking between them, and
|
||||
* it is what makes `fitView` run once per flow: xyflow queues the fit on
|
||||
* mount and resolves it as soon as the nodes have been measured.
|
||||
*/}
|
||||
<FlowEditorInner key={flowName} flowName={flowName} />
|
||||
</ReactFlowProvider>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user