Import these from @grafloria/engine.
On their own pages
Functions
arePortDataTypesCompatible
Free-function facade over the singleton — what PortModel/validators import.
tsfunction arePortDataTypesCompatible(from: string | undefined, to: string | undefined): boolean
buildDynamicPortCommands
The plan, as undoable commands. Empty array when nothing is due — so a caller can drive this on every link change without polluting the undo stack.
tsfunction buildDynamicPortCommands(node: NodeModel, links?: LinkModel[]): Command[]
buildDynamicPortCommandsForDiagram
Every node in the diagram that owes the allocator work.
tsfunction buildDynamicPortCommandsForDiagram(diagram: DiagramModel): Command[]
canConnectPortsWithRules
Boolean facade for call sites that don't care WHY.
tsfunction canConnectPortsWithRules(
source: PortModel,
target: PortModel,
context: ConnectionRuleContext = {}
): boolean
ensureSideAnchorPort
The hidden port a side-anchor handle names — created once per node and
handle, then re-used (a re-applied spec must not grow a second one). Placed
as a FRACTION of the node box, so it stays on its side when the node resizes. Returns null when handle is not a side anchor.
tsfunction ensureSideAnchorPort(node: NodeModel, handle: string): string | null
evaluatePortConnection
May a link be created FROM source TO target? Directional — swapping the
arguments is a different question and may well get a different answer.
tsfunction evaluatePortConnection(
source: PortModel,
target: PortModel,
context: ConnectionRuleContext = {}
): ConnectionVerdict
findPortGroup
Find the group a port belongs to: the node's own definitions first (most specific), then the registry for the node's type.
tsfunction findPortGroup(
port: PortModel,
node: NodeModel | undefined
): PortGroupDefinition | undefined
getNodePortGroups
Per-node group definitions, stored in node metadata so they serialize with the diagram (a node can carry a one-off group without registering a node type).
tsfunction getNodePortGroups(node: NodeModel | undefined): Record<string, PortGroupDefinition>
isSideAnchorPort
A port a side-anchor handle created (<node>__right@36).
tsfunction isSideAnchorPort(portId: string | undefined): boolean
parseSideAnchor
'right@36' → { side: 'right', at: { px: 36 } }; 'left@50%' → { at: { pct: 50 } }; anything else → null.
tsfunction parseSideAnchor(handle: string): { side: AnchorSide; at: { px?: number; pct?: number } } | null
planDynamicPorts
What must change so every dynamic group on node offers exactly spare free
ports? Idempotent: run it on a settled node and it returns an empty plan.
A port is "free" when it carries no links. Only ports the allocator itself
spawned (dynamic: true) are ever REMOVED — an authored port the user simply
hasn't wired yet is not surplus, it is the design.
tsfunction planDynamicPorts(node: NodeModel, links?: LinkModel[]): DynamicPortPlan
portTypeColor
Free-function facade over the singleton — what the renderer imports.
tsfunction portTypeColor(name: string | undefined): string | undefined
resolvePortConfig
Fold a port's group into its own fields. THE resolution seam — the renderer, the layout engine and the connection validator all read the result of this function and never the raw port fields, so group inheritance can never silently apply in one place and not another.
tsfunction resolvePortConfig(port: PortModel, node?: NodeModel): ResolvedPortConfig
setNodePortGroups
tsfunction setNodePortGroups(node: NodeModel, groups: Record<string, PortGroupDefinition>): void
sideAnchorPortId
The id of the port a side-anchor handle names on nodeId.
tsfunction sideAnchorPortId(nodeId: string, handle: string): string
Classes
PortGroupRegistry
Groups registered per node TYPE. A node type declares its port groups once
("the and-gate type has an in group and an out group"), and every node
of that type inherits them.
tsclass PortGroupRegistry
Methods
register(nodeType: string, group: PortGroupDefinition): voidregisterAll(nodeType: string, groups: PortGroupDefinition[]): voidget(nodeType: string, groupId: string): PortGroupDefinition | undefinedgetAll(nodeType: string): PortGroupDefinition[]unregister(nodeType: string, groupId?: string): voidclear(): void
PortTypeRegistry
tsclass PortTypeRegistry
Methods
register(definition: PortDataTypeDefinition): voidregisterAll(definitions: PortDataTypeDefinition[]): voidget(name: string): PortDataTypeDefinition | undefinedhas(name: string): booleanunregister(name: string): voidclear(): voidisCompatible(from: string | undefined, to: string | undefined): boolean— May a link carryfromintoto?
Compatibility is DIRECTIONAL on purpose: int → float is a widening that a
host may well allow while float → int is a lossy one it may not.
colorFor(name: string | undefined): string | undefined— The glyph colour for a data type, if one was registered.
Constants
ANY_PORT_TYPE
The wildcard: a port typed * (or declared compatible with *) fits anything.
tsconst ANY_PORT_TYPE: "*"
DEFAULT_PORT_GATING
tsconst DEFAULT_PORT_GATING: ResolvedPortGating
DEFAULT_PORT_LABEL_OFFSET
tsconst DEFAULT_PORT_LABEL_OFFSET: 6
DEFAULT_PORT_SPREAD_SPACING
tsconst DEFAULT_PORT_SPREAD_SPACING: 10
PORT_GROUPS_METADATA_KEY
Node metadata key holding per-node group definitions.
tsconst PORT_GROUPS_METADATA_KEY: "portGroups"
portGroupRegistry
The process-wide registry. Hosts register node-type groups at bootstrap.
tsconst portGroupRegistry: PortGroupRegistry
portTypeRegistry
The process-wide registry. Hosts register their data types at bootstrap.
tsconst portTypeRegistry: PortTypeRegistry
Interfaces
ConnectionRuleContext
tsinterface ConnectionRuleContext
Properties
| Name | Type | Default | Description |
|---|---|---|---|
sourceNode? | NodeModel | ||
targetNode? | NodeModel | ||
links? | LinkModel[] | The diagram's links — needed for the duplicate-link rule. | |
rejectDuplicatesByDefault? | boolean | Reject a second link between the same ordered port pair EVEN when the ports allow duplicates. Proximity-connect passes this (auto-linking a duplicate on a drag-near is never what the user meant); the explicit connection drag does not, preserving its historical permissiveness. | |
validators? | Array<(source: PortModel, target: PortModel) => boolean> | Extra host rules (connection groups, ACLs…). Run last. |
ConnectionVerdict
tsinterface ConnectionVerdict
Properties
| Name | Type | Default | Description |
|---|---|---|---|
ok | boolean | ||
reason? | ConnectionRejectionReason | ||
message? | string | Human-readable, safe to surface in a tooltip / live region. |
DynamicPortPlan
tsinterface DynamicPortPlan
Properties
| Name | Type | Default | Description |
|---|---|---|---|
add | PortModel[] | Ports to create, in order. | |
remove | string[] | Ids of surplus free ports to retire. |
DynamicPortSpec
Dynamic auto-ports: keep a group topped up with free ports so the user always has somewhere to drop the next link — the node-editor pattern (Blender / Unreal / n8n).
tsinterface DynamicPortSpec
Properties
| Name | Type | Default | Description |
|---|---|---|---|
enabled | boolean | ||
spare? | number | How many UNCONNECTED ports the group must always offer. Default 1. | |
max? | number | Hard cap on total ports in the group. 0 (default) = uncapped. | |
idPrefix? | string | Id prefix for spawned ports. Default <groupId>-. |
PortDataTypeDefinition
tsinterface PortDataTypeDefinition
Properties
| Name | Type | Default | Description |
|---|---|---|---|
name | string | The type's own name. | |
compatibleWith? | string[] | Types this one may ALSO connect to (beyond an exact name match). '*' means "compatible with everything" — the escape hatch for an any port. | |
color? | string | Affordance: the glyph colour for ports of this type. |
PortGatingSpec
Directional connectability.
Every field is optional and every default reproduces the old behaviour: isConnectableStart/End = true, from/toMaxLinks = null (unlimited), allowSelfLink = false, allowDuplicateLinks = true.
tsinterface PortGatingSpec
Properties
| Name | Type | Default | Description |
|---|---|---|---|
isConnectableStart? | boolean | May a link START here? Default true. | |
isConnectableEnd? | boolean | May a link END here? Default true. | |
fromMaxLinks? | number | null | Cap on OUTGOING links. null/undefined = unlimited. | |
toMaxLinks? | number | null | Cap on INCOMING links. null/undefined = unlimited. | |
maxConnections? | number | null | Cap on links in EITHER direction (the legacy knob). null = unlimited. | |
allowSelfLink? | boolean | Allow a link whose source node IS its target node. Default false. | |
allowDuplicateLinks? | boolean | Allow a SECOND link between the same ordered pair of ports. Default true. | |
allowedTypes? | string[] | Restrict which port data-types / system-types may attach. Empty = no restriction. |
PortGroupDefinition
A named, reusable bundle of port config on a node type. Ports name their
group and override ONLY what differs — replacing the old
top/right/bottom/left-only PortsConfig, in which "eight typed inputs down
the left edge, each with a label" could not be said at all.
tsinterface PortGroupDefinition
Properties
| Name | Type | Default | Description |
|---|---|---|---|
id | string | ||
side? | PortEdge | Default side for members that don't declare one. | |
layout? | PortLayoutSpec | ||
shape? | PortShapeSpec | ||
style? | Record<string, unknown> | Raw SVG presentation attributes merged onto the glyph (fill, stroke, …). | |
label? | Partial<PortLabelSpec> | Label defaults. Members supply/override text. | |
visibility? | PortVisibilityMode | ||
gating? | PortGatingSpec | ||
type? | 'input' | 'output' | 'bi' | Default port direction (input/output/bi) for members. | |
dataType? | string | ||
fromSpot? | PortSpot | ||
toSpot? | PortSpot | ||
spread? | PortSpreadSpec | ||
dynamic? | DynamicPortSpec |
PortLabelSpec
tsinterface PortLabelSpec
Properties
| Name | Type | Default | Description |
|---|---|---|---|
text | string | ||
layout? | PortLabelLayout | Default 'outside'. | |
offset? | number | Gap from the glyph EDGE (not its centre), in px. Default 6. | |
angle? | number | Extra rotation applied to the label, in degrees. Default 0. | |
keepUpright? | boolean | Auto-flip a label whose total rotation would leave it upside-down (|angle| > 90°) by adding 180°, so text always reads left-to-right. Default true. | |
fontSize? | number | ||
fontFamily? | string | ||
fontWeight? | number | string | ||
color? | string | ||
maxWidth? | number | Wrap width for the shared text-block engine. | |
className? | string | ||
noNudge? | boolean | Opt OUT of collision-aware nudging (see port-label.ts). Default false — i.e. crowded labels ARE nudged apart by default. |
PortLayoutSpec
tsinterface PortLayoutSpec
Properties
| Name | Type | Default | Description |
|---|---|---|---|
strategy | PortLayoutStrategyName | ||
args? | PortLayoutArgs |
PortShapeSpec
tsinterface PortShapeSpec
Properties
| Name | Type | Default | Description |
|---|---|---|---|
shape | PortGlyphShape | ||
size? | number | Full width AND height of the glyph box, in px. For a circle this is the DIAMETER (so size: 12 === the legacy portDefaultRadius: 6). Omit to inherit InteractionConfig.portDefaultRadius * 2. | |
width? | number | Non-square glyphs: override one axis. Falls back to size. | |
height? | number | ||
path? | string | shape:'path' only — SVG path data, centred on (0,0) in a size box. | |
rotation? | number | Rotate the glyph about its own centre, in degrees. |
PortSpot
tsinterface PortSpot
Properties
| Name | Type | Default | Description |
|---|---|---|---|
spot | PortSpotName | ||
direction? | PortEdge | The direction a link LEAVES (fromSpot) or APPROACHES (toSpot) the port. Defaults to the port's side — i.e. the outward normal — which is what the orthogonal router has always been handed. | |
distance? | number | Push the attachment point this many px further along direction. |
PortSpreadSpec
Spread N links landing on ONE port along that port's edge instead of piling them all on the centre point.
(Byte-stability.)
tsinterface PortSpreadSpec
Properties
| Name | Type | Default | Description |
|---|---|---|---|
enabled | boolean | ||
spacing? | number | Gap between adjacent lanes, in px. Default 10. | |
max? | number | Cap the number of distinct lanes; links beyond the cap reuse the outermost lane. 0 (default) = uncapped. |
ResolvedPortConfig
tsinterface ResolvedPortConfig
Properties
| Name | Type | Default | Description |
|---|---|---|---|
side | PortEdge | ||
layout? | PortLayoutSpec | ||
shape? | PortShapeSpec | ||
style | Record<string, unknown> | ||
label? | PortLabelSpec | ||
visibility? | PortVisibilityMode | ||
gating | ResolvedPortGating | ||
dataType? | string | ||
fromSpot? | PortSpot | ||
toSpot? | PortSpot | ||
spread? | PortSpreadSpec | ||
dynamic? | DynamicPortSpec | ||
groupId? | string | The group this resolved from, if any. |
ResolvedPortGating
Gating with every question ANSWERED — no undefined anywhere, because a
validator that has to ask "was this unset or set to false?" is a validator
with a bug waiting in it. null is the explicit "unlimited" for the caps.
tsinterface ResolvedPortGating
Properties
| Name | Type | Default | Description |
|---|---|---|---|
isConnectableStart | boolean | ||
isConnectableEnd | boolean | ||
allowSelfLink | boolean | ||
allowDuplicateLinks | boolean | ||
fromMaxLinks | number | null | ||
toMaxLinks | number | null | ||
maxConnections | number | null | ||
allowedTypes | string[] |
Types
AnchorSide
Also has every member of String, listed on its own entry.
tstype AnchorSide = 'top' | 'right' | 'bottom' | 'left';
ConnectionRejectionReason
Also has every member of String, listed on its own entry.
tstype ConnectionRejectionReason =
| 'self-port'
| 'self-link'
| 'not-connectable-start'
| 'not-connectable-end'
| 'node-not-connectable'
| 'direction'
| 'data-type'
| 'allowed-types'
| 'max-connections'
| 'from-max-links'
| 'to-max-links'
| 'duplicate-link'
| 'connection-group'
| 'custom';
PortEdge
Also has every member of String, listed on its own entry.
tstype PortEdge = 'left' | 'right' | 'top' | 'bottom';
PortGlyphShape
Also has every member of String, listed on its own entry.
The port's rendered marker.
path renders a caller-supplied SVG path (PortShapeSpec.path), authored in
a box of size centred on the port's anchor point.
tstype PortGlyphShape = 'circle' | 'square' | 'diamond' | 'triangle' | 'path';
PortLabelLayout
Also has every member of String, listed on its own entry.
Where a port's label sits relative to the glyph.
inside— pulled INTO the node body, opposite the port's outward normal.outside— pushed AWAY from the node, along the outward normal (default).orthogonal— offset perpendicular to the outward normal (reads along the edge, so a column of side ports doesn't stack labels on the same line).radial— offset along the ray from the node's centre through the port; the layout that actually works on ellipse / circle nodes, where "outward normal" and "away from centre" are the same thing only at the four cardinal points.
tstype PortLabelLayout = 'inside' | 'outside' | 'orthogonal' | 'radial';
PortLayoutStrategyName
Also has every member of String, listed on its own entry.
Named port-layout strategies. Every other strategy is an explicit opt-in that overrides it.
tstype PortLayoutStrategyName =
| 'shape'
| 'absolute'
| 'line'
| 'sideLinear'
| 'ellipse'
| 'ellipseSpread';
PortSpotName
Also has every member of String, listed on its own entry.
A named point on the port's glyph box. default means "whatever the port's
side implies" — the outward-facing edge midpoint, which is the historical
attachment behaviour (the glyph CENTRE, since the legacy glyph had no box).
tstype PortSpotName =
| 'default'
| 'center'
| 'top'
| 'right'
| 'bottom'
| 'left'
| 'topLeft'
| 'topRight'
| 'bottomLeft'
| 'bottomRight';
PortVisibilityMode
Also has every member of String, listed on its own entry.
tstype PortVisibilityMode = 'always' | 'on-hover' | 'never' | 'hidden';
Was this page helpful?