diff --git a/headless/README.md b/headless/README.md index 20d3938..cd0da58 100644 --- a/headless/README.md +++ b/headless/README.md @@ -892,3 +892,8 @@ valid ACK. Unknown fields/components/versions, unresolved requests and run/asset receipts stay raw. Existing stored raw receipts are not migrated by this policy. The recovery envelope remains unchanged: receipts are opaque JSON, and the adapter-local summary has its own version and explicit replay rejection. + +The application's initial loading fit targets the current canvas's direct node +members, including partition entries. Expanded descendant cards remain rendered +and pannable but cannot move their parent entry outside the initial viewport. +The manual fit control keeps its existing whole-scene behavior. diff --git a/src/components/canvas/headless-graph-canvas.tsx b/src/components/canvas/headless-graph-canvas.tsx index e7e4a13..60c9ed6 100644 --- a/src/components/canvas/headless-graph-canvas.tsx +++ b/src/components/canvas/headless-graph-canvas.tsx @@ -55,7 +55,14 @@ function CanvasView({ engine, board, viewId, renderers,fitLoading=true }: { engi if (liveView) lastView.current = liveView; const view = liveView ?? lastView.current!, flow = useReactFlow(); const canCreate=!loading||loading.version>=4&&engine.editor.getQueries(root.document).coverage.completeCanvasIds.includes(view.canvasId); - useEffect(()=>{if(!needsLoadingFit.current||!flow.viewportInitialized||!root.document.elements.size)return;needsLoadingFit.current=false;void flow.fitView({padding:.2,maxZoom:1});},[flow,root.document]); + useEffect(()=>{ + if(!needsLoadingFit.current||!flow.viewportInitialized||!root.document.canvases.has(view.canvasId))return; + // Expanded descendants can extend far beyond their partition entry. Initial + // framing belongs to the direct members of this canvas. + const nodes=engine.editor.getQueries(root.document).members(view.canvasId).filter(id=>root.document.elements.get(id)?.structure==='node').map(id=>({id})); + if(!nodes.length)return; + needsLoadingFit.current=false;void flow.fitView({nodes,padding:.2,maxZoom:1}); + },[engine,flow,root.document,view.canvasId]); const preparingCopy = [...(root.runtime.imports?.values() ?? [])].some(job => job.status === 'preparing' && job.source?.targetCanvasId === view.canvasId); const [editorFocused, setEditorFocused] = useState(false), focusEpoch = useRef(0); useEffect(() => { focusEpoch.current++; setEditorFocused(false); return () => { focusEpoch.current++; }; }, [engine,viewId]);