31 lines
2.0 KiB
TypeScript
31 lines
2.0 KiB
TypeScript
import type {Document,Geometry,Id,Registry} from './types.ts';
|
|
import {fault} from './values.ts';
|
|
import {unitScale} from './units.ts';
|
|
|
|
type PlacementStep={canvasId:Id;parentCanvasId:Id;entryId:Id;incarnation:number;componentId:string;dataVersion:number;geometry:Geometry;contentScale:number;unitScale:number};
|
|
|
|
/** A short-lived reader of the visible owner chain relative to one view, not the project root.
|
|
* Cache by owner only during this admission/publication, so multi-selection shares ancestry work. */
|
|
export function createGesturePlacementReader(document:Document,viewCanvasId:Id,registry:Registry){
|
|
const values=new Map<Id,readonly PlacementStep[]>();
|
|
return(ownerCanvasId:Id):readonly PlacementStep[]=>{
|
|
const cached=values.get(ownerCanvasId);if(cached)return cached;
|
|
if(!document.canvases.has(viewCanvasId))throw fault('canvas_missing',[viewCanvasId]);
|
|
const chain:PlacementStep[]=[],seen=new Set<Id>();let id=ownerCanvasId;
|
|
while(id!==viewCanvasId){
|
|
if(seen.has(id))throw fault('canvas_cycle',[id]);seen.add(id);
|
|
const parent=document.canvases.get(id)?.parent;
|
|
if(!parent)throw fault('target_outside_view',[ownerCanvasId]);
|
|
const entry=document.elements.get(parent.entryElementId);
|
|
// A future/unknown entry is a collapsed placeholder; never interpret its payload.
|
|
if(!entry||entry.structure!=='node'||registry.resolve(entry)!=='known')throw fault('target_hidden',[ownerCanvasId]);
|
|
const raw=entry.data.presentation,presentation=raw&&typeof raw==='object'&&!Array.isArray(raw)?raw:{};
|
|
if(presentation.collapsed===true)throw fault('target_hidden',[ownerCanvasId]);
|
|
const contentScale=typeof presentation.contentScale==='number'&&presentation.contentScale>0?presentation.contentScale:1;
|
|
chain.push({canvasId:id,parentCanvasId:parent.canvasId,entryId:entry.id,incarnation:entry.incarnation,componentId:entry.componentId,dataVersion:entry.dataVersion,geometry:entry.geometry,contentScale,unitScale:unitScale(raw)});
|
|
id=parent.canvasId;
|
|
}
|
|
values.set(ownerCanvasId,chain);return chain;
|
|
};
|
|
}
|