Files
upstream-tldraw/templates/branching-chat/client/nodes/nodePorts.tsx
upstream-mirror a774ac673a
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
2026-09-23 16:12:52 +05:00

97 lines
2.9 KiB
TypeScript

/**
* This file contains functions for working with ports and connections on nodes.
*/
import { createComputedCache, Editor, TLShapeId } from 'tldraw'
import { getConnectionBindings } from '../connection/ConnectionBindingUtil'
import { PortId } from '../ports/Port'
import { NodeShape } from './NodeShapeUtil'
import { getNodeTypePorts, NodeTypePorts } from './nodeTypes'
/**
* Get the ports for a node. This is cached, because we only want to re-evaluate it when the
* underlying records change.
*/
export function getNodePorts(editor: Editor, shape: NodeShape | TLShapeId): NodeTypePorts {
return nodePortsCache.get(editor, typeof shape === 'string' ? shape : shape.id) ?? {}
}
const nodePortsCache = createComputedCache(
'ports',
(editor: Editor, node: NodeShape): NodeTypePorts => getNodeTypePorts(editor, node)
)
/**
* A connection from one node to another.
*/
export interface NodePortConnection {
connectedShapeId: TLShapeId
connectionId: TLShapeId
terminal: 'start' | 'end'
ownPortId: PortId
connectedPortId: PortId
}
/**
* Get the connections for a node. This is cached.
*/
export function getNodePortConnections(
editor: Editor,
shape: NodeShape | TLShapeId
): NodePortConnection[] {
return nodePortConnectionsCache.get(editor, typeof shape === 'string' ? shape : shape.id) ?? []
}
const nodePortConnectionsCache = createComputedCache(
'port connections',
(editor: Editor, node: NodeShape) => {
const bindings = editor.getBindingsToShape(node.id, 'connection')
const connections: NodePortConnection[] = []
for (const binding of bindings) {
const oppositeTerminal = binding.props.terminal === 'start' ? 'end' : 'start'
const oppositeBinding = getConnectionBindings(editor, binding.fromId)[oppositeTerminal]
if (!oppositeBinding) continue
connections.push({
connectedShapeId: oppositeBinding.toId,
connectionId: binding.fromId,
terminal: binding.props.terminal,
ownPortId: binding.props.portId,
connectedPortId: oppositeBinding.props.portId,
})
}
return connections
},
{
areRecordsEqual: (a, b) => a.id === b.id,
}
)
/**
* Traverse the graph from a starting node, in a given direction, returning all the nodes that are
* connected to it (including the starting node).
*/
export function getAllConnectedNodes(
editor: Editor,
startingNode: TLShapeId | NodeShape,
direction?: 'start' | 'end'
) {
const toVisit = [typeof startingNode === 'string' ? startingNode : startingNode.id]
const found = new Set<TLShapeId>()
while (toVisit.length > 0) {
const nodeId = toVisit.shift()!
const node = editor.getShape(nodeId)
if (!node || !editor.isShapeOfType(node, 'node')) continue
if (found.has(node.id)) continue
found.add(node.id)
for (const connection of getNodePortConnections(editor, node)) {
if (direction && connection.terminal !== direction) continue
toVisit.push(connection.connectedShapeId)
}
}
return found
}