@gravity-ui/graph
Version:
Modern graph editor component
152 lines (151 loc) • 5.13 kB
TypeScript
import { Component } from "../../../lib";
import { TPoint } from "../../../utils/types/shapes";
export declare const IS_PORT_TYPE: "Port";
export type TPortId = string | number | symbol;
/**
* Port data structure
* Represents a connection point that can be attached to blocks, anchors, or custom components
*/
export type TPort<T = unknown> = {
/** Unique identifier for the port */
id: TPortId;
/** X coordinate of the port */
x: number;
/** Y coordinate of the port */
y: number;
/** Component that owns this port (block, anchor, etc.) */
component?: Component;
/** Whether the port is waiting for position data from its component */
lookup?: boolean;
/** Arbitrary metadata (port doesn't know what's inside) */
meta?: T;
};
/**
* PortState - Reactive state container for a connection port
*
* Manages the lifecycle and state of a port, including position updates,
* component ownership, and listener management for connections that use this port.
*
* ## Key Concepts:
*
* ### Lazy Creation
* Ports are created on-demand when connections need them, even if the target
* component doesn't exist yet. This solves initialization order problems.
*
* ### Lookup State
* When `lookup: true`, the port is waiting for its component to provide coordinates.
* When `lookup: false`, the port has valid coordinates and can be used for rendering.
*
* ### Listener Management
* Tracks which components are listening to this port's changes. When no listeners
* remain and no component owns the port, it can be safely garbage collected.
*/
export declare class PortState<T = unknown> {
$state: import("@preact/signals-core").Signal<TPort<T>>;
owner?: Component;
private $delegate;
private savedPoint;
/**
* Set of references observing this port's changes
*
* Used for reference counting to determine when the port can be safely deleted.
* Stores actual object references to ensure accurate counting and prevent duplicates.
*/
observers: Set<unknown>;
/**
* Get the port's unique identifier
*
* @returns {TPortId} The port's ID
*/
get id(): TPortId;
/**
* Get the port's effective X coordinate (respects delegation)
*
* @returns {number} The X coordinate
*/
get x(): number;
/**
* Get the port's effective Y coordinate (respects delegation)
*
* @returns {number} The Y coordinate
*/
get y(): number;
/**
* Get the component that owns this port
*
* @returns {Component | undefined} The owning component, if any
*/
get component(): Component | undefined;
$point: any;
/**
* Get whether the port is in lookup state (waiting for coordinates)
*
* @returns {boolean | undefined} True if waiting for coordinates, false if resolved
*/
get lookup(): boolean | undefined;
/**
* Get the port's metadata
*
* @returns {T | undefined} The metadata attached to this port
*/
get meta(): T | undefined;
constructor(port: TPort<T>);
/**
* Set the component that owns this port
* @param owner Component that will own this port (block, anchor, etc.)
* @returns void
*/
setOwner(owner: Component): void;
/**
* Remove the current owner from this port
*/
removeOwner(): void;
/**
* Add an observer reference to this port
* Stores the actual reference for accurate counting
* @param observer The object observing this port
*/
addObserver(observer: unknown): void;
/**
* Remove an observer reference from this port
* Removes the actual reference from the set
* @param observer The object to stop observing this port
*/
removeObserver(observer: unknown): void;
/**
* Update the port's position coordinates.
* When delegated, the position is saved but does not affect getPoint() —
* the effective position comes from the delegate port.
* @param x New X coordinate
* @param y New Y coordinate
*/
setPoint(x: number, y: number): void;
getPoint(): TPoint;
/**
* Delegate this port to mirror another port's position.
* While delegated, getPoint() returns the target port's position.
* Any setPoint() calls are saved and restored on undelegate().
* @param target The port to mirror
*/
delegate(target: PortState): void;
/**
* Remove delegation and restore the last saved position.
* If setPoint() was called during delegation, the last value is used.
* Otherwise, the position from before delegation is restored.
*/
undelegate(): void;
/**
* Whether this port is currently delegated to another port
*/
get isDelegated(): boolean;
/**
* Update port state with partial data
* @param port Partial port data to merge with current state
*/
updatePort(port: Partial<TPort<T>>): void;
/**
* Check if this port can be safely deleted
* @returns true if port has no owner and no observers
*/
canBeDeleted(): boolean;
}