import { FlowCoreMap } from '@emuanalytics/flow-rdf-core'; import * as lit_html from 'lit-html'; import * as lit from 'lit'; import { LitElement, CSSResultGroup, ReactiveController, ReactiveControllerHost, TemplateResult, PropertyValues, nothing, PropertyValueMap } from 'lit'; import * as chartjs_chart_matrix from 'chartjs-chart-matrix'; import * as chart_js from 'chart.js'; import { ChartComponentLike, Chart, ChartTypeRegistry, ChartOptions, ChartData, Plugin } from 'chart.js'; export { Chart as ChartJs } from 'chart.js'; import * as lit_html_directive_js from 'lit-html/directive.js'; import { Directive, PartInfo, ElementPart } from 'lit/directive.js'; import { AsyncDirective, PartInfo as PartInfo$1, ElementPart as ElementPart$1 } from 'lit/async-directive.js'; type FlowAfterCollapseEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-after-collapse': FlowAfterCollapseEvent; } } type FlowAfterExpandEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-after-expand': FlowAfterExpandEvent; } } type FlowAfterHideEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-after-hide': FlowAfterHideEvent; } } type FlowAfterShowEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-after-show': FlowAfterShowEvent; } } type FlowApplyEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-apply': FlowApplyEvent; } } type FlowBlurEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-blur': FlowBlurEvent; } } type FlowCancelEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-cancel': FlowCancelEvent; } } type FlowChangeEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-change': FlowChangeEvent; } } type FlowClearEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-clear': FlowClearEvent; } } type FlowCloseEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-close': FlowCloseEvent; } } type FlowCollapseEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-collapse': FlowCollapseEvent; } } type FlowCollapseTreeEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-collapse-tree': FlowCollapseTreeEvent; } } type FlowDragEvent = CustomEvent<{ x: number; y: number; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-drag': FlowDragEvent; } } type FlowDragDropEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-drag-drop': FlowDragDropEvent; } } type FlowDragEndEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-drag-end': FlowDragEndEvent; } } type FlowDragOverEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-drag-over': FlowDragOverEvent; } } type FlowDragStartEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-drag-start': FlowDragStartEvent; } } type FlowErrorEvent = CustomEvent<{ status?: number; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-error': FlowErrorEvent; } } type FlowExpandEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-expand': FlowExpandEvent; } } type FlowExpandTreeEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-expand-tree': FlowExpandTreeEvent; } } type FlowFinishEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-finish': FlowFinishEvent; } } type FlowFocusEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-focus': FlowFocusEvent; } } type FlowHideEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-hide': FlowHideEvent; } } type FlowHoverEvent = CustomEvent<{ phase: 'start' | 'move' | 'end'; value: number; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-hover': FlowHoverEvent; } } type FlowInitialFocusEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-initial-focus': FlowInitialFocusEvent; } } type FlowInputEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-input': FlowInputEvent; } } type FlowInvalidEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-invalid': FlowInvalidEvent; } } type FlowLazyChangeEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-lazy-change': FlowLazyChangeEvent; } } type FlowLazyLoadEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-lazy-load': FlowLazyLoadEvent; } } type FlowLoadEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-load': FlowLoadEvent; } } type FlowMapLoadEvent = CustomEvent<{ map: FlowCoreMap; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-map-load': FlowMapLoadEvent; } } type FlowMutationEvent = CustomEvent<{ mutationList: MutationRecord[]; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-mutation': FlowMutationEvent; } } type FlowPanelToggleEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-panel-toggle': FlowPanelToggleEvent; } } type FlowRemoveEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-remove': FlowRemoveEvent; } } type FlowRepositionEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-reposition': FlowRepositionEvent; } } type FlowRequestCloseEvent = CustomEvent<{ source: 'close-button' | 'keyboard' | 'overlay'; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-request-close': FlowRequestCloseEvent; } } type FlowResizeEvent = CustomEvent<{ entries: ResizeObserverEntry[]; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-resize': FlowResizeEvent; } } type EventTypeRequiresDetail = T extends keyof GlobalEventHandlersEventMap ? GlobalEventHandlersEventMap[T] extends CustomEvent> ? GlobalEventHandlersEventMap[T] extends CustomEvent> ? never : Partial extends GlobalEventHandlersEventMap[T]['detail'] ? never : T : never : never; type EventTypeDoesNotRequireDetail = T extends keyof GlobalEventHandlersEventMap ? GlobalEventHandlersEventMap[T] extends CustomEvent> ? GlobalEventHandlersEventMap[T] extends CustomEvent> ? T : Partial extends GlobalEventHandlersEventMap[T]['detail'] ? T : never : T : T; type EventTypesWithRequiredDetail = { [EventType in keyof GlobalEventHandlersEventMap as EventTypeRequiresDetail]: true; }; type EventTypesWithoutRequiredDetail = { [EventType in keyof GlobalEventHandlersEventMap as EventTypeDoesNotRequireDetail]: true; }; type WithRequired = T & { [P in K]-?: T[P]; }; type SlEventInit = T extends keyof GlobalEventHandlersEventMap ? GlobalEventHandlersEventMap[T] extends CustomEvent> ? GlobalEventHandlersEventMap[T] extends CustomEvent> ? CustomEventInit : Partial extends GlobalEventHandlersEventMap[T]['detail'] ? CustomEventInit : WithRequired, 'detail'> : CustomEventInit : CustomEventInit; type GetCustomEventType = T extends keyof GlobalEventHandlersEventMap ? GlobalEventHandlersEventMap[T] extends CustomEvent ? GlobalEventHandlersEventMap[T] : CustomEvent : CustomEvent; declare class FlowRdfElement extends LitElement { dir: string; lang: string; /** Emits a custom event with more convenient defaults. */ emit(name: EventTypeDoesNotRequireDetail, options?: SlEventInit | undefined): GetCustomEventType; emit(name: EventTypeRequiresDetail, options: SlEventInit): GetCustomEventType; /** * The component's standard tag name, such as `flow-ui-button`. `define()` registers the component with this tag name * when it isn't given one. * * Every component declares its own tag name. A component that extends another component does not inherit it. */ static readonly tagName?: string; /** * The Flo.w RDF UI components that this component renders internally. `define()` registers each of them with its * standard tag name, so that a component registered on its own renders correctly. * * Each component lists only the elements it renders itself. The dependencies of those elements are registered in * turn by their own `define()`. Elements that the application supplies as content, such as the `` * elements of a ``, are not dependencies and must be registered separately. */ static dependencies: (typeof FlowRdfElement)[]; /** * Registers this component as a custom element, together with the elements it renders internally (see * `dependencies`). * * Use this to register only the components an application uses, instead of calling `registerComponents()`: * * ```typescript * import { FlowUiButton } from '@emuanalytics/flow-rdf-ui'; * * // Registers and the elements it renders, such as * FlowUiButton.define(); * ``` * * Without a tag name, the component is registered with its standard tag name (see `tagName`). Pass a tag name only * to register the component under a different one. * * It is safe to call this more than once. A tag name that is already registered, whether by this method, by * `registerComponents()` or by the application with another class, is left unchanged. Dependencies are always * registered with their standard tag names, even when the component itself is given a custom tag name. * * @param name - The tag name to register the component as. Defaults to the component's standard `flow-ui-*` tag * name. * @param elementConstructor - The class to register. Defaults to the class this method is called on. * @param options - Options passed to `customElements.define()`. */ static define(name?: string, elementConstructor?: typeof FlowRdfElement, options?: ElementDefinitionOptions): void; } declare abstract class FlowRdfFormControl extends FlowRdfElement { static FLOW_UI_FORM_CONTROL_CLASS: string; class: string; /** The controls's size. */ size: string; /** Indicates that the control should display a divider */ divider: boolean; handleClassChange(): void; connectedCallback(): void; name: string; value: unknown; disabled?: boolean; defaultValue?: unknown; defaultChecked?: boolean; form?: string; pattern?: string; min?: number | string | Date; max?: number | string | Date; step?: number | 'any'; required?: boolean; minlength?: number; maxlength?: number; abstract get validity(): ValidityState; abstract get validationMessage(): string; abstract checkValidity(): boolean; abstract getForm(): HTMLFormElement | null; abstract reportValidity(): boolean; abstract setCustomValidity(message: string): void; renderDivider(): lit_html.TemplateResult<1>; } /** * * @tagname flow-ui-icon * @summary Icons are symbols that can be used to represent various options within an application. * @documentation https://developer.emu-analytics.net/docs/flow-ui-rdf/components/icon * @status stable * @since 2.0 * * @event flow-ui-load - Emitted when the icon has loaded. * @event flow-ui-error - Emitted when the icon fails to load due to an error. * * @csspart svg - The internal SVG element. */ declare class FlowUiIcon extends FlowRdfElement { static tagName: string; static styles: CSSResultGroup; /** Given a URL, this function returns the resulting SVG element or an appropriate error symbol. */ private static resolveIcon; private svg; /** The name of the icon to draw. Available names depend on the icon library being used. */ name?: string; /** * An external URL of an SVG file. Be sure you trust the content you are including, as it will be executed as code and * can result in XSS attacks. */ src?: string; /** * An alternate description to use for assistive devices. If omitted, the icon will be considered presentational and * ignored by assistive devices. */ label: string; /** The name of a registered custom icon library. */ library: string; connectedCallback(): void; firstUpdated(): void; disconnectedCallback(): void; private getUrl; /** * @internal */ handleLabelChange(): void; /** * @internal */ setIcon(): Promise; render(): SVGElement | null; } /** * @tagname flow-ui-menu-item * @summary Menu items provide options for the user to pick from in a menu. * @docgroup menu * * @dependency flow-ui-icon * * @slot - The menu item's label. * @slot prefix - Used to prepend an icon or similar element to the menu item. * @slot suffix - Used to append an icon or similar element to the menu item. * * @csspart base - The component's base wrapper. * @csspart checked-icon - The checked icon, which is only visible when the menu item is checked. * @csspart prefix - The prefix container. * @csspart label - The menu item label. * @csspart suffix - The suffix container. * @csspart submenu-icon - The submenu icon, visible only when the menu item has a submenu (not yet implemented). */ declare class FlowUiMenuItem extends FlowRdfElement { static tagName: string; static styles: CSSResultGroup; static dependencies: (typeof FlowUiIcon)[]; private cachedTextLabel; /** @internal */ defaultSlot: HTMLSlotElement; /** @internal */ menuItem: HTMLElement; /** The type of menu item to render. To use `checked`, this value must be set to `checkbox` or `radio`. */ type: 'normal' | 'checkbox' | 'radio'; /** Draws the item in a checked state. */ checked: boolean; /** A unique value to store in the menu item. This can be used as a way to identify menu items when selected. */ value: string; /** Draws the menu item in a disabled state, preventing selection. */ disabled: boolean; connectedCallback(): void; disconnectedCallback(): void; private handleDefaultSlotChange; private handleHostClick; /** @internal */ handleCheckedChange(): void; /** @internal */ handleDisabledChange(): void; /** @internal */ handleTypeChange(): void; /** @internal Returns a text label based on the contents of the menu item's default slot. */ getTextLabel(): string; render(): lit_html.TemplateResult<1>; } declare global { interface HTMLElementTagNameMap { 'flow-ui-menu-item': FlowUiMenuItem; } } type FlowSelectEvent = CustomEvent<{ item: FlowUiMenuItem; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-select': FlowSelectEvent; } } type FlowShowEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-show': FlowShowEvent; } } /** * @tagname flow-ui-carousel-item * @summary A carousel item represent a slide within a [carousel](./flow-ui-carousel). * @docgroup carousel * * @since 2.0 * @status experimental * * @slot - The carousel item's content.. * * @cssproperty --aspect-ratio - The slide's aspect ratio. Inherited from the carousel by default. * */ declare class FlowUiCarouselItem extends FlowRdfElement { static tagName: string; static styles: CSSResultGroup; /** @internal */ static isCarouselItem(node: Node): boolean; connectedCallback(): void; render(): lit_html.TemplateResult<1>; } declare global { interface HTMLElementTagNameMap { 'flow-ui-carousel-item': FlowUiCarouselItem; } } type FlowSlideChange = CustomEvent<{ index: number; slide: FlowUiCarouselItem; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-slide-change': FlowSlideChange; } } type FlowStartEvent = CustomEvent>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-start': FlowStartEvent; } } type FlowTabHideEvent = CustomEvent<{ name: string; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-tab-hide': FlowTabHideEvent; } } type FlowTabShowEvent = CustomEvent<{ name: string; }>; declare global { interface GlobalEventHandlersEventMap { 'flow-ui-tab-show': FlowTabShowEvent; } } declare global { interface Set { difference(other: Set): Set; intersection(other: Set): Set; } } /** * List of built-in edge routing names in registration order. * * @remarks * These routings are automatically registered when an EdgeRoutingManager is created: * - `orthogonal`: Routes edges with right-angle turns * - `bezier`: Routes edges with smooth Bezier curves * - `polyline`: Routes edges as straight line segments * * @category Types/Routing */ declare const BUILT_IN_EDGE_ROUTINGS: readonly ["orthogonal", "bezier", "polyline"]; /** * **Internal manager** for registration, selection, and execution of edge routing implementations. * * @remarks * **For application code, use {@link NgDiagramService} routing methods instead.** * This class is exposed primarily for middleware development where you can access it * via `context.edgeRoutingManager`. * * The manager comes pre-populated with built-in routings (`orthogonal`, `bezier`, `polyline`). * You can register custom routings at runtime. * * @example * ```typescript * const middleware: Middleware = { * name: 'routing-optimizer', * execute: (context, next) => { * const routingManager = context.edgeRoutingManager; * const defaultRouting = routingManager.getDefaultRouting(); * console.log('Using routing:', defaultRouting); * next(); * } * }; * ``` * * @public * @since 0.8.0 * @category Internals */ declare class EdgeRoutingManager { private routings; private defaultRouting; private getRoutingConfig; /** * Creates a new EdgeRoutingManager and registers built-in routings. * * @param defaultEdgeRouting - The routing to use when none is specified (defaults to `'orthogonal'`) * @param getRoutingConfiguration - Function returning the current routing configuration * * @internal */ constructor(defaultEdgeRouting: EdgeRoutingName, getRoutingConfiguration: () => EdgeRoutingConfig); /** * Registers (or replaces) a routing implementation. * * @param routing - The routing instance to register. Its name must be non-empty. */ registerRouting(routing: EdgeRouting): void; /** * Unregisters a routing by name. * * @param name - The routing name to remove */ unregisterRouting(name: EdgeRoutingName): void; /** * Gets a routing implementation by name. * * @param name - The routing name to look up * @returns The routing implementation or `undefined` if not registered */ getRouting(name: EdgeRoutingName): EdgeRouting | undefined; /** * Gets all registered routing names. * * @returns An array of registered routing names (built-in and custom) */ getRegisteredRoutings(): EdgeRoutingName[]; /** * Checks whether a routing is registered. * * @param name - The routing name to check * @returns `true` if registered; otherwise `false` */ hasRouting(name: EdgeRoutingName): boolean; /** * Computes the routed points for an edge using the specified routing algorithm. * * @param routingName - The routing to use. If omitted or undefined, the default routing is used. * @param context - The routing context containing source/target nodes, ports, edge data, etc. * @returns The computed polyline as an array of points * * @example * ```typescript * const points = routingManager.computePoints('orthogonal', { * sourceNode: node1, * targetNode: node2, * sourcePosition: { x: 100, y: 50 }, * targetPosition: { x: 300, y: 200 }, * edge: edge * }); * ``` */ computePoints(routingName: EdgeRoutingName | undefined, context: EdgeRoutingContext): Point[]; /** * Computes an SVG path string for the given points using the specified routing. * * @param routingName - The routing to use. If omitted or undefined, the default routing is used. * @param points - The points to convert into an SVG path string * @returns An SVG path string suitable for the `d` attribute of an SVG `` element * * @example * ```typescript * const points = [{ x: 0, y: 0 }, { x: 100, y: 100 }, { x: 200, y: 100 }]; * const path = routingManager.computePath('polyline', points); * // Returns: "M 0 0 L 100 100 L 200 100" * ``` */ computePath(routingName: EdgeRoutingName | undefined, points: Point[]): string; /** * Computes a point along the path at a given percentage. * * @remarks * If the selected routing implements `computePointOnPath`, it will be used. * Otherwise, falls back to linear interpolation between the first and last points. * * @param routingName - The routing to use. If omitted or undefined, the default routing is used. * @param points - The path points * @param percentage - Position along the path in range [0, 1] where 0 = start, 1 = end * @returns The interpolated point on the path * * @example * ```typescript * const points = [{ x: 0, y: 0 }, { x: 100, y: 100 }]; * const midpoint = routingManager.computePointOnPath('polyline', points, 0.5); * // Returns: { x: 50, y: 50 } * const quarterPoint = routingManager.computePointOnPath('polyline', points, 0.25); * // Returns: { x: 25, y: 25 } * ``` */ computePointOnPath(routingName: EdgeRoutingName | undefined, points: Point[], percentage: number): Point; /** * Computes a point along the path at a given pixel distance from the start. * * @remarks * If the selected routing implements `computePointAtDistance`, it will be used. * Otherwise, falls back to segment-based distance traversal along the points array. * Negative values measure from the end of the path. * * @param routingName - The routing to use. If omitted, the default routing is used. * @param points - The path points * @param distancePx - Distance in pixels (positive = from start, negative = from end) * @returns The point on the path at the given distance */ computePointAtDistance(routingName: EdgeRoutingName | undefined, points: Point[], distancePx: number): Point; /** * Sets the default routing to use for all edges when no specific routing is specified. * * @param name - The routing name to set as default */ setDefaultRouting(name: EdgeRoutingName): void; /** * Gets the current default routing name. * * @returns The name of the current default routing */ getDefaultRouting(): EdgeRoutingName; } /** * Type representing built-in edge routing names * @internal */ type BuiltInEdgeRoutingName = (typeof BUILT_IN_EDGE_ROUTINGS)[number]; /** * Type representing edge routing name - can be built-in or custom * * **Allowed values:** `'orthogonal' | 'bezier' | 'polyline'` * * @public * @since 0.8.0 * @category Types/Routing */ type EdgeRoutingName = LooseAutocomplete; /** * Context object containing all information needed for routing computation * * @public * @since 0.8.0 * @category Types/Routing */ interface EdgeRoutingContext { /** * Source port location */ sourcePoint: PortLocation; /** * Target port location */ targetPoint: PortLocation; /** * The edge being routed */ edge: Edge; /** * Source node */ sourceNode?: Node$1; /** * Target node */ targetNode?: Node$1; /** * Source port (if edge is connected to a specific port) */ sourcePort?: Port; /** * Target port (if edge is connected to a specific port) */ targetPort?: Port; } /** * Interface for routing implementations * * @public * @since 0.8.0 * @category Types/Routing */ interface EdgeRouting { /** * Name identifier for the routing. */ name: string; /** * Computes the points for the edge path. * This is the core routing logic that determines * how an edge is drawn between source and target. * * @param context - The routing context containing source/target info and layout state. * @param [config] - Optional configuration parameters for routing behavior. * @returns An array of points representing the routed edge path. */ computePoints(context: EdgeRoutingContext, config?: EdgeRoutingConfig): Point[]; /** * Generates an SVG path string from points. * Converts the routed points into a valid `d` attribute * for an `` SVG element. * * @param points - The points defining the edge path. * @param [config] - Optional configuration parameters for path generation. * @returns An SVG path string. */ computeSvgPath(points: Point[], config?: EdgeRoutingConfig): string; /** * Gets a point on the path at a given percentage (0-1). * Useful for positioning labels, decorations, or interaction handles. * * @param points - The points defining the path. * @param percentage - Position along the path (0 = start, 1 = end). * @returns The point at the given percentage along the path. */ computePointOnPath?(points: Point[], percentage: number): Point; /** * Gets a point on the path at a given pixel distance from the start. * Negative values measure from the end of the path. * * @param points - The points defining the path. * @param distancePx - Distance in pixels (positive = from start, negative = from end). * @returns The point at the given distance along the path. */ computePointAtDistance?(points: Point[], distancePx: number): Point; } /** * Interface representing size in the flow diagram * * @public * @since 0.8.0 * @category Types/Geometry */ interface Size { /** * Width dimension */ width: number; /** * Height dimension */ height: number; } /** * Interface representing a point in the flow diagram * * @public * @since 0.8.0 * @category Types/Geometry */ interface Point { /** * X coordinate of the point */ x: number; /** * Y coordinate of the point */ y: number; } /** * One of the four sides of a rectangular area. * * @public * @since 1.3.0 * @category Types/Model */ type Side = 'top' | 'right' | 'bottom' | 'left'; /** * Interface representing a port side on a node in the diagram * * @public * @since 0.8.0 * @category Types/Model */ type PortSide = Side; /** * Interface representing a rect in the flow diagram * * @public * @since 0.8.0 * @category Types/Geometry */ interface Rect { /** * X coordinate of the rect's top-left corner */ x: number; /** * Y coordinate of the rect's top-left corner */ y: number; /** * Width dimension */ width: number; /** * Height dimension */ height: number; } interface RectWithId extends Rect { id: string; } /** * Interface representing the location of a port on a node * * @public * @since 0.8.0 * @category Types/Model */ type PortLocation = { side: PortSide; } & Point; type DataObject = object; /** * @ignore */ type LooseAutocomplete = T | (string & {}); type DeepPartial = { [P in keyof T]?: T[P] extends (...args: unknown[]) => unknown ? T[P] : T[P] extends object ? DeepPartial : T[P]; }; /** * Type representing edge routing mode * * @public * @since 0.8.0 * @category Types/Routing */ type RoutingMode = 'manual' | 'auto'; /** * Identifies one endpoint of an edge. * * @public * @since 1.4.0 * @category Types/Model */ type EdgeEnd = 'source' | 'target'; /** * Interface representing an edge (connection) between nodes in the flow diagram * * @public * @since 0.8.0 * @category Types/Model */ interface Edge { /** * The unique identifier for the edge. */ id: string; /** * The source node of the edge. If empty string it will use sourcePosition. */ source: string; /** * The target node of the edge. If empty string it will use targetPosition. */ target: string; /** * The data associated with the edge. */ data: T; /** * The points of the edge defining the path. */ points?: Point[]; /** * Whether the edge is selected */ selected?: boolean; /** * Whether the edge is hidden. When not set, the edge is visible. * * A hidden edge keeps its geometry, does not block initialization or * `waitForMeasurements`, and is not routed. User interactions ignore it: * select-all, box selection and zoomToFit bounds. In the default render * mode the edge stays in the DOM with `display: none`. With virtualization * enabled it is removed from the DOM instead. An edge is also effectively * hidden when either endpoint node is effectively hidden. * * Programmatic APIs such as `select` and the z-order commands do not skip * hidden elements. It is up to the caller whether to use them on hidden * elements. * * Set by the user; the library only reads it. * @see {@link computedHidden} for the derived effective visibility. * @since 1.4.0 */ hidden?: boolean; /** * Whether the user can relink the ends of this edge. `true` allows both * ends, `'source'` or `'target'` allows only that end, and `false` allows * neither. When not set, `linking.defaultRelinkable` applies. * * Set by the user; the library only reads it. * @since 1.4.0 */ relinkable?: boolean | EdgeEnd; /** * @readonly * @remarks ComputedHidden is computed by the system and should not be set manually. * The effective visibility of the edge: `true` when its own `hidden` flag * or a template binding is set, or when either endpoint node is effectively * hidden. * @since 1.4.0 */ readonly computedHidden?: boolean; /** * The type of the edge declared in edgeTemplateMap. */ type?: string; /** * The port of the source node. */ sourcePort?: string; /** * The port of the target node. */ targetPort?: string; /** * The id of the source arrowhead of the edge. */ sourceArrowhead?: string; /** * The id of the target arrowhead of the edge. */ targetArrowhead?: string; /** * The routing of the edge. */ routing?: EdgeRoutingName; /** * The routing mode of the edge. * 'auto' (default): Points are computed automatically based on routing algorithm * 'manual': Points are provided by the user and routing algorithm is used to render the path */ routingMode?: RoutingMode; /** * The position of the edge start. */ sourcePosition?: Point; /** * The position of the edge end. */ targetPosition?: Point; /** * Whether the edge is temporary. */ temporary?: boolean; /** * The z-order of the edge. When set, overrides the default edge z-index * (which is derived from connected nodes). When a connected node is selected, * the node's elevation is added so the edge stays visible above elevated nodes. * * Set by `bringToFront` / `sendToBack` commands, or manually. * @see {@link computedZIndex} for the final rendered z-index. */ zOrder?: number; /** * @readonly * @remarks ComputedZIndex is computed by the system and should not be set manually. * The final z-index applied to the DOM element for rendering order. * Without `zOrder`: derived from `max(source, target)` connected node z-indices. * With `zOrder`: uses the explicit value plus connected node elevation. */ readonly computedZIndex?: number; /** * @readonly * @remarks MeasuredLabels are computed by the system and should not be set manually. * The labels of the edge with computed position and size. */ readonly measuredLabels?: EdgeLabel[]; } /** * Type representing an absolute edge label position in pixels. * Positive values measure from the source, negative from the target. * * @example `'30px'` — 30px from source, `'-20px'` — 20px from target * * @public * @since 1.1.0 * @category Types/Model */ type AbsoluteEdgeLabelPosition = `${number}px`; /** * Type representing edge label position — either relative (0-1) or absolute (`'Npx'`). * * - **Relative** (`number`, 0-1): percentage along the path. Clamped to [0, 1]. * - **Absolute** (`string`, `'Npx'`): pixel distance from source (positive) or target (negative). Clamped to path length. * * @public * @since 1.1.0 * @category Types/Model */ type EdgeLabelPosition = number | AbsoluteEdgeLabelPosition; /** * Interface representing a label of an edge. * * @public * @since 0.8.0 * @category Types/Model */ interface EdgeLabel { /** * The id of the label. */ id: string; /** * The position of the label on the edge. * * - **Relative** (`number`, 0-1): 0 is the source, 1 is the target, 0.5 is the midpoint. * - **Absolute** (`'Npx'`): pixel distance from source (positive) or target (negative). * * @example * ```ts * positionOnEdge: 0.5 // midpoint (relative) * positionOnEdge: '30px' // 30px from source (absolute) * positionOnEdge: '-20px' // 20px from target (absolute) * ``` */ positionOnEdge: EdgeLabelPosition; /** * The position of the label on flow. */ position?: Point; /** * The size of the label. */ size?: Size; } /** * The origin point options for port placement. * @category Types/Model */ type OriginPoint = 'topLeft' | 'topCenter' | 'topRight' | 'centerLeft' | 'center' | 'centerRight' | 'bottomLeft' | 'bottomCenter' | 'bottomRight'; /** * Interface representing all possible node types in the diagram * * @public * @since 0.8.0 * @category Types/Model */ type Node$1 = SimpleNode | GroupNode; /** * Interface representing a group node in the diagram * * @public * @since 0.8.0 * @category Types/Model */ interface GroupNode extends SimpleNode { /** * Flag indicating the node is a group */ isGroup: true; /** * Whether the group is highlighted. For example, when a node is being dragged over it. */ highlighted: boolean; } /** * Interface representing the most basic node in the diagram * * @public * @since 0.8.0 * @category Types/Model */ interface SimpleNode { /** * The unique identifier for the node. */ id: string; /** * The position of the node in the diagram. */ position: Point; /** * The data associated with the node. */ data: T; /** * The type of the node declared in nodeTemplateMap. */ type?: string; /** * Whether the node is selected. */ selected?: boolean; /** * Whether the node is hidden. When not set, the node is visible. * * A hidden node keeps its size and position and does not block * initialization or `waitForMeasurements`. User interactions ignore it: * hit-testing, select-all, box selection, keyboard move, drag, linking, * zoomToFit bounds and edge routing. In the default render mode the node * stays in the DOM with `display: none`. With virtualization enabled it is * removed from the DOM instead; its geometry stays in the model and is * measured again when the node becomes visible. Hiding a group hides all * of its descendants. Hiding a node hides the edges connected to it. * * Programmatic APIs such as `select`, `centerOnNode` and the z-order * commands do not skip hidden elements. It is up to the caller whether to * use them on hidden elements. * * Set by the user; the library only reads it. * @see {@link computedHidden} for the derived effective visibility. * @since 1.4.0 */ hidden?: boolean; /** * @readonly * @remarks ComputedHidden is computed by the system and should not be set manually. * The effective visibility of the node: `true` when its own `hidden` flag * or a template binding is set, or when any ancestor group is effectively * hidden. * @since 1.4.0 */ readonly computedHidden?: boolean; /** * The size of the node. */ size?: Size; /** * Whether the size of the node is automatically resized based on the content. */ autoSize?: boolean; /** * The z-order of the node. Controls relative ordering among nodes on the same hierarchy level. * With proper values, it can also influence ordering across different hierarchy levels, * since each nesting level adds +1 to the computed z-index per child. * - Root nodes: used directly as the base z-index (negative values allowed). * - Grouped nodes: acts as a minimum floor — cannot go below the parent's z-index. * * Set by `bringToFront` / `sendToBack` commands, or manually. * @see {@link computedZIndex} for the final rendered z-index. */ zOrder?: number; /** * @readonly * @remarks ComputedZIndex is computed by the system and should not be set manually. * The final z-index applied to the DOM element for rendering order. * Computed from `zOrder`, group hierarchy, and selection elevation. * Children are always above their parent group. */ readonly computedZIndex?: number; /** * @readonly * @remarks MeasuredPorts are computed by the system and should not be set manually. * The ports of the node with computed position and size. */ readonly measuredPorts?: Port[]; /** * Whether the node is resizable. */ resizable?: boolean; /** * Whether the node is rotatable. */ rotatable?: boolean; /** * Whether the node is draggable. */ draggable?: boolean; /** * The angle of the node from 0 to 360. */ angle?: number; /** * The id of the parent node. */ groupId?: Node$1['id']; /** * @readonly * @remarks MeasuredBounds are computed by the system and should not be set manually. * Bounding box that encompasses the node including its ports, accounting for rotation. */ measuredBounds?: Rect; } /** * Interface representing a port in the node. * * @public * @since 0.8.0 * @category Types/Model */ interface Port { /** * The unique identifier for the port. */ id: string; /** * The position of the port in the node. */ position?: Point; /** * The size of the port. */ size?: Size; /** * The type of the port. */ type: 'source' | 'target' | 'both'; /** * The id of the node that the port belongs to. */ nodeId: string; /** * The side of the node that the port is on. */ side: PortSide; } /** * Port properties owned by the measurement pipeline rather than by the * registering component. They are computed from the DOM and must never be * overwritten by authored data when a port component re-registers; every * other {@link Port} property is authored and is reconciled on re-registration. * * @internal */ declare const MEASURED_PORT_PROPERTIES: readonly ["size", "position"]; /** * Union of the {@link MEASURED_PORT_PROPERTIES} keys. Types the measurement * pipeline's view of a port, e.g. `Pick`. * * @internal */ type MeasuredPortProperty = (typeof MEASURED_PORT_PROPERTIES)[number]; /** * Position for diagram overlay panels (minimap, watermark, etc.). * * @public * @since 1.0.0 * @category Types */ type NgDiagramPanelPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; type InputEventName = 'copy' | 'cut' | 'paste' | 'select' | 'selectAll' | 'deleteSelection' | 'panning' | 'keyboardPanning' | 'wheelPanning' | 'pointerMoveSelection' | 'keyboardMoveSelection' | 'resize' | 'zoom' | 'linking' | 'relinking' | 'rotate' | 'paletteDrop' | 'boxSelection' | 'undo' | 'redo' | 'cancelInteraction'; interface BaseInputEvent { name: InputEventName; id: string; timestamp: number; modifiers: InputModifiers; } /** * Interface representing keyboard and modifier keys state during an input event. * * @public * @since 0.8.0 * @category Types/Configuration/Shortcuts */ interface InputModifiers { /** * Ctrl key (Windows/Linux) OR Cmd key (Mac) */ primary: boolean; /** * Alt key */ secondary: boolean; /** * Shift key */ shift: boolean; /** * Windows key OR Cmd key */ meta: boolean; } /** * Keyboard movement actions that map to directional events * * @public * @since 0.8.0 * @category Types/Configuration/Shortcuts */ type KeyboardMoveSelectionAction = 'keyboardMoveSelectionUp' | 'keyboardMoveSelectionDown' | 'keyboardMoveSelectionLeft' | 'keyboardMoveSelectionRight'; /** * Keyboard panning actions that map to directional events * * @public * @since 0.8.0 * @category Types/Configuration/Shortcuts */ type KeyboardPanAction = 'keyboardPanUp' | 'keyboardPanDown' | 'keyboardPanLeft' | 'keyboardPanRight'; /** * Keyboard zooming actions * * @public * @since 1.1.0 * @category Types/Configuration/Shortcuts */ type KeyboardZoomAction = 'keyboardZoomIn' | 'keyboardZoomOut'; /** * Pointer-only action names that can only be triggered by pointer events with modifiers * (e.g., Shift+Click, Ctrl+Click) * * @public * @since 0.8.0 * @category Types/Configuration/Shortcuts */ type PointerOnlyActionName = 'multiSelection' | 'boxSelection'; /** * Wheel-only action names that can only be triggered by wheel events with modifiers * (e.g., Shift+Wheel, Ctrl+Wheel) * * @public * @since 1.1.0 * @category Types/Configuration/Shortcuts */ type WheelOnlyActionName = 'zoom'; /** * Keyboard action names that can be triggered by keyboard events * * @public * @since 0.8.0 * @category Types/Configuration/Shortcuts */ type KeyboardActionName = KeyboardMoveSelectionAction | KeyboardPanAction | KeyboardZoomAction | Extract; /** * Normalized keyboard input for shortcut matching * Contains the key and already-normalized modifiers */ interface NormalizedKeyboardInput { key?: string; modifiers: InputModifiers; } /** * Defines a keyboard shortcut binding with a key * * @public * @since 0.8.0 * @category Types/Configuration/Shortcuts */ interface KeyboardShortcutBinding { /** * Key value (e.g., 'c', 'Delete', 'ArrowUp') * * @see https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values - Complete list of valid key values */ key: string; /** Required modifier keys (all are optional - omitted means no modifiers required) */ modifiers?: Partial; } /** * Defines a modifier-only shortcut binding (for pointer events) * * @public * @since 0.8.0 * @category Types/Configuration/Shortcuts */ interface ModifierOnlyShortcutBinding { /** * Key must not be present for modifier-only bindings */ key?: never; /** Required modifier keys - at least one modifier is typically required */ modifiers: Partial; } /** * Keyboard shortcut definition with key-based bindings * * @public * @since 0.8.0 * @category Types/Configuration/Shortcuts */ interface KeyboardShortcutDefinition { /** Action name for keyboard events */ actionName: KeyboardActionName; /** Key-based bindings (at least one must have a key) */ bindings: (KeyboardShortcutBinding | ModifierOnlyShortcutBinding)[]; } /** * Pointer-only shortcut definition with modifier-only bindings * * @public * @since 0.8.0 * @category Types/Configuration/Shortcuts */ interface PointerOnlyShortcutDefinition { /** Action name for pointer events */ actionName: PointerOnlyActionName; /** Modifier-only bindings (keys are not allowed) */ bindings: ModifierOnlyShortcutBinding[]; } /** * Wheel-only shortcut definition with modifier-only bindings * * @public * @since 1.1.0 * @category Types/Configuration/Shortcuts */ interface WheelOnlyShortcutDefinition { /** Action name for wheel events */ actionName: WheelOnlyActionName; /** Modifier-only bindings (keys are not allowed) */ bindings: ModifierOnlyShortcutBinding[]; } /** * Shortcut definition for registering keyboard and pointer shortcuts * * This is a discriminated union that enforces: * - Pointer-only actions (multiSelection, boxSelection) can only have modifier-only bindings * - Wheel-only actions (zoom) can only have modifier-only bindings * - Keyboard actions must have at least one key-based binding * * @public * @since 0.8.0 * @category Types/Configuration/Shortcuts */ type ShortcutDefinition = KeyboardShortcutDefinition | PointerOnlyShortcutDefinition | WheelOnlyShortcutDefinition; /** * Configuration for node resizing behavior. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface ResizeConfig { /** * Returns the minimum allowed size for a node. * @param node The node to compute the minimum size for. * @default () => ({ width: 20, height: 20 }) */ getMinNodeSize: (node: Node$1) => Size; /** * Allows resizing a group node smaller than its children bounds. * When set to false, a group node cannot be resized smaller than the bounding box of its children. * By default a group can be resized below children size. * @default true */ allowResizeBelowChildrenBounds: boolean; /** * The default resizable state for nodes. * @default true */ defaultResizable: boolean; } /** * Configuration for linking (edge creation) behavior. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface LinkingConfig { /** * The maximum distance (in pixels) at temporary edge will snap to target port. * @default 10 */ portSnapDistance: number; /** * Validates whether a connection between two nodes and ports is allowed. * * Called for every operation that creates a connection: drawing a new edge, * relinking an endpoint of an existing edge, and `attachEdge`. The optional * `context` tells which operation is being validated (since 1.4.0). * * `source` is `null` for draws started with `startLinkingFromPosition`. * When an edge is relinked or attached, the other end of that edge can be * free (dangling); the `source` or `target` for that end is then `null`. * * @param source The source node, or `null` when the source end is free. * @param sourcePort The source port. * @param target The target node, or `null` when the target end is free. * @param targetPort The target port. * @param context The operation being validated (`draw` when omitted). * @returns True if the connection is valid, false otherwise. * @default () => true */ validateConnection: (source: Node$1 | null, sourcePort: Port | null, target: Node$1 | null, targetPort: Port | null, context?: ConnectionValidationContext) => boolean; /** * Allows customization of the temporary edge object shown while the user is dragging to create a new edge. * Receives the default temporary edge (with source/target node/port IDs and positions) * and should return a fully-formed Edge object for rendering the temporary edge. * @param defaultTemporaryEdgeData The default temporary edge data (may be incomplete). * @returns The Edge object to use for the temporary edge. * @default (edge) => Edge */ temporaryEdgeDataBuilder: (defaultTemporaryEdgeData: Edge) => Edge; /** * Allows customization of the final edge object when the user completes edge creation. * Receives the default finalized edge (with source/target node/port IDs) * and should return a fully-formed Edge object to be added to the flow. * @param defaultFinalEdgeData The default finalized edge data (may be incomplete). * @returns The Edge object to use for the finalized edge. * @default (edge) => Edge */ finalEdgeDataBuilder: (defaultFinalEdgeData: Edge) => Edge; /** * Enable edge panning when the routed edge is near the edge of the viewport. * * @default true */ edgePanningEnabled: boolean; /** * Multiplier for edge panning speed while routing edge is near the edge of the viewport. * * @default 10 */ edgePanningForce: number; /** * The threshold in pixels for edge panning to start. * If the mouse pointer is within this distance from the edge of the viewport, panning will be triggered. * * @default 30 */ edgePanningThreshold: number; /** * Whether to select a node when the user presses a port to start linking. * When true (default), pressing a port also triggers node selection events. * When false, port press only initiates the linking gesture without selecting the node. * * @default true * @since 1.2.0 */ selectNodeOnPortPress: boolean; /** * Default `relinkable` value for edges that do not set their own. `true` * lets the user drag both ends of an edge to another port, `'source'` or * `'target'` allows only that end, and `false` allows neither. A selected * edge shows a handle at each end that can be relinked. Dragging a handle * previews the new connection and commits it on drop. A drop on empty * canvas detaches the endpoint when `danglingEdges.enabled` is true; * otherwise the relink is reverted. * * Relinking uses the same `portSnapDistance`, edge panning and * `temporaryEdgeDataBuilder` settings as edge drawing. Each drop is * validated with `validateConnection`, which receives a context with * `reason: 'relink'` and the edge being relinked. * * @default false * @since 1.4.0 */ defaultRelinkable: boolean | EdgeEnd; } /** * Configuration for dangling edges: edges with one or both endpoints not * connected to any node. A free endpoint has an empty `source` or `target`, * and its position is stored in `sourcePosition` or `targetPosition`. * * The feature is off by default: an edge dropped on empty canvas is * discarded, and deleting a node deletes its edges. * * @public * @since 1.4.0 * @category Types/Configuration/Features */ interface DanglingEdgesConfig { /** * Master switch for dangling edges. When true, an edge drawn onto empty * canvas is kept as a dangling edge instead of being discarded, and a * relink dropped on empty canvas detaches that endpoint. It also enables * `detachEdge` and `startLinkingFromPosition`. * * A drop on a port that the edge cannot connect to (for example a port * with the wrong direction) does not count as a drop on empty canvas. Such * a draw is discarded and such a relink is reverted. * @default false */ enabled: boolean; /** * Decides per edge whether a draw or relink dropped on empty canvas keeps * the edge as a dangling edge. Called only when `enabled` is true. For a * draw, `edge` is the final edge, after `linking.finalEdgeDataBuilder` has * run. For a relink, `edge` is the edge as it would be after the detach. * Returning false discards the drawn edge or reverts the relink, which is * also what happens when the feature is off. * @param edge The edge that would be kept. * @param dropPosition The position where the pointer was released, in flow coordinates. * @default undefined (keep every edge) */ shouldKeepOnDrop?: (edge: Edge, dropPosition: Point) => boolean; /** * When true, deleting a node keeps its edges as dangling edges instead of * deleting them. Each freed endpoint stays anchored where its port was. * Requires `enabled` to be true. * * An edge is still deleted, not detached, in these cases: * - The edge itself is part of the deleted selection. An explicit delete * always wins. * - The edge is hidden only because of the node it loses, for example the * edges of the collapsed children of a deleted group. Detaching it would * turn invisible wiring into a visible dangling edge. An edge that is * hidden for another reason (its own `hidden` flag, a template binding, * or a hidden node at the other end) is detached like any other edge and * stays hidden. * - The edge loses both endpoints in the same delete. It becomes a dual * dangling edge only when {@link shouldDetachOnNodeDelete} is provided * and returns true for both ends. * @default false */ detachOnNodeDelete: boolean; /** * Decides per endpoint whether it is detached (kept as a free endpoint) or * deleted together with the node. Called only when `enabled` and * `detachOnNodeDelete` are true, once for each endpoint that loses its * node. Returning false deletes the edge. An edge that loses both * endpoints at once survives as a dual dangling edge only when this * callback is provided and returns true for both ends. * @param edge The edge that loses a node. * @param deletedNode The node being deleted. * @param end The endpoint of `edge` that is connected to `deletedNode`. * @default undefined (detach every edge, except edges losing both ends) */ shouldDetachOnNodeDelete?: (edge: Edge, deletedNode: Node$1, end: EdgeEnd) => boolean; } /** * Context passed to {@link LinkingConfig.validateConnection}. It describes the * operation that is being validated. * * - `draw` — a new edge is being drawn, by a pointer gesture or by * `startLinking` / `startLinkingFromPosition`. * - `relink` — an endpoint of `edge` is being dragged to a new target. * - `attach` — `NgDiagramModelService.attachEdge` connects an endpoint of `edge`. * * @public * @since 1.4.0 * @category Types/Configuration/Features */ interface ConnectionValidationContext { /** The operation being validated. */ reason: 'draw' | 'relink' | 'attach'; /** The existing edge whose endpoint is being connected (relink and attach only). */ edge?: Edge; /** Which endpoint of `edge` is being connected (relink and attach only). */ end?: EdgeEnd; } /** * Configuration for node grouping behavior. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface GroupingConfig { /** * Determines if a node can be grouped into a group node. * @param node The node to group. * @param group The group node. * @returns True if the node can be grouped, false otherwise. * @default () => true */ canGroup: (node: Node$1, group: Node$1) => boolean; } /** * Configuration for zoom-to-fit behavior. * * @category Types/Configuration/Features */ interface ZoomToFitConfig { /** * The default padding (in pixels) to use for zoom-to-fit operations. * Supports CSS-like padding syntax: * - Single number: applies to all sides * - [v, h]: vertical, horizontal * - [t, h, b]: top, horizontal, bottom * - [t, r, b, l]: top, right, bottom, left * Can be overridden per command invocation. * @default 50 */ padding: number | [number, number] | [number, number, number] | [number, number, number, number]; /** * Whether to automatically zoom to fit all content when the diagram is initialized. * @default false */ onInit: boolean; } /** * Configuration for zooming behavior. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface ZoomConfig { /** * The minimum allowed zoom level. * @default 0.01 */ min: number; /** * The maximum allowed zoom level. * @default 10.0 */ max: number; /** * The zoom step increment. * @default 0.03 */ step: number; /** * Configuration for zoom-to-fit operations. */ zoomToFit: ZoomToFitConfig; } /** * Configuration for the diagram background. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface BackgroundConfig { /** * Distance in pixels between consecutive dots in the background pattern. * @default 30 */ dotSpacing?: number; /** * The size of the smallest grid cell (minor grid spacing). * Supports rectangular grids by specifying different width and height values. * @default { width: 10, height: 10 } */ cellSize?: Size; /** * Specifies how often major grid lines occur, measured in counts of minor grid cells. * E.g., { x: 5, y: 5 } draws a major vertical line every 5 minor columns and * a major horizontal line every 5 minor rows. * @default { x: 5, y: 5 } */ majorLinesFrequency?: { x: number; y: number; }; } /** * Configuration for node rotation behavior. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface NodeRotationConfig { /** * Determines if rotation snapping should be enabled for a node. * @param node The node to check for rotation snapping. * @returns True if rotation should snap, false otherwise. * @default () => false */ shouldSnapForNode: (node: Node$1) => boolean; /** * Computes the snap angle for a node's rotation. * @param node The node to compute the snap angle for. * @returns The angle in degrees to snap to, or null if default snapping should be used. * @default () => null */ computeSnapAngleForNode: (node: Node$1) => number | null; /** * The default snap angle in degrees. Used if computeSnapAngleForNode returns null. * @default 30 */ defaultSnapAngle: number; /** * The default rotatable state for nodes. * @default true */ defaultRotatable: boolean; } /** * Configuration for node dragging behavior. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface SnappingConfig { /** * Determines if a node should snap to grid while dragging. * @param node The node being dragged. * @returns True if the node should snap to grid, false otherwise. * @default () => false */ shouldSnapDragForNode: (node: Node$1) => boolean; /** * Determines if a node should snap to grid while resizing. * @param node The node being resized. * @returns True if the node should snap to grid, false otherwise. * @default () => false */ shouldSnapResizeForNode: (node: Node$1) => boolean; /** * Computes the snap size for a node while dragging. If null is returned, a default snap size will be used. * If computeSnapForNodeDrag is used, it takes precedence over defaultDragSnap. * @param node The node to compute the snap size for dragging. * @returns The snap size for the node while dragging, or null. * @default () => null */ computeSnapForNodeDrag: (node: Node$1) => Size | null; /** * Computes the snap size for a node while resizing. If null is returned, a default snap size will be used. * @param node The node to compute the snap size for resizing. * @returns The snap size for the node while resizing, or null. * @default () => null */ computeSnapForNodeSize: (node: Node$1) => Size | null; /** * Computes the snap offset for a node while resizing. The snapped size follows the * sequence `offset + n * snap` per axis, so a node with a 60px header snapping every * 50px can snap to 60, 110, 160, ... instead of 50, 100, 150, ... * If null is returned, {@link defaultResizeSnapOffset} is used. * If computeSnapOffsetForNodeSize is used, it takes precedence over defaultResizeSnapOffset. * @param node The node to compute the snap offset for resizing. * @returns The snap offset for the node while resizing, or null. * @default () => null * @since 1.3.0 */ computeSnapOffsetForNodeSize: (node: Node$1) => Size | null; /** * The default snap size for node dragging. * If computeSnapForNodeDrag is used, it takes precedence over this value. * @default { width: 10, height: 10 } */ defaultDragSnap: Size; /** * The default snap size for node resizing. * @default { width: 10, height: 10 } */ defaultResizeSnap: Size; /** * The default snap offset for node resizing. The snapped size follows the * sequence `offset + n * snap` per axis (see {@link computeSnapOffsetForNodeSize}). * If computeSnapOffsetForNodeSize is used, it takes precedence over this value. * @default { width: 0, height: 0 } * @since 1.3.0 */ defaultResizeSnapOffset: Size; } /** * Configuration for selection moving behavior. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface SelectionMovingConfig { /** * Enable edge panning when the moved node is near the edge of the viewport. * * @default true */ edgePanningEnabled: boolean; /** * Multiplier for edge panning speed while dragging nodes near the edge of the viewport. * * @default 10 */ edgePanningForce: number; /** * The threshold in pixels for edge panning to start. * If the mouse pointer is within this distance from the edge of the viewport, panning will be triggered. * * @default 30 */ edgePanningThreshold: number; } /** * Configuration for z-index layering behavior. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface ZIndexConfig { /** * Whether z-index middleware is enabled. * @default true */ enabled: boolean; /** * The z-index value added to selected elements' computed z-index. * Applied cumulatively — a selected child inside a selected parent * receives this value twice (once from the parent's elevation, once from its own). * @default 10000 */ selectedZIndex: number; /** * The z-index value for temporary edge. * @default 2147483647 */ temporaryEdgeZIndex: number; /** * Whether edges should appear above their connected nodes. * @default false */ edgesAboveConnectedNodes: boolean; /** * Whether selected elements should be elevated by adding `selectedZIndex` to their computed z-index. * @default true */ elevateOnSelection: boolean; } /** * Configuration for edge routing behavior. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface EdgeRoutingConfig { /** * The default edge routing algorithm to use for edges. * Can be one of the built-in routing names or a custom string for user-defined routing. * @see EdgeRoutingName * @default 'orthogonal' */ defaultRouting: EdgeRoutingName; /** configuration options for bezier routing */ bezier?: { /** bezier control point offset * @default 100 */ bezierControlOffset?: number; }; /** configuration options for orthogonal routing */ orthogonal?: { /** first/last segment length * @default 20 */ firstLastSegmentLength?: number; /** maximum corner radius * @default 15 */ maxCornerRadius?: number; }; /** * Allow custom edge routing configurations. */ [edgeRoutingName: string]: Record | EdgeRoutingName | undefined; } /** * Configuration for box selection behavior. * * @public * @since 0.8.0 * @category Types/Configuration/Features */ interface BoxSelectionConfig { /** * Whether to select nodes that are only partially within the selection box. * @default true */ partialInclusion?: boolean; /** * Whether to select nodes in real-time as the selection box is being drawn. * If false, nodes will only be selected when the box selection ends. * @default true */ realtime?: boolean; } /** * Configuration for viewport virtualization behavior. * When enabled, only nodes and edges visible in the viewport (plus padding) are rendered, * significantly improving performance for large diagrams. * * @public * @since 1.0.0 * @category Types/Configuration/Features */ interface VirtualizationConfig { /** * Whether viewport virtualization is enabled. * When disabled, all nodes/edges are rendered regardless of viewport. * @default false */ enabled: boolean; /** * Padding multiplier relative to viewport size. * The actual padding is calculated as: max(viewportWidth, viewportHeight) * padding * For example, 0.5 means 50% of the viewport size as padding in each direction. * @default 0.5 */ padding: number; /** * Delay in milliseconds after panning stops before re-rendering visible nodes. * @default 100 */ idleDelay?: number; } /** * Configuration for the default Node Templates * * @public * @since 1.3.0 * @category Types/Configuration/Features */ interface DefaultNodeTemplateConfig { /** * When explicitly set to `true` this will remove the ports in the default Node Template * @default undefined; */ removePorts: boolean; } /** * The main configuration interface for the flow system. * * This type defines all available configuration options for the diagram engine. * * For most use cases, you should use {@link NgDiagramConfig}, which allows you to override only the properties you need. * * @public * @since 0.8.0 * @category Types/Configuration */ interface FlowConfig { /** * Computes a unique ID for a node. * @returns The node's unique ID. */ computeNodeId: () => string; /** * Computes a unique ID for an edge. * @returns The edge's unique ID. */ computeEdgeId: () => string; /** * Configuration for node resizing. */ resize: ResizeConfig; /** * Configuration for linking (edge creation). */ linking: LinkingConfig; /** * Configuration for dangling edges (edges with unconnected endpoints). * @since 1.4.0 */ danglingEdges: DanglingEdgesConfig; /** * Configuration for node grouping. */ grouping: GroupingConfig; /** * Configuration for zooming. */ zoom: ZoomConfig; /** * Configuration for edge routing. */ edgeRouting: EdgeRoutingConfig; /** * Configuration for background behavior. */ background: BackgroundConfig; /** * Configuration for node rotation behavior. */ nodeRotation: NodeRotationConfig; /** * Configuration for snapping behavior. */ snapping: SnappingConfig; /** * Configuration for selection moving behavior. */ selectionMoving: SelectionMovingConfig; /** * Configuration for z-index layering behavior. */ zIndex: ZIndexConfig; /** * Configuration for box selection behavior. */ boxSelection: BoxSelectionConfig; /** * Configuration for viewport virtualization. * Improves performance for large diagrams by only rendering visible elements. */ virtualization: VirtualizationConfig; /** * Configuration for keyboard shortcuts. */ shortcuts: ShortcutDefinition[]; /** * Enables or disables debug mode for the diagram. * When enabled, additional console logs are printed. * @default false */ debugMode: boolean; /** * @since 0.9.0 * * Hides the ngDiagram watermark when set to true. * @default undefined */ hideWatermark?: boolean; /** * @since 1.2.0 * * Sets the preferred position for the ngDiagram watermark. * If the chosen position collides with a registered panel (e.g., minimap), * the watermark shifts to the nearest available corner. * @default 'bottom-right' */ watermarkPosition?: NgDiagramPanelPosition; /** * @since 0.9.0 * * Enables or disables panning on the diagram. * When set to false, user is not able to move the viewport by panning. * @default true */ viewportPanningEnabled: boolean; /** * @since 1.0.0 * * Enables or disables node dragging on the diagram. * When set to false, users cannot move nodes via mouse dragging or keyboard arrow keys. * @default true */ nodeDraggingEnabled: boolean; /** * @since 1.3.0 * Configuration options for the default Node Templates */ defaultNode?: DefaultNodeTemplateConfig; } /** * Interface representing the viewport of the diagram. * * @public * @since 0.8.0 * @category Types/Model */ interface Viewport { /** X coordinate of the viewport center */ x: number; /** Y coordinate of the viewport center */ y: number; /** Scale factor of the viewport */ scale: number; /** Width of the viewport */ width?: number; /** Height of the viewport */ height?: number; } /** * Interface representing the metadata of the diagram. * * @public * @since 0.8.0 * @category Types/Model */ interface Metadata { /** * Viewport of the diagram */ viewport: Viewport; /** * Custom user data associated with the diagram */ data?: T; } interface AddToGroupCommand { name: 'addToGroup'; groupId: Node$1['id']; nodeIds: Node$1['id'][]; } interface AddNodesCommand { name: 'addNodes'; nodes: Node$1[]; } interface PaletteDropNodeCommand { name: 'paletteDropNode'; node: Node$1; } interface UpdateNodeCommand { name: 'updateNode'; id: string; nodeChanges: Partial; } interface UpdateNodesCommand { name: 'updateNodes'; nodes: (Pick & Partial)[]; } interface DeleteNodesCommand { name: 'deleteNodes'; ids: string[]; } interface ClearModelCommand { name: 'clearModel'; } interface AddEdgesCommand { name: 'addEdges'; edges: Edge[]; } interface UpdateEdgeCommand { name: 'updateEdge'; id: string; edgeChanges: Partial; } interface UpdateEdgesCommand { name: 'updateEdges'; edges: (Pick & Partial)[]; } interface DeleteEdgesCommand { name: 'deleteEdges'; ids: string[]; } interface AddPortsBulkCommand { name: 'addPortsBulk'; additions: Map; } interface UpdatePortsBulkCommand { name: 'updatePortsBulk'; updates: Map; }[]>; } interface DeletePortsBulkCommand { name: 'deletePortsBulk'; deletions: Map; } interface AddEdgeLabelsBulkCommand { name: 'addEdgeLabelsBulk'; additions: Map; } interface UpdateEdgeLabelsBulkCommand { name: 'updateEdgeLabelsBulk'; updates: Map; }[]>; } interface DeleteEdgeLabelsBulkCommand { name: 'deleteEdgeLabelsBulk'; deletions: Map; } interface CenterOnRectCommand { name: 'centerOnRect'; rect: Rect; } interface CenterOnNodeCommand { name: 'centerOnNode'; nodeOrId: string | Node$1; } interface CopyCommand { name: 'copy'; } interface PasteCommand { name: 'paste'; position?: Point; } interface CutCommand { name: 'cut'; } interface DeleteSelectionCommand { name: 'deleteSelection'; } interface HighlightGroupCommand { name: 'highlightGroup'; groupId: Node$1['id']; nodes: Node$1[]; } interface HighlightGroupClearCommand { name: 'highlightGroupClear'; } interface InitCommand { name: 'init'; /** IDs of nodes currently rendered (for virtualization) */ renderedNodeIds?: string[]; /** IDs of edges currently rendered (for virtualization) */ renderedEdgeIds?: string[]; } interface CancelLinkingCommand { name: 'cancelLinking'; } interface FinishLinkingCommand { name: 'finishLinking'; position?: Point; } interface FinishLinkingToPositionCommand { name: 'finishLinkingToPosition'; position: Point; } interface FinishRelinkingCommand { name: 'finishRelinking'; /** The drop position in flow coordinates. */ position: Point; } /** * State tracking a node resize operation in progress. * * @public * @since 0.8.0 * @category Internals */ interface ResizeActionState { /** Initial width of the node before resize. */ startWidth: number; /** Initial height of the node before resize. */ startHeight: number; /** Initial X coordinate in screen space where the resize started. */ startX: number; /** Initial Y coordinate in screen space where the resize started. */ startY: number; /** Initial X position of the node in diagram space. */ startNodePositionX: number; /** Initial Y position of the node in diagram space. */ startNodePositionY: number; /** Reference to the node being resized. */ resizingNode: Node$1; /** Set when the resize is aborted; carried into `nodeResizeEnded`. */ cancelReason?: GestureCancelReason; } /** * State tracking an edge creation operation in progress. * * @public * @since 0.8.0 * @category Internals */ interface LinkingActionState { /** ID of the node where the edge starts. */ sourceNodeId: string; /** ID of the port where the edge starts. */ sourcePortId: string; /** Temporary edge displayed while creating the connection. */ temporaryEdge: Edge | null; /** Position where the pointer was released. */ dropPosition?: Point; /** Reason the linking gesture was cancelled (set by finishLinking on failure paths). */ cancelReason?: EdgeDrawCancelReason; /** * Present while an endpoint of an existing edge is being relinked. Until the * gesture ends, the original edge is not rendered and the temporary edge * represents it. `relink.end` is the end of the temporary edge that follows * the pointer (a normal draw always drags the target end). * * @since 1.4.0 */ relink?: LinkingRelinkContext; /** * Reason the relink gesture ended without changing the edge (set by * `finishRelinking` when the relink fails). * * @since 1.4.0 */ relinkCancelReason?: EdgeRelinkCancelReason; } /** * Context of an edge relink gesture carried inside the linking action state. * * @public * @since 1.4.0 * @category Internals */ interface LinkingRelinkContext { /** ID of the edge whose endpoint is being dragged. */ edgeId: string; /** Which endpoint of the edge is being dragged. */ end: EdgeEnd; /** Snapshot of the edge as it was when the gesture started. */ originalEdge: Edge; } /** * State containing copied nodes and edges for paste operations. * * @public * @since 0.8.0 * @category Internals */ interface CopyPasteActionState { /** Array of nodes that were copied. */ copiedNodes: Node$1[]; /** Array of edges that were copied. */ copiedEdges: Edge[]; } /** * State tracking which group is currently highlighted. * * @public * @since 0.8.0 * @category Internals */ interface HighlightGroupActionState { /** ID of the highlighted group, or null if no group is highlighted. */ highlightedGroupId: string | null; } /** * State tracking a node rotation operation in progress. * * @public * @since 0.8.0 * @category Internals */ interface RotationActionState { /** Angle in degrees at the start of the rotation operation. */ startAngle: number; /** Initial angle of the node before rotation. */ initialNodeAngle: number; /** ID of the node being rotated. */ nodeId: string; /** Set when the rotation is aborted; carried into `nodeRotateEnded`. */ cancelReason?: GestureCancelReason; } /** * State tracking a drag operation in progress. * * @public * @since 0.8.0 * @category Internals */ interface DraggingActionState { /** IDs of all nodes participating in the drag (selected + children, filtered by draggable). */ nodeIds: string[]; /** Input modifiers (e.g., Ctrl, Shift) active during the drag. */ modifiers: InputModifiers; /** * Accumulated deltas per node that haven't yet resulted in a snap movement. * Key is node ID, value is the accumulated delta that hasn't been applied due to snapping. */ accumulatedDeltas: Map; /** * Whether the pointer has moved beyond the move threshold, indicating an actual drag. * `false` when the drag state is first created (on pointer down), `true` once movement exceeds the threshold. */ movementStarted: boolean; /** Set when the drag is aborted; carried into `nodeDragEnded`. */ cancelReason?: GestureCancelReason; } /** * State tracking a panning operation in progress. * * @public * @since 1.1.2 * @category Internals */ interface PanningActionState { /** Whether panning is currently active. */ active: boolean; } /** * State tracking whether a selection gesture has changed the selection. * * Set by selection commands when they apply changes, cleared when * the `selectionGestureEnded` event is emitted on `selectEnd`. * * @public * @since 1.1.2 * @category Internals */ interface SelectionActionState { /** Whether selection has changed since the gesture started. */ selectionChanged: boolean; } /** * Interface representing the current state of various user interactions in the diagram. * * This state is read-only and automatically managed by the library. It provides * information about active operations such as resizing, linking, dragging, and other * user interactions. Use this to observe the current state, not to modify it. * * @public * @since 0.8.0 * @category Internals */ interface ActionState { /** * State related to node resizing action */ resize?: ResizeActionState; /** * State related to linking nodes */ linking?: LinkingActionState; /** * State related to copy-paste actions */ copyPaste?: CopyPasteActionState; /** * State related to highlighting groups */ highlightGroup?: HighlightGroupActionState; /** * State related to node rotation */ rotation?: RotationActionState; /** * State related to dragging elements */ dragging?: DraggingActionState; /** * State related to panning the viewport */ panning?: PanningActionState; /** * State related to selection gestures */ selection?: SelectionActionState; } interface MoveTemporaryEdgeCommand { name: 'moveTemporaryEdge'; position: Point; } interface StartLinkingCommand { name: 'startLinking'; source: string; sourcePort?: string; } interface StartLinkingFromPositionCommand { name: 'startLinkingFromPosition'; position: Point; } interface StartRelinkingCommand { name: 'startRelinking'; edgeId: string; end: EdgeEnd; } /** * Core implementation of CommandHandler interface * Handles command emission and registration of callbacks for system commands */ declare class CommandHandler$1 implements CommandHandler { private callbacks; readonly flowCore: FlowCore; constructor(flowCore: FlowCore); /** * Emit a system command to all registered callbacks for the command type * @param commandName Command name * @param rest Command props */ emit(commandName: K, ...props: IsEmpty> extends true ? [] | [WithoutName>] : [WithoutName>]): Promise; /** * Internal emit method that can bypass transaction checking * @param commandName Command name * @param bypassTransaction Whether to bypass transaction checking * @param rest Command props */ emitInternal(commandName: K, bypassTransaction: boolean, ...props: IsEmpty> extends true ? [] | [WithoutName>] : [WithoutName>]): Promise; /** * Register a callback for specific command types * @param commandName Type of command to listen for * @param callback Function to be called when command occurs * @returns Function to unregister the callback */ register(commandName: K, callback: CommandCallback): () => void; private getCommandCallbacks; } type ResizeDirection = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'left' | 'right' | 'top' | 'bottom'; declare abstract class EventHandler { protected readonly flow: FlowCore; /** * State whose end/cancel claimed the teardown. Never reset — a fresh state * object per gesture means a stale claim cannot match a live one. */ private claimedTeardownState; constructor(flow: FlowCore); /** Handles one input event. Invoked un-awaited — implementations must tolerate interleaving at every await. */ abstract handle(event: TEvent): void | Promise; /** * Claims the teardown of the gesture owning `state`, so a racing cancel() * (or a second one) no-ops. Requires one state object per gesture lifetime — * linking stamps its replaced state instead, drag uses `DragGesture.ended`. */ protected claimTeardown(state: unknown): void; /** Whether `state`'s teardown was already claimed by an in-flight end or cancel. */ protected isTeardownClaimed(state: unknown): boolean; /** * Aborts the tracked gesture without the side effects of a normal `end` * (no edge creation, no group drop). Default: no-op. * * @returns Whether anything was torn down — `false` when there is no gesture * or its teardown is already claimed by an in-flight end or cancel. */ cancel(): boolean | Promise; } declare abstract class InputEventsRouter { private handlers; emit(event: TEvent): void | Promise; register(eventName: K, handler: EventHandler): void; registerDefaultCallbacks(flow: FlowCore): void; hasHandler(eventName: InputEventName): boolean; /** * Aborts the gesture tracked by the handler registered for `eventName`. * No-op when the handler is missing or has no gesture in progress. * * @returns Whether the handler actually tore anything down */ cancel(eventName: InputEventName): Promise; } type FlushCallback = (all: Map) => void | Promise; /** * Returns the set of item IDs that are already measured for a given key. * Used at flush time to filter out redundant adds (e.g. virtualization re-mounts * a component for an item that was never deleted from the model). */ type GetMeasuredIdsFn = (key: string) => Set; /** * Generic batch processor that collects operations (add, update, delete) within * the same JavaScript tick and flushes them together in a single microtask. * * Before flushing, two deduplication strategies are applied: * 1. **Intent cancellation**: matching add+delete pairs for the same item ID are * removed from both queues (e.g. type change destroys and recreates a port * with the same ID in the same tick). * 2. **Measurement filtering**: remaining adds with no matching delete are checked * via `getMeasuredIds`. If the item is already measured, the add is dropped * (e.g. virtualization re-mounts a component for a port that was never deleted * from the model). * * Remaining operations are flushed sequentially in order: adds → updates → deletes. * Each operation is awaited before the next begins, ensuring that later * operations read fresh state left by earlier ones. * * Callbacks are stored per-key, so different callers can safely use the same * BatchProcessor instance with different flush targets. * * @typeParam TAdd - Type of items being added (must have an `id` property) * @typeParam TUpdate - Type of update descriptors */ declare class BatchProcessor { private readonly getMeasuredIds?; private readonly pendingAdds; private readonly pendingUpdates; private readonly pendingDeletes; private flushScheduled; private lastFlush; constructor(getMeasuredIds?: GetMeasuredIdsFn | undefined); processAdd(key: string, item: TAdd, onFlush: FlushCallback): void; processUpdate(key: string, update: TUpdate, onFlush: FlushCallback): void; processDelete(key: string, itemId: string, onFlush: FlushCallback): void; private scheduleFlush; /** * Flushes all pending operations. * First cancels matching add+delete intents for the same item ID, * then filters out redundant adds for items that are already measured, * then executes remaining operations sequentially: adds → updates → deletes. * Each callback is awaited before the next to prevent read-modify-write races. */ private flush; /** * Groups entries by callback reference and invokes each callback once * with all its keys collected into a single Map. */ private invokeCallbacks; /** * Cancels out items that appear in both pendingAdds and pendingDeletes for the same key. * This prevents scenarios where an add+delete (or delete+add) in the same tick * produces counter-intuitive results due to flush ordering. */ private cancelMatchingIntents; /** * Filters out adds for items that are already measured and have no matching delete. * This runs after cancelMatchingIntents, so any remaining add without a delete * is an "orphaned" add — typically from virtualization re-mounting a component * for an item that was never removed from the model. */ private filterAlreadyMeasuredAdds; private getOrCreate; private takeAll; } interface LabelUpdate { labelId: string; labelChanges: Partial; } declare class LabelBatchProcessor extends BatchProcessor { constructor(getEdgeById: (edgeId: string) => Edge | null | undefined); } interface MeasurementTrackingConfig { discoveryWindowMs?: number; debounceMs?: number; } /** * Tracks pending measurements and notifies when all measurements are complete. * * This class coordinates asynchronous DOM measurements (node sizes, port positions, labels, etc.) * with transaction completion using a two-phase observation model. * * ## Timing Model * * ### Phase 1: Discovery Window * After `registerParticipants()` is called, a discovery window opens. The tracker waits * to see if any measurement activity occurs for the registered participant entities. * * - If a **measurement signal** arrives (via `signalMeasurement()`): transitions to Phase 2. * - If a **ResizeObserver early signal** arrives (via `signalObserverActivity()`): * if remaining time is below `OBSERVER_ACTIVITY_MIN_REMAINING`, the timer resets * to full `discoveryWindowMs`, giving the double-RAF pipeline time to deliver. * - If the timer expires with no activity: resolves — nothing to measure. * * ### Phase 2: Debounce * Once the first measurement arrives, subsequent measurements reset a debounce timer. * When no measurements arrive for `debounceMs`, measurements are considered settled. * * @example * ```typescript * tracker.requestTracking({ discoveryWindowMs: 50, debounceMs: 50 }); * tracker.registerParticipants(['node:abc', 'edge:xyz']); // starts discovery window * * // ResizeObserver fired for a participant — extend if running low * tracker.signalObserverActivity('node:abc'); * * // Measurement arrived — transition to debounce * tracker.signalMeasurement('node:abc'); * * await tracker.waitForMeasurements(); * ``` * * @internal */ declare class MeasurementTracker { private phase; private participantIds; private pendingConfig; private discoveryWindow; private debounce; private settlementPromise; private settlementResolve; /** * Stages tracking configuration for the next middleware-driven registration pass. * Called before `applyUpdate()` when `waitForMeasurements` is requested. */ requestTracking(config?: MeasurementTrackingConfig): void; /** * Returns true if tracking has been requested via `requestTracking()`. * Used by the measurement-tracking middleware to decide first-pass vs subsequent-pass mode. */ isTrackingRequested(): boolean; /** * Clears a staged tracking request. */ cancelTrackingRequest(): void; /** * Registers entities that participated in the transaction. * Consumes the pending config from `requestTracking()`. * * If entityIds is empty (full no-op), just clears the pending config. * Otherwise, adds IDs to `participantIds` and starts the discovery window. * * @param entityIds - Prefixed entity IDs (e.g. 'node:abc', 'edge:xyz') */ registerParticipants(entityIds: string[]): void; /** * Registers participants outside the middleware-driven transaction flow — used by * `invalidateMeasurements`, where measurements come from re-observing DOM elements * rather than a state-update pass. Settles like the transaction path (the discovery * window expires on its own, so `waitForMeasurements()` cannot hang), never consumes * a staged tracking request, and joining an active round keeps its window durations * unless an explicit config is given. * * @param entityIds - Prefixed entity IDs (e.g. 'node:abc', 'edge:xyz') */ trackParticipants(entityIds: string[], config?: MeasurementTrackingConfig): void; /** * Removes entities from the current tracking round — used when an entity * becomes effectively hidden, which clears its pending measurement * expectations. Signals for removed ids no longer extend the observation * window; settlement stays timer-driven, so the round still resolves on its * own schedule. * * @param entityIds - Prefixed entity IDs (e.g. 'node:abc', 'edge:xyz') */ unregisterParticipants(entityIds: string[]): void; /** Shared registration body; `null` config keeps the current window durations. */ private register; /** * Signals that a ResizeObserver fired for a participant entity before batch processing. * This is an early indicator that measurements are in the pipeline (the double-RAF * processing hasn't delivered them yet). * * In both phases, if the remaining time is below `OBSERVER_ACTIVITY_MIN_REMAINING`, * the active timer resets to its full duration. */ signalObserverActivity(entityId: string): void; /** * Signals that an actual measurement arrived for a participant entity * (e.g., `measuredPorts`, `size`, `position`, `measuredLabels` changed via `setState`). * * - During discovery window: transitions to debounce phase. * - During debounce phase: resets the debounce timer. */ signalMeasurement(entityId: string): void; /** * Returns a promise that resolves when all currently pending measurements are complete. * If there are no pending measurements, resolves immediately. */ waitForMeasurements(): Promise; hasPendingMeasurements(): boolean; private activeTimer; private remainingTime; private startTimer; private clearTimer; private resolve; } declare class MiddlewareManager { private middlewareChain; private eventEmitterMiddleware; private measurementTrackingMiddleware; private hiddenComputationMiddleware; private hiddenComputationFinalizeMiddleware; private measuredBoundsMiddleware; readonly flowCore: FlowCore; constructor(flowCore: FlowCore, middlewares?: MiddlewareChain); isRegistered(name: string): boolean; /** * Registers a new middleware in the chain * @param middleware Middleware to register * @returns Function to unregister the middleware */ register>(middleware: T): () => void; /** * Unregister a middleware from the chain * @param name Name of the middleware to unregister */ unregister(name: string): void; /** * Executes all registered middlewares in sequence * @param initialState Initial state to be transformed * @param stateUpdate State update to be applied * @param modelActionTypes Model action types which trigger the middleware (array for transactions, single-element for direct calls) * @returns State after all middlewares have been applied */ execute(initialState: FlowState, stateUpdate: FlowStateUpdate, modelActionTypes: ModelActionTypes): Promise; } declare class ModelLookup { private readonly flowCore; private _nodesMap; private _edgesMap; private _directChildrenMap; private _descendantsCache; private _connectedEdgesMap; private _danglingEdges; constructor(flowCore: FlowCore); /** * Desynchronizes the model lookup */ desynchronize(): void; /** * Gets the nodes map if it is not synchronized synchronize it * @returns Nodes map */ get nodesMap(): Map; /** * Gets the edges map if it is not synchronized synchronize it * @returns Edges map */ get edgesMap(): Map>; /** * Gets the direct children map if it is not synchronized synchronize it * @returns Direct children map */ get directChildrenMap(): Map; /** * Gets the connected edges map if it is not synchronized synchronize it * @returns Connected edges map */ get connectedEdgesMap(): Map; /** * Committed edges with at least one free (unconnected) endpoint. Rebuilt * lazily after a state change with one pass over all edges (the same profile * as {@link connectedEdgesMap}), then served from cache until the next * change, so consumers iterate only the dangling subset. * @returns Dangling edges array */ get danglingEdges(): Edge[]; /** * Gets the descendants cache if it is not synchronized synchronize it * @returns Descendants cache */ private get descendantsCache(); /** * Builds a map of group nodes to their children * @param nodes Nodes array * @returns Map where key is group id and value is array of child ids */ private buildDirectChildrenMap; /** * Builds a map of nodes to their connected edges * @param edges Edges array * @returns Map where key is node id and value is array of connected edge ids */ private buildConnectedEdgesMap; /** * Gets a node by id * @param nodeId Node id * @returns Node */ getNodeById(nodeId: string): Node$1 | null; /** * Gets an edge by id * @param edgeId Edge id * @returns Edge */ getEdgeById(edgeId: string): Edge | null; /** * Gets all edges connected to a node * @param nodeId Node id * @returns Array of edges where the node is either source or target */ getConnectedEdges(nodeId: string): Edge[]; /** * Gets all nodes connected to a node via edges * @param nodeId Node id * @returns Array of nodes connected to the given node */ getConnectedNodes(nodeId: string): Node$1[]; /** * Gets the source and target nodes of an edge * @param edgeId Edge id * @returns Object containing source and target nodes, or null if edge doesn't exist */ getNodeEnds(edgeId: string): { source: Node$1; target: Node$1; } | null; /** * Gets all children ids for a given group node id * @param groupId group node id * @returns Array of child node ids */ private getChildrenIds; /** * Gets all children nodes for a given group node id * @param groupId group node id * @returns Array of child nodes */ getChildren(groupId: string): Node$1[]; /** * Gets all descendant IDs for a given group node id (with caching) * @param groupId group node id * @returns Array of all descendant node ids (children, grandchildren, etc.) */ getAllDescendantIds(groupId: string): Node$1['id'][]; /** * Recursively computes all descendants for a given group node id * @param groupId group node id * @returns Array of all descendant node ids */ private computeAllDescendants; /** * Gets all descendant nodes for a given group node id * @param groupId group node id * @returns Array of all descendant nodes (children, grandchildren, etc.) */ getAllDescendants(groupId: string): Node$1[]; /** * Checks if a node has children * @param nodeId Node id * @returns True if the node has children */ hasChildren(nodeId: string): boolean; /** * Checks if a node has any descendants (children, grandchildren, etc.) * @param nodeId Node id * @returns True if the node has any descendants */ hasDescendants(nodeId: string): boolean; /** * Gets the children map (read-only access) * @returns Children map */ getChildrenMap(): ReadonlyMap; /** * Gets all selected nodes * @returns Array of directly selected nodes */ getSelectedNodes(): Node$1[]; /** * Gets the children of a node * @param nodeId Node id * @param directOnly Whether to get only direct children * @returns Array of children nodes */ getNodeChildren(nodeId: string, { directOnly }?: { directOnly?: boolean; }): Node$1[]; /** * Gets the children ids of a node * @param nodeId Node id * @param directOnly Whether to get only direct children * @returns Array of children node ids */ getNodeChildrenIds(nodeId: string, { directOnly }?: { directOnly?: boolean; }): Node$1['id'][]; /** * Gets all selected nodes with their children * @returns Array of selected nodes with their children */ getSelectedNodesWithChildren({ directOnly }?: { directOnly?: boolean; }): Node$1[]; /** * Gets all selected edges * @returns Array of selected edges */ getSelectedEdges(): Edge[]; /** * Checks if a node is descendant of a group node * @param nodeId Node id * @param groupId Group node id * @returns True if the node is descendant of the group node */ isNodeDescendantOfGroup(nodeId: string, groupId: string): boolean; /** * Check for potential circular dependency between a node and a group * @param nodeId Node id * @param groupId Group node id * @returns True if the group is a descendant of the node or the node is the group */ wouldCreateCircularDependency(nodeId: string, groupId: string): boolean; /** * Gets the full chain of parent group Nodes for a given nodeId. * @param nodeId Node id * @returns Array of parent group Node objects, from closest parent to farthest ancestor */ getParentChain(nodeId: string): GroupNode[]; } interface PortUpdate { portId: string; portChanges: Partial; } declare class PortBatchProcessor extends BatchProcessor { constructor(getNodeById: (nodeId: string) => Node$1 | null | undefined); } interface RenderStrategyResult { nodes: Node$1[]; edges: Edge[]; nodeIds: Set; edgeIds: Set; } interface RenderStrategy { /** * Initializes the strategy. Sets up model change handlers and starts the init process. */ init(): void; process(nodes: Node$1[], edges: Edge[], viewport: Viewport | undefined): RenderStrategyResult; /** * Checks if a node is currently rendered (visible in viewport). * In direct mode, always returns true. In virtualized mode, checks the cached visible nodes. */ isNodeRendered(nodeId: string): boolean; } /** * Manages keyboard shortcuts and input event matching * * Supports two types of shortcuts: * 1. Key-based shortcuts: Require a specific key with optional modifiers (e.g., Ctrl+C for copy) * 2. Modifier-only shortcuts: Require only modifier keys without a specific key (e.g., Alt for box-selection) * * @example * // Key-based shortcut * { * actionName: 'copy', * bindings: [{ key: 'c', modifiers: { primary: true } }] * } * * @example * // Modifier-only shortcut (useful for modal interactions like box-selection) * { * actionName: 'boxSelection', * bindings: [{ modifiers: { secondary: true } }] // Triggered when Alt is pressed * } */ declare class ShortcutManager { private readonly flowCore; constructor(flowCore: FlowCore); /** * Find all matching shortcuts for normalized keyboard input * * Each shortcut must have a binding that matches the input * * @param input - Normalized keyboard input (key + already-normalized modifiers) * @returns Array of matching shortcut definitions (empty if no matches) */ match(input: NormalizedKeyboardInput): ShortcutDefinition[]; /** * Check if the current modifiers match any binding for a specific action * * Useful for checking modifier-only shortcuts (like box-selection triggered by pointer events) * * @param actionName - The action name to check * @param modifiers - The current modifier state * @returns true if any binding for this action matches the modifiers * * @example * // Check if current modifiers match box selection shortcut * if (shortcutManager.matchesAction('boxSelection', { modifiers: event.modifiers })) { * // Start box selection * } */ matchesAction(actionName: LooseAutocomplete, input: NormalizedKeyboardInput): boolean; /** * Check if a normalized keyboard input matches a shortcut binding * * Compares: * - Key values (if specified in binding) - case-insensitive for single letters * - Modifier states * * Matching rules: * - If binding has a key: input must have the same key (case-insensitive for letters) * - If binding has no key (modifier-only): input must also have no key * (modifier-only shortcuts are for pointer events, not keyboard events) * * @param input - Normalized keyboard input * @param binding - Shortcut binding to match against * @returns true if the input matches the binding */ private matchBinding; /** * Check if modifiers match a binding's modifier requirements * * Ensures exact modifier matching: * - All modifiers specified in binding must match the input * - All modifiers NOT specified in binding must be false in the input * - Exception: meta modifier is ignored when checking if not explicitly specified in binding, * because on macOS, meta and primary both map to the Command key * * @param modifiers - Current modifier state * @param binding - Shortcut binding to match against * @returns true if modifiers match the binding's requirements exactly */ private matchModifiers; /** * Check if two keys match, using case-insensitive comparison for single letters * * This ensures shortcuts work regardless of CapsLock state. * Special keys like "Delete", "ArrowUp", etc. are compared as-is. * * @param inputKey - The key from the keyboard input * @param bindingKey - The key defined in the shortcut binding * @returns true if the keys match */ private keysMatch; } declare class SpatialHash { private readonly cellSize; private readonly grid; private readonly idToCells; private readonly idToRect; process(nodes: Node$1[]): void; query(range: Rect): RectWithId[]; queryIds(range: Rect): string[]; private _query; private nodeToRect; private addToCell; private removeFromCell; private updateInCell; private addToGrid; private updateInGrid; private removeFromGrid; private getCellsRange; private getCells; } /** * Options for configuring transaction behavior. * * @public * @since 0.9.0 * @category Types/Middleware */ interface TransactionOptions { /** * When true, the transaction promise will not resolve until all measurements * (node sizes, port positions, etc.) triggered by the transaction are complete. * * This is useful when you need to perform operations that depend on measured values, * such as `zoomToFit()` after adding nodes or edges. * * @default false * * @example * ```typescript * // Without waitForMeasurements - zoomToFit might not include new nodes * await diagramService.transaction(() => { * modelService.addNodes([newNode]); * }); * viewportService.zoomToFit(); // May not account for new node dimensions * * // With waitForMeasurements - zoomToFit will include new nodes * await diagramService.transaction(() => { * modelService.addNodes([newNode]); * }, { waitForMeasurements: true }); * viewportService.zoomToFit(); // Correctly includes new node dimensions * ``` */ waitForMeasurements?: boolean; } interface TransactionContext { /** * Emits a command in the core system. * @param name - The name of the command to emit. * @returns A promise that resolves when the command is emitted. */ emit: CommandHandler['emit']; /** * Discards all changes in the current transaction */ abort(): void; /** * Saves a point in the transaction. * @param name - The name of the savepoint. */ savepoint(name: string): void; /** * Rolls back the transaction to a previously created savepoint * or to the beginning of the transaction if no savepoint is provided. * @param savepoint - The name of the savepoint to rollback to. */ rollbackTo(savepoint?: string): void; /** * Starts a new nested transaction. * @param name - The name of the transaction. * @param callback - The callback to execute in the transaction. * @returns A promise that resolves when the transaction is complete. */ transaction(name: LooseAutocomplete, callback: TransactionCallback): Promise; /** * Checks if the transaction has changes. * @returns True if the transaction has changes, false otherwise. */ hasChanges(): boolean; /** * Checks if the transaction is dirty. * @returns True if the transaction is dirty, false otherwise. */ isDirty(): boolean; /** * Gets the queued updates in the transaction. * @returns Readonly array of queued updates. */ getQueuedUpdates(): readonly { update: FlowStateUpdate; actionTypes: ModelActionTypes; }[]; } type TransactionCallback = (context: TransactionContext) => void | Promise; /** * Result of a transaction execution. * * @public * @since 0.8.0 * @category Types/Middleware */ interface TransactionResult { /** * Results of the transaction as a state update */ results: FlowStateUpdate; /** * Number of commands emitted during the transaction */ commandsCount: number; /** * All action types that were executed within the transaction. * @since 0.9.0 */ actionTypes: ModelActionTypes; } interface TransactionState { name: LooseAutocomplete; queue: { update: FlowStateUpdate; actionTypes: ModelActionTypes; }[]; savepoints: Map; isAborted: boolean; parent: Transaction | null; } declare class Transaction { private readonly name; private readonly parent; private readonly flowCore; private queue; private savepoints; private _isAborted; private children; private _context; constructor(name: LooseAutocomplete, parent: Transaction | null, flowCore: TFlowCore); /** * Get the transaction context, creating it lazily if needed */ get context(): TransactionContext; /** * Check if the transaction has been completely aborted */ isAborted(): boolean; /** * Completely abort the transaction, making it unusable. * This also aborts all child transactions. */ abort(): void; /** * Create a savepoint that can be rolled back to later */ addSavepoint(name: string): void; /** * Rollback to a savepoint or to the beginning of the transaction. * Unlike abort(), this keeps the transaction active. * @param savepointName - If provided, rollback to this savepoint. If not provided, rollback to the beginning. */ rollback(savepointName?: string): void; /** * Commit the transaction by merging changes to parent or applying them */ commit(): void; /** * Check if the transaction can be committed (not aborted and has changes) */ canCommit(): boolean; /** * Ensure the transaction is not aborted, throwing an error if it is */ private ensureNotAborted; hasChanges(): boolean; getQueue(): readonly { update: FlowStateUpdate; actionTypes: ModelActionTypes; }[]; queueUpdate(update: FlowStateUpdate, actionTypes: ModelActionTypes): void; getState(): TransactionState; mergeToParent(): void; getMergedUpdates(): { mergedUpdate: FlowStateUpdate; commandsCount: number; actionTypes: ModelActionTypes; }; } declare class TransactionManager { private readonly flowCore; private transactionStack; private pendingOptions; constructor(flowCore: TFlowCore); transaction(callback: TransactionCallback): Promise; transaction(callback: TransactionCallback, options: TransactionOptions): Promise; transaction(name: LooseAutocomplete, callback: TransactionCallback): Promise; transaction(name: LooseAutocomplete, callback: TransactionCallback, options: TransactionOptions): Promise; /** * Gets the options for the current root transaction. * Returns null if no transaction is active or no options were provided. */ getCurrentOptions(): TransactionOptions | null; queueUpdate(update: FlowStateUpdate, actionTypes: ModelActionTypes): void; isActive(): boolean; getTransactionName(): LooseAutocomplete | null; getCurrentTransaction(): Transaction | null; private parseArgs; } interface Updater { /** * Apply a single node size change */ applyNodeSize(nodeId: string, size: NonNullable): void; /** * Apply node size changes in a single batch */ applyNodeSizes(updates: { id: string; size: NonNullable; }[]): void; /** * Add a port to a node */ addPort(nodeId: string, port: Port): void; /** * Apply port changes (size, position, side, type, etc.) */ applyPortChanges(nodeId: string, portUpdates: PortUpdate[]): void; /** * Add an edge label */ addEdgeLabel(edgeId: string, label: EdgeLabel): void; /** * Apply edge label changes (size, positionOnEdge, etc.) */ applyEdgeLabelChanges(edgeId: string, labelUpdates: LabelUpdate[]): void; /** * Delete an edge label */ deleteEdgeLabel(edgeId: string, labelId: string): void; } /** * InitUpdater batches all initialization data and applies it in a single state update. * * Strategy: * 1. Wait for entity creation to stabilize (addPort, addEdgeLabel) using StabilityDetectors * 2. Immediately collect measurements (applyNodeSize, applyPortChanges, applyEdgeLabelChanges) * 3. Finish when: entities stabilized AND all rendered entities have measurements * 4. Apply everything in one setState * 5. Queue late arrivals to prevent data loss during finish transition * 6. Safety timeout: If measurements don't arrive within MEASUREMENT_TIMEOUT, force finish * * Note: With virtualization, only rendered nodes/edges are tracked for initialization. * Non-rendered elements will be initialized when they become visible. */ declare class InitUpdater implements Updater { private flowCore; /** Flag indicating whether initialization has completed */ isInitialized: boolean; /** Flag indicating whether entity additions (ports/labels) have stabilized */ private entitiesStabilized; /** Detects when port additions have stabilized */ private portStabilityDetector; /** Detects when label additions have stabilized */ private labelStabilityDetector; /** Collects all initialization data and applies it to diagram state */ private initState; /** Queues updates that arrive during finish to prevent data loss */ private lateArrivalQueue; /** Callback to execute when initialization completes */ private onCompleteCallback?; /** Safety timeout to prevent indefinite waiting for measurements */ private measurementTimeout; /** Effectively hidden node ids at init time — populated in start() */ private hiddenNodeIds; /** Effectively hidden edge ids at init time — populated in start() */ private hiddenEdgeIds; /** * Creates a new InitUpdater. * * @param flowCore - The FlowCore instance to update */ constructor(flowCore: FlowCore); /** * Starts the initialization process. * Collects pre-existing measurements and waits for entity additions to stabilize. * * @param nodes - Rendered nodes to track for initialization * @param edges - Rendered edges to track for initialization * @param onComplete - Optional callback to execute after initialization completes */ start(nodes: Node$1[], edges: Edge[], onComplete?: () => void | Promise): void; /** * Recomputes effective visibility and drops measurement expectations for * entities that became hidden — hidden elements never deliver valid * measurements and must not keep initialization waiting. Entities that * became visible are not re-added; they measure through the observer path. * Safe no-op after initialization completes. */ refreshHiddenEntities(): void; /** * Records a node size measurement. * Queues the update if finishing is in progress, otherwise records and attempts to finish. * * @param nodeId - The node ID * @param size - The measured size */ applyNodeSize(nodeId: string, size: NonNullable): void; applyNodeSizes(updates: { id: string; size: NonNullable; }[]): void; /** * Adds a new port created during initialization. * Queues if finishing, otherwise adds to init state and notifies stability detector. * * @param nodeId - The node ID the port belongs to * @param port - The port to add */ addPort(nodeId: string, port: Port): void; /** * Applies port changes (size, position, side, type, etc.). * During initialization, only size/position measurements are tracked for init completion. * Non-geometric changes (side, type) are ignored since ports are being created with initial values. * * @param nodeId - The node ID the ports belong to * @param portUpdates - Array of port updates */ applyPortChanges(nodeId: string, portUpdates: PortUpdate[]): void; /** * Adds a new edge label created during initialization. * Queues if finishing, otherwise adds to init state and notifies stability detector. * * @param edgeId - The edge ID the label belongs to * @param label - The label to add */ addEdgeLabel(edgeId: string, label: EdgeLabel): void; /** * Deletes an edge label. During initialization, queues for replay after init completes. */ deleteEdgeLabel(edgeId: string, labelId: string): void; /** * Applies edge label changes (size, positionOnEdge, etc.). * During initialization, only size measurements are tracked for init completion. * Non-size changes (positionOnEdge) are ignored since labels are being created with initial values. * * @param edgeId - The edge ID the labels belong to * @param labelUpdates - Array of label updates */ applyEdgeLabelChanges(edgeId: string, labelUpdates: LabelUpdate[]): void; /** * Attempts to finish initialization if conditions are met. * Conditions: not already finishing, not initialized, entities stabilized, all rendered entities measured. */ private tryFinish; /** * Completes initialization by applying all collected data. * Marks as finishing, applies state, executes callback, marks as initialized, processes late arrivals. */ private finish; /** * Forces initialization to finish even if conditions aren't fully met. * Used as a fallback when entity stabilization fails. */ private forceFinish; /** * Starts a safety timeout to prevent indefinite waiting for measurements. * If measurements don't arrive within MEASUREMENT_TIMEOUT, initialization is forced to complete. * This handles cases where entities may not be measurable (e.g., display: none). */ private startMeasurementTimeout; /** * Clears the measurement timeout if it's active. */ private clearMeasurementTimeout; } declare class InternalUpdater implements Updater { private readonly flowCore; private readonly onPortAddsFlush; private readonly onPortUpdatesFlush; private readonly onPortDeletesFlush; private readonly onLabelAddsFlush; private readonly onLabelUpdatesFlush; private readonly onLabelDeletesFlush; constructor(flowCore: FlowCore); /** * @internal */ applyNodeSize(nodeId: string, size: NonNullable): void; /** * @internal */ applyNodeSizes(updates: { id: string; size: NonNullable; }[]): void; /** * @internal * An add for a port already in the model is a component recreation whose * batched add never lands — re-apply its authored (non-measured) properties. */ addPort(nodeId: string, port: Port): void; /** * @internal */ deletePort(nodeId: string, portId: string): void; /** * @internal * Filters out updates where no property actually differs from current state. */ applyPortChanges(nodeId: string, portUpdates: PortUpdate[]): void; /** * @internal * See {@link addPort} — same recreation handling for labels. */ addEdgeLabel(edgeId: string, label: EdgeLabel): void; /** * @internal */ deleteEdgeLabel(edgeId: string, labelId: string): void; /** * @internal * Filters out updates where no property actually differs from current state. */ applyEdgeLabelChanges(edgeId: string, labelUpdates: LabelUpdate[]): void; /** * Drops measured geometry (size + position) from updates carrying a 0×0 size — * the display: none signature — so hiding an observed port never corrupts its * last valid geometry. Non-measured properties in the same update still apply. */ private rejectZeroSizePortGeometry; /** * See {@link rejectZeroSizePortGeometry} — same guard for edge labels. */ private rejectZeroSizeLabelGeometry; /** * Filters out port updates where none of the changed properties actually differ from current state. */ private filterUnchangedPortUpdates; /** * Filters out label updates where none of the changed properties actually differ from current state. */ private filterUnchangedLabelUpdates; } /** * Monotonic generation counter — the standard O(1) cache-invalidation idiom. * * A producer calls {@link bump} whenever the tracked aspect actually changed; * consumers remember the {@link version} they last saw and treat a mismatch * as "invalidate and re-read". Unlike a dirty flag it supports any number of * independent consumers, and unlike caching derived values (e.g. counts) it * cannot alias two different states. * * @internal */ declare class ChangeGeneration { private v; bump(): void; get version(): number; } /** * One free (unconnected) endpoint of a dangling edge. * * @public * @since 1.4.0 * @category Types/Model */ interface DanglingEndpoint { /** The dangling edge. */ edge: Edge; /** Which endpoint of the edge is free. */ end: EdgeEnd; /** The position the free endpoint is anchored at. */ position: Point; } /** * Registry for template-declared hidden state. * * Ports and edge labels are declared in templates, not in the model, so their * `hidden` inputs (and the template-level hidden bindings for nodes and edges) * cannot live on model objects. The rendering layer writes the declared state * here; core reads it as one of the raw sources feeding effective-visibility * computation. Everything downstream reads effective visibility * (`computedHidden` on nodes/edges, `isPortHidden`/`isLabelHidden` for * template-owned items) — never raw flags. * * Absence means visible: entries exist only for currently hidden items. * * @internal */ declare class TemplateVisibilityRegistry { private readonly hiddenNodes; private readonly hiddenEdges; /** nodeId -> hidden port ids */ private readonly hiddenPorts; /** edgeId -> hidden label ids */ private readonly hiddenLabels; /** * Invoked when the hidden state of a node or edge changes. * Wired by FlowCore to re-run effective-visibility computation. * Port/label changes do not trigger it — their hidden state is read live * at each consumer and never stamped on the model. */ onNodeOrEdgeVisibilityChange?: () => void; /** * Invoked when the hidden state of a port or edge label changes. * Wired by FlowCore to prune initialization measurement expectations — * post-init, port/label hidden state is read live and needs no state pass. */ onPortOrLabelVisibilityChange?: () => void; setNodeHidden(nodeId: string, hidden: boolean): void; setEdgeHidden(edgeId: string, hidden: boolean): void; setPortHidden(nodeId: string, portId: string, hidden: boolean): void; setLabelHidden(edgeId: string, labelId: string, hidden: boolean): void; isNodeHidden(nodeId: string): boolean; isEdgeHidden(edgeId: string): boolean; isPortHidden(nodeId: string, portId: string): boolean; isLabelHidden(edgeId: string, labelId: string): boolean; /** * Silently drops every entry owned by a removed node (its own hidden * declaration and its ports'). No change callbacks fire — the element is * gone, so there is nothing to recompute or re-render for it; the goal is * only that a future element reusing the id starts visible. */ removeNodeEntries(nodeId: string): void; /** See {@link removeNodeEntries} — same cleanup for a removed edge. */ removeEdgeEntries(edgeId: string): void; /** @returns true when the stored state actually changed */ private setFlag; /** @returns true when the stored state actually changed */ private setNestedFlag; } declare class FlowCore { readonly renderer: Renderer; readonly inputEventsRouter: InputEventsRouter; readonly environment: EnvironmentInfo; private _model; private _config; readonly initUpdater: InitUpdater; readonly internalUpdater: InternalUpdater; private readonly updateSemaphore; readonly commandHandler: CommandHandler$1; readonly middlewareManager: MiddlewareManager; readonly spatialHash: SpatialHash; readonly modelLookup: ModelLookup; readonly transactionManager: TransactionManager; readonly portBatchProcessor: PortBatchProcessor; readonly labelBatchProcessor: LabelBatchProcessor; readonly actionStateManager: ActionStateManager; readonly edgeRoutingManager: EdgeRoutingManager; readonly eventManager: EventManager; readonly shortcutManager: ShortcutManager; readonly measurementTracker: MeasurementTracker; readonly templateVisibilityRegistry: TemplateVisibilityRegistry; /** * Bumped by the hidden-computation middleware whenever a pass changed some * element's effective visibility (`computedHidden`). Render caches keyed on * things a visibility toggle does not change (element counts, viewport) * compare its version as an O(1) invalidation signal. * @internal */ readonly visibilityGeneration: ChangeGeneration; private readonly interactionCoordinator; private readonly directRenderStrategy; private readonly virtualizedRenderStrategy; readonly getFlowOffset: () => Point; readonly getViewportSize: () => { width: number; height: number; }; constructor(modelAdapter: ModelAdapter, renderer: Renderer, inputEventsRouter: InputEventsRouter, environment: EnvironmentInfo, middlewares?: MiddlewareChain, getFlowOffset?: () => Point, getViewportSize?: () => { width: number; height: number; }, config?: DeepPartial); destroy(): void; private destroyed; /** Whether a template-visibility flush microtask is already queued. */ private templateVisibilityFlushScheduled; /** Whether the queued flush must run a middleware pass (node/edge change). */ private templateVisibilityFlushNeedsPass; /** * Coalesces template-visibility registry callbacks: any number of registry * writes landing in the same microtask tick get one * {@link InitUpdater.refreshHiddenEntities} prune and (for node/edge * changes) one `templateVisibilityChange` middleware pass. Both flags are * cleared BEFORE the flush body runs, so a write landing while the pass is * still in flight re-arms the flush and gets exactly one follow-up. */ private scheduleTemplateVisibilityFlush; private init; /** * Sets initial viewport size from element dimensions. * * This must be called BEFORE renderStrategy.init() for two reasons: * 1. The viewport size is needed for features like zoomToFit on init * 2. At this point, no onChange callbacks are registered yet, so updateMetadata won't trigger events * * Without this, the ResizeObserver might not fire on reinitialization, * leaving viewport.width/height as undefined. */ private initializeViewportSize; /** * Gets the current model that flow core is using */ get model(): ModelAdapter; /** * Gets the current environment information */ getEnvironment(): EnvironmentInfo; get config(): FlowConfig; updateConfig(updatedConfig: DeepPartial): void; /** * Registers a new middleware in the chain * @param middleware Middleware to register * @returns Function to unregister the middleware */ registerMiddleware(middleware: Middleware): () => void; /** * Unregister a middleware from the chain * @param name Name of the middleware to unregister */ unregisterMiddleware(name: string): void; /** * Gets the current state of the flow */ getState(): FlowState; /** * Gets the active render strategy based on virtualization config. * When virtualization is enabled, uses VirtualizedRenderStrategy. * When disabled, uses DirectRenderStrategy. */ get renderStrategy(): RenderStrategy; /** * Sets the current state of the flow * @param state State to set */ setState(state: FlowState): void; /** * Executes a function within a transaction context. * All state updates within the callback are batched and applied atomically. * * @example * // Simple transaction * await flowCore.transaction(async (tx) => { * await tx.emit('addNode', { node }); * await tx.emit('selectNode', { nodeId: node.id }); * }); * * // Named transaction * await flowCore.transaction('batchUpdate', async (tx) => { * await tx.emit('updateNodes', { nodes }); * if (error) { * tx.rollback(); // Discard all changes * } * }); * * // With savepoints * await flowCore.transaction(async (tx) => { * await tx.emit('step1', {}); * tx.savepoint('afterStep1'); * * await tx.emit('step2', {}); * if (step2Failed) { * tx.rollbackTo('afterStep1'); * } * }); * * // Wait for measurements to complete before continuing * await flowCore.transaction(async (tx) => { * await tx.emit('addNodes', { nodes: [newNode] }); * }, { waitForMeasurements: true }); * // Now safe to call zoomToFit() - node dimensions are measured * await viewportService.zoomToFit(); */ transaction(callback: TransactionCallback): Promise; transaction(callback: TransactionCallback, options: TransactionOptions): Promise; transaction(name: LooseAutocomplete, callback: TransactionCallback): Promise; transaction(name: LooseAutocomplete, callback: TransactionCallback, options: TransactionOptions): Promise; /** * Applies an update to the flow state * @param stateUpdate Partial state to apply * @param modelActionTypes Action type(s) that triggered this update. Can be a single type or an array of types (from transactions). */ applyUpdate(stateUpdate: FlowStateUpdate, modelActionTypes: LooseAutocomplete | ModelActionTypes): Promise; /** * Runs an update through the middleware chain and commits it to the model, * bypassing the active-transaction routing in `applyUpdate`. */ private applyUpdateToModel; /** * Opens an out-of-band measurement round (used by `invalidateMeasurements`) and * resolves once the triggered measurements settle. */ trackMeasurements(entityIds: string[]): Promise; /** * Fast-path for viewport-only updates (panning/zooming). * Bypasses middleware chain and only updates viewport metadata. * Use this for high-frequency viewport changes where middleware processing is unnecessary. */ applyViewportOnlyUpdate(viewportUpdate: Partial): void; /** * Converts a client position to a flow position * @param clientPosition Client position * @returns { x: number, y: number } Flow position */ clientToFlowPosition(clientPosition: Point): Point; /** * Converts a flow position to a client position * @param flowPosition Flow position * @returns { x: number, y: number } Client position */ flowToClientPosition(flowPosition: Point): Point; /** * Converts a client position to a position relative to the flow viewport * @param clientPosition Client position * @returns position on the flow viewport */ clientToFlowViewportPosition(clientPosition: Point): Point; /** * Gets a node by id * @param nodeId Node id * @returns Node */ getNodeById(nodeId: string): Node$1 | null; /** * Gets an edge by id * @param edgeId Edge id * @returns Edge */ getEdgeById(edgeId: string): Edge | null; /** * Registers a cleanup for the gesture that is starting; it runs when * {@link cancelActiveInteraction} aborts the gesture. The caller must * unregister it in its own normal teardown, or stale cleanups accumulate. * * @returns Function that unregisters the callback */ registerInteractionCleanup(cleanup: () => void): () => void; /** * Whether {@link cancelActiveInteraction} is mid-flight — its rollback has * not committed yet, so input read now could capture geometry it is about * to rewrite. */ isCancellingInteraction(): boolean; /** * Whether an interactive gesture (linking, dragging, resizing, rotating, * panning) is currently in progress, or a gesture's listener cleanup is * still registered. */ hasActiveInteraction(): boolean; /** * Aborts the in-progress gesture (linking, drag, resize, rotate or pan): * removes its listeners, restores the state it modified (the viewport is * not rolled back) and fires the "ended" event with the `cancelled` reason. * No-op when nothing is active, when the gesture is already completing, or * while a transaction is active (refused with a console warning). * * @returns Whether any gesture or registered cleanup was torn down */ cancelActiveInteraction(): Promise; /** * Gets all nodes in a range from a point * @param point Point to check from * @param range Range to check in * @returns Array of nodes in range */ getNodesInRange(point: Point, range: number): Node$1[]; /** * Gets the nearest node in a range from a point * @param point Point to check from * @param range Range to check in * @returns Nearest node in range or null */ getNearestNodeInRange(point: Point, range: number): Node$1 | null; /** * Gets the nearest port in a range from a point * @param point Point to check from * @param range Range to check in * @returns Nearest port in range or null */ getNearestPortInRange(point: Point, range: number): Port | null; /** * Gets all edges connected to a node * @param nodeId Node id * @returns Array of edges where the node is either source or target */ getConnectedEdges(nodeId: string): Edge[]; /** * Gets all nodes connected to a node via edges * @param nodeId Node id * @returns Array of nodes connected to the given node */ getConnectedNodes(nodeId: string): Node$1[]; /** * Gets the source and target nodes of an edge * @param edgeId Edge id * @returns Object containing source and target nodes, or null if edge doesn't exist */ getNodeEnds(edgeId: string): { source: Node$1; target: Node$1; } | null; /** * Gets all children nodes for a given group node id * @param groupId group node id * @returns Array of child nodes */ getChildren(groupId: string): Node$1[]; /** * Gets all nested children (descendants) of a group node * @param groupId Group node id * @returns Array of all descendant nodes (children, grandchildren, etc.) */ getChildrenNested(groupId: string): Node$1[]; /** * Checks if a node is a nested child (descendant) of a group node * @param nodeId Node id * @param groupId Group node id * @returns True if the node is part of the group's nested subgraph */ isNestedChild(nodeId: string, groupId: string): boolean; /** * Gets the full chain of parent group Nodes for a given nodeId. * @param nodeId Node id * @returns Array of parent group Node objects, from closest parent to farthest ancestor */ getParentHierarchy(nodeId: string): GroupNode[]; /** * Detects collision with other nodes by finding all nodes whose rectangles intersect * with the specified node's bounding rectangle. * * @param nodeId - The ID of the node to check for collisions * @returns An array of Nodes that overlap with the specified node */ getOverlappingNodes(nodeId: string): Node$1[]; /** * Detects collision with other nodes by finding all nodes whose rectangles intersect * with the specified node's bounding rectangle. * * @param node - The node to check for collisions * @returns An array of Nodes that overlap with the specified node */ getOverlappingNodes(node: Node$1): Node$1[]; /** * Checks if a node is currently rendered (visible in viewport). * In direct mode, always returns true. In virtualized mode, checks if the node * is in the current set of visible nodes. * * @param nodeId Node id to check * @returns True if the node is currently rendered */ isNodeCurrentlyRendered(nodeId: string): boolean; /** * Returns the current zoom scale */ getScale(): number; /** * Returns the current viewport */ getViewport(): Viewport; get updater(): Updater; /** * Returns true if the diagram has completed its initialization phase. */ get isInitialized(): boolean; /** * Returns true if virtualization is enabled. */ get isVirtualizationActive(): boolean; setDebugMode(debugMode: boolean): void; } interface MoveNodesByCommand { name: 'moveNodesBy'; nodes: Node$1[]; delta: Point; } interface MoveNodesStartCommand { name: 'moveNodesStart'; /** Ids of the nodes the starting gesture drags — reported by `nodeDragStarted`. */ nodeIds?: string[]; } interface MoveNodesStopCommand { name: 'moveNodesStop'; /** Ids of the nodes the ending gesture dragged — reported by `nodeDragEnded`. */ nodeIds?: string[]; } interface MoveViewportByCommand { name: 'moveViewportBy'; x: number; y: number; } interface MoveViewportCommand { name: 'moveViewport'; x: number; y: number; } interface RemoveFromGroupCommand { name: 'removeFromGroup'; groupId: GroupNode['id']; nodeIds: Node$1['id'][]; } interface ResizeNodeCommand { name: 'resizeNode'; id: string; size: Required['size']; position?: Node$1['position']; disableAutoSize?: boolean; } interface ResizeNodeStartCommand { name: 'resizeNodeStart'; /** Id of the node the starting gesture resizes — reported by `nodeResizeStarted`. */ nodeId?: string; } interface ResizeNodeStopCommand { name: 'resizeNodeStop'; /** Id of the node the ending gesture resized — reported by `nodeResizeEnded`. */ nodeId?: string; } interface RotateNodeToCommand { name: 'rotateNodeTo'; nodeId: string; angle: number; } interface RotateNodeStartCommand { name: 'rotateNodeStart'; /** Id of the node the starting gesture rotates — reported by `nodeRotateStarted`. */ nodeId?: string; } interface RotateNodeStopCommand { name: 'rotateNodeStop'; /** Id of the node the ending gesture rotated — reported by `nodeRotateEnded`. */ nodeId?: string; } interface SelectCommand { name: 'select'; nodeIds?: string[]; edgeIds?: string[]; multiSelection?: boolean; } interface DeselectCommand { name: 'deselect'; nodeIds?: string[]; edgeIds?: string[]; } interface DeselectAllCommand { name: 'deselectAll'; } interface SelectEndCommand { name: 'selectEnd'; } interface SelectAllCommand { name: 'selectAll'; } interface BringToFrontCommand { name: 'bringToFront'; nodeIds?: string[]; edgeIds?: string[]; } interface SendToBackCommand { name: 'sendToBack'; nodeIds?: string[]; edgeIds?: string[]; } interface ZoomCommand { name: 'zoom'; x: number; y: number; scale: number; } interface ZoomToFitCommand { name: 'zoomToFit'; nodeIds?: string[]; edgeIds?: string[]; padding?: number | [number, number] | [number, number, number] | [number, number, number, number]; } /** * Type for system commands that can be emitted by InputEventHandler or user */ type Command = InitCommand | SelectCommand | SelectAllCommand | SelectEndCommand | DeselectCommand | DeselectAllCommand | MoveNodesByCommand | MoveNodesStartCommand | MoveNodesStopCommand | DeleteSelectionCommand | AddNodesCommand | UpdateNodeCommand | UpdateNodesCommand | PaletteDropNodeCommand | DeleteNodesCommand | AddEdgesCommand | UpdateEdgeCommand | UpdateEdgesCommand | DeleteEdgesCommand | CopyCommand | CutCommand | PasteCommand | MoveViewportCommand | MoveViewportByCommand | StartLinkingCommand | MoveTemporaryEdgeCommand | FinishLinkingCommand | CancelLinkingCommand | StartLinkingFromPositionCommand | FinishLinkingToPositionCommand | StartRelinkingCommand | FinishRelinkingCommand | ResizeNodeCommand | ResizeNodeStartCommand | ResizeNodeStopCommand | ZoomCommand | AddPortsBulkCommand | UpdatePortsBulkCommand | DeletePortsBulkCommand | BringToFrontCommand | SendToBackCommand | AddEdgeLabelsBulkCommand | UpdateEdgeLabelsBulkCommand | DeleteEdgeLabelsBulkCommand | RotateNodeToCommand | RotateNodeStartCommand | RotateNodeStopCommand | HighlightGroupCommand | HighlightGroupClearCommand | AddToGroupCommand | ClearModelCommand | RemoveFromGroupCommand | CenterOnNodeCommand | CenterOnRectCommand | ZoomToFitCommand; /** * Type for command name */ type CommandName = Command['name']; /** * Type for command by name */ type CommandByName = Extract; /** * Type for command without name */ type WithoutName = Omit; /** * Type for command without name */ type IsEmpty = keyof WithoutName extends never ? true : false; /** * Type for command callback function. * A returned promise is awaited by `emit`, so emit resolves only after the command finished applying its updates. */ type CommandCallback = (command: CommandByName) => void | Promise; /** * Interface for interpreting and routing system commands * This is a core component that handles commands from InputEventHandler or user */ interface CommandHandler { readonly flowCore: FlowCore; /** * Emit a system command * @param command Command to emit */ emit(commandName: K, ...props: IsEmpty> extends true ? [] | [WithoutName>] : [WithoutName>]): Promise; /** * Register a callback for specific command types * @param commandType Type of command to listen for * @param callback Function to be called when command occurs */ register(commandType: K, callback: CommandCallback): void; } /** * Interface representing environment information * * @public * @since 0.8.0 * @category Internals */ interface EnvironmentInfo { /** User Operating system name */ os: LooseAutocomplete<'MacOS' | 'Windows' | 'Linux' | 'iOS' | 'Android' | 'Unknown'> | null; /** User Browser name (when applicable) */ browser: LooseAutocomplete<'Chrome' | 'Firefox' | 'Safari' | 'Edge' | 'Opera' | 'IE' | 'Other'> | null; /** Platform identity for high-level adapter routing */ runtime: LooseAutocomplete<'web' | 'node' | 'other'> | null; /** Current timestamp in ms */ now: () => number; /** Generates a unique ID */ generateId: () => string; } /** * Array of model action types, used to track all actions in a transaction or a single action. * Supports both known action types with autocomplete and custom string action types. * * @example * ```typescript * const middleware: Middleware = { * name: 'logger', * execute: (context, next) => { * console.log('Action types:', context.modelActionTypes.join(', ')); * next(); * } * }; * ``` * * @public * @since 0.9.0 * @category Types/Middleware */ type ModelActionTypes = LooseAutocomplete[]; /** * Individual model action type that can trigger middleware execution. * These represent all possible operations that modify the diagram state. * * @example * ```typescript * const blockedActions: ModelActionType[] = ['addNodes', 'deleteNodes', 'updateNode']; * ``` * * @public * @since 0.8.0 * @category Types/Middleware */ type ModelActionType = 'init' | 'changeSelection' | 'moveNodesBy' | 'deleteSelection' | 'addNodes' | 'updateNode' | 'updateNodes' | 'deleteNodes' | 'clearModel' | 'paletteDropNode' | 'addEdges' | 'updateEdge' | 'deleteEdges' | 'deleteElements' | 'addEdgeLabelsBulk' | 'updateEdgeLabelsBulk' | 'deleteEdgeLabelsBulk' | 'addPortsBulk' | 'updatePortsBulk' | 'deletePortsBulk' | 'paste' | 'moveViewport' | 'resizeNode' | 'resizeNodeStart' | 'resizeNodeStop' | 'cancelResize' | 'startLinking' | 'startLinkingFromPosition' | 'moveTemporaryEdge' | 'finishLinking' | 'startRelinking' | 'finishRelinking' | 'zoom' | 'changeZOrder' | 'rotateNodeTo' | 'rotateNodeStart' | 'rotateNodeStop' | 'cancelRotate' | 'highlightGroup' | 'highlightGroupClear' | 'moveNodes' | 'moveNodesStart' | 'moveNodesStop' | 'cancelDrag' | 'selectEnd' | 'templateVisibilityChange'; /** * The complete state of the flow diagram. * Represents the current state of all nodes, edges, and metadata. * * @public * @since 0.8.0 * @category Types/Model */ interface FlowState { /** All nodes currently in the diagram */ nodes: Node$1[]; /** All edges currently in the diagram */ edges: Edge[]; /** Diagram metadata (selection, viewport, etc.) */ metadata: Metadata; } /** * Records a state update made by a specific middleware. * Used to track the history of state transformations through the middleware chain. * * @example * ```typescript * const middleware: Middleware = { * name: 'audit-logger', * execute: (context, next) => { * // Check what previous middlewares did * context.history.forEach(update => { * console.log(`${update.name} modified:`, update.stateUpdate); * }); * next(); * } * }; * ``` * * @public * @since 0.8.0 * @category Types/Middleware */ interface MiddlewareHistoryUpdate { /** The name of the middleware that made the update */ name: string; /** The state update that was applied */ stateUpdate: FlowStateUpdate; } /** * Describes a set of changes to apply to the diagram state. * Middlewares can modify state by passing a FlowStateUpdate to the `next()` function. * * @example * ```typescript * const middleware: Middleware = { * name: 'auto-arranger', * execute: (context, next) => { * // Apply state changes * next({ * nodesToUpdate: [ * { id: 'node1', position: { x: 100, y: 200 } }, * { id: 'node2', position: { x: 300, y: 200 } } * ], * metadataUpdate: { * viewport: { x: 0, y: 0, zoom: 1 } * } * }); * } * }; * ``` * * @public * @since 0.8.0 * @category Types/Middleware */ interface FlowStateUpdate { /** Nodes to add to the diagram */ nodesToAdd?: Node$1[]; /** Partial node updates (only changed properties need to be specified) */ nodesToUpdate?: (Partial & { id: Node$1['id']; })[]; /** IDs of nodes to remove from the diagram */ nodesToRemove?: string[]; /** Edges to add to the diagram */ edgesToAdd?: Edge[]; /** Partial edge updates (only changed properties need to be specified) */ edgesToUpdate?: (Partial & { id: Edge['id']; })[]; /** IDs of edges to remove from the diagram */ edgesToRemove?: string[]; /** Partial metadata update (viewport, selection, etc.) */ metadataUpdate?: Partial; /** * IDs of nodes currently rendered in the viewport. * - `undefined` means all nodes are rendered (DirectRenderStrategy / no virtualization) * - `string[]` means only those specific IDs are rendered (VirtualizedRenderStrategy) * Used by 'init' action to track which nodes need measurement. * @internal */ renderedNodeIds?: string[]; /** * IDs of edges currently rendered in the viewport. * - `undefined` means all edges are rendered (DirectRenderStrategy / no virtualization) * - `string[]` means only those specific IDs are rendered (VirtualizedRenderStrategy) * Used by 'init' action to track which edges need measurement. * @internal */ renderedEdgeIds?: string[]; /** * Node ids of the gesture that emitted this lifecycle pass (moveNodes/ * resizeNode/rotateNode start/stop) — the lifecycle emitters read it so their * events report the emitting gesture even when the live action state already * belongs to a newer one; absent means fall back to the live state. Not part * of the model state. * @internal */ gestureNodeIds?: string[]; } /** * Helper functions for checking what changed during middleware execution. * These helpers track all cumulative changes from the initial state update and all previous middlewares. * * @public * @since 0.8.0 * @category Types/Middleware */ interface MiddlewareHelpers { /** * Checks if a specific node has been modified. * @param id - The node ID to check * @returns true if the node was modified (any property changed) by the initial state update or any previous middleware */ checkIfNodeChanged: (id: string) => boolean; /** * Checks if a specific edge has been modified. * @param id - The edge ID to check * @returns true if the edge was modified (any property changed) by the initial state update or any previous middleware */ checkIfEdgeChanged: (id: string) => boolean; /** * Checks if a specific node was added. * @param id - The node ID to check * @returns true if the node was added by the initial state update or any previous middleware */ checkIfNodeAdded: (id: string) => boolean; /** * Checks if a specific node was removed. * @param id - The node ID to check * @returns true if the node was removed by the initial state update or any previous middleware */ checkIfNodeRemoved: (id: string) => boolean; /** * Checks if a specific edge was added. * @param id - The edge ID to check * @returns true if the edge was added by the initial state update or any previous middleware */ checkIfEdgeAdded: (id: string) => boolean; /** * Checks if a specific edge was removed. * @param id - The edge ID to check * @returns true if the edge was removed by the initial state update or any previous middleware */ checkIfEdgeRemoved: (id: string) => boolean; /** * Checks if any node has one or more of the specified properties changed. * @param props - Array of property names to check (e.g., ['position', 'size']) * @returns true if any node has any of these properties modified by the initial state update or any previous middleware */ checkIfAnyNodePropsChanged: (props: string[]) => boolean; /** * Checks if any edge has one or more of the specified properties changed. * @param props - Array of property names to check (e.g., ['sourcePosition', 'targetPosition']) * @returns true if any edge has any of these properties modified by the initial state update or any previous middleware */ checkIfAnyEdgePropsChanged: (props: string[]) => boolean; /** * Checks if any nodes were added. * @returns true if at least one node was added by the initial state update or any previous middleware */ anyNodesAdded: () => boolean; /** * Checks if any edges were added. * @returns true if at least one edge was added by the initial state update or any previous middleware */ anyEdgesAdded: () => boolean; /** * Checks if any nodes were removed. * @returns true if at least one node was removed by the initial state update or any previous middleware */ anyNodesRemoved: () => boolean; /** * Checks if any edges were removed. * @returns true if at least one edge was removed by the initial state update or any previous middleware */ anyEdgesRemoved: () => boolean; /** * Gets all node IDs that have one or more of the specified properties changed. * @param props - Array of property names to check (e.g., ['position', 'size']) * @returns Array of node IDs that have any of these properties modified by the initial state update or any previous middleware */ getAffectedNodeIds: (props: string[]) => string[]; /** * Gets all edge IDs that have one or more of the specified properties changed. * @param props - Array of property names to check (e.g., ['sourcePosition', 'targetPosition']) * @returns Array of edge IDs that have any of these properties modified by the initial state update or any previous middleware */ getAffectedEdgeIds: (props: string[]) => string[]; /** * Gets all node IDs that have any property changed, regardless of which property. * @since 1.2.2 * @returns Array of node IDs that were modified by the initial state update or any previous middleware */ getChangedNodeIds: () => string[]; /** * Gets all edge IDs that have any property changed, regardless of which property. * @since 1.2.2 * @returns Array of edge IDs that were modified by the initial state update or any previous middleware */ getChangedEdgeIds: () => string[]; /** * Gets all nodes that were added. * @returns Array of node instances that were added by the initial state update or any previous middleware */ getAddedNodes: () => Node$1[]; /** * Gets all edges that were added. * @returns Array of edge instances that were added by the initial state update or any previous middleware */ getAddedEdges: () => Edge[]; /** * Gets all nodes that were removed. * Uses `initialNodesMap` to access the removed instances. * @returns Array of node instances that were removed by the initial state update or any previous middleware */ getRemovedNodes: () => Node$1[]; /** * Gets all edges that were removed. * Uses `initialEdgesMap` to access the removed instances. * @returns Array of edge instances that were removed by the initial state update or any previous middleware */ getRemovedEdges: () => Edge[]; } /** * The context object passed to middleware execute functions. * Provides access to the current state, helper functions, and configuration. * * @example * ```typescript * const middleware: Middleware = { * name: 'validation', * execute: (context, next, cancel) => { * // Check if any nodes were added * if (context.helpers.anyNodesAdded()) { * console.log('Nodes added:', context.state.nodes); * } * * // Access configuration * console.log('Cell size:', context.config.background.cellSize); * * // Check what actions triggered this (supports transactions with multiple actions) * if (context.modelActionTypes.includes('addNodes')) { * // Validate new nodes * const isValid = validateNodes(context.state.nodes); * if (!isValid) { * cancel(); // Block the operation * return; * } * } * * next(); // Continue to next middleware * } * }; * ``` * * @public * @since 0.8.0 * @category Types/Middleware */ interface MiddlewareContext { /** The state before any modifications (before the initial action and before any middleware modifications) */ initialState: FlowState; /** The current state (includes the initial modification and all changes from previous middlewares) */ state: FlowState; /** * Map for quick node lookup by ID. * Contains the current state after previous middleware processing. * Use this to access nodes by ID instead of iterating through `state.nodes`. */ nodesMap: Map; /** * Map for quick edge lookup by ID. * Contains the current state after previous middleware processing. * Use this to access edges by ID instead of iterating through `state.edges`. */ edgesMap: Map; /** * The initial nodes map before any modifications (before the initial action and before any middleware modifications). * Use this to compare state before and after all modifications. * Common usage: Access removed node instances that no longer exist in `nodesMap`. */ initialNodesMap: Map; /** * The initial edges map before any modifications (before the initial action and before any middleware modifications). * Use this to compare state before and after all modifications. * Common usage: Access removed edge instances that no longer exist in `edgesMap`. */ initialEdgesMap: Map; /** * Map from node ID to connected edge IDs (edges where node is source or target) * before any modifications (before the initial action and before any middleware modifications). * Use this to find edges connected to specific nodes without scanning all edges. * @since 1.2.3 */ initialConnectedEdgesMap: Map; /** * The action that triggered the middleware execution. * @deprecated Use `modelActionTypes` instead, which supports multiple actions from transactions. * For single actions, this returns the first (and only) action type. */ modelActionType: ModelActionType; /** * All action types that triggered the middleware execution. * For transactions, this contains the transaction name followed by all action types * from commands executed within the transaction. * For single commands outside transactions, this is a single-element array. * * @example * ```typescript * // For a transaction named 'batchUpdate' with addNodes and moveViewport commands: * // modelActionTypes = ['batchUpdate', 'addNodes', 'moveViewport'] * * // For a single command outside a transaction: * // modelActionTypes = ['addNodes'] * ``` * * @since 0.9.0 */ modelActionTypes: ModelActionTypes; /** Helper functions to check what changed (tracks all cumulative changes from the initial action and all previous middlewares) */ helpers: MiddlewareHelpers; /** All state updates from previous middlewares in the chain */ history: MiddlewareHistoryUpdate[]; /** Manager for action states (resizing, linking, etc.) */ actionStateManager: ActionStateManager; /** Manager for edge routing algorithms */ edgeRoutingManager: EdgeRoutingManager; /** * The initial state update that triggered the middleware chain. * Middlewares can add their own updates to the state, so this may not contain all modifications * that will be applied. Use `helpers` to get actual knowledge about all changes. */ initialUpdate: FlowStateUpdate; /** The current diagram configuration */ config: FlowConfig; /** Environment information (browser, rendering engine, etc.) */ environment: EnvironmentInfo; } /** * Middleware interface for intercepting and modifying diagram state changes. * * Middlewares form a chain where each can: * - Inspect the current state and action type * - Modify the state by passing updates to `next()` * - Block operations by calling `cancel()` * - Perform side effects (logging, validation, etc.) * * @template TName - The middleware name type (string literal for type safety) * * @example * ```typescript * // Read-only middleware that blocks modifications * const readOnlyMiddleware: Middleware<'read-only'> = { * name: 'read-only', * execute: (context, next, cancel) => { * const blockedActions = ['addNodes', 'deleteNodes', 'updateNode']; * if (context.modelActionTypes.some((action) => blockedActions.includes(action))) { * console.warn('Action blocked in read-only mode'); * cancel(); * return; * } * next(); * } * }; * * // Auto-snap middleware that modifies positions * const snapMiddleware: Middleware<'auto-snap'> = { * name: 'auto-snap', * execute: (context, next) => { * const gridSize = 20; * const nodesToSnap = context.helpers.getAffectedNodeIds(['position']); * * const updates = nodesToSnap.map(id => { * const node = context.nodesMap.get(id)!; * return { * id, * position: { * x: Math.round(node.position.x / gridSize) * gridSize, * y: Math.round(node.position.y / gridSize) * gridSize * } * }; * }); * * next({ nodesToUpdate: updates }); * } * }; * * // Register middleware * ngDiagramService.registerMiddleware(snapMiddleware); * ``` * * @public * @since 0.8.0 * @category Types/Middleware */ interface Middleware { /** Unique identifier for the middleware */ name: TName; /** * The middleware execution function. * * @param context - Complete context including state, helpers, and configuration * @param next - Call this to continue to the next middleware (optionally with state updates) * @param cancel - Call this to abort the entire operation */ execute: (context: MiddlewareContext, next: (stateUpdate?: FlowStateUpdate) => Promise, cancel: () => void) => Promise | void; } /** * An array of middlewares that will be executed in sequence. * * @public * @since 0.8.0 * @category Types/Middleware */ type MiddlewareChain = Middleware[]; /** * Interface representing a snapshot of the diagram model state. * * This read-only interface is provided by the library when the model changes. * It contains the complete current state of nodes, edges, and metadata. * Typically received in `onChange` callbacks to observe model updates. * * @public * @since 0.8.0 * @category Types/Model */ interface ModelChanges { /** Current array of all nodes in the diagram. */ nodes: Node$1[]; /** Current array of all edges in the diagram. */ edges: Edge[]; /** Current metadata associated with the diagram. */ metadata: Metadata; } /** * Interface for model adapters that handle the data management of a flow diagram * * @public * @since 0.8.0 * @category Types/Model */ interface ModelAdapter { /** * Destroy the model adapter and clean up resources * This should be called when the model is no longer needed to prevent memory leaks */ destroy(): void; /** * Get all nodes in the model */ getNodes(): Node$1[]; /** * Get all edges in the model */ getEdges(): Edge[]; /** * Update nodes in the model * @param nodes Array of nodes to set * @param nodesFn Function that takes current nodes and returns new nodes */ updateNodes(nodes: Node$1[]): void; updateNodes(nodesFn: (nodes: Node$1[]) => Node$1[]): void; /** * Update edges in the model * @param edges Array of edges to set * @param edgesFn Function that takes current edges and returns new edges */ updateEdges(edges: Edge[]): void; updateEdges(edgesFn: (edges: Edge[]) => Edge[]): void; /** * Get metadata associated with the model */ getMetadata(): Metadata; /** * Set metadata for the model * @param metadata Metadata to set * @param metadataFn Function that takes current metadata and returns new metadata */ updateMetadata(metadata: Metadata): void; updateMetadata(metadataFn: (metadata: Metadata) => Metadata): void; /** * Register a callback to be called when the model changes * @param callback Function to be called on changes */ onChange(callback: ({ nodes, edges, metadata }: ModelChanges) => void): void; /** * Unregister a callback from being called when the model changes * @param callback Function to unregister from changes */ unregisterOnChange(callback: ({ nodes, edges, metadata }: ModelChanges) => void): void; /** * Undo the last change */ undo(): void; /** * Redo the last undone change */ redo(): void; /** * Convert the model to a JSON string */ toJSON(): string; } /** * Interface representing the entire model of the flow diagram * * @public * @since 0.8.0 * @category Types/Model */ interface Model { /** * Array of nodes in the diagram */ nodes: Node$1[]; /** * Array of edges connecting the nodes */ edges: Edge[]; /** * Metadata associated with the diagram */ metadata: Partial; } /** * Interface for the Renderer that handles drawing the flow diagram */ interface Renderer { /** * Draws the current state of the flow diagram * @param nodes List of nodes to render * @param edges List of edges to render * @param viewport Viewport to render */ draw(nodes: Node$1[], edges: Edge[], viewport: Viewport): void; } /** * Map of all available diagram events and their payload types * * @public * @since 0.8.0 * @category Types/Events */ interface DiagramEventMap$1 { /** * Event emitted when the diagram initialization is complete. * * This event fires after all nodes and edges including their internal parts * (ports, labels) have been measured and positioned. */ diagramInit: DiagramInitEvent$1; /** * Event emitted when selected nodes are moved within the diagram. * * This event fires when the user moves nodes manually by dragging or * programmatically using the diagram node service. */ selectionMoved: SelectionMovedEvent; /** * Event emitted when the selection state changes in the diagram. * * This event fires when the user selects or deselects nodes and edges through * clicking or programmatically using the diagram selection service. */ selectionChanged: SelectionChangedEvent; /** * Event emitted when selected elements are deleted from the diagram. * * This event fires when the user deletes nodes and edges using the delete key, * or programmatically through the diagram service. */ selectionRemoved: SelectionRemovedEvent; /** * Event emitted when nodes are grouped or ungrouped. * * This event fires when the user moves nodes in or out of a group node, * changing their group membership status. */ groupMembershipChanged: GroupMembershipChangedEvent; /** * Event emitted when a node is rotated in the diagram. * * This event fires when the user rotates a node manually using the rotation handle * or programmatically using the diagram node service. */ selectionRotated: SelectionRotatedEvent; /** * Event emitted when the viewport changes through panning or zooming. * * This event fires during pan and zoom operations, including mouse wheel zoom, * and programmatic viewport changes. */ viewportChanged: ViewportChangedEvent; /** * Event emitted when a user manually draws an edge between two nodes. * * This event only fires for user-initiated edge creation through the UI, * but not for programmatically added edges. * * @deprecated Use `edgeDrawEnded` instead, which fires for both successful and cancelled draws. */ edgeDrawn: EdgeDrawnEvent; /** * Event emitted when an edge draw gesture ends, regardless of outcome. * * Fires on every linking completion — both successful and cancelled. * For successful draws, includes the created edge and target. * For cancelled draws, includes the cancellation reason. * * @since 1.2.0 */ edgeDrawEnded: EdgeDrawEndedEvent; /** * Event emitted when the user starts dragging an endpoint of an existing * edge (the relinking gesture). * * @since 1.4.0 */ edgeRelinkStarted: EdgeRelinkStartedEvent; /** * Event emitted when an edge relink gesture ends, regardless of outcome. * * Fires when the dragged endpoint is dropped, whether it was reconnected to * a port, left dangling on empty canvas, or reverted (invalid drop or * cancelled gesture). * * @since 1.4.0 */ edgeRelinkEnded: EdgeRelinkEndedEvent; /** * Event emitted when clipboard content is pasted into the diagram. * * This event fires when nodes and edges are added via paste operations, * either through keyboard shortcuts or programmatic paste commands. */ clipboardPasted: ClipboardPastedEvent; /** * Event emitted when a node or group size changes. * * This event fires when a node is resized manually by dragging resize handles * or programmatically using resize methods. */ nodeResized: NodeResizedEvent; /** * Event emitted when a palette item is dropped onto the diagram. * * This event fires when users drag items from the palette and drop them * onto the canvas to create new nodes. */ paletteItemDropped: PaletteItemDroppedEvent; /** * Event emitted when a node resize operation begins. * * This event fires once when the user starts resizing a node by dragging * a resize handle. */ nodeResizeStarted: NodeResizeStartedEvent; /** * Event emitted when a node resize operation ends. * * This event fires when the user releases the pointer after resizing a node. * The node will have its final size when this event is received. */ nodeResizeEnded: NodeResizeEndedEvent; /** * Event emitted when a node rotation operation begins. * * This event fires once when the user starts rotating a node by dragging * the rotation handle. */ nodeRotateStarted: NodeRotateStartedEvent; /** * Event emitted when a node rotation operation ends. * * This event fires when the user releases the pointer after rotating a node. * The node will have its final angle when this event is received. */ nodeRotateEnded: NodeRotateEndedEvent; /** * Event emitted when a selection gesture is complete. * * This event fires on pointerup after a selection operation completes - * whether from clicking a node/edge, box selection, or select-all. */ selectionGestureEnded: SelectionGestureEndedEvent; /** * Event emitted when a node drag operation begins. * * This event fires once when the drag threshold is crossed, signaling the * start of a drag operation. */ nodeDragStarted: NodeDragStartedEvent; /** * Event emitted when a node drag operation ends. * * This event fires when the user releases the pointer after dragging nodes. * Nodes will have their final positions when this event is received. */ nodeDragEnded: NodeDragEndedEvent; } /** * Event payload emitted when the diagram initialization is complete. * * This event fires after all nodes and edges including their internal parts * (ports, labels) have been measured and positioned. * * @public * @since 0.8.0 * @category Types/Events */ interface DiagramInitEvent$1 { /** All nodes present in the diagram after initialization */ nodes: Node$1[]; /** All edges present in the diagram after initialization */ edges: Edge[]; /** Current viewport configuration including position and scale */ viewport: Viewport; } /** * Event payload emitted when selected nodes are moved within the diagram. * * This event fires when the user moves nodes manually by dragging or programmatically * using the {@link NgDiagramNodeService.moveNodesBy} method. * * @public * @since 0.8.0 * @category Types/Events */ interface SelectionMovedEvent { /** Nodes that were moved with their updated positions */ nodes: Node$1[]; } /** * Event payload emitted when the selection state changes in the diagram. * * This event fires when the user selects or deselects nodes and edges through clicking * or programmatically using the {@link NgDiagramSelectionService}. * * @public * @since 0.8.0 * @category Types/Events */ interface SelectionChangedEvent { /** Currently selected nodes */ selectedNodes: Node$1[]; /** Currently selected edges */ selectedEdges: Edge[]; /** Previously selected nodes before the change */ previousNodes: Node$1[]; /** Previously selected edges before the change */ previousEdges: Edge[]; } /** * Event payload emitted when a selection gesture is complete. * * This event fires on pointerup after a selection operation completes — * whether from clicking a node/edge, box selection, or select-all. * * @public * @since 1.1.0 * @category Types/Events */ interface SelectionGestureEndedEvent { /** Currently selected nodes after the selection gesture */ nodes: Node$1[]; /** Currently selected edges after the selection gesture */ edges: Edge[]; } /** * Event payload emitted when the viewport changes through panning or zooming. * * This event fires during pan and zoom operations, including mouse wheel zoom, * and programmatic viewport changes. * * @public * @since 0.8.0 * @category Types/Events */ interface ViewportChangedEvent { /** Current viewport state after the change */ viewport: Viewport; /** Previous viewport state before the change */ previousViewport: Viewport; } /** * Event payload emitted when a user manually draws an edge between two nodes. * * This event only fires for user-initiated edge creation through the UI, * but not for programmatically added edges. * * @deprecated Use {@link EdgeDrawEndedEvent} instead, which fires for both successful and cancelled draws. * @public * @since 0.8.0 * @category Types/Events */ interface EdgeDrawnEvent { /** The newly created edge object */ edge: Edge; /** The source node from which the edge originates */ source: Node$1; /** The target node to which the edge connects */ target: Node$1; /** Source port identifier if connected to a specific port */ sourcePort?: string; /** Target port identifier if connected to a specific port */ targetPort?: string; } /** * Reason an edge draw gesture was cancelled. * * - `noTarget` — the user released on empty space (no target node/port snapped) * - `invalidConnection` — `validateConnection()` returned false * - `invalidTarget` — the target node doesn't exist or the target port has wrong type * - `cancelled` — the gesture was aborted programmatically (e.g. Esc key, * {@link NgDiagramService.cancelActiveInteraction}) * * @public * @since 1.2.0 * @category Types/Events */ type EdgeDrawCancelReason = 'noTarget' | 'invalidConnection' | 'invalidTarget' | 'cancelled'; /** * Reason an interactive gesture (drag, resize, rotation) ended without a normal * pointer release. * * - `cancelled` — the gesture was aborted programmatically (e.g. Esc key, * {@link NgDiagramService.cancelActiveInteraction}) * * @public * @since 1.3.0 * @category Types/Events */ type GestureCancelReason = 'cancelled'; /** * Event payload emitted when an edge draw gesture ends, regardless of outcome. * * Fires on every linking completion — both successful and cancelled. * For successful completions, `edge`, `target`, and `targetPort` are populated. * For cancellations, `reason` indicates why the gesture was cancelled. * * @public * @since 1.2.0 * @category Types/Events */ interface EdgeDrawEndedEvent { /** * The source node from which the edge was drawn. * Undefined for draws started from empty canvas * (see {@link NgDiagramService.startLinkingFromPosition}). */ source?: Node$1; /** Source port identifier if connected to a specific port */ sourcePort?: string; /** The position where the pointer was released */ dropPosition: Point; /** Whether the edge was successfully created */ success: boolean; /** The created edge (only present on success) */ edge?: Edge; /** The target node (only present on success) */ target?: Node$1; /** Target port identifier (only present on success) */ targetPort?: string; /** The reason the draw was cancelled (only present on cancel) */ reason?: EdgeDrawCancelReason; } /** * Reason an edge relink gesture ended without changing the edge. * * - `noTarget` — the endpoint was dropped on empty canvas while dangling * edges are disabled, or `danglingEdges.shouldKeepOnDrop` returned false * for the detached edge * - `invalidConnection` — the drop target failed validation: it was rejected * by `linking.validateConnection` (context reason `relink`), or it is not a * valid target at all (hidden node, hidden or missing port, port with the * wrong direction) * - `cancelled` — the gesture was aborted (Esc key, * {@link NgDiagramService.cancelActiveInteraction}, or another gesture took * over the pointer), or the endpoint was dropped back on its original node * and port, which changes nothing * * @public * @since 1.4.0 * @category Types/Events */ type EdgeRelinkCancelReason = 'noTarget' | 'invalidConnection' | 'cancelled'; /** * Event payload emitted when the user starts dragging an endpoint of an * existing edge. * * @public * @since 1.4.0 * @category Types/Events */ interface EdgeRelinkStartedEvent { /** The edge being relinked (snapshot at gesture start). */ edge: Edge; /** Which endpoint is being dragged. */ end: EdgeEnd; } /** * Event payload emitted when an edge relink gesture ends, regardless of outcome. * * On success the edge was either reconnected (`target` and `targetPort` are * set) or left dangling (`edge` has a free endpoint anchored at * `dropPosition`). On failure the edge is unchanged and `reason` explains why. * * @public * @since 1.4.0 * @category Types/Events */ interface EdgeRelinkEndedEvent { /** The edge after the relink (unchanged snapshot when `success` is false). */ edge: Edge; /** Which endpoint was dragged. */ end: EdgeEnd; /** The node the endpoint was connected to before the relink, if any. */ previousNode?: Node$1; /** The port the endpoint was connected to before the relink, if any. */ previousPort?: string; /** The anchor position of the endpoint before the relink, present only when the endpoint was free (dangling). */ previousPosition?: Point; /** The position where the pointer was released. */ dropPosition: Point; /** Whether the edge was changed (reconnected or left dangling). */ success: boolean; /** The node the endpoint was reconnected to (only present on reconnect). */ target?: Node$1; /** The port the endpoint was reconnected to (only present on reconnect). */ targetPort?: string; /** The reason the relink was reverted (only present on failure). */ reason?: EdgeRelinkCancelReason; } /** * Event payload emitted when clipboard content is pasted into the diagram. * * This event fires when nodes and edges are added via paste operations, * either through keyboard shortcuts or programmatic paste commands. * * @public * @since 0.8.0 * @category Types/Events */ interface ClipboardPastedEvent { /** Nodes that were pasted into the diagram */ nodes: Node$1[]; /** Edges that were pasted into the diagram */ edges: Edge[]; } /** * Event payload emitted when a node or group size changes. * * This event fires when a node is resized manually by dragging resize handles * or programmatically using resize methods. * * @public * @since 0.8.0 * @category Types/Events */ interface NodeResizedEvent { /** Node that was resized with its updated size */ node: Node$1; /** Previous size of the node before the change */ previousSize: Size; } /** * Event payload emitted when a palette item is dropped onto the diagram. * * This event fires when users drag items from the palette and drop them * onto the canvas to create new nodes. * * @public * @since 0.8.0 * @category Types/Events */ interface PaletteItemDroppedEvent { /** The node that was created from the dropped palette item */ node: Node$1; /** The position where the item was dropped */ dropPosition: Point; } /** * Event payload emitted when selected elements are deleted from the diagram. * * This event fires when the user deletes nodes and edges using the delete key, * or programmatically through the diagram service. * * @public * @since 0.8.0 * @category Types/Events */ interface SelectionRemovedEvent { /** Nodes that were deleted from the diagram */ deletedNodes: Node$1[]; /** Edges that were deleted from the diagram */ deletedEdges: Edge[]; /** * Edges that were detached into dangling edges instead of being deleted * (see `danglingEdges.detachOnNodeDelete`). The snapshots are taken after * the detach: the freed endpoints already have an empty `source`/`target` * and their anchor positions set. Empty when nothing was detached. * * @since 1.4.0 */ detachedEdges: Edge[]; } /** * Event payload emitted when nodes are grouped or ungrouped. * * This event fires when the user moves nodes in or out of a group node, * changing their group membership status. * * @public * @since 0.8.0 * @category Types/Events */ interface GroupMembershipChangedEvent { /** Nodes added to groups, organized by target group */ grouped: { nodes: Node$1[]; targetGroup: GroupNode; }[]; /** Nodes removed from groups */ ungrouped: Node$1[]; } /** * Event payload emitted when a node is rotated in the diagram. * * This event fires when the user rotates a node manually using the rotation handle * or programmatically using the {@link NgDiagramNodeService} rotation methods. * * @public * @since 0.8.0 * @category Types/Events */ interface SelectionRotatedEvent { /** The node that was rotated */ node: Node$1; /** The new angle of the node in degrees */ angle: number; /** The previous angle of the node in degrees */ previousAngle: number; } /** * Event payload emitted when a node resize operation begins. * * This event fires once when the user starts resizing a node by dragging * a resize handle. * * @public * @since 1.1.0 * @category Types/Events */ interface NodeResizeStartedEvent { /** The node being resized */ node: Node$1; } /** * Event payload emitted when a node resize operation ends. * * This event fires when the user releases the pointer after resizing a node. * The node will have its final size when this event is received. * * @public * @since 1.1.0 * @category Types/Events */ interface NodeResizeEndedEvent { /** The node that was resized, with its final size */ node: Node$1; /** Present when the resize ended without a normal pointer release */ cancelReason?: GestureCancelReason; } /** * Event payload emitted when a node rotation operation begins. * * This event fires once when the user starts rotating a node by dragging * the rotation handle. * * @public * @since 1.1.0 * @category Types/Events */ interface NodeRotateStartedEvent { /** The node being rotated */ node: Node$1; } /** * Event payload emitted when a node rotation operation ends. * * This event fires when the user releases the pointer after rotating a node. * The node will have its final angle when this event is received. * * @public * @since 1.1.0 * @category Types/Events */ interface NodeRotateEndedEvent { /** The node that was rotated, with its final angle */ node: Node$1; /** Present when the rotation ended without a normal pointer release */ cancelReason?: GestureCancelReason; } /** * Event payload emitted when a node drag operation begins. * * This event fires once when the drag threshold is crossed, signaling the * start of a drag operation. * * @public * @since 1.1.0 * @category Types/Events */ interface NodeDragStartedEvent { /** Nodes being dragged */ nodes: Node$1[]; } /** * Event payload emitted when a node drag operation ends. * * This event fires when the user releases the pointer after dragging nodes. * Nodes will have their final positions when this event is received. * * @public * @since 1.1.0 * @category Types/Events */ interface NodeDragEndedEvent { /** Nodes that were dragged, with their final positions */ nodes: Node$1[]; /** Present when the drag ended without a normal pointer release */ cancelReason?: GestureCancelReason; } /** * Type for event listeners */ type EventListener = (event: T) => void; /** * Type for event unsubscribe function */ type UnsubscribeFn = () => void; /** * Internal event map that extends the public DiagramEventMap with internal-only events. * These events are used internally by the library but are not part of the public API. * * @internal */ interface InternalDiagramEventMap extends DiagramEventMap$1 { /** * Event emitted when the action state changes. * * This event fires when an action like resizing, rotating, or linking * starts or ends, allowing subscribers to react to state changes. * * @internal - For internal use only. Use the `actionState` signal on NgDiagramService instead. */ actionStateChanged: ActionStateChangedEvent; } /** * Event payload emitted when the action state changes. * * This event fires when an action like resizing, rotating, or linking * starts or ends, allowing subscribers to react to state changes. * * @internal */ interface ActionStateChangedEvent { /** The current action state */ actionState: Readonly; } /** * Manages event subscriptions and emissions for the diagram */ declare class EventManager { private listeners; private enabled; private deferredEmits; /** * Subscribe to an event * @param event The event name * @param callback The callback to invoke when the event is emitted * @returns A function to unsubscribe */ on(event: K, callback: EventListener): UnsubscribeFn; /** * Subscribe to an event that will only fire once * @param event The event name * @param callback The callback to invoke when the event is emitted * @returns A function to unsubscribe */ once(event: K, callback: EventListener): UnsubscribeFn; /** * Emit an event * @param event The event name * @param payload The event payload */ emit(event: K, payload: InternalDiagramEventMap[K]): void; /** * Queue an event to be emitted later * @param event The event name * @param payload The event payload */ deferredEmit(event: K, payload: InternalDiagramEventMap[K]): void; /** * Remove all listeners for an event, or a specific listener * @param event The event name * @param callback Optional specific callback to remove */ off(event: K, callback?: EventListener): void; /** * Remove all event listeners */ offAll(): void; /** * Enable or disable event emissions * @param enabled Whether events should be emitted */ setEnabled(enabled: boolean): void; /** * Check if event emissions are enabled */ isEnabled(): boolean; /** * Check if there are any listeners for an event * @param event The event name * @returns True if there are listeners */ hasListeners(event: keyof InternalDiagramEventMap): boolean; /** * Flush all deferred emits */ flushDeferredEmits(): void; /** * Clear all deferred emits without executing them */ clearDeferredEmits(): void; private removeListener; } /** * **Internal manager** for temporary state during ongoing user actions. * Tracks the state of interactive operations like resizing, linking, rotating, and dragging * until the action completes. * * @remarks * **For application code, use {@link NgDiagramService.actionState} signal instead.** * This class is exposed primarily for middleware development where you can access it * via `context.actionStateManager`. * * @example * ```typescript * const middleware: Middleware = { * name: 'resize-validator', * execute: (context, next, cancel) => { * const resizeState = context.actionStateManager.resize; * if (resizeState) { * console.log('Currently resizing node:', resizeState.nodeId); * } * next(); * } * }; * ``` * * @public * @since 0.8.0 * @category Internals */ declare class ActionStateManager { private readonly eventManager; private state; constructor(eventManager: EventManager); /** * Gets the current action state (readonly). * * @returns The complete action state object */ getState(): Readonly; /** * Emits an 'actionStateChanged' event with the current state. * @internal */ private emitStateChanged; /** * Gets the current resize action state. * * @returns The resize state if a resize is in progress, undefined otherwise */ get resize(): ResizeActionState | undefined; /** * Sets the resize action state. * * @param value - The resize state to set, or undefined to clear */ set resize(value: ResizeActionState | undefined); /** * Gets the current linking action state. * * @returns The linking state if a link is being created, undefined otherwise */ get linking(): LinkingActionState | undefined; /** * Sets the linking action state. * * @param value - The linking state to set, or undefined to clear */ set linking(value: LinkingActionState | undefined); /** * Gets the current copy/paste action state. * * @returns The copy/paste state if a copy/paste operation is in progress, undefined otherwise */ get copyPaste(): CopyPasteActionState | undefined; /** * Sets the copy/paste action state. * * @param value - The copy/paste state to set, or undefined to clear */ set copyPaste(value: CopyPasteActionState | undefined); /** * Gets the current highlight group action state. * * @returns The highlight group state if a group is being highlighted, undefined otherwise */ get highlightGroup(): HighlightGroupActionState | undefined; /** * Sets the highlight group action state. * * @param value - The highlight group state to set, or undefined to clear */ set highlightGroup(value: HighlightGroupActionState | undefined); /** * Gets the current rotation action state. * * @returns The rotation state if a rotation is in progress, undefined otherwise */ get rotation(): RotationActionState | undefined; /** * Sets the rotation action state. * * @param value - The rotation state to set, or undefined to clear */ set rotation(value: RotationActionState | undefined); /** * Gets the current dragging action state. * * @returns The dragging state if nodes are being dragged, undefined otherwise */ get dragging(): DraggingActionState | undefined; /** * Sets the dragging action state. * * @param value - The dragging state to set, or undefined to clear */ set dragging(value: DraggingActionState | undefined); /** * Gets the current panning action state. * * @returns The panning state if viewport is being panned, undefined otherwise */ get panning(): PanningActionState | undefined; /** * Sets the panning action state. * * @param value - The panning state to set, or undefined to clear */ set panning(value: PanningActionState | undefined); /** * Clears the resize action state. */ clearResize(): void; /** * Clears the linking action state. */ clearLinking(): void; /** * Clears the copy/paste action state. */ clearCopyPaste(): void; /** * Clears the highlight group action state. */ clearHighlightGroup(): void; /** * Clears the rotation action state. */ clearRotation(): void; /** * Clears the dragging action state. */ clearDragging(): void; /** * Checks if a resize operation is currently in progress. */ isResizing(): boolean; /** * Checks if a linking operation is currently in progress. */ isLinking(): boolean; /** * Checks if a rotation operation is currently in progress. */ isRotating(): boolean; /** * Checks if a dragging operation is currently in progress. */ isDragging(): boolean; /** * Clears the panning action state. */ clearPanning(): void; /** * Checks if a panning operation is currently in progress. */ isPanning(): boolean; /** * Gets the current selection action state. * * @returns The selection state if set, undefined otherwise */ get selection(): SelectionActionState | undefined; /** * Sets the selection action state. * * @param value - The selection state to set, or undefined to clear */ set selection(value: SelectionActionState | undefined); /** * Clears the selection action state. */ clearSelection(): void; } /** * What an observed element is: a node, one of a node's ports, or one of an edge's labels. * * @internal */ type ObservedElementMetadata = { type: 'port'; nodeId: string; portId: string; } | { type: 'edge-label'; edgeId: string; labelId: string; } | { type: 'node'; nodeId: string; }; /** @internal */ interface CapturedResizeEntry { entry: ResizeObserverEntry; /** The id of the node under an active resize gesture when the observer delivered the entry, if any. */ resizingNodeId: string | undefined; } /** @internal */ interface BatchedResizeObserverConfig { /** Processes the batched entries after the double-rAF stabilization. */ processBatch: (entries: CapturedResizeEntry[]) => void; /** Sampled synchronously at each observer delivery, to stamp the entries. */ activeResizeNodeId: () => string | undefined; /** Called when the observer delivers entries, before batch processing is scheduled. */ onObserverActivity?: (metadata: ObservedElementMetadata[]) => void; } /** * One `ResizeObserver` for every node, port and edge label of a diagram (ngDiagram's * `BatchResizeObserverService`). * * Entries are collected and processed together two animation frames after the observer delivers them, so layout * has settled. Only the newest entry per element is kept. Each element is indexed under its owner (`node:` for * nodes and their ports, `edge:` for labels), so all of an owner's elements can be re-measured at once. * * The {@link DiagramRuntime} owns one instance, as `runtime.resizeObserver`; elements observe themselves through * it and {@link DiagramResizeProcessor} consumes the batches. * * @internal */ declare class BatchedResizeObserver { private observer; private observedElements; private entityIndex; private config; private rafId; private pendingEntries; constructor(); /** Sets the batch processor and the activity callbacks. */ configure(config: BatchedResizeObserverConfig): void; /** Observes an element's size, recording what it is. */ observe(element: Element, metadata: ObservedElementMetadata): void; /** Stops observing an element. Safe for an element that was never observed. */ unobserve(element: Element): void; /** * Makes the observer deliver a fresh entry for the element. Use it when the element moved without changing * size, which `ResizeObserver` alone does not report. */ invalidate(element: Element): void; getMetadata(element: Element): ObservedElementMetadata | undefined; /** * Re-measures a node's element and all its ports. * * @returns The entity keys invalidated: `['node:']`, or `[]` when nothing is observed for the node */ invalidateNode(nodeId: string): string[]; /** * Re-measures all of an edge's labels. * * @returns The entity keys invalidated: `['edge:']`, or `[]` when nothing is observed for the edge */ invalidateEdgeLabels(edgeId: string): string[]; /** * Re-measures every observed element. * * @returns The entity keys invalidated */ invalidateAll(): string[]; /** Disconnects the observer and drops pending work. The instance cannot be used afterwards. */ destroy(): void; private invalidateByKey; private getEntityKey; private addToEntityIndex; private removeFromEntityIndex; private processBatch; } /** @internal */ interface CursorPosition extends Point { timestamp: number; } /** * The last known mouse position in client coordinates (ngDiagram's `CursorPositionTrackerService`), kept up to date * by the diagram's `CursorPositionTrackerController`. Paste uses it to place pasted nodes under the cursor, and * manual linking to start the temporary edge there. One per diagram, as `runtime.cursorPosition`. * * @internal */ declare class CursorPositionTracker { private lastPosition; /** Records a client position. */ updatePosition(x: number, y: number): void; /** A copy of the last known position. */ getLastPosition(): CursorPosition; /** Whether the last position was recorded within the last five seconds. */ hasRecentPosition(): boolean; } /** * Environment information for the diagram core: OS and browser detection, a clock and an id generator. Ported from * ngDiagram's `EnvironmentProviderService`. Outside a browser (SSR, Node) it reports `runtime: 'node'` and no OS or * browser. * * @internal */ declare class DiagramEnvironment implements EnvironmentInfo { get os(): EnvironmentInfo['os'] | null; get browser(): EnvironmentInfo['browser'] | null; get runtime(): EnvironmentInfo['runtime']; /** Whether the code runs in a browser, with `window` and `document`. */ get isClient(): boolean; now(): number; generateId(): string; private detectOS; private detectBrowser; } /** * Browser events that the router understands and can normalize. * * @internal */ type DomInputEvent = KeyboardEvent | WheelEvent | PointerEvent | DragEvent | TouchEvent; /** * A `PointerEvent` with the flags that input controllers set to coordinate. Several controllers see the same * event as it bubbles (and on `document`), and each one checks the flags of the controllers before it, so * **listener order matters**. See the epic (ISSUE-9660) for the order on the diagram host. * * @internal */ interface PointerInputEvent extends PointerEvent { moveSelectionHandled?: boolean; zoomingHandled?: boolean; linkingHandled?: boolean; relinkHandled?: boolean; rotateHandled?: boolean; selectHandled?: boolean; boxSelectionHandled?: boolean; } /** * Bridges DOM events to the core input handlers. Ported from ngDiagram's `InputEventsRouterService`. * * Input controllers build a core event with {@link DomInputEventsRouter.getBaseEvent} (id, timestamp and * modifiers normalized across OSes: the primary modifier is Cmd on macOS and Ctrl elsewhere), add the event name and * payload, and pass it to `emit()`. `eventGuards` holds the common checks. * * @internal */ declare class DomInputEventsRouter extends InputEventsRouter { private readonly environment; constructor(environment: DiagramEnvironment); /** Creates the common part of a core input event from a DOM event. */ getBaseEvent(event: DomInputEvent): Omit; /** Guards for common event properties: type, modifiers, buttons and keys. */ readonly eventGuards: { isPointerEvent: (event: Event) => event is PointerEvent; isKeyboardEvent: (event: Event) => event is KeyboardEvent; isWheelEvent: (event: Event) => event is WheelEvent; isDomEvent: (event: Event) => event is DomInputEvent; withPrimaryModifier: (event: Event) => boolean; withSecondaryModifier: (event: Event) => boolean; withShiftModifier: (event: Event) => boolean; withMetaModifier: (event: Event) => boolean; withoutModifiers: (event: Event) => boolean; withPrimaryButton: (event: Event) => boolean; isArrowKeyPressed: (event: Event) => boolean; isKeyPressed: (key: string) => (event: Event) => boolean; isKeyComboPressed: (key: string, ...mods: (keyof InputModifiers)[]) => (event: Event) => boolean; }; private getPrimaryModifierKey; private isPointerEvent; private isKeyboardEvent; private isWheelEvent; private isDomEvent; private getModifiers; } /** Removes a subscription. Calling it more than once is safe. */ type Unsubscribe = () => void; /** * Listener of a {@link ReadonlyObservable}, called with the new value and the value it replaced. * * @typeParam T - Type of the value. */ type ObservableListener = (value: T, previous: T) => void; /** * A value that changes over time, returned by the diagram API. Read the current value with `value`, and call * `subscribe()` to be notified of changes. In a Lit element, use a {@link DiagramObserver} to re-render when the * value changes. * * @example * Log the zoom scale whenever it changes: * ```ts * const unsubscribe = diagram.api.viewport.scale.subscribe((scale) => console.log('Scale', scale)); * ... * unsubscribe(); * ``` * * @typeParam T - Type of the value. */ interface ReadonlyObservable { /** The current value. */ readonly value: T; /** * Calls `listener` whenever the value changes. The listener is not called for the current value. * * @param listener - Function called with the new and the previous value. * @returns A function that removes the subscription. */ subscribe(listener: ObservableListener): Unsubscribe; } /** @internal */ interface ObservableOptions { /** Decides whether a new value is the same as the current one, so no listener runs. Defaults to `Object.is`. */ equals?: (a: T, b: T) => boolean; } /** @internal */ declare class Observable implements ReadonlyObservable { private _value; private readonly equals; private readonly entries; private readonlyView?; constructor(initialValue: T, options?: ObservableOptions); get value(): T; /** The number of active subscriptions. */ get subscriberCount(): number; /** * Sets the value and notifies listeners if it changed. * * @returns Whether the value changed */ set(value: T): boolean; /** Sets the value from the current one. */ update(fn: (previous: T) => T): boolean; subscribe(listener: ObservableListener): Unsubscribe; /** A view without `set`, to hand to consumers. */ asReadonly(): ReadonlyObservable; /** @internal Called by {@link batch}. */ notifyAfterBatch(previous: unknown): void; private notify; } /** * A Lit reactive controller that re-renders its host element whenever an observable of the diagram API changes. * It subscribes while the host is connected and calls `requestUpdate()` on every change. The source can be set * later, for example once the element has found its diagram, with {@link DiagramObserver.setSource}. * * The optional callback runs whenever the controller sees a value different from the last one it saw, including on * the first subscription and after the host reconnects. * * @example * Show the number of selected nodes in a Lit element: * ```ts * class SelectionInfo extends LitElement { * private selection = new DiagramObserver(this, diagram.api.selection.selection); * * render() { * return html`${this.selection.value?.nodes.length ?? 0} nodes selected`; * } * } * ``` * * @typeParam T - Type of the observed value. */ declare class DiagramObserver implements ReactiveController { private readonly host; private readonly callback?; private source?; private unsubscribe?; private connected; private hasSeen; private lastSeen?; /** * Constructs a new `DiagramObserver` instance and adds it to `host`. * * @param host - Element to re-render. * @param source - Observable to observe. If not specified, set it later with {@link DiagramObserver.setSource}. * @param callback - Function called with each new value. */ constructor(host: ReactiveControllerHost, source?: ReadonlyObservable, callback?: ((value: T) => void) | undefined); /** The source's current value, or `undefined` without a source. */ get value(): T | undefined; /** * Replaces the observed observable. * * @param source - Observable to observe, or `undefined` to stop observing. */ setSource(source: ReadonlyObservable | undefined): void; /** @internal */ hostConnected(): void; /** @internal */ hostDisconnected(): void; private attach; private detach; private handle; } /** * The core `Renderer`. Like ngDiagram's `RendererService`, it only stores what the core's render strategy hands * it; the diagram element observes the values and renders them. * * `draw()` sets all three observables in one {@link batch}, so a listener on any of them sees the other two * already updated. `nodes` and `edges` notify only when an item changes (by reference), is added, removed or * moved, and `viewport` only when it is a new object, so a pan or zoom notifies only `viewport`. The virtualized * render strategy hands over new arrays of the same items on every pan step; they do not notify. * * @internal */ declare class LitRenderer implements Renderer { private readonly _nodes; private readonly _edges; private readonly _viewport; /** The nodes to render, after virtualization and visibility filtering. */ readonly nodes: ReadonlyObservable; /** The edges to render, including the temporary edge while linking. */ readonly edges: ReadonlyObservable; readonly viewport: ReadonlyObservable; draw(nodes: Node$1[], edges: Edge[], viewport: Viewport): void; /** Clears everything, for when the diagram's FlowCore is destroyed. */ reset(): void; } /** The id of the built-in arrow marker, for an edge's `sourceArrowhead` / `targetArrowhead`. */ declare const DIAGRAM_ARROW_MARKER_ID = "flow-ui-diagram-arrow"; /** * The diagram's SVG edge markers, by id (ngDiagram's `MarkerRegistryService`). One per diagram, owned by the * runtime as `runtime.markerRegistry`. * * An SVG `url(#id)` reference only resolves inside its own document or shadow root, and every * `flow-ui-diagram-base-edge` draws in its own shadow root. So edges do not reference a shared ``: they * clone the registered one into their own `` ({@link DiagramMarkerRegistry.clone}). ngDiagram does this only * in Safari. * * The built-in arrow ({@link DIAGRAM_ARROW_MARKER_ID}, and `ng-diagram-arrow`, the core's id for the arrowhead of * drawn edges) is always available; registering a marker with the same id overrides it until that marker is * unregistered. `flow-ui-diagram-marker` registers the others. * * @internal */ declare class DiagramMarkerRegistry { /** Whether cloned markers keep `context-stroke` / `context-fill` (false in Safari). */ readonly supportsContextStroke: boolean; private readonly builtIns; private readonly _markers; /** The registered markers by id, built-ins included. A new map on every change, so edges re-render. */ readonly markers: ReadonlyObservable>; constructor(); /** Registers (or replaces) the marker with this id. */ register(id: string, element: SVGMarkerElement): void; /** * Unregisters the marker with this id. With `element`, only when that element is the one registered, so a * marker that was replaced does not remove its replacement. A built-in marker with the same id comes back. */ unregister(id: string, element?: SVGMarkerElement): void; has(id: string): boolean; /** A deep copy of the marker with the id `newId`, or `null` when no marker has the id `markerId`. */ clone(markerId: string, newId: string): SVGMarkerElement | null; } /** A port's measured geometry, relative to its node and in flow units. @internal */ type MeasuredPortData = Required>; /** * Measures port geometry from the DOM (ngDiagram's `UpdatePortsService`). Port elements plug one in through * {@link DiagramResizeProcessor.portMeasurer}; until then, port entries are skipped and nodes are measured * without their ports. * * @internal */ interface DiagramPortMeasurer { /** Measures one port element relative to its node, or returns `null` when it cannot. */ getPortData(portElement: Element): MeasuredPortData | null; /** Measures every port inside a node element. */ getNodePortsData(nodeElement: Element, nodeId: string): (MeasuredPortData & { id: string; })[]; } /** What the processor needs from the {@link DiagramRuntime}. @internal */ interface DiagramResizeProcessorSource { readonly flowCore: ReadonlyObservable; readonly actionState: ReadonlyObservable>; } /** * Turns batches from the {@link BatchedResizeObserver} into core updates (ngDiagram's * `FlowResizeBatchProcessorService`): node sizes through `updater.applyNodeSizes`, port geometry through * `updater.applyPortChanges` and label sizes through `updater.applyEdgeLabelChanges`. Changes under 1px are * ignored. It also signals observer activity to the core's `measurementTracker`, and re-measures a node once its * resize gesture ends. * * The runtime creates one per diagram. It reads the current FlowCore on every batch, so it survives FlowCore * re-creation. * * @internal */ declare class DiagramResizeProcessor { private readonly source; private readonly observer; /** The runtime sets its port registry here. Without a measurer, port measurements are skipped. */ portMeasurer: DiagramPortMeasurer | null; private readonly unsubscribeActionState; constructor(source: DiagramResizeProcessorSource, observer: BatchedResizeObserver); destroy(): void; /** * Re-measures the resized node once its gesture ends. Measurements of that node taken during the gesture are * dropped (see `processNodeBatch`), and when CSS (`min-width`, say) stops the DOM following the model size, the * observer never fires again by itself, so the model would keep a size the DOM never reached. */ private watchResizeGestureEnd; private processAllResizes; private processPortBatch; private processNodeBatch; private processEdgeLabelBatch; private getBorderBoxSize; } /** * Knows which port elements belong to which node element, and measures them: the Lit version of ngDiagram's * `UpdatePortsService`. It is the runtime's {@link DiagramPortMeasurer}. * * ngDiagram finds a port's node with `closest()` and a node's ports with `querySelectorAll()`. Neither crosses * shadow roots, and a port can sit inside the shadow root of a tag-name node template, so here each * `flow-ui-diagram-port` attaches itself to the node element it got from the node context. * * A port's geometry is measured relative to its node element: `(port rect - node rect) / scale`, in flow units. * Ports that are not rendered (`display: none`, for example a hidden port) are skipped, so they keep their last * measured geometry. * * @internal */ declare class DiagramPortRegistry implements DiagramPortMeasurer { private readonly getScale; private readonly ports; private readonly portsByNode; /** @param getScale The current viewport scale, the one the DOM is transformed with. */ constructor(getScale: () => number); /** Attaches a port element to its node element, or updates its id. */ attach(portElement: Element, nodeElement: Element, portId: string): void; /** Detaches a port element. Safe for an element that was never attached. */ detach(portElement: Element): void; /** The port elements attached to a node element, in attachment order. */ getNodePorts(nodeElement: Element): Element[]; getPortData(portElement: Element): MeasuredPortData | null; getNodePortsData(nodeElement: Element, _nodeId: string): (MeasuredPortData & { id: string; })[]; private scale; private removeFromNode; } /** * The rectangle of the box selection in progress, in diagram viewport coordinates (pixels from the diagram's * top-left corner), or `null` when there is none. The box-selection controllers write it; `flow-ui-diagram` draws * it as the selection rectangle. Ported from ngDiagram's `BoxSelectionProviderService`, which was application-wide; * here there is one per diagram (`runtime.boxSelection`). * * @internal */ declare class DiagramBoxSelectionProvider { readonly boundingBox: Observable; } /** * The pointer and touch gestures that claim the diagram's shared gesture marker ({@link DiagramTouchEventsState}). * * @internal */ declare enum DiagramEventName { Rotate = "rotate", Resize = "resize", Move = "move", BoxSelection = "box-selection", Linking = "linking", Panning = "panning", Zooming = "zooming", /** A touch long press on a node or edge that opened a context menu (a flow-rdf-ui addition). */ ContextMenu = "context-menu" } /** * The gesture that currently owns the diagram's pointers, shared by the input controllers so that concurrent * gestures (mostly multi-touch: a node drag and a two-finger pan) stay out of each other's way. Ported from * ngDiagram's `TouchEventsStateService`, which was application-wide; here there is one per diagram * (`runtime.touchEventsState`). * * Only the controller that set the marker may clear it. * * @internal */ declare class DiagramTouchEventsState { private readonly _currentEvent; /** The gesture that owns the marker, or `null`. */ readonly currentEvent: ReadonlyObservable; setCurrentEvent(event: DiagramEventName | null): void; clearCurrentEvent(): void; rotateHandled(): boolean; resizeHandled(): boolean; moveHandled(): boolean; boxSelectionHandled(): boolean; linkingHandled(): boolean; panningHandled(): boolean; zoomingHandled(): boolean; contextMenuHandled(): boolean; } /** * What the runtime needs from the element that hosts the diagram. The core calls these lazily, so they can read * the DOM. * * @internal */ interface DiagramRuntimeHost { /** The client position of the diagram's top-left corner, used to turn client points into flow points. */ getFlowOffset(): Point; /** The size of the diagram's viewport in CSS pixels. */ getViewportSize(): { width: number; height: number; }; /** The diagram's client rect, for edge panning while dragging. Defaults to a rect built from the two above. */ getClientRect?(): DOMRect; /** The diagram's `selectionMode`, read on every press. Defaults to `'default'`. */ getSelectionMode?(): DiagramSelectionMode; } /** @internal */ interface DiagramRuntimeOptions { /** Defaults to a new {@link DiagramEnvironment}. */ environment?: DiagramEnvironment; } /** @internal */ interface DiagramRuntimeInitOptions { model: ModelAdapter; /** Defaults to {@link BUILTIN_MIDDLEWARES}. */ middlewares?: MiddlewareChain; config?: DeepPartial; } /** * Manual linking (ngDiagram's `ManualLinkingService`): starts an edge-drawing gesture from code, which the pointer * then drives. The diagram's `ManualLinkingController` provides it as `runtime.manualLinking`; `api.startLinking()` * uses it. * * @internal */ interface DiagramManualLinking { startLinking(node: Node$1, portId?: string): void; startLinkingFromPosition(position: Point): void; } /** * The diagram-wide relink gesture (ngDiagram's `RelinkingGestureService`), provided by the diagram's * `RelinkingGestureController` as `runtime.relinkingGesture`. Relink handles on base edges start it. * * @internal */ interface DiagramRelinkingGesture { /** Registers a `pointerdown` on an endpoint handle as a relink candidate. Returns whether it was claimed. */ beginRelink(event: PointerInputEvent, edge: Edge, end: EdgeEnd): boolean; /** `true` while an endpoint is being dragged. */ readonly active: ReadonlyObservable; } /** * The stable per-diagram holder of the core, the equivalent of ngDiagram's `FlowCoreProviderService`. One instance * lives as long as its `flow-ui-diagram` element and survives FlowCore re-creation (a new `model`), so elements * can hold on to it (through {@link diagramRuntimeContext}) and to its observables. * * It owns the renderer, the input-events router and the environment, and exposes the shared state as observables: * * - `flowCore`: the current FlowCore, or `null` before `init()` and after `destroy()` * - `isInitialized`: `true` once the core's `diagramInit` event has fired for the current FlowCore (deferred by one * task, as in ngDiagram); the canvas stays hidden until then * - `config`: the resolved FlowConfig, refreshed by {@link DiagramRuntime.updateConfig} * - `actionState`: the core's action state (resizing, linking, and so on) * - `renderer.nodes`, `renderer.edges`, `renderer.viewport`: what to render * * It also owns the diagram's one {@link BatchedResizeObserver} (`resizeObserver`), which nodes, ports and labels * observe themselves through, and the {@link DiagramResizeProcessor} (`resizeProcessor`) that writes the * measurements into the current FlowCore. Ports attach themselves to their node element in `portRegistry`, which * is the processor's port measurer, and edges clone their arrowheads from `markerRegistry`. * * Core events are subscribed through {@link DiagramRuntime.on}; those subscriptions are re-attached to each new * FlowCore. * * @internal */ declare class DiagramRuntime { readonly environment: DiagramEnvironment; readonly renderer: LitRenderer; readonly inputEventsRouter: DomInputEventsRouter; private readonly _flowCore; private readonly _isInitialized; private readonly _config; private readonly _actionState; readonly flowCore: ReadonlyObservable; readonly isInitialized: ReadonlyObservable; readonly config: ReadonlyObservable; readonly actionState: ReadonlyObservable>; /** The shared size observer for nodes, ports and edge labels. */ readonly resizeObserver: BatchedResizeObserver; /** Writes the observer's measurements into the current FlowCore. */ readonly resizeProcessor: DiagramResizeProcessor; /** Which port elements belong to which node element; measures them for the resize processor. */ readonly portRegistry: DiagramPortRegistry; /** The SVG markers edges can use as arrowheads, the built-in arrow included. */ readonly markerRegistry: DiagramMarkerRegistry; /** The gesture that currently owns the pointers, shared by the input controllers. */ readonly touchEventsState: DiagramTouchEventsState; /** The rectangle of the box selection in progress, drawn by the diagram. */ readonly boxSelection: DiagramBoxSelectionProvider; /** The last known mouse position, kept by the cursor-position-tracker controller. */ readonly cursorPosition: CursorPositionTracker; /** Manual linking for `api.startLinking()`, set by the diagram's `ManualLinkingController`. */ manualLinking?: DiagramManualLinking; /** The relink gesture that relink handles start, set by the diagram's `RelinkingGestureController`. */ relinkingGesture?: DiagramRelinkingGesture; /** * The diagram's `nodeTemplateMap`, kept current by the diagram, for elements outside its content layer that * render nodes the same way (palette item previews). */ readonly nodeTemplateMap: Observable; /** The diagram's API (`diagram.api`), set by the diagram, for template contexts outside its content layer. */ api?: DiagramApi; private readonly host; private readonly stableListeners; private readonly initListeners; private coreUnsubscribes; private initTimer; constructor(host: DiagramRuntimeHost, options?: DiagramRuntimeOptions); /** The diagram's client rect (`getBoundingClientRect()` of the `flow-ui-diagram` element). */ getDiagramRect(): DOMRect; /** How presses change the selection: the diagram's `selectionMode` (`'default'` for any unknown value). */ get selectionMode(): DiagramSelectionMode; /** Whether a FlowCore currently exists. */ get hasFlowCore(): boolean; /** * Destroys the current FlowCore, if any, and creates a new one for `model`. The core draws into the renderer * synchronously during construction, then measures and emits `diagramInit` asynchronously. */ init({ model, middlewares, config }: DiagramRuntimeInitOptions): FlowCore; /** * Destroys the current FlowCore. This also destroys its model adapter, as in ngDiagram, so a model cannot be * reused after its diagram is destroyed. Listeners registered with {@link DiagramRuntime.on} are kept. */ destroy(): void; /** The current FlowCore. Throws before `init()` and after `destroy()`. */ provide(): FlowCore; /** Merges `config` into the current FlowCore's config and refreshes the `config` observable. */ updateConfig(config: DeepPartial): void; /** * Subscribes to a core event on the current FlowCore and on every FlowCore created later, until the returned * function is called. `diagramInit` listeners run after `isInitialized` turns `true`. */ on(event: K, callback: EventListener): UnsubscribeFn; /** * Redraws once a draw or relink has cleared its linking state. The core draws only on model changes, and the * relinked edge is left out of the drawing while the linking state names it. The finish commands clear that state * after their last model write; ngDiagram's model notifies through an Angular effect, which runs after that, but * the default model here notifies in a microtask, which can run before it. Without this the temporary edge would * stay on screen in place of the relinked edge until the next model change. */ private redrawAfterLinking; private attach; private callSafely; } /** * Base class of the diagram API facades, giving access to the current diagram engine (ngDiagram's * `NgDiagramBaseService`). * * @internal */ declare abstract class DiagramApiBase { /** @internal */ protected readonly runtime: DiagramRuntime; /** @internal */ constructor(runtime: DiagramRuntime); /** * The current engine. Throws before the diagram has a model. * * @internal */ protected get flowCore(): FlowCore; } /** * Clipboard operations, available as `diagram.api.clipboard`. The clipboard is internal to the diagram, not the * system clipboard. * * @example * Copy the selection and paste it at a point: * ```ts * await diagram.api.clipboard.copy(); * await diagram.api.clipboard.paste({ x: 300, y: 200 }); * ``` */ declare class DiagramClipboardApi extends DiagramApiBase { /** * Copies the selection to the clipboard. * * Copying a node also copies all of its descendants (including the hidden children of a collapsed group) and * the edges between the copied nodes. Selected nodes and edges that are effectively hidden are skipped, as in * `deleteSelection()`. * * A selected edge is copied even when the nodes at its ends are not. {@link DiagramClipboardApi.paste} then * recreates it with a free end in place of each node that was not copied. * * @returns A promise that resolves once the selection has been copied. */ copy(): Promise; /** * Cuts the selection to the clipboard. It works like {@link DiagramClipboardApi.copy}: cutting a collapsed group * also cuts its hidden children, and pasting restores them. * * @returns A promise that resolves once the change has been applied to the model. Inside a transaction, it * resolves right away and the change is applied when the transaction commits. */ cut(): Promise; /** * Pastes the clipboard content, centered at a position. * * An edge end whose node was copied together with the edge connects to the pasted copy of the node. An end whose * node was **not** copied is pasted as a free end: `source` or `target` is set to `''`, and * `sourcePosition` or `targetPosition` holds the last position where the edge was attached, moved together with * the pasted content. So pasting a single edge never duplicates the connection between the original nodes. * Ends that were already free stay free. Free ends count like node positions when the content is * centered, so pasting only edges centers them at `position`. An edge whose free end has no known position (the * edge was never routed) is skipped. * * @param position - Paste position in flow coordinates. * @param options - Measurement options. Set `waitForMeasurements` to `true` to resolve only after the pasted * elements have been measured. Use this before calling `zoomToFit()` or `centerOnNode()`. * @returns A promise that resolves once the change has been applied to the model. Inside a transaction, it * resolves right away and the change is applied when the transaction commits. */ paste(position: DiagramPoint, options?: DiagramMeasurementOptions): Promise; } /** * Methods for managing group membership, available as `diagram.api.groups`. * * @example * Add two nodes to a group: * ```ts * await diagram.api.groups.addToGroup('group-1', ['node-1', 'node-2']); * ``` */ declare class DiagramGroupsApi extends DiagramApiBase { /** * Adds nodes to a group. * * @param groupId - Group node ID. * @param nodeIds - IDs of the nodes to add. * @returns A promise that resolves once the change has been applied to the model. Inside a transaction, it * resolves right away and the change is applied when the transaction commits. */ addToGroup(groupId: string, nodeIds: string[]): Promise; /** * Highlights a group, for example to show where dragged nodes would be dropped. * * @param groupId - Group node ID. * @param nodes - Nodes to highlight as part of the group. * @returns A promise that resolves once the change has been applied. */ highlightGroup(groupId: string, nodes: DiagramNode[]): Promise; /** * Clears every group highlight. * * @returns A promise that resolves once the change has been applied. */ highlightGroupClear(): Promise; /** * Removes nodes from a group. * * @param groupId - Group node ID. * @param nodeIds - IDs of the nodes to remove. * @returns A promise that resolves once the change has been applied to the model. Inside a transaction, it * resolves right away and the change is applied when the transaction commits. */ removeFromGroup(groupId: string, nodeIds: string[]): Promise; } /** * Methods for reading and changing the diagram model, available as `diagram.api.model`. * * The `nodes`, `edges` and `metadata` observables follow the model of the current diagram engine. Methods that * change the model return a promise that resolves once the change has been applied. Inside a transaction (see * {@link DiagramApi.transaction}), the promise resolves right away and the change is applied when the transaction * commits. * * @example * Add two nodes and an edge between them: * ```ts * const api = await diagram.initialized; * await api.model.addNodes([ * { id: 'a', position: { x: 0, y: 0 }, data: { label: 'A' } }, * { id: 'b', position: { x: 200, y: 0 }, data: { label: 'B' } } * ]); * await api.model.addEdges([{ id: 'a-b', source: 'a', sourcePort: 'port-right', target: 'b', targetPort: 'port-left', data: {} }]); * ``` */ declare class DiagramModelApi extends DiagramApiBase { private readonly _nodes; private readonly _edges; private readonly _metadata; private observedModel?; /** The nodes in the model. Empty before the diagram has a model. */ readonly nodes: ReadonlyObservable; /** The edges in the model. Empty before the diagram has a model. */ readonly edges: ReadonlyObservable; /** The model metadata, including the viewport. */ readonly metadata: ReadonlyObservable; /** @internal */ constructor(runtime: DiagramRuntime); /** * Returns the model adapter the diagram is using. * * @returns The current model adapter. */ getModel(): DiagramModelAdapter; /** * Serializes the model to a JSON string. Pass the parsed result to `initializeModel()` to restore it. * * @returns The model as a JSON string. */ toJSON(): string; /** * Adds edges to the diagram. * * @param edges - Edges to add. * @param options - Measurement options. Set `waitForMeasurements` to `true` to resolve only after the added * elements (for example edge labels) have been measured. * @returns A promise that resolves once the change has been applied to the model. */ addEdges(edges: DiagramEdge[], options?: DiagramMeasurementOptions): Promise; /** * Adds nodes to the diagram. * * @param nodes - Nodes to add. * @param options - Measurement options. Set `waitForMeasurements` to `true` to resolve only after the added * nodes have been measured. Use this before calling `zoomToFit()` or `centerOnNode()`. * @returns A promise that resolves once the change has been applied to the model. */ addNodes(nodes: DiagramNode[], options?: DiagramMeasurementOptions): Promise; /** * Returns an edge by ID. * * @typeParam T - Type of the edge's `data`. * @param edgeId - Edge ID. * @returns The edge, or `null` if it does not exist. */ getEdgeById(edgeId: string): DiagramEdge | null; /** * Returns the node nearest to a point, within a range. * * @typeParam T - Type of the node's `data`. * @param point - Point in flow coordinates. * @param range - Search range in flow units. * @returns The nearest node in range, or `null`. */ getNearestNodeInRange(point: DiagramPoint, range: number): DiagramNode | null; /** * Returns the port nearest to a point, within a range. * * @param point - Point in flow coordinates. * @param range - Search range in flow units. * @returns The nearest port in range, or `null`. */ getNearestPortInRange(point: DiagramPoint, range: number): DiagramPort | null; /** * Returns the free (unconnected) ends of all edges in the model. An edge with two free ends gives two * entries. Temporary and effectively hidden edges are skipped. * * @returns The free ends, each with its edge, end and anchor position. */ getDanglingEndpoints(): DiagramDanglingEndpoint[]; /** * Returns the free edge end nearest to a point, within a range. It works like * {@link DiagramModelApi.getNearestPortInRange}, but for the free ends of dangling edges. Temporary and * effectively hidden edges are skipped. * * @param point - Point in flow coordinates. * @param range - Search range in flow units. * @returns The nearest free end in range, or `null`. */ getNearestDanglingEndpointInRange(point: DiagramPoint, range: number): DiagramDanglingEndpoint | null; /** * Detaches one end of an edge, so that it becomes a free (dangling) end. * * When `position` is not specified, the end stays anchored where it is: at the current position of its * port when the edge was connected to a port, otherwise at the routed end of the edge. An end that is * already free only moves, and only when `position` is specified. * * This requires `danglingEdges.enabled` in the configuration. Otherwise the method does nothing and logs a * warning. * * @param edgeId - ID of the edge to detach. * @param end - End to detach: `'source'` or `'target'`. * @param position - Anchor position of the freed end, in flow coordinates. * @returns A promise that resolves once the change has been applied to the model. */ detachEdge(edgeId: string, end: DiagramEdgeEnd, position?: DiagramPoint): Promise; /** * Attaches one end of an edge to a node and, optionally, to one of its ports. This is the opposite of * {@link DiagramModelApi.detachEdge}. * * The same checks as for dropping a relinked edge apply: the node must exist and be visible, and the port must * exist, be visible and accept the direction of the end. The connection is then validated with * `linking.validateConnection` from the configuration, which receives the attached node as `source` or `target` * according to `end`, and a context with `reason: 'attach'`. * * @param edgeId - ID of the edge to attach. * @param end - End to attach: `'source'` or `'target'`. * @param nodeId - ID of the node to attach to. * @param portId - ID of the port to attach to. If not specified, the end is attached to the node without a * port. * @returns A promise of whether the connection was valid and applied. */ attachEdge(edgeId: string, end: DiagramEdgeEnd, nodeId: string, portId?: string): Promise; /** * Returns a node by ID. * * @typeParam T - Type of the node's `data`. * @param nodeId - Node ID. * @returns The node, or `null` if it does not exist. */ getNodeById(nodeId: string): DiagramNode | null; /** * Returns all nodes within a range of a point. * * @typeParam T - Type of the nodes' `data`. * @param point - Point in flow coordinates. * @param range - Search range in flow units. * @returns The nodes in range. */ getNodesInRange(point: DiagramPoint, range: number): DiagramNode[]; /** * Returns the edges connected to a node. * * @typeParam T - Type of the edges' `data`. * @param nodeId - Node ID. * @returns The edges that have the node as their source or target. */ getConnectedEdges(nodeId: string): DiagramEdge[]; /** * Returns the nodes connected to a node by edges. * * @typeParam T - Type of the nodes' `data`. * @param nodeId - Node ID. * @returns The nodes at the other end of the node's edges. */ getConnectedNodes(nodeId: string): DiagramNode[]; /** * Returns the source and target nodes of an edge. * * @typeParam S - Type of the source node's `data`. * @typeParam T - Type of the target node's `data`. * @param edgeId - Edge ID. * @returns The source and target nodes, or `null` if the edge does not exist. */ getNodeEnds(edgeId: string): { source: DiagramNode; target: DiagramNode; } | null; /** * Returns the direct children of a group. * * @typeParam T - Type of the nodes' `data`. * @param groupId - Group node ID. * @returns The child nodes. */ getChildren(groupId: string): DiagramNode[]; /** * Returns all descendants of a group: its children, their children and so on. * * @typeParam T - Type of the nodes' `data`. * @param groupId - Group node ID. * @returns The descendant nodes. */ getChildrenNested(groupId: string): DiagramNode[]; /** * Returns whether a node is a descendant of a group. * * @param nodeId - Node ID. * @param groupId - Group node ID. * @returns `true` if the node is a child of the group, or of one of its nested groups. */ isNestedChild(nodeId: string, groupId: string): boolean; /** * Returns the chain of groups a node belongs to. * * @typeParam T - Type of the group nodes' `data`. * @param nodeId - Node ID. * @returns The parent groups, from the closest parent to the farthest ancestor. */ getParentHierarchy(nodeId: string): DiagramGroupNode[]; /** * Returns the nodes whose rectangles intersect the bounding rectangle of a node. Use this method to detect * collisions. * * @typeParam T - Type of the nodes' `data`. * @param nodeId - ID of the node to check. * @returns The overlapping nodes. */ getOverlappingNodes(nodeId: string): DiagramNode[]; /** * Returns the nodes whose rectangles intersect the bounding rectangle of a node. Use this method to detect * collisions, for example for a node that is not in the model yet. * * @typeParam T - Type of the nodes' `data`. * @param node - Node to check. * @returns The overlapping nodes. */ getOverlappingNodes(node: DiagramNode): DiagramNode[]; /** * Returns the axis-aligned bounding rectangle of nodes and edges. * * Node bounds come from `measuredBounds`, which include the measured ports and the rotation, not from the raw * `position` and `size`. Nodes must therefore already be measured (rendered), and the result can be larger than * the node rectangles because of the ports. Edges contribute their routed `points` and their measured labels. * Effectively hidden nodes and edges (`computedHidden`) are left out. * * @param nodes - Nodes to include. * @param edges - Edges to include. * @returns The bounding rectangle. When there is nothing to measure, a zero-size rectangle at the origin. */ computePartsBounds(nodes: DiagramNode[], edges: DiagramEdge[]): DiagramRect; /** * Updates the properties of an edge. * * @param edgeId - Edge ID. * @param edge - Edge properties to change. * @param options - Measurement options. Set `waitForMeasurements` to `true` to resolve only after the * measurements the update triggers have completed. * @returns A promise that resolves once the change has been applied to the model. */ updateEdge(edgeId: string, edge: Partial, options?: DiagramMeasurementOptions): Promise; /** * Replaces the `data` of an edge. * * @typeParam T - Type of the edge's `data`. * @param edgeId - Edge ID. * @param data - New edge data. * @param options - Measurement options. Set `waitForMeasurements` to `true` to resolve only after the * measurements the update triggers (for example re-rendered edge labels) have completed. * @returns A promise that resolves once the change has been applied to the model. */ updateEdgeData(edgeId: string, data: T, options?: DiagramMeasurementOptions): Promise; /** * Updates the properties of a node. * * @param nodeId - Node ID. * @param node - Node properties to change. * @param options - Measurement options. Set `waitForMeasurements` to `true` to resolve only after the * measurements the update triggers have completed. * @returns A promise that resolves once the change has been applied to the model. */ updateNode(nodeId: string, node: Partial, options?: DiagramMeasurementOptions): Promise; /** * Replaces the `data` of a node. * * @typeParam T - Type of the node's `data`. * @param nodeId - Node ID. * @param data - New node data. * @param options - Measurement options. Set `waitForMeasurements` to `true` to resolve only after the * measurements the update triggers (for example a template resized by the new data) have completed. * @returns A promise that resolves once the change has been applied to the model. */ updateNodeData(nodeId: string, data: T, options?: DiagramMeasurementOptions): Promise; /** * Updates several nodes at once. * * @param nodes - Node changes. Each must include the node `id`. * @param options - Measurement options. Set `waitForMeasurements` to `true` to resolve only after the * measurements the update triggers have completed. * @returns A promise that resolves once the change has been applied to the model. */ updateNodes(nodes: (Pick & Partial)[], options?: DiagramMeasurementOptions): Promise; /** * Updates several edges at once. * * @param edges - Edge changes. Each must include the edge `id`. * @param options - Measurement options. Set `waitForMeasurements` to `true` to resolve only after the * measurements the update triggers have completed. * @returns A promise that resolves once the change has been applied to the model. */ updateEdges(edges: (Pick & Partial)[], options?: DiagramMeasurementOptions): Promise; /** * Deletes edges. * * @param ids - IDs of the edges to delete. * @returns A promise that resolves once the change has been applied to the model. */ deleteEdges(ids: string[]): Promise; /** * Deletes nodes. * * Deleting a group also deletes all of its descendants, and the edges connected to any deleted node are removed * as well. This is the same behavior as deleting the selection. * * @param ids - IDs of the nodes to delete. * @returns A promise that resolves once the change has been applied to the model. */ deleteNodes(ids: string[]): Promise; private observeModel; private modelListener; } /** * Methods for moving, resizing, rotating and reordering nodes, available as `diagram.api.nodes`. * * Every method returns a promise that resolves once the change has been applied to the model. Inside a * transaction (see {@link DiagramApi.transaction}), the promise resolves right away and the change is applied when * the transaction commits. * * @example * Move a node 10 units right and 20 units down: * ```ts * const node = diagram.api.model.getNodeById('node-1'); * await diagram.api.nodes.moveNodesBy([node], { x: 10, y: 20 }); * ``` */ declare class DiagramNodesApi extends DiagramApiBase { /** * Moves nodes by an offset. Edges connected to the nodes are routed again. * * @param nodes - Nodes to move. * @param delta - Offset in flow units. * @returns A promise that resolves once the change has been applied to the model. */ moveNodesBy(nodes: DiagramNode[], delta: DiagramPoint): Promise; /** * Resizes a node. The node's `autoSize` must be `false`, or `disableAutoSize` must be `true`. * * @param id - Node ID. * @param size - New size in flow units. * @param position - New position of the node, in flow coordinates. * @param disableAutoSize - Set to `true` to turn off the node's `autoSize`. * @param options - Measurement options. Set `waitForMeasurements` to `true` to resolve only after the * measurements the resize triggers have completed. * @returns A promise that resolves once the change has been applied to the model. */ resizeNode(id: string, size: DiagramSize, position?: DiagramPoint, disableAutoSize?: boolean, options?: DiagramMeasurementOptions): Promise; /** * Rotates a node to an angle. * * @param nodeId - Node ID. * @param angle - Rotation angle in degrees. * @returns A promise that resolves once the change has been applied to the model. */ rotateNodeTo(nodeId: string, angle: number): Promise; /** * Brings nodes and edges to the front (the highest z-index). * * @param nodeIds - IDs of the nodes to bring to the front. * @param edgeIds - IDs of the edges to bring to the front. * @returns A promise that resolves once the change has been applied to the model. */ bringToFront(nodeIds?: string[], edgeIds?: string[]): Promise; /** * Sends nodes and edges to the back (the lowest z-index). * * @param nodeIds - IDs of the nodes to send to the back. * @param edgeIds - IDs of the edges to send to the back. * @returns A promise that resolves once the change has been applied to the model. */ sendToBack(nodeIds?: string[], edgeIds?: string[]): Promise; } /** * Methods for reading and changing the selection, available as `diagram.api.selection`. * * Every method returns a promise that resolves once the change has been applied to the model. Inside a * transaction (see {@link DiagramApi.transaction}), the promise resolves right away and the change is applied when * the transaction commits. * * @example * Select a node and an edge, then log the selection: * ```ts * await diagram.api.selection.select(['node-1'], ['edge-1']); * console.log(diagram.api.selection.selection.value); * ``` */ declare class DiagramSelectionApi extends DiagramApiBase { /** * The selected nodes and edges. It notifies only when the selected nodes or edges change. */ readonly selection: ReadonlyObservable; /** @internal */ constructor(runtime: DiagramRuntime, model: DiagramModelApi); /** * Selects nodes and edges. * * @param nodeIds - IDs of the nodes to select. * @param edgeIds - IDs of the edges to select. * @returns A promise that resolves once the change has been applied to the model. */ select(nodeIds?: string[], edgeIds?: string[]): Promise; /** * Deselects nodes and edges. * * @param nodeIds - IDs of the nodes to deselect. * @param edgeIds - IDs of the edges to deselect. * @returns A promise that resolves once the change has been applied to the model. */ deselect(nodeIds?: string[], edgeIds?: string[]): Promise; /** * Deselects every selected node and edge. * * @returns A promise that resolves once the change has been applied to the model. */ deselectAll(): Promise; /** * Deletes the selected nodes and edges. * * @returns A promise that resolves once the change has been applied to the model. */ deleteSelection(): Promise; } /** * Methods and observables for the diagram viewport (pan and zoom), available as `diagram.api.viewport`. * * Two coordinate systems are used. The diagram's own coordinates, in which node positions are given, are called * flow coordinates. Client coordinates are the browser's viewport coordinates, as in `MouseEvent.clientX`. * * Every method that changes the viewport returns a promise that resolves once the change has been applied. Inside a * transaction (see {@link DiagramApi.transaction}), the promise resolves right away and the change is applied when * the transaction commits. * * @example * Zoom in by 20% and move the viewport: * ```ts * await diagram.api.viewport.zoom(1.2); * await diagram.api.viewport.moveViewport(100, 200); * ``` */ declare class DiagramViewportApi extends DiagramApiBase { /** The current viewport: the pan offset (`x`, `y`) and zoom `scale`. */ readonly viewport: ReadonlyObservable; /** The current zoom scale. */ readonly scale: ReadonlyObservable; /** Whether the zoom scale is below the configured maximum. `false` before the diagram has a model. */ readonly canZoomIn: ReadonlyObservable; /** Whether the zoom scale is above the configured minimum. `false` before the diagram has a model. */ readonly canZoomOut: ReadonlyObservable; /** @internal */ constructor(runtime: DiagramRuntime); /** The minimum zoom scale from the configuration. */ get minZoom(): number; /** The maximum zoom scale from the configuration. */ get maxZoom(): number; /** * Converts a client position to a flow position. * * @param clientPosition - Position in client coordinates. * @returns The position in flow coordinates. */ clientToFlowPosition(clientPosition: DiagramPoint): DiagramPoint; /** * Converts a client position to a position relative to the diagram's top-left corner. * * @param clientPosition - Position in client coordinates. * @returns The position relative to the diagram element. */ clientToFlowViewportPosition(clientPosition: DiagramPoint): DiagramPoint; /** * Converts a flow position to a client position. * * @param flowPosition - Position in flow coordinates. * @returns The position in client coordinates. */ flowToClientPosition(flowPosition: DiagramPoint): DiagramPoint; /** * Moves the viewport to a pan offset. * * @param x - Horizontal pan offset in pixels. * @param y - Vertical pan offset in pixels. * @returns A promise that resolves once the change has been applied to the model. */ moveViewport(x: number, y: number): Promise; /** * Moves the viewport by an offset. * * @param dx - Horizontal offset in pixels. * @param dy - Vertical offset in pixels. * @returns A promise that resolves once the change has been applied to the model. */ moveViewportBy(dx: number, dy: number): Promise; /** * Sets the pan offset and zoom scale of the viewport. A scale outside the configured bounds is clamped, with a * warning. * * @example * Reset the viewport to the origin at 50% zoom: * ```ts * await diagram.api.viewport.setViewport(0, 0, 0.5); * ``` * * @param x - Horizontal pan offset in pixels. * @param y - Vertical pan offset in pixels. * @param scale - Zoom scale. * @returns A promise that resolves once the change has been applied to the model. */ setViewport(x: number, y: number, scale: number): Promise; /** * Zooms the viewport by a factor. * * @param factor - Zoom factor, for example `1.1` to zoom in by 10% or `0.9` to zoom out by 10%. * @param center - Point to zoom towards. If not specified, the viewport's pan offset is used. * @returns A promise that resolves once the change has been applied to the model. */ zoom(factor: number, center?: DiagramPoint): Promise; /** * Fits the diagram content, or some of it, into the visible area. * * Always `await` the change to the model before calling this method (for example * `await api.model.deleteNodes(...)`). A change that is not awaited is not yet applied when `zoomToFit()` reads * the model, so the viewport fits the old content. * * Nodes that were just added or changed may not be measured yet. Use the `waitForMeasurements` option of the * change, or of a transaction, to fit them accurately: * ```ts * await api.model.addNodes([newNode], { waitForMeasurements: true }); * await api.viewport.zoomToFit(); * ``` * * @example * Fit everything, with custom padding, or only some nodes: * ```ts * await api.viewport.zoomToFit(); * await api.viewport.zoomToFit({ padding: [50, 100, 50, 100] }); * await api.viewport.zoomToFit({ nodeIds: ['node-1', 'node-2'] }); * ``` * * @param options - Which nodes and edges to fit, and the padding around them. * @returns A promise that resolves once the change has been applied to the model. */ zoomToFit(options?: DiagramZoomToFitOptions): Promise; /** * Centers a node in the viewport. A node that was just added may not be measured yet: add it with * `waitForMeasurements` first, as for {@link DiagramViewportApi.zoomToFit}. * * @param nodeOrId - Node, or node ID, to center on. * @returns A promise that resolves once the change has been applied to the model. */ centerOnNode(nodeOrId: string | DiagramNode): Promise; /** * Centers a rectangle in the viewport. * * @param rect - Rectangle in flow coordinates. * @returns A promise that resolves once the change has been applied to the model. */ centerOnRect(rect: DiagramRect): Promise; } /** * The public API of a `flow-ui-diagram`, available as `diagram.api` and from the `diagram.initialized` promise: * * | Member | What it does | * | --- | --- | * | `model` | Reads and changes nodes and edges | * | `nodes` | Moves, resizes, rotates and reorders nodes | * | `selection` | Reads and changes the selection | * | `viewport` | Pans, zooms and converts coordinates | * | `groups` | Manages group membership | * | `clipboard` | Copies, cuts and pastes | * | everything else | Configuration, events, middlewares, routings, linking, transactions and measurements | * * State that changes over time is returned as read-only observables: read the current value with `value`, and call * `subscribe(listener)` to be notified of changes. In a Lit element, * a {@link DiagramObserver} re-renders the element when an observable changes. * * The object is stable for the lifetime of the element, across model changes, so it is safe to keep a reference. * Most methods need the diagram engine, which exists once the diagram has a `model`: they throw before that. Wait * for `diagram.initialized` (or the `flow-ui-diagram-init` event) before using the API, so that the content has * also been measured. * * :::info * Registered middlewares and routings, and `setEventsEnabled()`, apply to the current diagram engine. Setting a new * `model` creates a new engine, so register them again. Event listeners added with * {@link DiagramApi.addEventListener} are kept. * ::: * * @example * Wait for the diagram, add a node and fit the view: * ```ts * const api = await diagram.initialized; * await api.model.addNodes([{ id: 'new', position: { x: 100, y: 100 }, data: { label: 'New node' } }], { * waitForMeasurements: true * }); * await api.viewport.zoomToFit(); * ``` */ declare class DiagramApi extends DiagramApiBase { /** Reads and changes the model: nodes, edges and metadata. */ readonly model: DiagramModelApi; /** Moves, resizes, rotates and reorders nodes. */ readonly nodes: DiagramNodesApi; /** Reads and changes the selection. */ readonly selection: DiagramSelectionApi; /** Pans and zooms the viewport and converts between client and flow coordinates. */ readonly viewport: DiagramViewportApi; /** Manages group membership. */ readonly groups: DiagramGroupsApi; /** Copies, cuts and pastes the selection. */ readonly clipboard: DiagramClipboardApi; private readonly listeners; /** @internal */ constructor(runtime: DiagramRuntime); /** * Whether the diagram is initialized: every node, port and label has been measured. It turns `true` when * `flow-ui-diagram-init` fires, and back to `false` while a new model initializes. */ get isInitialized(): ReadonlyObservable; /** * The resolved configuration, or `null` before the diagram has a model. Change it with * {@link DiagramApi.updateConfig}. */ get config(): ReadonlyObservable | null>; /** * The state of the gesture in progress (resizing, rotating, linking and so on). The diagram manages it; it * changes when a gesture starts or ends. */ get actionState(): ReadonlyObservable>; /** * Merges a partial configuration into the current configuration. * * @example * Enable debug mode: * ```ts * diagram.api.updateConfig({ debugMode: true }); * ``` * * @param config - Configuration properties to change. */ updateConfig(config: DiagramConfig): void; /** * Returns information about the environment the diagram runs in (operating system, browser and so on). * * @returns The environment information. */ getEnvironment(): DiagramEnvironmentInfo; /** * Adds a middleware to the end of the middleware chain. Use with care: a faulty middleware can slow down or * break every state update. * * @param middleware - Middleware to add. * @returns A function that removes the middleware again. */ registerMiddleware(middleware: DiagramMiddleware): () => void; /** * Removes a middleware from the middleware chain. * * @param name - Name of the middleware to remove. */ unregisterMiddleware(name: string): void; /** * Registers a custom edge routing. Edges use it when their `routing` is its name. * * @example * Register a routing that draws straight lines: * ```ts * diagram.api.registerRouting({ * name: 'straight', * computePoints: ({ sourcePoint, targetPoint }) => [sourcePoint, targetPoint], * computeSvgPath: (points) => points.map(({ x, y }, i) => `${i ? 'L' : 'M'} ${x},${y}`).join(' ') * }); * ``` * * @param routing - Routing implementation. */ registerRouting(routing: DiagramEdgeRouting): void; /** * Unregisters an edge routing. * * @param name - Name of the routing to unregister. */ unregisterRouting(name: string): void; /** * Returns the names of the registered edge routings. * * @returns The routing names. */ getRegisteredRoutings(): string[]; /** * Sets the routing of edges that do not specify one. * * @param name - Name of a registered routing. */ setDefaultRouting(name: string): void; /** * Returns the name of the routing used by edges that do not specify one. * * @returns The default routing name. */ getDefaultRouting(): string; /** * Starts drawing an edge from a node, for example from a context menu action. The free end of the edge starts * at the last known pointer position and follows the pointer until a click finishes the draw: a click on a port * connects the edge to it, as when dragging from a port. Escape cancels the draw. * * The call is ignored with a warning while another edge is being drawn or relinked, and when the node does not * exist or is hidden. * * @param node - Node the edge starts from. * @param portId - ID of the port the edge starts from. If not specified, the edge starts from the node itself. */ startLinking(node: DiagramNode, portId?: string): void; /** * Starts drawing an edge from a position on the canvas instead of from a node, for example from a context menu * action. The free end of the edge follows the pointer until a click finishes the draw: a click on a port * connects the edge to that port, and a click on empty canvas leaves both ends free, which is kept when * `danglingEdges.shouldKeepOnDrop` allows it. * * This requires `danglingEdges.enabled` in the configuration, because an edge drawn from a position has no * source node. Otherwise the call is ignored with a warning. * * @param position - Start position in flow coordinates. */ startLinkingFromPosition(position: DiagramPoint): void; /** * Aborts the gesture in progress (linking, dragging, resizing, rotating or panning). It removes the gesture's * listeners, restores the state the gesture changed (positions, size, angle and the temporary edge, but not the * viewport) and fires the matching "ended" event with the `cancelled` reason. * * It does nothing when no gesture is active or the gesture is already completing, and while a transaction is * active (with a warning). The Escape key calls it by default, through the `cancelInteraction` shortcut. * * @returns A promise of whether a gesture was aborted. */ cancelActiveInteraction(): Promise; /** * Adds a listener for a diagram engine event. Every engine event is also dispatched on the element as a * `flow-ui-diagram-*` DOM event. * * The listener can be added before the diagram has a model, and it is kept when a new model re-creates the * engine. A `diagramInit` listener runs when `isInitialized` turns `true`. * * @example * Log selection changes: * ```ts * const unsubscribe = diagram.api.addEventListener('selectionChanged', (event) => { * console.log('Selection changed', event.selectedNodes); * }); * ``` * * @param event - Event name. * @param callback - Function called with the event payload. * @returns A function that removes the listener. */ addEventListener(event: K, callback: DiagramEventListener): Unsubscribe; /** * Adds a listener for a diagram engine event that is removed after it has been called once. See * {@link DiagramApi.addEventListener}. * * @example * Run code once the diagram is initialized: * ```ts * diagram.api.addEventListenerOnce('diagramInit', (event) => console.log('Diagram initialized', event)); * ``` * * @param event - Event name. * @param callback - Function called with the event payload. * @returns A function that removes the listener. */ addEventListenerOnce(event: K, callback: DiagramEventListener): Unsubscribe; /** * Removes listeners added with {@link DiagramApi.addEventListener} or {@link DiagramApi.addEventListenerOnce}. * The `flow-ui-diagram-*` DOM events are not affected. * * @example * Remove one listener, or every listener for an event: * ```ts * diagram.api.removeEventListener('selectionChanged', onSelectionChanged); * diagram.api.removeEventListener('selectionChanged'); * ``` * * @param event - Event name. * @param callback - Listener to remove. If not specified, every listener for the event is removed. */ removeEventListener(event: K, callback?: DiagramEventListener): void; /** * Removes every listener added with {@link DiagramApi.addEventListener} or * {@link DiagramApi.addEventListenerOnce}. The `flow-ui-diagram-*` DOM events are not affected. */ removeAllEventListeners(): void; /** * Enables or disables diagram engine events. While they are disabled, neither API listeners nor the * `flow-ui-diagram-*` DOM events are called. A new model re-creates the engine with events enabled. * * @param enabled - Set to `true` to enable events, or `false` to disable them. */ setEventsEnabled(enabled: boolean): void; /** * Returns whether diagram engine events are enabled. * * @returns `true` if events are enabled. */ areEventsEnabled(): boolean; /** * Returns whether an event has listeners added with {@link DiagramApi.addEventListener} or * {@link DiagramApi.addEventListenerOnce}. * * @param event - Event name. * @returns `true` if the event has API listeners. */ hasEventListeners(event: keyof DiagramEventMap): boolean; /** * Runs a function, which may be async, in a transaction: every model change made inside it through the API is * applied at once, as one update, when the function returns (or its promise resolves). * * @example * Add nodes and edges in one update, and wait until they are measured: * ```ts * await diagram.api.transaction( * async () => { * const { nodes, edges } = await fetchDiagram(); * diagram.api.model.addNodes(nodes); * diagram.api.model.addEdges(edges); * }, * { waitForMeasurements: true } * ); * await diagram.api.viewport.zoomToFit(); * ``` * * @param callback - Function that makes the changes. * @param options - Transaction options. Set `waitForMeasurements` to `true` to resolve only after the added * or changed elements have been measured. * @returns A promise of the transaction result, which resolves once the transaction has been committed to the * model. */ transaction(callback: () => void | Promise, options?: DiagramTransactionOptions): Promise; /** * Measures diagram elements again. Without options, every node, port and edge label is measured again; * otherwise only the specified nodes (with their ports) and edge labels. Use this method when a template * changes size in a way the diagram cannot observe. * * The returned promise resolves once the measurements have settled, so the elements' `size`, `measuredPorts` * and `measuredLabels` are up to date. It never hangs: an element that delivers no new measurement (removed, * zero-size or unchanged) settles when the discovery window expires, and when nothing matching the options is * observed, it resolves immediately. Measurements running at the same time settle together. * * :::warning * Do not `await` this method inside an active transaction (measurements are applied only at commit, so the * promise resolves before the new geometry lands) or inside a middleware (the update pipeline is not * re-entrant, so the `await` deadlocks). Calling it without `await` is safe in both. * ::: * * @example * Measure one node again and wait for its new geometry: * ```ts * await diagram.api.invalidateMeasurements({ nodes: [{ nodeId: 'node-1' }] }); * ``` * * @param options - Elements to measure again. * @returns A promise that resolves once the new measurements have been applied. */ invalidateMeasurements(options?: DiagramInvalidateMeasurementsOptions): Promise; private invalidateObservedElements; private manualLinking; private addListener; private removeListener; } /** A diagram node: a simple node or a group. */ type DiagramNode = Node$1; /** A node that is not a group. */ type DiagramSimpleNode = SimpleNode; /** A group node, which other nodes can belong to. */ type DiagramGroupNode = GroupNode; /** A diagram edge. */ type DiagramEdge = Edge; /** An edge's label, as registered by `flow-ui-diagram-edge-label` and stored in the edge's `measuredLabels`. */ type DiagramEdgeLabel = EdgeLabel; /** * Where a label sits along its edge: a number from 0 (source) to 1 (target), or an absolute distance such as * `'30px'` from the source or `'-20px'` from the target. */ type DiagramEdgeLabelPosition = EdgeLabelPosition; /** A node's port, as registered by `flow-ui-diagram-port` and stored in the node's `measuredPorts`. */ type DiagramPort = Port; /** The side of a node a port is on. */ type DiagramPortSide = PortSide; /** Which point of a port lies on its node's side. */ type DiagramOriginPoint = OriginPoint; /** A side of a node, as in the `activeSides` of `flow-ui-diagram-resize-adornment`. */ type DiagramSide = Side; /** The line or corner handle a node resize is dragged by. */ type DiagramResizeDirection = ResizeDirection; /** The data an edge, node or port carries. */ type DiagramDataObject = DataObject; /** The serializable diagram content: nodes, edges and metadata. */ type DiagramModel = Model; /** The diagram metadata, including the viewport. */ type DiagramMetadata = Metadata; /** * Stores the diagram model. Create the default in-memory adapter with `initializeModel()`, or implement this * interface (for example over a state store) and prepare it with `initializeModelAdapter()`. */ type DiagramModelAdapter = ModelAdapter; /** * The diagram configuration accepted by the `config` property: any subset of {@link DiagramFlowConfig}. See the * [Configuration Reference](/flow-rdf/diagrams/configuration) for every option and its default. */ type DiagramConfig = PartialConfig; type PartialConfig = { [P in keyof T]?: T[P] extends (...args: never) => unknown ? T[P] : T[P] extends object ? PartialConfig : T[P]; }; /** * The fully resolved diagram configuration, with every default filled in: the value of `api.config`. See the * [Configuration Reference](/flow-rdf/diagrams/configuration) for every option and its default. */ type DiagramFlowConfig = FlowConfig; /** * A middleware, which can inspect and change every state update. * * @typeParam TName - Type of the middleware's `name`. */ type DiagramMiddleware = Middleware; /** An ordered list of middlewares. */ type DiagramMiddlewareChain = MiddlewareChain; /** The pan offset and zoom scale of the diagram. */ type DiagramViewport = Viewport; /** A point in flow or client coordinates. */ type DiagramPoint = Point; /** A width and height. */ type DiagramSize = Size; /** A rectangle. */ type DiagramRect = Rect; /** The state of the gesture in progress (resizing, rotating, linking and so on), from `api.actionState`. */ type DiagramActionState = ActionState; /** The environment a diagram runs in (operating system, browser and so on), from `api.getEnvironment()`. */ type DiagramEnvironmentInfo = EnvironmentInfo; /** An edge routing implementation, registered with `api.registerRouting()`. */ type DiagramEdgeRouting = EdgeRouting; /** An end of an edge: `'source'` or `'target'`. */ type DiagramEdgeEnd = EdgeEnd; /** A free (unconnected) end of a dangling edge, from `api.model.getDanglingEndpoints()`. */ type DiagramDanglingEndpoint = DanglingEndpoint; /** The `linking` part of the diagram configuration: edge drawing and relinking (validation, snapping and so on). */ type DiagramLinkingConfig = LinkingConfig; /** The `danglingEdges` part of the diagram configuration: edges with free (unconnected) ends. */ type DiagramDanglingEdgesConfig = DanglingEdgesConfig; /** What `linking.validateConnection` is validating: a draw, a relink or `api.model.attachEdge()`. */ type DiagramConnectionValidationContext = ConnectionValidationContext; /** The linking part of {@link DiagramActionState}, while an edge is drawn or relinked. */ type DiagramLinkingActionState = LinkingActionState; /** The relink part of {@link DiagramLinkingActionState}, while an edge end is dragged. */ type DiagramLinkingRelinkContext = LinkingRelinkContext; /** Why an edge draw ended without creating an edge. */ type DiagramEdgeDrawCancelReason = EdgeDrawCancelReason; /** Why an edge relink ended without changing the edge. */ type DiagramEdgeRelinkCancelReason = EdgeRelinkCancelReason; /** A keyboard, pointer or wheel shortcut in the `shortcuts` configuration; see `configureShortcuts()`. */ type DiagramShortcutDefinition = ShortcutDefinition; /** Options of `api.transaction()`. */ type DiagramTransactionOptions = TransactionOptions; /** The result of `api.transaction()`. */ type DiagramTransactionResult = TransactionResult; /** * A diagram engine event listener, added with `api.addEventListener()`. * * @typeParam T - Type of the event payload. */ type DiagramEventListener = EventListener; /** * Maps diagram engine event names to their payload types, for `api.addEventListener()`. `flow-ui-diagram` also * emits each event as a `flow-ui-diagram-*` DOM event with the payload as `detail` (for example, `selectionChanged` * as `flow-ui-diagram-selection-changed`). */ interface DiagramEventMap { /** Every node, port and edge label has been measured and the diagram is shown. */ diagramInit: DiagramInitEvent; /** Selected nodes were moved, by dragging or through the API. */ selectionMoved: DiagramSelectionMovedEvent; /** The selected nodes or edges changed. */ selectionChanged: DiagramSelectionChangedEvent; /** Selected nodes and edges were deleted. */ selectionRemoved: DiagramSelectionRemovedEvent; /** Nodes were moved into or out of a group. */ groupMembershipChanged: DiagramGroupMembershipChangedEvent; /** A node was rotated. */ selectionRotated: DiagramSelectionRotatedEvent; /** The viewport was panned or zoomed. */ viewportChanged: DiagramViewportChangedEvent; /** * The user drew an edge between two nodes. * * @deprecated Use `edgeDrawEnded` instead, which is also emitted when a draw is canceled. */ edgeDrawn: DiagramEdgeDrawnEvent; /** An edge-drawing gesture ended, whether an edge was created or not. */ edgeDrawEnded: DiagramEdgeDrawEndedEvent; /** The user started dragging an end of an existing edge. */ edgeRelinkStarted: DiagramEdgeRelinkStartedEvent; /** An edge relink gesture ended: the edge was reconnected, left dangling or reverted. */ edgeRelinkEnded: DiagramEdgeRelinkEndedEvent; /** Nodes and edges were pasted. */ clipboardPasted: DiagramClipboardPastedEvent; /** A node or group changed size. */ nodeResized: DiagramNodeResizedEvent; /** A palette item was dropped onto the diagram. */ paletteItemDropped: DiagramPaletteItemDroppedEvent; /** The user started resizing a node. */ nodeResizeStarted: DiagramNodeResizeStartedEvent; /** The user finished resizing a node. */ nodeResizeEnded: DiagramNodeResizeEndedEvent; /** The user started rotating a node. */ nodeRotateStarted: DiagramNodeRotateStartedEvent; /** The user finished rotating a node. */ nodeRotateEnded: DiagramNodeRotateEndedEvent; /** A selection gesture (click, box selection or select-all) ended. */ selectionGestureEnded: DiagramSelectionGestureEndedEvent; /** A node drag crossed the drag threshold. */ nodeDragStarted: DiagramNodeDragStartedEvent; /** The user finished dragging nodes. */ nodeDragEnded: DiagramNodeDragEndedEvent; } /** Measurement options of the API methods that change the model. */ interface DiagramMeasurementOptions { /** * Set to `true` to resolve the returned promise only once the elements the change adds or affects have been * measured. Ignored, with a warning, inside a transaction: pass it to the transaction instead. Defaults to * `false`. */ waitForMeasurements?: boolean; } /** * Which elements `api.invalidateMeasurements()` measures again. Without options, every element is measured again. */ interface DiagramInvalidateMeasurementsOptions { /** Nodes to measure again. Measuring a node again also measures its ports. */ nodes?: { nodeId: string; }[]; /** Edges whose labels to measure again. */ edges?: { edgeId: string; }[]; } /** * How pointer presses on `flow-ui-diagram` change the selection (its `selectionMode`): `'default'` replaces the * selection unless the multi-selection modifier is held, and `'toggle'` adds or removes each tapped node or edge. */ type DiagramSelectionMode = 'default' | 'toggle'; /** The selected nodes and edges, from `api.selection.selection`. */ interface DiagramSelection { /** Selected nodes. */ nodes: DiagramNode[]; /** Selected edges. */ edges: DiagramEdge[]; } /** Options of `api.viewport.zoomToFit()`. */ interface DiagramZoomToFitOptions { /** IDs of the nodes to fit. If not specified, all nodes are fitted. */ nodeIds?: string[]; /** * IDs of the edges to fit. If not specified, the edges with both ends among the fitted nodes are fitted, or all * edges when `nodeIds` is not specified either. */ edgeIds?: string[]; /** * Padding around the content in pixels, with the CSS shorthand forms: one value for every side, * `[vertical, horizontal]`, `[top, horizontal, bottom]` or `[top, right, bottom, left]`. Defaults to `50`. */ padding?: number | [number, number] | [number, number, number] | [number, number, number, number]; } /** What a node template is rendered with. */ interface DiagramNodeTemplateContext { /** The node, including runtime properties such as `selected` and `measuredBounds`. */ node: N; /** Whether the node is selected. */ selected: boolean; /** The diagram's API. */ api: DiagramApi; } /** What an edge template is rendered with. */ interface DiagramEdgeTemplateContext { /** The edge, including runtime properties such as `selected` and `points`. */ edge: E; /** Whether the edge is selected. */ selected: boolean; /** The diagram's API. */ api: DiagramApi; } /** * How a node type is rendered: either a function that returns a Lit template (or anything else Lit can render), * or the tag name of a custom element. A custom element receives the `node`, `selected` and `api` properties. * * Templates render into the light DOM of `flow-ui-diagram`, so the page or component that hosts the diagram * styles render-function templates. */ type DiagramNodeTemplate = string | ((context: DiagramNodeTemplateContext) => unknown); /** How an edge type is rendered. See {@link DiagramNodeTemplate}. */ type DiagramEdgeTemplate = string | ((context: DiagramEdgeTemplateContext) => unknown); /** * Maps node `type` values to templates, as a `Map` or a plain object. Nodes without a `type` use the default * node (or group) template; a type that is not in the map also falls back to the default, with a warning. * * @example * ```ts * diagram.nodeTemplateMap = { * note: ({ node }) => html`
${node.data.text}
`, * chart: 'my-chart-node' * }; * ``` */ type DiagramNodeTemplateMap = ReadonlyMap> | Record>; /** Maps edge `type` values to templates. See {@link DiagramNodeTemplateMap}. */ type DiagramEdgeTemplateMap = ReadonlyMap> | Record>; /** The `detail` of `flow-ui-diagram-init`: the nodes, edges and viewport once the diagram is first shown. */ interface DiagramInitEvent { /** Nodes in the diagram. */ nodes: DiagramNode[]; /** Edges in the diagram. */ edges: DiagramEdge[]; /** Viewport of the diagram. */ viewport: DiagramViewport; } /** The `detail` of `flow-ui-diagram-selection-moved`. */ type DiagramSelectionMovedEvent = SelectionMovedEvent; /** The `detail` of `flow-ui-diagram-selection-changed`. */ type DiagramSelectionChangedEvent = SelectionChangedEvent; /** The `detail` of `flow-ui-diagram-selection-removed`. */ type DiagramSelectionRemovedEvent = SelectionRemovedEvent; /** The `detail` of `flow-ui-diagram-group-membership-changed`. */ type DiagramGroupMembershipChangedEvent = GroupMembershipChangedEvent; /** The `detail` of `flow-ui-diagram-selection-rotated`. */ type DiagramSelectionRotatedEvent = SelectionRotatedEvent; /** The `detail` of `flow-ui-diagram-viewport-changed`. */ type DiagramViewportChangedEvent = ViewportChangedEvent; /** The `detail` of `flow-ui-diagram-edge-drawn`. */ type DiagramEdgeDrawnEvent = EdgeDrawnEvent; /** The `detail` of `flow-ui-diagram-edge-draw-ended`. */ type DiagramEdgeDrawEndedEvent = EdgeDrawEndedEvent; /** The `detail` of `flow-ui-diagram-edge-relink-started`. */ type DiagramEdgeRelinkStartedEvent = EdgeRelinkStartedEvent; /** The `detail` of `flow-ui-diagram-edge-relink-ended`. */ type DiagramEdgeRelinkEndedEvent = EdgeRelinkEndedEvent; /** The `detail` of `flow-ui-diagram-clipboard-pasted`. */ type DiagramClipboardPastedEvent = ClipboardPastedEvent; /** The `detail` of `flow-ui-diagram-node-resized`. */ type DiagramNodeResizedEvent = NodeResizedEvent; /** The `detail` of `flow-ui-diagram-palette-item-dropped`. */ type DiagramPaletteItemDroppedEvent = PaletteItemDroppedEvent; /** The `detail` of `flow-ui-diagram-node-resize-started`. */ type DiagramNodeResizeStartedEvent = NodeResizeStartedEvent; /** The `detail` of `flow-ui-diagram-node-resize-ended`. */ type DiagramNodeResizeEndedEvent = NodeResizeEndedEvent; /** The `detail` of `flow-ui-diagram-node-rotate-started`. */ type DiagramNodeRotateStartedEvent = NodeRotateStartedEvent; /** The `detail` of `flow-ui-diagram-node-rotate-ended`. */ type DiagramNodeRotateEndedEvent = NodeRotateEndedEvent; /** The `detail` of `flow-ui-diagram-selection-gesture-ended`. */ type DiagramSelectionGestureEndedEvent = SelectionGestureEndedEvent; /** The `detail` of `flow-ui-diagram-node-drag-started`. */ type DiagramNodeDragStartedEvent = NodeDragStartedEvent; /** The `detail` of `flow-ui-diagram-node-drag-ended`. */ type DiagramNodeDragEndedEvent = NodeDragEndedEvent; /** * The `detail` of `flow-ui-diagram-context-menu`, which `flow-ui-diagram` emits when the user asks for a context * menu: a right-click (or the platform's equivalent) on a node, an edge or the background, or a touch long press on * a node or edge. */ interface DiagramContextMenuEvent { /** The node or edge the menu is for, or `undefined` for the background. */ target?: DiagramNode | DiagramEdge; /** What the menu is for: a `'node'`, an `'edge'` or the background (`'diagram'`). */ targetType: 'node' | 'edge' | 'diagram'; /** The input that asked for the menu. A context menu key press is reported as `'mouse'`. */ pointerType: 'mouse' | 'pen' | 'touch'; /** Where the menu was asked for, in client (viewport) coordinates. Open the menu here. */ clientPosition: DiagramPoint; /** The same point in flow coordinates, for example to paste or add nodes there. */ flowPosition: DiagramPoint; /** * The native event: the `contextmenu` event, or for a long press the `touchstart` that began it (or the browser's * own `contextmenu` for the long press, on browsers that fire one first). */ originalEvent: MouseEvent | TouchEvent; } /** The `background` part of the diagram configuration: dot spacing and grid cell sizes. */ type DiagramBackgroundConfig = BackgroundConfig; /** A corner of the diagram, for the `position` of the minimap and the zoom controls. */ type DiagramPanelPosition = NgDiagramPanelPosition; /** The shape of a node in the minimap. */ type DiagramMinimapNodeShape = 'rect' | 'circle' | 'ellipse'; /** * Style overrides for a node in the minimap, returned by the minimap's `nodeStyle` function. Every property is * optional; properties that are not set use the `--flow-ui-diagram-minimap-node-*` custom properties. */ interface DiagramMinimapNodeStyle { /** The node's shape. Defaults to `'rect'`. */ shape?: DiagramMinimapNodeShape; /** The fill color. */ fill?: string; /** The stroke color. */ stroke?: string; /** The stroke width, in minimap pixels. */ strokeWidth?: number; /** The opacity, from 0 to 1. */ opacity?: number; /** * Space-separated names added to the node's class and to its `part` names (next to `node`), so page CSS can * style it with `flow-ui-diagram-minimap::part()`. */ cssClass?: string; } /** * Computes the minimap style of a node. Return `null` or `undefined` to use the defaults. * * @example * ```ts * minimap.nodeStyle = (node) => ({ * fill: node.type === 'database' ? '#4caf50' : undefined, * opacity: node.selected ? 1 : 0.6 * }); * ``` */ type DiagramMinimapNodeStyleFn = (node: DiagramNode) => DiagramMinimapNodeStyle | null | undefined; /** What a minimap node template is rendered with. */ interface DiagramMinimapNodeTemplateContext { /** The diagram node. */ node: N; /** The style from the minimap's `nodeStyle` function, or an empty object. */ nodeStyle: DiagramMinimapNodeStyle; } /** * How a node type is drawn in the minimap: a function that returns a Lit template, or the tag name of a custom * element, which receives the `node` and `nodeStyle` properties. The content is rendered as HTML inside an SVG * `foreignObject` that covers the node's bounds, so it should fill its container (`width: 100%; height: 100%`). * It renders in the minimap's shadow root, so style it inline or inside the custom element. */ type DiagramMinimapNodeTemplate = string | ((context: DiagramMinimapNodeTemplateContext) => unknown); /** * Maps node `type` values to minimap node templates, as a `Map` or a plain object. Nodes whose type is not in the * map are drawn as plain shapes (see {@link DiagramMinimapNodeStyle}). */ type DiagramMinimapNodeTemplateMap = ReadonlyMap> | Record>; /** * The base data of a palette item. Palette item data should extend it and include at least a `label`, which the * default node template shows. */ interface DiagramBasePaletteItemData { /** The display label of the item and of the node it creates. */ label: string; } /** * The node properties a palette item for a simple node carries. Dropping the item creates a node with these * properties, a new `id` and the drop point as its `position`. */ type DiagramPaletteSimpleNodeData = Pick, 'type' | 'data' | 'resizable' | 'rotatable' | 'size' | 'angle' | 'autoSize' | 'zOrder'>; /** The node properties a palette item for a group carries: {@link DiagramPaletteSimpleNodeData} plus `isGroup`. */ type DiagramPaletteGroupNodeData = DiagramPaletteSimpleNodeData & Pick; /** * An item of a diagram palette (`flow-ui-diagram-palette-item`): the node or group that dragging it onto a * diagram creates. * * @example * ```ts * const item: DiagramPaletteItem = { * type: 'task', * data: { label: 'Task' }, * size: { width: 180, height: 60 }, * autoSize: false * }; * ``` */ type DiagramPaletteItem = DiagramPaletteSimpleNodeData | DiagramPaletteGroupNodeData; /** * The `flow-ui-diagram-init` event, emitted when every node, port and label has been measured and the diagram is shown. */ type FlowUiDiagramInitEvent = CustomEvent; /** * The `flow-ui-diagram-selection-moved` event, emitted when selected nodes are moved, by dragging or through the API. */ type FlowUiDiagramSelectionMovedEvent = CustomEvent; /** The `flow-ui-diagram-selection-changed` event, emitted when the selected nodes or edges change. */ type FlowUiDiagramSelectionChangedEvent = CustomEvent; /** The `flow-ui-diagram-selection-removed` event, emitted when selected nodes and edges are deleted. */ type FlowUiDiagramSelectionRemovedEvent = CustomEvent; /** The `flow-ui-diagram-group-membership-changed` event, emitted when nodes are moved into or out of a group. */ type FlowUiDiagramGroupMembershipChangedEvent = CustomEvent; /** The `flow-ui-diagram-selection-rotated` event, emitted when a node is rotated. */ type FlowUiDiagramSelectionRotatedEvent = CustomEvent; /** The `flow-ui-diagram-viewport-changed` event, emitted when the viewport is panned or zoomed. */ type FlowUiDiagramViewportChangedEvent = CustomEvent; /** * The `flow-ui-diagram-edge-drawn` event, emitted when the user draws an edge between two nodes. Deprecated: use * `flow-ui-diagram-edge-draw-ended` instead. */ type FlowUiDiagramEdgeDrawnEvent = CustomEvent; /** * The `flow-ui-diagram-edge-draw-ended` event, emitted when an edge-drawing gesture ends, whether an edge was created * or not. */ type FlowUiDiagramEdgeDrawEndedEvent = CustomEvent; /** * The `flow-ui-diagram-edge-relink-started` event, emitted when the user starts dragging an end of an existing edge. */ type FlowUiDiagramEdgeRelinkStartedEvent = CustomEvent; /** * The `flow-ui-diagram-edge-relink-ended` event, emitted when an edge relink gesture ends: the edge is reconnected, * left dangling or reverted. */ type FlowUiDiagramEdgeRelinkEndedEvent = CustomEvent; /** The `flow-ui-diagram-clipboard-pasted` event, emitted when nodes and edges are pasted. */ type FlowUiDiagramClipboardPastedEvent = CustomEvent; /** The `flow-ui-diagram-node-resized` event, emitted when a node or group changes size. */ type FlowUiDiagramNodeResizedEvent = CustomEvent; /** The `flow-ui-diagram-palette-item-dropped` event, emitted when a palette item is dropped onto the diagram. */ type FlowUiDiagramPaletteItemDroppedEvent = CustomEvent; /** The `flow-ui-diagram-node-resize-started` event, emitted when the user starts resizing a node. */ type FlowUiDiagramNodeResizeStartedEvent = CustomEvent; /** The `flow-ui-diagram-node-resize-ended` event, emitted when the user finishes resizing a node. */ type FlowUiDiagramNodeResizeEndedEvent = CustomEvent; /** The `flow-ui-diagram-node-rotate-started` event, emitted when the user starts rotating a node. */ type FlowUiDiagramNodeRotateStartedEvent = CustomEvent; /** The `flow-ui-diagram-node-rotate-ended` event, emitted when the user finishes rotating a node. */ type FlowUiDiagramNodeRotateEndedEvent = CustomEvent; /** * The `flow-ui-diagram-selection-gesture-ended` event, emitted when a selection gesture (click, box selection or * select-all) ends. */ type FlowUiDiagramSelectionGestureEndedEvent = CustomEvent; /** The `flow-ui-diagram-node-drag-started` event, emitted when a node drag crosses the drag threshold. */ type FlowUiDiagramNodeDragStartedEvent = CustomEvent; /** The `flow-ui-diagram-node-drag-ended` event, emitted when the user finishes dragging nodes. */ type FlowUiDiagramNodeDragEndedEvent = CustomEvent; /** * The `flow-ui-diagram-context-menu` event, emitted when the user asks for a context menu on a node, an edge or the * background (a right-click, or a touch long press on a node or an edge). Calling `event.preventDefault()` will cancel * the browser's context menu. */ type FlowUiDiagramContextMenuEvent = CustomEvent; /** Every `flow-ui-diagram-*` event, by name. */ interface FlowUiDiagramEventMap { 'flow-ui-diagram-init': FlowUiDiagramInitEvent; 'flow-ui-diagram-selection-moved': FlowUiDiagramSelectionMovedEvent; 'flow-ui-diagram-selection-changed': FlowUiDiagramSelectionChangedEvent; 'flow-ui-diagram-selection-removed': FlowUiDiagramSelectionRemovedEvent; 'flow-ui-diagram-group-membership-changed': FlowUiDiagramGroupMembershipChangedEvent; 'flow-ui-diagram-selection-rotated': FlowUiDiagramSelectionRotatedEvent; 'flow-ui-diagram-viewport-changed': FlowUiDiagramViewportChangedEvent; 'flow-ui-diagram-edge-drawn': FlowUiDiagramEdgeDrawnEvent; 'flow-ui-diagram-edge-draw-ended': FlowUiDiagramEdgeDrawEndedEvent; 'flow-ui-diagram-edge-relink-started': FlowUiDiagramEdgeRelinkStartedEvent; 'flow-ui-diagram-edge-relink-ended': FlowUiDiagramEdgeRelinkEndedEvent; 'flow-ui-diagram-clipboard-pasted': FlowUiDiagramClipboardPastedEvent; 'flow-ui-diagram-node-resized': FlowUiDiagramNodeResizedEvent; 'flow-ui-diagram-palette-item-dropped': FlowUiDiagramPaletteItemDroppedEvent; 'flow-ui-diagram-node-resize-started': FlowUiDiagramNodeResizeStartedEvent; 'flow-ui-diagram-node-resize-ended': FlowUiDiagramNodeResizeEndedEvent; 'flow-ui-diagram-node-rotate-started': FlowUiDiagramNodeRotateStartedEvent; 'flow-ui-diagram-node-rotate-ended': FlowUiDiagramNodeRotateEndedEvent; 'flow-ui-diagram-selection-gesture-ended': FlowUiDiagramSelectionGestureEndedEvent; 'flow-ui-diagram-node-drag-started': FlowUiDiagramNodeDragStartedEvent; 'flow-ui-diagram-node-drag-ended': FlowUiDiagramNodeDragEndedEvent; 'flow-ui-diagram-context-menu': FlowUiDiagramContextMenuEvent; } declare global { interface GlobalEventHandlersEventMap extends FlowUiDiagramEventMap { } } /** * Removes runtime-computed properties from a node before initialization or serialization. */ type StripNodeRuntimePropertiesFn = (node: DiagramNode) => DiagramNode; /** * Removes runtime-computed properties from an edge before initialization or serialization. */ type StripEdgeRuntimePropertiesFn = (edge: DiagramEdge) => DiagramEdge; /** * Strips runtime-computed properties from a node (`selected`, `measuredPorts`, `measuredBounds`, `computedZIndex`, * `computedHidden`, `_internalId`). * * The core recomputes these during initialization, and stale values loaded from persistence make the measurement * system skip fresh DOM measurement. This is the default used by `initializeModel` and `initializeModelAdapter`. * A custom strip function should wrap this one rather than reimplement it. */ declare function stripNodeRuntimeProperties(node: DiagramNode): DiagramNode; /** * Strips runtime-computed properties from an edge (`sourcePosition`, `targetPosition`, `measuredLabels`, * `computedZIndex`, `computedHidden`, `_internalId`). * * Free ends of dangling edges are the exception: when `source` or `target` is empty, the matching `sourcePosition` * or `targetPosition` is authored data, the only record of that end, so it is kept. */ declare function stripEdgeRuntimeProperties(edge: DiagramEdge): DiagramEdge; type ChangeCallback = (data: ModelChanges) => void; /** * The default in-memory model adapter (see {@link DiagramModelAdapter}), created by `initializeModel()`. * * Change notifications are coalesced: any number of writes in one task (`FlowCore.setState()` makes three in a * row: nodes, edges, metadata) produce one `onChange` call, in a microtask, with the latest state. A write that * keeps the same array or object reference does not count as a change. * * Undo and redo are not supported; they log a warning. Supply a custom adapter for history. */ declare class DefaultDiagramModelAdapter implements DiagramModelAdapter { /** * Strips runtime-computed properties from nodes in `toJSON()`. Replacing it to keep runtime properties will * probably break the diagram when the data is loaded back. Set it through `initializeModel` options. */ stripNodeRuntimeProperties: StripNodeRuntimePropertiesFn; /** Strips runtime-computed properties from edges in `toJSON()`. See `stripNodeRuntimeProperties`. */ stripEdgeRuntimeProperties: StripEdgeRuntimePropertiesFn; private nodes; private edges; private metadata; private callbacks; private notificationScheduled; /** Bumped by `destroy()` so a notification queued before it is dropped. */ private generation; destroy(): void; getNodes(): DiagramNode[]; getEdges(): DiagramEdge[]; getMetadata(): DiagramMetadata; updateNodes(next: DiagramNode[] | ((prev: DiagramNode[]) => DiagramNode[])): void; updateEdges(next: DiagramEdge[] | ((prev: DiagramEdge[]) => DiagramEdge[])): void; updateMetadata(next: DiagramMetadata | ((prev: DiagramMetadata) => DiagramMetadata)): void; onChange(callback: ChangeCallback): void; unregisterOnChange(callback: ChangeCallback): void; undo(): void; redo(): void; toJSON(): string; private scheduleNotification; } /** * Options for {@link initializeModel} and {@link initializeModelAdapter}. */ interface InitializeModelOptions { /** * Replaces the function that strips runtime-computed properties from nodes during initialization (and, for the * model created by {@link initializeModel}, in `toJSON()`). Use at your own risk: stale runtime values * (`selected`, `measuredPorts`, `measuredBounds`, `computedZIndex`, `computedHidden`, `_internalId`) will * probably break the diagram. Prefer wrapping {@link stripNodeRuntimeProperties}. */ stripNodeRuntimeProperties?: StripNodeRuntimePropertiesFn; /** * Replaces the function that strips runtime-computed properties from edges. Use at your own risk; prefer * wrapping {@link stripEdgeRuntimeProperties}, which already keeps the free end of a dangling edge. */ stripEdgeRuntimeProperties?: StripEdgeRuntimePropertiesFn; /** Generates the internal ids. Defaults to the shared diagram environment. */ environment?: Pick; } /** * Creates the default model adapter seeded with initial nodes, edges and metadata. * * This only creates the initial model. Change it, or read current data, through the diagram API. * * @example * ```ts * diagram.model = initializeModel({ * nodes: [{ id: '1', position: { x: 0, y: 0 }, data: { label: 'Node 1' } }], * edges: [] * }); * ``` */ declare function initializeModel(model?: Partial, options?: InitializeModelOptions): DefaultDiagramModelAdapter; /** * Prepares an existing model adapter for a diagram: optionally seeds it with `model`, then strips runtime * properties from every node and edge and gives each a fresh internal id. Use it with a custom * {@link DiagramModelAdapter}. The strip options only affect initialization here; a custom adapter's `toJSON()` is its * own business. */ declare function initializeModelAdapter(adapter: A, model?: Partial, options?: InitializeModelOptions): A; /** The class {@link diagramGroupHighlighted} adds while the group is highlighted. */ declare const DIAGRAM_GROUP_HIGHLIGHT_CLASS = "flow-ui-diagram-group-highlight"; declare class DiagramGroupHighlightedDirective extends Directive { constructor(partInfo: PartInfo); render(_node: DiagramNode | undefined): symbol; update(part: ElementPart, [node]: [DiagramNode | undefined]): symbol; } /** * Gives a group template's element the built-in highlight, shown while a node is dragged over the group (the * group's `highlighted` flag, which the diagram sets). * * Apply it to the root element of a render-function group template, or to the element inside a * `flow-ui-diagram-resize-adornment`, with the template's `node`. The element gets the * `flow-ui-diagram-node-wrapper` class, plus `flow-ui-diagram-group-highlight` while the group is highlighted, and * the diagram gives it the highlight border and inner shadow (`--flow-ui-diagram-group-border-color-highlight`, * `--flow-ui-diagram-group-box-shadow-color-highlight`, `--flow-ui-diagram-group-highlight-size`). Combine it with * `diagramNodeSelected()` for the selected look. * * ```ts * const nodeTemplateMap = { * lane: ({ node }) => html` * *
${node.data.title}
*
* ` * }; * ``` */ declare const diagramGroupHighlighted: (_node: DiagramNode | undefined) => lit_html_directive_js.DirectiveResult; declare class DiagramHiddenDirective extends AsyncDirective { private element?; private hidden; private runtime?; private nodeContext?; private edgeContext?; private contextsResolved; /** While the owner's wrapper has not received its node or edge yet: waits for it. */ private ownerSubscription?; /** The owner's identity on the first write, which guards the teardown of a replaced element. */ private ownerInternalId?; private declaration?; private applyScheduled; private warnedVirtualization; private warnedOutsideTemplate; constructor(partInfo: PartInfo$1); render(_hidden?: unknown): symbol; update(part: ElementPart$1, args: [unknown?]): symbol; protected reconnected(): void; /** ngDiagram's `ngOnDestroy`: clears this template's declaration, unless the element is gone or replaced. */ protected disconnected(): void; private scheduleApply; private apply; private resolveContexts; private resolveOwner; private write; } /** * Hides the node or edge that owns the template from inside the template: the template equivalent of the model's * `hidden` flag. * * Apply it to any element of a node or edge template, in an element binding. `diagramHidden()` without an * argument hides, like a bare `hidden` attribute; `diagramHidden(false)` shows. * * ```ts * // A tag-name node template (a Lit element with a `node` property) with its own `collapsed` state * render() { * return html`
${this.node.data.title}
`; * } * ``` * * It finds its node or edge through the diagram's contexts, so it works in a render-function template as well as * in a tag-name template's shadow root. A render-function template is only called again when its node or edge * changes (or the template map is replaced), so there it suits values derived from the node or edge. * * The element is hidden when any of these applies: the model `hidden` flag, this binding, a hidden ancestor group, * or, for an edge, a hidden endpoint node. All of them feed the same effective visibility (`computedHidden`). * Hidden elements stay in the DOM with `display: none`, never hold up initialization or `waitForMeasurements`, * and are ignored by user interactions. Programmatic APIs such as `select` do not skip hidden elements. * * Use the model `hidden` flag (`api.model.updateNodes()`) to hide many elements at once, or visibility that * belongs to your data. The binding is a per-template UI state: a template that stops rendering it clears its * declaration. * * Not supported with virtualization: hiding the element would remove the template that holds the binding. With * virtualization on, the binding is ignored and a console warning is logged. Use the model `hidden` flag instead. */ declare const diagramHidden: (_hidden?: unknown) => lit_html_directive_js.DirectiveResult; /** * The middleware chain a diagram uses unless its `middlewares` property says otherwise. * * @internal */ declare const BUILTIN_MIDDLEWARES: [Middleware, Middleware<"z-index">, Middleware]; /** * The tuple type of the default middleware chain, which {@link createMiddlewares} passes to its callback. */ type DiagramMiddlewares = typeof BUILTIN_MIDDLEWARES; /** * Builds a middleware chain from the defaults: remove, replace or add middlewares. * * Use with extreme caution: removing or breaking a required middleware can break the diagram. * * @example * ```ts * diagram.middlewares = createMiddlewares((defaults) => [...defaults, loggingMiddleware]); * ``` * * @param middlewares - Receives the default chain and returns the chain to use. * @returns The middleware chain, for the diagram's `middlewares` property. */ declare function createMiddlewares(middlewares: (defaults: DiagramMiddlewares) => TMiddlewares): TMiddlewares; /** * The `DataTransfer` type a `flow-ui-diagram-palette-item` puts its item under (as JSON), next to `text/plain`. * A custom drag source can set it too: `flow-ui-diagram` accepts a drop carrying this type, or `text/plain` with * the JSON of a palette item. */ declare const DIAGRAM_PALETTE_ITEM_MIME_TYPE = "application/x-flow-ui-diagram-palette-item"; /** * Put this class on a node template's element (or any element between it and its ports) to highlight a port while * the pointer is over it. */ declare const DIAGRAM_PORT_HOVERABLE_CLASS = "flow-ui-diagram-port-hoverable"; /** * Put this class on a node template's element (or any element between it and its ports) to highlight all of the * node's ports while the pointer is over the node, except during a resize or rotation. The default node template * has it. */ declare const DIAGRAM_PORT_HOVERABLE_OVER_NODE_CLASS = "flow-ui-diagram-port-hoverable-over-node"; /** * Returns whether an end of an edge is free, that is, not connected to a node. A free end has an empty `source` or * `target`, and its position is stored in `sourcePosition` or `targetPosition`. * * @param edge - Edge to check. * @param end - End to check. If not specified, both ends are checked. * @returns `true` when the end (or, without `end`, either end) is free. */ declare function hasFreeEndpoint(edge: DiagramEdge, end?: DiagramEdgeEnd): boolean; /** * Returns whether an edge is dangling, that is, whether at least one of its ends is not connected to a node. * * @param edge - Edge to check. * @returns `true` when at least one end is free. * * @example * Find the IDs of the dangling edges in a model: * ```ts * const danglingIds = diagram.api.model.getModel().getEdges().filter(isDanglingEdge).map((edge) => edge.id); * ``` */ declare function isDanglingEdge(edge: DiagramEdge): boolean; /** * Returns the free ends of the given edges. An edge with both ends free gives two entries. Ends without a stored * position are skipped, as are temporary and hidden edges. * * Use `api.model.getDanglingEndpoints()` for the free ends of the edges in a diagram. * * @param edges - Edges to scan. * @returns The free ends, with their edge, end and position. */ declare function getDanglingEndpoints(edges: readonly DiagramEdge[]): DiagramDanglingEndpoint[]; /** * Returns the free edge end nearest to a point, within a maximum distance. Temporary and hidden edges are skipped. * * @param edges - Edges to scan. * @param point - Point to measure from, in flow coordinates. * @param range - Maximum distance from `point`. * @returns The nearest free end, or `null` when none is within `range`. */ declare function getNearestDanglingEndpointInRange(edges: readonly DiagramEdge[], point: DiagramPoint, range: number): DiagramDanglingEndpoint | null; /** * Returns the position a detached edge end stays at: the current position of the port when the end was connected to * a port, otherwise the matching end of the edge's routed path, or the center of the node as a last resort. Call it * while the node is still in the model. * * @param edge - Edge whose end is detached. * @param end - End to detach. * @param node - Node the end is connected to, if it is still in the model. * @returns The position, or `null` when none can be computed. */ declare function computeDetachAnchor(edge: DiagramEdge, end: DiagramEdgeEnd, node: DiagramNode | null | undefined): DiagramPoint | null; /** * Returns whether the user can relink an end of an edge. The edge's own `relinkable` value applies when it is set, * otherwise `defaultRelinkable`. `true` allows both ends, `'source'` or `'target'` allows only that end, and any other * value allows neither. * * @param edge - Edge to check. * @param end - End to check. * @param defaultRelinkable - The `linking.defaultRelinkable` configuration value. * @returns `true` when the user can relink that end. */ declare function isEdgeEndRelinkable(edge: DiagramEdge, end: DiagramEdgeEnd, defaultRelinkable: boolean | DiagramEdgeEnd): boolean; /** * Merges shortcut definitions into a base list. A definition replaces the base definition with the same * `actionName`, and definitions for other actions are added. Use it to build the `shortcuts` configuration. * * @param userShortcuts - Shortcut definitions to merge. * @param baseShortcuts - Shortcut definitions to merge into. Defaults to the built-in shortcuts. * @returns The merged shortcut definitions. * * @example * Move the selection up with the W key instead of the arrow key, keeping the other built-in shortcuts: * ```ts * diagram.config = { * shortcuts: configureShortcuts([{ actionName: 'keyboardMoveSelectionUp', bindings: [{ key: 'w' }] }]) * }; * ``` * * @example * Change the paste shortcut of a running diagram, keeping its other shortcuts: * ```ts * const currentShortcuts = diagram.api.config.value?.shortcuts; * const pasteShortcut = { actionName: 'paste', bindings: [{ key: 'b', modifiers: { primary: true } }] }; * diagram.api.updateConfig({ shortcuts: configureShortcuts([pasteShortcut], currentShortcuts) }); * ``` */ declare function configureShortcuts(userShortcuts: DiagramShortcutDefinition[], baseShortcuts?: DiagramShortcutDefinition[]): DiagramShortcutDefinition[]; /** The class {@link diagramNodeSelected} puts on every element it is applied to. */ declare const DIAGRAM_NODE_WRAPPER_CLASS = "flow-ui-diagram-node-wrapper"; /** The class {@link diagramNodeSelected} adds while the node is selected. */ declare const DIAGRAM_NODE_SELECTED_CLASS = "flow-ui-diagram-node-selected"; declare class DiagramNodeSelectedDirective extends Directive { constructor(partInfo: PartInfo); render(_node: DiagramNode | undefined): symbol; update(part: ElementPart, [node]: [DiagramNode | undefined]): symbol; } /** * Gives a node template's element the built-in selected look. * * Apply it to the root element of a render-function node template, or to the element inside a * `flow-ui-diagram-resize-adornment`, with the template's `node`. The element gets the `flow-ui-diagram-node-wrapper` * class, plus `flow-ui-diagram-node-selected` while the node is selected, and the diagram gives it the selected box * shadow (`--flow-ui-diagram-selected-node-box-shadow`). The diagram's styles only reach those two places; style * other elements with the class yourself, or use the template's `selected` value. * * ```ts * const nodeTemplateMap = { * card: ({ node }) => html`
${node.data.title}
` * }; * ``` * * A tag-name template receives `selected` as a property instead, and can style `:host([selected])` once it reflects * it. */ declare const diagramNodeSelected: (_node: DiagramNode | undefined) => lit_html_directive_js.DirectiveResult; /** * How an element names the diagram it works with: the `id` of a `flow-ui-diagram` (the `diagram` attribute), the * element itself (the `diagram` property), or nothing, to use the diagram the element is inside. */ type DiagramReference = string | HTMLElement | null | undefined; declare module '@shoelace-style/animations' { export type Animation = Keyframe[]; export const animations: Animation[]; export const easings: { [key: string]: string }; export const bounce: Animation; export const flash: Animation; export const headShake: Animation; export const heartBeat: Animation; export const jello: Animation; export const pulse: Animation; export const rubberBand: Animation; export const shake: Animation; export const shakeX: Animation; export const shakeY: Animation; export const swing: Animation; export const tada: Animation; export const wobble: Animation; export const backInDown: Animation; export const backInLeft: Animation; export const backInRight: Animation; export const backInUp: Animation; export const backOutDown: Animation; export const backOutLeft: Animation; export const backOutRight: Animation; export const backOutUp: Animation; export const bounceIn: Animation; export const bounceInDown: Animation; export const bounceInLeft: Animation; export const bounceInRight: Animation; export const bounceInUp: Animation; export const bounceOut: Animation; export const bounceOutDown: Animation; export const bounceOutLeft: Animation; export const bounceOutRight: Animation; export const bounceOutUp: Animation; export const fadeIn: Animation; export const fadeInBottomLeft: Animation; export const fadeInBottomRight: Animation; export const fadeInDown: Animation; export const fadeInDownBig: Animation; export const fadeInLeft: Animation; export const fadeInLeftBig: Animation; export const fadeInRight: Animation; export const fadeInRightBig: Animation; export const fadeInTopLeft: Animation; export const fadeInTopRight: Animation; export const fadeInUp: Animation; export const fadeInUpBig: Animation; export const fadeOut: Animation; export const fadeOutBottomLeft: Animation; export const fadeOutBottomRight: Animation; export const fadeOutDown: Animation; export const fadeOutDownBig: Animation; export const fadeOutLeft: Animation; export const fadeOutLeftBig: Animation; export const fadeOutRight: Animation; export const fadeOutRightBig: Animation; export const fadeOutTopLeft: Animation; export const fadeOutTopRight: Animation; export const fadeOutUp: Animation; export const fadeOutUpBig: Animation; export const flip: Animation; export const flipInX: Animation; export const flipInY: Animation; export const flipOutX: Animation; export const flipOutY: Animation; export const lightSpeedInLeft: Animation; export const lightSpeedInRight: Animation; export const lightSpeedOutLeft: Animation; export const lightSpeedOutRight: Animation; export const rotateIn: Animation; export const rotateInDownLeft: Animation; export const rotateInDownRight: Animation; export const rotateInUpLeft: Animation; export const rotateInUpRight: Animation; export const rotateOut: Animation; export const rotateOutDownLeft: Animation; export const rotateOutDownRight: Animation; export const rotateOutUpLeft: Animation; export const rotateOutUpRight: Animation; export const slideInDown: Animation; export const slideInLeft: Animation; export const slideInRight: Animation; export const slideInUp: Animation; export const slideOutDown: Animation; export const slideOutLeft: Animation; export const slideOutRight: Animation; export const slideOutUp: Animation; export const hinge: Animation; export const jackInTheBox: Animation; export const rollIn: Animation; export const rollOut: Animation; export const zoomIn: Animation; export const zoomInDown: Animation; export const zoomInLeft: Animation; export const zoomInRight: Animation; export const zoomInUp: Animation; export const zoomOut: Animation; export const zoomOutDown: Animation; export const zoomOutLeft: Animation; export const zoomOutRight: Animation; export const zoomOutUp: Animation; } /** * Returns a list of all supported animation names. * * Supply the required animation as the `name` property of the * `` component. */ declare function getAnimationNames(): string[]; /** * Returns a list of all supported easing method names. * * Supply the required easing method as the `easing` property of the * `` component. */ declare function getEasingNames(): string[]; /** * @internal * * Registers standard Chart.js components and plugins, * and sets default options. */ declare function initializeChartJs(): void; declare function registerChartComponent(...components: ChartComponentLike[]): void; interface BaseColorStopOptions { type: string; label?: string; } interface StringColorStopOptions { type: 'string'; } interface NumberColorStopOptions { type: 'number'; min?: number; max?: number; step?: number; units?: string; } interface SelectColorStopOptions { type: 'select'; options: Array; } type ColorStopOptions = StringColorStopOptions | NumberColorStopOptions | SelectColorStopOptions; interface ColorStopValue { value: string | number; color: string; options?: { regex: boolean; caseSensitive: boolean; }; } interface BaseColorMapperField { name?: string; field: string; } interface StringColorMapperField extends StringColorStopOptions, BaseColorMapperField { type: 'string'; } interface NumberColorMapperField extends NumberColorStopOptions, BaseColorMapperField { type: 'number'; } interface SelectColorMapperField extends SelectColorStopOptions, BaseColorMapperField { type: 'select'; } type ColorMapperField = StringColorMapperField | NumberColorMapperField | SelectColorMapperField; interface ColorMapperOptions { fields: Record; } interface ColorMapperValue { mode: 'fixed' | 'data-driven'; field: string | undefined; type?: 'string' | 'number' | 'select'; defaultColor?: string; colorStops: ColorStopValue[]; } declare function colorMapperValueToMaplibreExpression(value: ColorMapperValue): string; declare function escapeMaplibreString(value: string): string; /** * * The following code shows how to import FontAwesome SVG icons from the `flow-rdf-ui/icons` package and add them to the * default icon library. * ```js * // Import and register icons * import {fasHouse, fasGear, fasUser} from '@emuanalytics/flow-rdf-ui/icons'; * import {addIcons} from '@emuanalytics/flow-rdf-ui'; * addIcons({fasHouse, fasGear, fasUser}); * ``` * * Icons are registered under their camelCase name **and** kebab-case name. * Once registered, they can be used in the following way: * * ```html * * ``` * * Note that missing or mis-spelled icons will be displayed as . * * For a list of available icons, see the [FontAwesome icon gallery](https://fontawesome.com/search?o=r&m=free). */ declare const addIcons: (icons: { [name: string]: string; }) => void; type IconLibraryResolver = (name: string) => string; type IconLibraryMutator = (svg: SVGElement) => void; /** * * Use this function to add a custom icon library to the registry or override an existing one. * Provide a resolver function that returns the URL of the icon based on its name. * Optionally, provide a mutator function that modifies the SVG element of the icon. * * Two icon libraries are included by default: * - `system` (System icons used by `flow-rdf-ui` components) * - `default` (FontAwesome 6.4.2) * * To use a custom icon library, set the `library` property of the `` component * to the registered name of the library. If omitted, the `default` library is used. * * ```typescript * // Register FontAwesome icon library using SVGs from Flo.w CDN * registerIconLibrary('fa', { * resolver: (name) => { * const filename = name.replace(/^fa[rbs]-/, ''); * let folder = 'regular'; * if (name.substring(0, 4) === 'fas-') folder = 'solid'; * if (name.substring(0, 4) === 'fab-') folder = 'brands'; * return `https://flow-cdn.emu-analytics.net/icons/fontawesome-6.4.2/${folder}/${filename}.svg`; * }, * mutator: (svg) => svg.setAttribute('fill', 'currentColor') * }); * ``` * * ```html * * ``` * * @param name The name of the custom icon library. * @param options The icon library resolver and optional mutator. * @param options.resolver A function that returns the URL of given icon. * @param options.mutator An optional function that mutates the SVG element of the icon. */ declare function registerIconLibrary(name: string, options: { resolver: IconLibraryResolver; mutator?: IconLibraryMutator; }): void; /** * Removes a custom icon library from the registry. */ declare function unregisterIconLibrary(name: string): void; /** * Set the default locale used by date/time-sensitive components including * ``, `` and ``. * * The default locale is can be overridden by setting the `locale` attribute * of date/time-sensitive components. * * @param locale Locale code (e.g. `'en'`, `'en-US'`, `'es-ES'`) */ declare function setDefaultLocale(locale: string): void; /** * Set the default timezone used by date/time-sensitive components including * ``, `` and ``. * * The default timezone is can be overridden by setting the `timezone` attribute * of date/time-sensitive components. * * @param timezone Timezone (e.g. `'Europe/London'`, `'America/New_York'`) */ declare function setDefaultTimeZone(timezone: string): void; type FunctionParams = T extends (...args: infer U) => string ? U : []; interface Translation$1 { $code: string; $name: string; $dir: 'ltr' | 'rtl'; } interface DefaultTranslation extends Translation$1 { $code: string; $name: string; $dir: 'ltr' | 'rtl'; [key: string]: any; } interface ExistsOptions { lang: string; includeFallback: boolean; } /** Registers one or more translations */ declare function registerTranslation(...translation: Translation$1[]): void; /** @internal */ declare class LocalizeController$1 implements ReactiveController { host: ReactiveControllerHost & HTMLElement; constructor(host: ReactiveControllerHost & HTMLElement); hostConnected(): void; hostDisconnected(): void; /** * Gets the host element's directionality as determined by the `dir` attribute. The return value is transformed to * lowercase. */ dir(): string; /** * Gets the host element's language as determined by the `lang` attribute. The return value is transformed to * lowercase. */ lang(): string; private getTranslationData; /** Determines if the specified term exists, optionally checking the fallback translation. */ exists(key: K, options: Partial): boolean; /** Outputs a translated term. */ term(key: K, ...args: FunctionParams): string; /** Outputs a localized date in the specified format. */ date(dateToFormat: Date | string, options?: Intl.DateTimeFormatOptions): string; /** Outputs a localized number in the specified format. */ number(numberToFormat: number | string, options?: Intl.NumberFormatOptions): string; /** Outputs a localized time in relative format. */ relativeTime(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string; } /** @internal */ declare class LocalizeController extends LocalizeController$1 { } interface Translation extends Translation$1 { $code: string; $name: string; $dir: 'ltr' | 'rtl'; carousel: string; clearEntry: string; close: string; copy: string; currentValue: string; dateAfterMax: (max: string) => string; dateBeforeMin: (min: string) => string; dateRangeTooLong: (maxRange: string) => string; goToSlide: (slide: number, count: number) => string; hidePassword: string; loading: string; nextSlide: string; numOptionsSelected: (num: number) => string; previousSlide: string; progress: string; rangeEndTime: string; rangeStartTime: string; remove: string; resize: string; scrollToEnd: string; scrollToStart: string; selectAColorFromTheScreen: string; showPassword: string; slideNum: (slide: number) => string; toggleColorFormat: string; } type NoUnion = T extends U ? ([U] extends [T] ? T : never) : never; /** * @tagname flow-ui-query-builder * @summary Query builder component * * @dependency flow-ui-date-time-picker * @dependency flow-ui-divider * @dependency flow-ui-dropdown * @dependency flow-ui-icon-button * @dependency flow-ui-input * @dependency flow-ui-menu * @dependency flow-ui-menu-item * @dependency flow-ui-option * @dependency flow-ui-select * @dependency flow-ui-tool-button * @dependency flow-ui-tool-button-group * * @event flow-ui-input - Emitted when the control's value changes. * @event flow-ui-change - Emitted when the control's value changes. * @event flow-ui-select - Emitted when a custom menu item is selected. * @event flow-ui-remove - Emitted when the user attempts to remove a rule or ruleset. Calling `event.preventDefault()` will cancel the removal. * @event flow-ui-clear - Emitted when the user clears all rules from the tool menu. * @event flow-ui-apply - Emitted when the user presses 'Enter' twice in the same value input control. * * @slot label - The component's label. Alternatively, you can use the `label` attribute. * @slot help-text - Text that describes how to use the component. Alternatively, you can use the `help-text` attribute. */ declare class FlowUiQueryBuilder extends FlowRdfElement { static tagName: string; static styles: CSSResultGroup; static dependencies: (typeof FlowRdfElement)[]; private static fieldDefinitions; private _value; private enterKeyElement; /** * Register a custom field definition. * * A field definition is used to add support for a custom field type. A field type comprises: * * - a field `type` string * - a `template` function that returns the template for the field's value control * - an array of `operators` that are valid for the field * * @param type * @param fieldDefinition */ static registerFieldDefinition(type: T, fieldDefinition: FlowQueryBuilderFieldDefinition>): void; private readonly hasSlotController; /** @internal - add form control class */ class: string; /** The query builder's value object. */ value: FlowQueryBuilderRuleSet; /** The query builder's configuration object. */ config: FlowQueryBuilderConfig; /** The query builder's size. */ size: 'small' | 'medium' | 'large'; /** Disables the select control. */ disabled: boolean; /** The query builders's label. If you need to display HTML, use the `label` slot instead. */ label: string; /** The query builders's help text. If you need to display HTML, use the `help-text` slot instead. */ helpText: string; /** Display tree connector lines between query rules */ treeLines: boolean; /** @internal */ subQueryBuilder: boolean; /** Display control borders */ borders: boolean; connectedCallback(): void; /** @internal */ handleClassChange(): void; /** @internal */ handleValueChange(): void; private valueTemplateForRule; private getDefault; private handleAddRule; /** * Handles removal of a rule set (displayed by a sub-query builder) in response to a remove event. * * @param ev * @param index */ private handleRemoveRule; private handleSubQueryValueChange; private handleFieldChanged; private handleOperatorChanged; private handleConditionChange; private handleRuleMenuSelect; handleValueKeyDown(ev: KeyboardEvent): void; private handleToolbarMenuSelect; private emitValueChange; private operatorsForField; private defaultOperatorsForFieldType; private toolbarTemplate; private ruleTemplate; private ruleValueTemplate; private subQueryBuilderTemplate; private emptyRulesetTemplate; render(): lit_html.TemplateResult<1>; } /** * An abstract logical expression used to represent a user-defined query or filter. * * A rule set consists of one or more rules, where each rule is a single logical expression * of the form ` ` (for example, `name == 'John'`). A rule set combines * its rules using a condition, which can be either `and` or `or`. Rule sets can be nested to * create complex queries. * * Rule sets are typically created by the end-user using the [Query Builder](/flow-rdf/flow-rdf-ui/web-components/flow-ui-query-builder) UI component. */ interface FlowQueryBuilderRuleSet { /** The combining condition for rules in this rule set (`and` or `or`). */ condition: string; /** One or more rules or rule sets to combine into a logical expression.*/ rules: Array; } /** * A single abstract logical expression. Combined into a {@link FlowQueryBuilderRuleSet} to represent a user-defined query or filter. * * A rule is a single logical expression of the form ` ` (for example, `name == 'John'`). * * Supported operators are: * * - `=`: `` exactly equals ``. * - `!=`: `` does not equal ``. * - `<`: `` less than ``. * - `<=`: `` less than or equal to ``. * - `>`: `` greater than ``. * - `>=`: `` greater than or equal to ``. * - `in`: `` in list of values. `` is an array. (select-type fields only) * - `!in`: `` not in list of values. `` is an array. (select-type fields only) * - `contains`: `` contains substring ``. (string fields only) * - `!contains`: `` does not contain substring ``. (string fields only) * - `like`: `` matches a wildcard pattern ``. (string fields only) * - `!like`: `` does not matched a wildcard pattern ``. (string fields only) * - `regex`: `` matches a regular expression pattern ``. (string fields only) * - `!regex`: `` does not match a regular expression pattern ``. (string fields only) * - `between`: `` is greater than or equal to `[0]` and less than `[1]`. `` is an array of * two ISO8601 date/time strings. (date, time and datetime fields only) * * Wildcard patterns use `*` to match any sequence of characters and `?` to match any single character. * * Regular expressions use the JavaScript regular expression syntax. * * The string-matching operators are case-sensitive by default. Specify `caseInsensitive: true` in the {@link FlowQueryBuilderStringField} field definition to use case-insensitive matching. * */ interface FlowQueryBuilderRule { /** Field identifier. */ field?: string; /** Rule value. */ value?: ValueType; /** Rule operator. */ operator?: string; /** Set to `false` to disable a rule without removing it from its parent ruleset. */ enabled?: boolean; } /** * An individual option for a select-type Query Builder field. */ interface FlowQueryBuilderOption { /** Display name of the value. */ name: string; /** Option identifier. */ value: string; } /** The set of field definitions comprising a {@link FlowQueryBuilderConfig} definition. */ interface FlowQueryBuilderFieldMap { [key: string]: FlowQueryBuilderField; } /** * Base interface for a Query Builder field definition. The field definition specifies how to display * a field in the Query Builder UI and how to convert the user-entered value to a concrete filter expression. * * The following field types are supported: * * - `string`: A text field, displayed as an input box. Supports string-matching operators. * - `number`: A numeric field, displayed as an numeric input box with stepper controls. Supports numeric comparison operators. * - `date`: A date field, displayed as a date picker. Supports numeric comparison operators and `between`. * - `time`: A time field, displayed as a time picker. Supports numeric comparison operators and `between`. * - `datetime`: A date-time field, displayed as a date-time picker. Supports numeric comparison operators and * `between`. * - `select`: A select field, displayed as a dropdown list. Supports `in` and `!in` operators. * * In addition, all field types support equality operators (`=`, `!=`). * * @typeParam ValueType - The underlying type of the field value. */ interface FlowQueryBuilderFieldBase { /** Display name for the field. */ name: string; /** Field type: `string`, `number`, `datetime`, `date`, `time`, `select`. */ type: string; /** @internal */ value?: ValueType; /** Set to `true` to allow the field to be `null`. */ nullable?: boolean; /** Optionally override supported operators for the field. */ operators?: string[]; /** Default value for the field: static value or value-producing function. */ defaultValue?: ValueType | (() => ValueType); /** Default operator for the field. */ defaultOperator?: string; /** * Optional function to convert the user-entered value before applying a rule set converter. For the `between` * operator, the function is called separately for each end of the range. */ convertValue?: (value: ValueType) => any; /** Optional validator function to validate the user-entered value. */ validator?: (rule: FlowQueryBuilderRule) => string; } /** * Field definition for a string-type Query Builder field. */ interface FlowQueryBuilderStringField extends FlowQueryBuilderFieldBase { type: 'string'; /** Set to `true` to perform case-insensitive matching for `like` and `regex` operators. */ caseInsensitive?: boolean; } /** * Field definition for a number-type Query Builder field. */ interface FlowQueryBuilderNumberField extends FlowQueryBuilderFieldBase { type: 'number'; /** Minimum allowed value for the field. */ min?: number; /** Maximum allowed value for the field. */ max?: number; /** Step size used by the field stepper controls. */ step?: number; } /** * Base interface for date/time-type Query Builder fields. * * Note that the underlying value type for date/time fields is an ISO 8601 string. */ interface FlowQueryBuilderDateTimeFieldBase extends FlowQueryBuilderFieldBase { /** Luxon date format for display of the field value. */ dateFormat?: string | (() => string); /** Time zone specifier for display of the field value. */ timezone?: string | (() => string); /** Locale code for display of the field value. */ locale?: string | (() => string); } /** * Field definition for a datetime-type Query Builder field. */ interface FlowQueryBuilderDateTimeField extends FlowQueryBuilderDateTimeFieldBase { type: 'datetime'; } /** * Field definition for a date-type Query Builder field. */ interface FlowQueryBuilderDateField extends FlowQueryBuilderDateTimeFieldBase { type: 'date'; } /** * Field definition for a time-type Query Builder field. */ interface FlowQueryBuilderTimeField extends FlowQueryBuilderDateTimeFieldBase { type: 'time'; } /** * Field definition for a select-type Query Builder field. * * The underlying value type for select fields is a string (single-select) or an array of strings (multi-select). * When the `in` or `!in` operator is selected, the field acts as a multi-select field. For other operators, * the field acts as a single-select field. * */ interface FlowQueryBuilderSelectField extends FlowQueryBuilderFieldBase { type: 'select'; /** The selectable options for the field. */ options?: FlowQueryBuilderOption[]; } /** * Map of field type names to field definitions for expansion of type parameters. */ interface FlowQueryBuilderFieldTypeMap { string: FlowQueryBuilderStringField; number: FlowQueryBuilderNumberField; datetime: FlowQueryBuilderDateTimeField; date: FlowQueryBuilderDateField; time: FlowQueryBuilderTimeField; select: FlowQueryBuilderSelectField; } type FlowQueryBuilderFieldType = keyof FlowQueryBuilderFieldTypeMap; /** * The set of field types supported by the Query Builder. See {@link FlowQueryBuilderFieldBase}. */ type FlowQueryBuilderField = FlowQueryBuilderFieldTypeMap[keyof FlowQueryBuilderFieldTypeMap]; type FlowQueryBuilderTemplateFn = (rule: FlowQueryBuilderRule, field: FlowQueryBuilderFieldTypeMap[FieldType], qb: FlowUiQueryBuilder, update: () => void) => TemplateResult; /** * Configuration for a [Query Builder](/flow-rdf/flow-rdf-ui/web-components/flow-ui-query-builder) instance. * * The configuration specifies the set of fields available, * how to display those fields in the Query Builder UI, and how to convert the user-defined query to a concrete filter expression. */ interface FlowQueryBuilderConfig { fields: FlowQueryBuilderFieldMap; } interface FlowQueryBuilderFieldDefinition { operators: string[]; template: FlowQueryBuilderTemplateFn; } /** * Options common to all Query Builder converters. These options are used to modify how a Query Builder * ruleset is converted to one of the supported concrete filter implementations: * * - Flo.w query definition - {@link flowQueryConverter} * - JavaScript filter function - {@link javascriptFilterConverter} * - Map layer filter - {@link mapLayerFilterConverter} */ interface FlowQueryBuilderConverterOptions { /** Subset of fields defined in the query ruleset to include in the converted result. */ includeFields?: string[]; /** Subset of fields defined in the query ruleset to exclude from the converted result. */ excludeFields?: string[]; /** Map of fields to rename in the converted result. */ renameFields?: Record; /** Set to `true` to throw an exception on error. By default, the problematic Query Builder field is ignored. */ throwOnError?: boolean; } type FlowQueryBuilderConverter = (ruleSet: FlowQueryBuilderRuleSet, config: FlowQueryBuilderConfig, options?: FlowQueryBuilderConverterOptions) => R; /** * Recursively applies filters to the supplied {@link FlowQueryBuilderRuleSet} * returning a new rule set. * * This is used to sanitize user queries before they are executed by removing * excluded fields or including only the specified fields. * * Note that `includeFields` takes precedence over `excludeFields`. * * ```ts * const ruleSet = { * condition: 'and', * rules: [ { field: 'a', ... }, { field: 'b', ... }, { field: 'c', ... } ] * }; * * const filteredRuleSet = filterRuleSet(ruleSet, { excludeFields: ['b', 'c'] }); * ``` * * @param ruleset Rule set to filter * @param options Filter rules * @param options.excludeFields Fields to exclude from the {@link FlowQueryBuilderRuleSet} * @param options.includeFields Fields to include in the {@link FlowQueryBuilderRuleSet} */ declare function filterRuleSet(ruleset: FlowQueryBuilderRuleSet, options: { excludeFields?: string[]; includeFields?: string[]; }): FlowQueryBuilderRuleSet; /** * Recursively renames fields in the supplied {@link FlowQueryBuilderRuleSet} * returning a new rule set. * * This can be used to sanitize user queries before they are executed. * * ```ts * const ruleSet = { * condition: 'and', * rules: [ { field: 'a', ... }, { field: 'b', ... }, ... } ] * }; * * const renamedRuleSet = renameRuleSetFields(ruleSet, { a: 'renamedA' }); * * // renamedRuleSet = { * // condition: 'and', * // rules: [ { field: 'renamedA', ... }, { field: 'b', ... }, ... } ] * // }; * * ``` * * @param ruleset Rule set to rename. * @param replacements Set of field name replacements. * @returns A new {@link FlowQueryBuilderRuleSet} with renamed fields. */ declare function renameRuleSetFields(ruleset: FlowQueryBuilderRuleSet, replacements: Record): FlowQueryBuilderRuleSet; /** * Recursively applies a tranform function to the supplied {@link FlowQueryBuilderRuleSet} returning a new rule set. * * The transform function should expect a single `FlowQueryBuilderRule` and return: * * - the same rule unmodified or modified in place * - `undefined` to exclude the rule from the rule set * * This can be used to modify and sanitize rule sets before they are used to perform queries. * * @param ruleSet Query builder rule set to transform. * @param transformFn Transform function * @returns A new {@link FlowQueryBuilderRuleSet} with transformed rules. */ declare function transformRuleSet(ruleSet: FlowQueryBuilderRuleSet, transformFn: (rule: FlowQueryBuilderRule) => FlowQueryBuilderRule | undefined, clone?: boolean): FlowQueryBuilderRuleSet; /** * Recursively count the number of active rules in the supplied {@link FlowQueryBuilderRuleSet}. * * An 'active' rules is defined as having a valid field and being enabled. * * @param ruleSet Query builder rule set to count. * @returns The number of active rules in the rule set. */ declare function countRuleSet(ruleset: FlowQueryBuilderRuleSet): number; /** * Helper function to determine if the supplied argument is a {@link FlowQueryBuilderRule} */ declare const isRule: (r: unknown) => r is FlowQueryBuilderRule; /** * Helper function to determine if the supplied argument is a {@link FlowQueryBuilderRuleSet} */ declare const isRuleSet: (r: unknown) => r is FlowQueryBuilderRuleSet; /** * Helper function to determine if the supplied argument is a {@link FlowQueryBuilderRule} or {@link FlowQueryBuilderRuleSet} */ declare const isRuleOrRuleset: (r: unknown) => r is FlowQueryBuilderRule | FlowQueryBuilderRuleSet; /** * The start and end of a `between` rule's `[start, end]` value, each converted with the field's `convertValue` * function, if any. Gives `undefined` if the value isn't an array of two values. * * For a time field, a range that ends at 24:00 (the start of the day after its start) has no upper bound, because * every time of day is before it. The end is then `undefined`. * * @internal */ declare function betweenRuleValues(rule: FlowQueryBuilderRule, field: FlowQueryBuilderField): [any, any | undefined] | undefined; declare const converter$2: FlowQueryBuilderConverter; declare class JavaScriptFilterError extends Error { constructor(msg: string); } /** * A JavaScript function that implements the logical expression defined by a user-specified {@link FlowQueryBuilderRuleSet}. The function * accepts a data object as an argument and returns a boolean result indicating whether the data object matches the rule set. * * The filter function is typically created by using the {@link javascriptFilterConverter} converter function, prior to applying * the filter to a collection of data objects returned from a dataset query. * * The filter function has an additional `expression` property that contains the generated JavaScript expression for debugging purposes. * * @typeParam TData The type of the data object to be filtered. */ type JavaScriptFilterFn = ((data: TData) => boolean) & { /** The generated filter expression (for debugging purposes). */ expression: string; }; /** * A Query Builder converter that generates a JavaScript filter function from a user-specified {@link FlowQueryBuilderRuleSet}. * * The generated filter function accepts a data object as an argument and returns a boolean result indicating whether the data object * matches the rule set. * * This converter is typically used to apply a user-defined filter produced by the [Query Builder](/flow-rdf/flow-rdf-ui/web-components/flow-ui-query-builder) component to a collection of data objects returned * from a Flo.w reactive query. The filter is applied client-side as an alternative to server-side filtering using the {@link flowQueryConverter} converter. * * See [Examples](#filtering-reactive-query-results) for example usage. * * * ### The generated filter function * * The abstract logical expression defined by the Query Builder ruleset is compiled into a safe and efficient JavaScript function that is designed * to be passed to the Array.filter method. To view the generated JavaScript expression for debugging purposes, inspect the `expression` property * of the returned filter function. Note that the generated expression makes use of two internal helper functions: `get(prop, data)` to retrieve a * sanitized property from the data object, and `regex(regex, value, caseInsensitive)` to compile, cache and evaluate regular expressions. * * Optionally, specify a type parameter when calling {@link javascriptFilterConverter} to strongly type the `data` parameter of the resulting filter function. * * @param ruleset Flo.w Query Builder ruleset to convert * @param config Flo.w Query Builder field configuration * @param options Converter options * * @typeParam TData The type of the data object to be filtered. Optionally specify to strongly type the returned filter function. * * @returns A function that accepts a data object and returns a boolean result indicating whether the data object matches the ruleset * * @example ### Basic usage ```typescript // Query Builder field configuration const config = { fields: { name: {name: 'Area Name', type: 'string', caseInsensitive: true }, no2: {name: 'NO₂ (ppm)', type: 'number' }; } }; // Query Builder ruleset const ruleset = { "condition": "and", "rules": [ { "enabled": true, "operator": "like", "value": "bar*", "field": "name" }, { "enabled": true, "operator": ">", "value": 20, "field": "no2" } ] } const filterFn = javascriptFilterConverter(ruleset, config); filterFn.expression; // -> 'return (regex("^bar.*$", get("name", data), true)) && (get("no2", data) > 20);' const data = [...]; // Array of data objects const filteredData = data.filter(filterFn); ``` @example ### Filtering reactive query results The filter is applied to the results of a Flo.w reactive query in a computed property. The computed property will be re-evaluated whenever the query results or the filter ruleset changes. The computed property can be bound to a map data source to display the filtered results on a map. ```typescript // Reactive state store class AppState extends StateStore { ... // User-defined Query Builder ruleset bound to Query Builder component @observable.ref queryBuilderRuleSet: FlowQueryBuilderRuleSet = { condition: 'and', rules: [] }; // Reactive query airQualityQuery = query>(() => { const queryDefinition: QueryDefinition = { datasetId: 'airquality', format: 'geojson' }; return queryDefinition; }); // Application of client-side filter to query results @computed get filteredAirQuality() { // Bail out if results not yet retrieved if (!this.airQualityQuery.results) { return null; } // Apply javascript filter to features const filterFn = javascriptFilterConverter(this.queryBuilderRuleSet, queryBuilderConfig); const filteredFeatures = this.airQualityQuery.results.features.filter((f) => filterFn(f.properties)); // Note: return a new FeatureCollection rather than mutating query results in-place return featureCollection(filteredFeatures); } } ``` */ declare const converter$1: (ruleset: FlowQueryBuilderRuleSet, config: FlowQueryBuilderConfig, options?: FlowQueryBuilderConverterOptions) => JavaScriptFilterFn; declare const converter: FlowQueryBuilderConverter; /** * Registers every Flo.w RDF UI component as a custom element with its standard `flow-ui-*` tag name, except the * diagram components. * * This is a convenient way to get started. Note that it bundles every component into your application, whether or * not the application uses it. This includes large dependencies such as MapLibre GL JS (used by ``) and * Chart.js (used by ``). * * We recommend registering only the components your application uses instead. To do this, call the `define()` method * of each component class, as shown in the example below. `define()` registers the component with its standard tag * name, and also registers the elements that the component renders internally, such as the `` of a * ``. Components that you do not import are left out of the bundle. * * Elements that you place inside a component as content, such as the `` elements of a * ``, must be registered separately. It is safe to combine `define()` and `registerComponents()`. A tag * name that is already registered is left unchanged. * * The diagram components (`` and the other `flow-ui-diagram-*` elements) are not registered, so that * applications that do not use a diagram do not bundle it. Register the diagram components that your application uses * with `define()`. `FlowUiDiagram.define()` also registers the elements that the diagram's default templates render. * * `FlowRdfAngularModule.forRoot()` in the `flow-rdf-angular` support library calls this function. * * @example * Register only the button and map components: * ```typescript * import { FlowUiButton, FlowUiMap } from '@emuanalytics/flow-rdf-ui'; * * FlowUiButton.define(); * FlowUiMap.define(); * ``` * * @returns A promise that resolves when all the components have been defined. */ declare function registerComponents(): Promise; /** * Initializes the `flow-rdf-ui` library. * * Call this once when your application starts, before registering components with their `define()` method or with * {@link registerComponents}. * * This function is called automatically when using the `flow-rdf-angular` * support library. */ declare function initialize(): void; interface VirtualElement { getBoundingClientRect: () => DOMRect; contextElement?: Element; } /** * @tagname flow-ui-popup * @summary Popup is a utility that lets you declaratively anchor "popup" containers to another element. * @event flow-ui-reposition - Emitted when the popup is repositioned. This event can fire a lot, so avoid putting expensive * operations in your listener or consider debouncing it. * * @slot - The popup's content. * @slot anchor - The element the popup will be anchored to. If the anchor lives outside of the popup, you can use the * `anchor` attribute or property instead. * * @csspart arrow - The arrow's container. Avoid setting `top|bottom|left|right` properties, as these values are * assigned dynamically as the popup moves. This is most useful for applying a background color to match the popup, and * maybe a border or box shadow. * @csspart popup - The popup's container. Useful for setting a background color, box shadow, etc. * @csspart hover-bridge - The hover bridge element. Only available when the `hover-bridge` option is enabled. * * @cssproperty [--arrow-size=6px] - The size of the arrow. Note that an arrow won't be shown unless the `arrow` * attribute is used. * @cssproperty [--arrow-color] - The color of the arrow. * @cssproperty [--auto-size-available-width] - A read-only custom property that determines the amount of width the * popup can be before overflowing. Useful for positioning child elements that need to overflow. This property is only * available when using `auto-size`. * @cssproperty [--auto-size-available-height] - A read-only custom property that determines the amount of height the * popup can be before overflowing. Useful for positioning child elements that need to overflow. This property is only * available when using `auto-size`. */ declare class FlowUiPopup extends FlowRdfElement { static tagName: string; static styles: CSSResultGroup; private anchorEl; private cleanup; /** @internal A reference to the internal popup container. Useful for animating and styling the popup with JavaScript. */ popup: HTMLElement; private arrowEl; /** * The element the popup will be anchored to. If the anchor lives outside of the popup, you can provide the anchor * element `id`, a DOM element reference, or a `VirtualElement`. If the anchor lives inside the popup, use the * `anchor` slot instead. */ anchor: Element | string | VirtualElement; /** * Activates the positioning logic and shows the popup. When this attribute is removed, the positioning logic is torn * down and the popup will be hidden. */ active: boolean; /** * The preferred placement of the popup. Note that the actual placement will vary as configured to keep the * panel inside of the viewport. */ placement: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'right' | 'right-start' | 'right-end' | 'left' | 'left-start' | 'left-end'; /** * Determines how the popup is positioned. The `absolute` strategy works well in most cases, but if overflow is * clipped, using a `fixed` position strategy can often workaround it. */ strategy: 'absolute' | 'fixed'; /** The distance in pixels from which to offset the panel away from its anchor. */ distance: number; /** The distance in pixels from which to offset the panel along its anchor. */ skidding: number; /** * Attaches an arrow to the popup. The arrow's size and color can be customized using the `--arrow-size` and * `--arrow-color` custom properties. For additional customizations, you can also target the arrow using * `::part(arrow)` in your stylesheet. */ arrow: boolean; /** * The placement of the arrow. The default is `anchor`, which will align the arrow as close to the center of the * anchor as possible, considering available space and `arrow-padding`. A value of `start`, `end`, or `center` will * align the arrow to the start, end, or center of the popover instead. */ arrowPlacement: 'start' | 'end' | 'center' | 'anchor'; /** * The amount of padding between the arrow and the edges of the popup. If the popup has a border-radius, for example, * this will prevent it from overflowing the corners. */ arrowPadding: number; /** * When set, placement of the popup will flip to the opposite site to keep it in view. You can use * `flipFallbackPlacements` to further configure how the fallback placement is determined. */ flip: boolean; /** * If the preferred placement doesn't fit, popup will be tested in these fallback placements until one fits. Must be a * string of any number of placements separated by a space, e.g. "top bottom left". If no placement fits, the flip * fallback strategy will be used instead. * */ flipFallbackPlacements: string; /** * When neither the preferred placement nor the fallback placements fit, this value will be used to determine whether * the popup should be positioned using the best available fit based on available space or as it was initially * preferred. */ flipFallbackStrategy: 'best-fit' | 'initial'; /** * The flip boundary describes clipping element(s) that overflow will be checked relative to when flipping. By * default, the boundary includes overflow ancestors that will cause the element to be clipped. If needed, you can * change the boundary by passing a reference to one or more elements to this property. */ flipBoundary: Element | Element[]; /** The amount of padding, in pixels, to exceed before the flip behavior will occur. */ flipPadding: number; /** Moves the popup along the axis to keep it in view when clipped. */ shift: boolean; /** * The shift boundary describes clipping element(s) that overflow will be checked relative to when shifting. By * default, the boundary includes overflow ancestors that will cause the element to be clipped. If needed, you can * change the boundary by passing a reference to one or more elements to this property. */ shiftBoundary: Element | Element[]; /** The amount of padding, in pixels, to exceed before the shift behavior will occur. */ shiftPadding: number; /** When set, this will cause the popup to automatically resize itself to prevent it from overflowing. */ autoSize: 'horizontal' | 'vertical' | 'both'; /** Syncs the popup's width or height to that of the anchor element. */ sync: 'width' | 'height' | 'both'; /** * The auto-size boundary describes clipping element(s) that overflow will be checked relative to when resizing. By * default, the boundary includes overflow ancestors that will cause the element to be clipped. If needed, you can * change the boundary by passing a reference to one or more elements to this property. */ autoSizeBoundary: Element | Element[]; /** The amount of padding, in pixels, to exceed before the auto-size behavior will occur. */ autoSizePadding: number; /** * When a gap exists between the anchor and the popup element, this option will add a "hover bridge" that fills the * gap using an invisible element. This makes listening for events such as `mouseenter` and `mouseleave` more sane * because the pointer never technically leaves the element. The hover bridge will only be drawn when the popover is * active. */ hoverBridge: boolean; connectedCallback(): Promise; disconnectedCallback(): void; /** @internal */ updated(changedProps: Map): Promise; private handleAnchorChange; private start; private stop; /** Forces the popup to recalculate and reposition itself. */ reposition(): void; private updateHoverBridge; render(): lit_html.TemplateResult<1>; } declare global { interface HTMLElementTagNameMap { 'flow-ui-popup': FlowUiPopup; } } /** * @tagname flow-ui-tooltip * @summary Tooltips display additional information based on a specific action. * * @dependency flow-ui-popup * * @slot - The tooltip's target element. Avoid slotting in more than one element, as subsequent ones will be ignored. * @slot content - The content to render in the tooltip. Alternatively, you can use the `content` attribute. * * @event flow-ui-show - Emitted when the tooltip begins to show. * @event flow-ui-after-show - Emitted after the tooltip has shown and all animations are complete. * @event flow-ui-hide - Emitted when the tooltip begins to hide. * @event flow-ui-after-hide - Emitted after the tooltip has hidden and all animations are complete. * * @csspart base - The component's base wrapper, an `` element. * @csspart base__popup - The popup's exported `popup` part. Use this to target the tooltip's popup container. * @csspart base__arrow - The popup's exported `arrow` part. Use this to target the tooltip's arrow. * @csspart body - The tooltip's body where its content is rendered. * * @cssproperty --max-width - The maximum width of the tooltip before its content will wrap. * @cssproperty --hide-delay - The amount of time to wait before hiding the tooltip when hovering. * @cssproperty --show-delay - The amount of time to wait before showing the tooltip when hovering. * * @animation tooltip.show - The animation to use when showing the tooltip. * @animation tooltip.hide - The animation to use when hiding the tooltip. */ declare class FlowUiTooltip extends FlowRdfElement { static tagName: string; static styles: CSSResultGroup; static dependencies: (typeof FlowUiPopup)[]; private hoverTimeout; private readonly localize; /** @internal */ defaultSlot: HTMLSlotElement; /** @internal */ body: HTMLElement; /** @internal */ popup: FlowUiPopup; /** The tooltip's content. If you need to display HTML, use the `content` slot instead. */ content: string; /** * The preferred placement of the tooltip. Note that the actual placement may vary as needed to keep the tooltip * inside of the viewport. */ placement: 'top' | 'top-start' | 'top-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end'; /** Disables the tooltip so it won't show when triggered. */ disabled: boolean; /** The distance in pixels from which to offset the tooltip away from its target. */ distance: number; /** Indicates whether or not the tooltip is open. You can use this in lieu of the show/hide methods. */ open: boolean; /** The distance in pixels from which to offset the tooltip along its target. */ skidding: number; /** * Controls how the tooltip is activated. Possible options include `click`, `hover`, `focus`, and `manual`. Multiple * options can be passed by separating them with a space. When manual is used, the tooltip must be activated * programmatically. */ trigger: string; /** * Enable this option to prevent the tooltip from being clipped when the component is placed inside a container with * `overflow: auto|hidden|scroll`. Hoisting uses a fixed positioning strategy that works in many, but not all, * scenarios. */ hoist: boolean; connectedCallback(): void; firstUpdated(): void; disconnectedCallback(): void; private handleBlur; private handleClick; private handleFocus; private handleKeyDown; private handleMouseOver; private handleMouseOut; private hasTrigger; /** @internal */ handleOpenChange(): Promise; /** @internal */ handleOptionsChange(): Promise; /** @internal */ handleDisabledChange(): void; /** Shows the tooltip. */ show(): Promise; /** Hides the tooltip */ hide(): Promise; render(): lit_html.TemplateResult<1>; } declare global { interface HTMLElementTagNameMap { 'flow-ui-tooltip': FlowUiTooltip; } } /** * @tagname flow-ui-progress-ring * @summary Progress rings are used to show the progress of a determinate operation in a circular fashion. * * @slot label - A label to show inside the ring. * * @csspart base - The component's base wrapper. * @csspart label - The progress ring label. * * @cssproperty --size - The diameter of the progress ring (cannot be a percentage). * @cssproperty --track-width - The width of the track. * @cssproperty --track-color - The color of the track. * @cssproperty --indicator-width - The width of the indicator. Defaults to the track width. * @cssproperty --indicator-color - The color of the indicator. * @cssproperty --indicator-transition-duration - The duration of the indicator's transition when the value changes. */ declare class FlowUiProgressRing extends FlowRdfElement { static tagName: string; static styles: CSSResultGroup; private readonly localize; /** A custom label for assistive devices. */ label: string; /** The current progress as a percentage, 0 to 100. */ value: number; /** If the progress animation is indeterminate */ indeterminate: boolean; /** The progress ring's theme variant */ variant: 'primary' | 'secondary' | 'success' | 'neutral' | 'warning' | 'danger'; /** The progress ring's size */ size: 'small' | 'medium' | 'large'; connectedCallback(): void; render(): lit_html.TemplateResult<1>; } /** * @tagname flow-ui-button * @summary Buttons represent actions that are available to the user. * * @dependency flow-ui-icon * @dependency flow-ui-progress-ring * * @event flow-ui-blur - Emitted when the button loses focus. * @event flow-ui-focus - Emitted when the button gains focus. * @event flow-ui-invalid - Emitted when the form control has been checked for validity and its constraints aren't satisfied. * * @slot - The button's label. * @slot prefix - A presentational prefix icon or similar element. * @slot suffix - A presentational suffix icon or similar element. * * @csspart base - The component's base wrapper. * @csspart prefix - The container that wraps the prefix. * @csspart label - The button's label. * @csspart suffix - The container that wraps the suffix. * @csspart caret - The button's caret icon, an `` element. */ declare class FlowUiButton extends FlowRdfFormControl { static tagName: string; static styles: CSSResultGroup; static dependencies: (typeof FlowUiIcon | typeof FlowUiProgressRing)[]; private readonly formControlController; private readonly hasSlotController; private readonly localize; /** @internal */ button: HTMLButtonElement | HTMLLinkElement; private hasFocus; label: string; /** The button's theme variant. */ variant: 'default' | 'primary' | 'secondary' | 'success' | 'neutral' | 'warning' | 'danger' | 'text'; /** The button's size. */ size: 'small' | 'medium' | 'large'; /** Draws the button with a caret. Used to indicate that the button triggers a dropdown menu or similar behavior. */ caret: boolean; /** Disables the button. */ disabled: boolean; /** Draws the button in a loading state. */ loading: boolean; /** Draws an outlined button. */ outline: boolean; /** Draws a pill-style button with rounded edges. */ pill: boolean; /** * Draws a circular FAB. When this attribute is present, the button expects a single `` in the * default slot. */ fabCircle: boolean; /** * Draws a square FAB. When this attribute is present, the button expects a single `` in the * default slot. */ fabSquare: boolean; /** * The type of button. Note that the default value is `button` instead of `submit`, which is opposite of how native * `