|
|
@ -892,6 +892,30 @@ function getAdapter(nodeType: NodeType | null): ComposerAdapter<WorkflowNodeData |
|
|
return null; |
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function getAbsoluteNodePosition( |
|
|
|
|
|
node: WorkflowNode, |
|
|
|
|
|
nodes: WorkflowNode[] |
|
|
|
|
|
): { x: number; y: number } { |
|
|
|
|
|
const nodeById = new Map(nodes.map((item) => [item.id, item])); |
|
|
|
|
|
const visited = new Set<string>(); |
|
|
|
|
|
|
|
|
|
|
|
const resolve = (current: WorkflowNode): { x: number; y: number } => { |
|
|
|
|
|
if (!current.parentId || visited.has(current.id)) return current.position; |
|
|
|
|
|
visited.add(current.id); |
|
|
|
|
|
|
|
|
|
|
|
const parent = nodeById.get(current.parentId); |
|
|
|
|
|
if (!parent) return current.position; |
|
|
|
|
|
|
|
|
|
|
|
const parentPosition = resolve(parent); |
|
|
|
|
|
return { |
|
|
|
|
|
x: parentPosition.x + current.position.x, |
|
|
|
|
|
y: parentPosition.y + current.position.y, |
|
|
|
|
|
}; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
return resolve(node); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
function deriveComposerContext(nodes: WorkflowNode[], edges: WorkflowEdge[]): ComposerContext { |
|
|
function deriveComposerContext(nodes: WorkflowNode[], edges: WorkflowEdge[]): ComposerContext { |
|
|
const selectedNodes = nodes.filter((node) => node.selected); |
|
|
const selectedNodes = nodes.filter((node) => node.selected); |
|
|
if (selectedNodes.length === 0) { |
|
|
if (selectedNodes.length === 0) { |
|
|
@ -1702,6 +1726,10 @@ export function GenerationComposer() { |
|
|
() => context.node ? getComposerNodeDimensions(context.node) : null, |
|
|
() => context.node ? getComposerNodeDimensions(context.node) : null, |
|
|
[context.node] |
|
|
[context.node] |
|
|
); |
|
|
); |
|
|
|
|
|
const selectedNodePosition = useMemo( |
|
|
|
|
|
() => context.node ? getAbsoluteNodePosition(context.node, nodes) : null, |
|
|
|
|
|
[context.node, nodes] |
|
|
|
|
|
); |
|
|
const safeZoom = zoom > 0 ? zoom : 1; |
|
|
const safeZoom = zoom > 0 ? zoom : 1; |
|
|
const viewportWidth = typeof window === "undefined" ? Number.POSITIVE_INFINITY : window.innerWidth; |
|
|
const viewportWidth = typeof window === "undefined" ? Number.POSITIVE_INFINITY : window.innerWidth; |
|
|
const visibleLeft = -viewportX / safeZoom; |
|
|
const visibleLeft = -viewportX / safeZoom; |
|
|
@ -1709,15 +1737,15 @@ export function GenerationComposer() { |
|
|
const composerWidth = isComposerCollapsed ? COMPOSER_COLLAPSED_WIDTH : COMPOSER_EXPANDED_WIDTH; |
|
|
const composerWidth = isComposerCollapsed ? COMPOSER_COLLAPSED_WIDTH : COMPOSER_EXPANDED_WIDTH; |
|
|
const composerFlowWidth = composerWidth / safeZoom; |
|
|
const composerFlowWidth = composerWidth / safeZoom; |
|
|
const viewportMargin = COMPOSER_VIEWPORT_MARGIN / safeZoom; |
|
|
const viewportMargin = COMPOSER_VIEWPORT_MARGIN / safeZoom; |
|
|
const inlineComposerPosition = context.node && selectedNodeDimensions |
|
|
const inlineComposerPosition = context.node && selectedNodeDimensions && selectedNodePosition |
|
|
? (() => { |
|
|
? (() => { |
|
|
const centeredLeft = context.node.position.x + selectedNodeDimensions.width / 2 - composerFlowWidth / 2; |
|
|
const centeredLeft = selectedNodePosition.x + selectedNodeDimensions.width / 2 - composerFlowWidth / 2; |
|
|
const minLeft = visibleLeft + viewportMargin; |
|
|
const minLeft = visibleLeft + viewportMargin; |
|
|
const maxLeft = visibleRight - composerFlowWidth - viewportMargin; |
|
|
const maxLeft = visibleRight - composerFlowWidth - viewportMargin; |
|
|
const left = maxLeft >= minLeft |
|
|
const left = maxLeft >= minLeft |
|
|
? Math.min(Math.max(centeredLeft, minLeft), maxLeft) |
|
|
? Math.min(Math.max(centeredLeft, minLeft), maxLeft) |
|
|
: minLeft; |
|
|
: minLeft; |
|
|
const belowTop = context.node.position.y + selectedNodeDimensions.height + viewportMargin; |
|
|
const belowTop = selectedNodePosition.y + selectedNodeDimensions.height + viewportMargin; |
|
|
|
|
|
|
|
|
return { |
|
|
return { |
|
|
left, |
|
|
left, |
|
|
|