# Foblex Flow — Full LLM-readable reference > The most adopted node editor library for Angular (by npm weekly downloads) — Angular-native, for production workflow builders, AI pipelines, and interactive diagram editors. MIT licensed. This file concatenates the canonical content LLMs need to answer substantive questions about Foblex Flow without fetching individual URLs. --- ## 1. What Foblex Flow is Foblex Flow is an Angular library (not a framework, not a platform) that provides primitives for building node-based user interfaces — workflow builders, AI pipeline tools, visual editors, and interactive diagrams. It is distributed as the npm package `@foblex/flow` under the MIT license. The current 19.x line has Angular `>=17.3.0` peer dependencies (older Angular applications must pin an earlier Foblex Flow line). It is not a React wrapper and not framework-agnostic — it is built from the ground up on Angular primitives: standalone components, signals, change detection, and SSR. **In plain terms**: if you need your users to drag nodes around a canvas, draw connections between them, edit the graph, and ship it inside an Angular app, Foblex Flow is the rendering and interaction layer you embed. Your domain rules, persistence, and backend integration stay under your control. **What it is NOT**: - Not a charting package or a static SVG helper. - Not a read-only graph renderer. - Not a hosted workflow product. - Not a framework-agnostic graph engine wrapped for Angular. ## 2. Project facts - **Package**: `@foblex/flow` on npm — https://www.npmjs.com/package/@foblex/flow - **Current version**: v19.1.6 (July 2026) - **Current download data**: https://www.npmjs.com/package/@foblex/flow - **GitHub**: https://github.com/Foblex/f-flow - **License**: MIT - **Supports**: Angular 17.3+ ## 3. Core mental model - Classic mode is the default: your app owns graph records, validates and handles interaction events, and Angular rerenders its state. - Managed mode is opt-in through `provideFFlow(withFlowState())`: `FFlowState` maintains typed records and undo/redo for supported gestures. - In both modes your app defines domain fields and owns validation policy, permissions, persistence, backend integration, and business meaning. - Both modes render state through normal Angular templates. - Connections are connector-to-connector (`fSourceId` → `fTargetId` referencing `fConnectorId`), not generic node-to-node edges. - Do NOT assume React Flow style APIs such as [nodes], [edges], setNodes(), addEdge(). - Diagnostics use stable FFxxxx codes (see https://flow.foblex.com/docs/errors). Dev-mode warnings cover unresolved connection ids (FF1001), zero-height hosts (FF1002), and FF1004–FF1009; they are stripped from production builds. A connector outside a node throws FF1003 in every build. - Nested control flow needs ngProjectAs: nodes/groups/connections inside nested @if/@for blocks (or a wrapper element) are NOT projected into — they render detached and invisible with no error (dev mode warns FF1004). Wrap the block with (groups: "[fGroups]", connections: "[fConnections]"). A single top-level @for/@if directly inside is fine. ## 4. Installation ```bash ng add @foblex/flow ``` For Nx workspaces: ```bash nx g @foblex/flow:add ``` Manual installation: ```bash npm install @foblex/flow @foblex/platform@^1.0.4 @foblex/mediator@^1.1.3 @foblex/2d@^1.2.2 @foblex/utils@^1.1.1 ``` Include the default theme in angular.json: ```json "styles": [ "src/styles.scss", "node_modules/@foblex/flow/styles/default.scss" ] ``` ### Peer Dependencies ```json { "@angular/common": ">=17.3.0", "@angular/core": ">=17.3.0", "@foblex/platform": "^1.0.4", "@foblex/mediator": "^1.1.3", "@foblex/2d": "^1.2.2", "@foblex/utils": "^1.1.1" } ``` ### Module Import For standalone components (recommended): ```typescript import { FFlowModule } from '@foblex/flow'; @Component({ standalone: true, imports: [FFlowModule], }) ``` For module-based apps: ```typescript import { FFlowModule } from '@foblex/flow'; @NgModule({ imports: [FFlowModule], }) ``` ### Angular Version Compatibility | @foblex/flow | Published Angular peer range | |---------------|------------------------------| | 19.x | >=17.3.0 | | 18.5–18.6 | >=17.3.0 | | 18.0–18.4 | >=15.0.0 | | 17.9.5 | >=15.0.0 | | 16.0.0 | >=12.0.0 | | 12.6.3 | >=12.0.0 | The current repository uses Angular 20.3. A peer range is not evidence that every future Angular major has already been tested; check current CI and release notes when upgrading. ## 5. Minimal working example ```html
Source Node
Target Node
``` ```typescript import { Component } from '@angular/core'; import { FFlowModule } from '@foblex/flow'; @Component({ selector: 'app-my-flow', standalone: true, imports: [FFlowModule], templateUrl: './my-flow.component.html', }) export class MyFlowComponent {} ``` ## 6. Typical use cases - **Workflow builders** — define steps, conditions, handlers - **AI agent and pipeline canvases** — chain prompts, tools, retrievers - **Call-flow and IVR editors** — contact-center routing - **Low-code platforms** — visual program composition - **Schema and ER-diagram editors** — relational design tools - **BPMN and process diagrams** — business-process editing - **UML / sequence / class diagrams** — software design tools ## 7. React Flow vs Foblex Flow If you're in an Angular codebase and evaluating both: | | Foblex Flow | React Flow + angular-react wrapper | |---|---|---| | Framework primitives | Angular standalone components, signals, DI | React components + glue layer | | State model | Classic app-owned records or optional typed FFlowState | React hooks bridged into Angular | | SSR | Angular Universal supported | Requires extra bridging | | Bundle size impact | Angular-only, no React runtime | Adds React + React-DOM + wrapper | | Community size | Smaller, focused on Angular | Larger, React-first | | Undo/redo, virtualization, workers | All present | All present | | License | MIT | MIT core + optional Pro subscription | **When to pick React Flow instead**: you're in a React codebase; you need the larger React-ecosystem community; you want a turnkey paid commercial tier (React Flow Pro). **When to pick Foblex Flow**: you're shipping an Angular app and don't want to drag React into it; you want SSR without bridging; you want either an event-driven app-owned model or an opt-in typed Angular state layer. --- ## 8. API Reference ### f-flow (FFlowComponent) Root container required for every diagram. Bootstraps runtime and provides integration point for all extensions. Selector: `f-flow` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fFlowId | InputSignal\ | f-flow-{id} | Unique flow identifier | | fCache | InputSignal\ | false | Enable the optional geometry cache; measure before enabling | #### Outputs | Output | Type | Description | |--------|------|-------------| | fNodesRendered | OutputEmitterRef\ | Emits when render cycle finishes nodes/groups | | fFullRendered | OutputEmitterRef\ | Emits after full render including connections | | fLoaded | OutputEmitterRef\ | Deprecated alias for fFullRendered | #### Methods | Method | Signature | Description | |--------|-----------|-------------| | redraw | redraw(): void | Request a connection redraw | | reset | reset(): void | Resets internal state; re-emits on next render | | getNodesBoundingBox | getNodesBoundingBox(): IRect \| null | Returns bounding box of all nodes/groups | | getSelection | getSelection(): ICurrentSelection | Returns selected node/group/connection ids | | getPositionInFlow | getPositionInFlow(position: IPoint): IRect | Converts viewport point to flow coordinates | | getState | getState(options?: IFFlowStateOptions): IFFlowState | Exports full flow state; `{ measuredSize: true }` includes measured node sizes | | selectAll | selectAll(): void | Selects all items | | select | select(nodesAndGroups: string[], connections: string[], isSelectedChanged?: boolean): void | Selects specific items | | clearSelection | clearSelection(): void | Clears all selection | #### CSS Classes `.f-component`, `.f-flow` --- ### f-canvas (FCanvasComponent) Viewport layer that applies pan and zoom transforms. All diagram content must be inside f-canvas. Selector: `f-canvas` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | position | InputSignal\ | { x: 0, y: 0 } | Canvas pan position | | scale | InputSignal\ | 1 | Canvas zoom scale | | debounceTime | InputSignal\ | 0 | Debounce ms for fCanvasChange | | fLayers | EFCanvasLayer[] | [GROUPS, CONNECTIONS, NODES] | Stacking order of the built-in layers, bottom to top; app-wide default via provideFFlow(withFCanvas({ layers })) | #### Outputs | Output | Type | Description | |--------|------|-------------| | fCanvasChange | OutputEmitterRef\ | Emits on position or scale change | #### Methods | Method | Signature | Description | |--------|-----------|-------------| | redraw | redraw(): void | Force immediate redraw | | getPosition | getPosition(): IPoint | Get current pan position | | getScale | getScale(): number | Get current zoom scale | | setScale | setScale(scale: number, toPosition?: IPoint): void | Set zoom with optional pivot point | | resetScale | resetScale(): void | Reset zoom to 1 | | resetScaleAndCenter | resetScaleAndCenter(animated?: boolean, emitCanvasChange?: boolean): void | Reset zoom and center content; optionally suppress `fCanvasChange` | | resetScaleAndCenterGroupOrNode | resetScaleAndCenterGroupOrNode(id: string, animated?: boolean, emitCanvasChange?: boolean): void | Reset zoom to 1 and center on a specific item; optionally suppress `fCanvasChange` | | fitToScreen | fitToScreen(padding?: IPoint, animated?: boolean, emitCanvasChange?: boolean): void | Fit all content in viewport; optionally suppress `fCanvasChange` | | centerGroupOrNode | centerGroupOrNode(id: string, animated?: boolean, emitCanvasChange?: boolean): void | Center on a specific item while preserving zoom; optionally suppress `fCanvasChange` | #### CSS Classes `.f-canvas`, `.f-connections-container`, `.f-canvas-dragging` --- ### fNode (FNodeDirective) Turns an HTML element into a draggable, selectable node. Apply as an attribute directive. Selector: `[fNode]` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fNodeId | InputSignal\ | f-node-{id} | Unique node identifier | | fNodeParentId | InputSignal\ | null | Parent group/node id for hierarchy | | fNodePosition | ModelSignal\ | { x: 0, y: 0 } | Node position in flow coordinates | | fNodeSize | InputSignal\ | undefined | Optional fixed size override | | fNodeRotate | ModelSignal\ | 0 | Rotation angle in degrees | | fConnectOnNode | InputSignal\ | true | Allow connection drop on node body | | fMinimapClass | InputSignal\ | [] | Extra CSS classes for minimap representation | | fNodeDraggingDisabled | InputSignal\ | false | Disable node dragging | | fNodeSelectionDisabled | InputSignal\ | false | Disable node selection | | fIncludePadding | InputSignal\ | true | Include CSS padding in bounds calculation | | fAutoExpandOnChildHit | InputSignal\ | false | Auto-expand parent when child dragged inside | | fAutoSizeToFitChildren | InputSignal\ | false | Auto-resize to fit all child nodes | #### Outputs | Output | Type | Description | |--------|------|-------------| | fNodePositionChange | OutputEmitterRef\ | Emits when position is finalized after drag | | fNodeRotateChange | OutputEmitterRef\ | Emits when rotation is finalized | | fNodeSizeChange | OutputEmitterRef\ | Emits when size is finalized after resize | #### Methods | Method | Signature | Description | |--------|-----------|-------------| | refresh | refresh(): void | Force geometry recalculation | #### CSS Classes `.f-node`, `.f-selected`, `.f-node-dragging-disabled`, `.f-node-selection-disabled` --- ### fGroup (FGroupDirective) Container element for organizing nodes. Behaves like a node with position, size, rotation, selection, and drag. Selector: `[fGroup]` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fGroupId | string | f-group-{id} | Unique group identifier | | fGroupParentId | string \| null | null | Parent group/node id | | fGroupPosition | IPoint | { x: 0, y: 0 } | Group position (model binding) | | fGroupSize | ISize \| undefined | undefined | Container size | | fGroupRotate | number | 0 | Rotation degrees (model binding) | | fConnectOnNode | boolean | true | Allow connection drop on group | | fMinimapClass | string \| string[] | [] | CSS classes for minimap | | fGroupDraggingDisabled | boolean | false | Disable group dragging | | fGroupSelectionDisabled | boolean | false | Disable group selection | | fIncludePadding | boolean | true | Include padding in bounds | | fAutoExpandOnChildHit | boolean | false | Auto-expand on child drag | | fAutoSizeToFitChildren | boolean | false | Auto-resize to fit children | #### Outputs | Output | Type | Description | |--------|------|-------------| | fGroupPositionChange | OutputEmitterRef\ | Position finalized | | fGroupRotateChange | OutputEmitterRef\ | Rotation finalized | | fGroupSizeChange | OutputEmitterRef\ | Size finalized | #### Methods | Method | Signature | Description | |--------|-----------|-------------| | refresh | refresh(): void | Force geometry recalculation | #### CSS Classes `.f-group`, `.f-selected`, `.f-group-dragging-disabled`, `.f-group-selection-disabled` --- ### fConnector (FConnectorDirective) Unified connector that replaces `fNodeOutput`, `fNodeInput`, and `fNodeOutlet`. One id per connector; behavior is controlled by `fConnectorType`. Selector: `[fConnector]` ```ts type FConnectorType = 'source' | 'target' | 'source-target' | 'outlet'; ``` - `source` — can start a connection and be used as `fSourceId` - `target` — can accept a connection and be used as `fTargetId` - `source-target` (default) — one id supports both behaviors - `outlet` — shared start surface; the emitted `FCreateConnectionEvent.sourceId` is the resolved real source connector id from the same node #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fConnectorId | InputSignal\ | f-connector-{id} | Unique connector id | | fConnectorType | InputSignal\ | source-target | Connector behavior | | fConnectorDisabled | InputSignal\ | false | Disable this connector | | fConnectorMultiple | InputSignal\ | true | Allow multiple connections | | fConnectorCategory | InputSignal\ | undefined | Optional category for connection rules | | fConnectorConnectableSide | EFConnectableSide | AUTO | Preferred dock side | | fConnectorSelfConnectable | boolean | true | Allow same-node connection (source/source-target) | | fCanBeConnectedTo | InputSignal\ | [] | Allow-list of target ids or categories (replaces fCanBeConnectedInputs) | | fConnectionFromOutlet | InputSignal\ | false | Outlet only: draw the preview line from the outlet rect | #### Host Attributes `data-f-connector-id`, `data-f-connector-type` #### CSS Classes `.f-connector`, `.f-connector-source`, `.f-connector-target`, `.f-connector-source-target`, `.f-connector-outlet`, `.f-connector-disabled`, `.f-connector-connected`, `.f-connector-connectable`, `.f-connector-not-connectable`, `.f-connector-multiple` ```html
``` --- ### fNodeOutput (FNodeOutputDirective) **Deprecated:** use `fConnector` with `fConnectorType="source"`. Marks an element as an output connector — the source endpoint for connections. Selector: `[fNodeOutput]` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fOutputId | InputSignal\ | f-node-output-{id} | Unique connector id | | fOutputMultiple | boolean | false | Allow multiple outgoing connections | | fOutputDisabled | boolean | false | Disable this connector | | fOutputConnectableSide | EFConnectableSide | AUTO | Preferred dock side (auto/top/right/bottom/left) | | isSelfConnectable | boolean | true | Allow same-node connection | | fCanBeConnectedInputs | string[] | [] | Allow-list of target input ids or categories | #### CSS Classes `.f-node-output`, `.f-node-output-multiple`, `.f-node-output-disabled`, `.f-node-output-self-connectable`, `.f-node-output-connected`, `.f-node-output-not-connectable` --- ### fNodeInput (FNodeInputDirective) **Deprecated:** use `fConnector` with `fConnectorType="target"`. Marks an element as an input connector — the target endpoint for connections. Selector: `[fNodeInput]` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fInputId | InputSignal\ | f-node-input-{id} | Unique connector id | | fInputCategory | InputSignal\ | undefined | Optional category for connection rules | | fInputMultiple | InputSignal\ | true | Allow multiple incoming connections | | fInputDisabled | InputSignal\ | false | Disable this connector | | fInputConnectableSide | EFConnectableSide | AUTO | Preferred dock side | #### CSS Classes `.f-node-input`, `.f-node-input-multiple`, `.f-node-input-disabled`, `.f-node-input-connected`, `.f-node-input-not-connectable` --- ### fNodeOutlet (FNodeOutletDirective) **Deprecated:** use `fConnector` with `fConnectorType="outlet"`. Single shared start-connection point for nodes with multiple outputs. Selector: `[fNodeOutlet]` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fOutletId | string | f-node-outlet-{id} | Unique outlet id | | fOutletDisabled | boolean | false | Disable interactions | | isConnectionFromOutlet | boolean | false | Draw line from outlet edge | | fCanBeConnectedInputs | string[] | [] | Allow-list of targets | #### CSS Classes `.f-node-outlet`, `.f-node-outlet-disabled` --- ### f-connection (FConnectionComponent) Renders an SVG connection edge between source and target connectors. Selector: `f-connection` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fConnectionId | InputSignal\ | f-connection-{id} | Unique connection id | | fSourceId | InputSignal\ | '' | Source connector id; must resolve for the connection to render | | fTargetId | InputSignal\ | '' | Target connector id; must resolve for the connection to render | | fSourceSide | InputSignal\ | DEFAULT | Override source dock side | | fTargetSide | InputSignal\ | DEFAULT | Override target dock side | | fOutputId | InputSignal\ | '' | Deprecated: use fSourceId | | fInputId | InputSignal\ | '' | Deprecated: use fTargetId | | fOutputSide | InputSignal\ | DEFAULT | Deprecated: use fSourceSide | | fInputSide | InputSignal\ | DEFAULT | Deprecated: use fTargetSide | | fReassignDisabled | InputSignal\ | false | Disable drag-to-reassign | | fSelectionDisabled | InputSignal\ | false | Disable selection | | fBehavior | InputSignal\ | FIXED | Connection behavior (FIXED, FIXED_CENTER, or FLOATING) | | fType | InputSignal\ | STRAIGHT | Visual type (STRAIGHT, BEZIER, SEGMENT, ADAPTIVE_CURVE, or custom) | | fOffset | InputSignal\ | 12 | Min straight length before curve | | fRadius | InputSignal\ | 8 | Radius for rounded corners | | fReassignableStart | InputSignal\ | false | Enable source/start endpoint reassignment | #### Content Projection - `f-connection-gradient` — Projected gradient for stroke colors - `f-connection-waypoints` — Editable intermediate points - `f-connection-marker-arrow` / `f-connection-marker-circle` — SVG markers #### CSS Classes `.f-connection`, `.f-selected`, `.f-connection-selection-disabled`, `.f-connection-reassign-disabled`, `.f-connection-path`, `.f-connection-selection`, `.f-connection-drag-handle`, `.f-connection-content` --- ### f-connection-for-create (FConnectionForCreateComponent) Preview line shown during drag-to-create interaction. Selector: `f-connection-for-create` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fRadius | number | 8 | Corner radius | | fOffset | number | 12 | Distance from connector | | fBehavior | EFConnectionBehavior | FIXED | Connection behavior | | fType | EFConnectionType | STRAIGHT | Visual type | | fInputSide | EFConnectionConnectableSide | DEFAULT | Input side hint | | fOutputSide | EFConnectionConnectableSide | DEFAULT | Output side hint | --- ### f-snap-connection (FSnapConnectionComponent) Temporary snap helper shown during connection create/reassign when near a valid target. Selector: `f-snap-connection` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fSnapThreshold | number | 20 | Snap activation distance in pixels | | fRadius | number | 8 | Corner radius | | fOffset | number | 12 | Distance from connector | | fBehavior | EFConnectionBehavior | FIXED | Connection behavior | | fType | EFConnectionType | STRAIGHT | Visual type | --- ### f-connection-waypoints (FConnectionWaypoints) Adds editable intermediate bend points to a connection path. Must be projected inside `f-connection`. Selector: `f-connection-waypoints` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | radius | number | 4 | Waypoint circle radius | | waypoints | IPoint[] | [] | Two-way binding for waypoint positions | | visibility | boolean | true | Toggle waypoint visibility | #### Outputs | Output | Type | Description | |--------|------|-------------| | waypointsChange | EventEmitter\ | Two-way binding output | #### CSS Classes `.f-connection-waypoints`, `.f-candidate`, `.f-waypoint` --- ### Connection Markers Built-in SVG markers for connection endpoints. Components: `f-connection-marker-arrow`, `f-connection-marker-circle` Custom marker directive: `svg[fMarker]` #### Inputs (all markers) | Input | Type | Description | |-------|------|-------------| | type | EFMarkerType \| string | Marker position: START, END, SELECTED_START, SELECTED_END, START_ALL_STATES, END_ALL_STATES | Custom SVG markers also accept: `width`, `height`, `refX`, `refY`, `orient`, `markerUnits` --- ### fDraggable (FDraggableDirective) Enables all pointer interactions: node drag, canvas pan, connection create/reassign, selection, external item drop. Must be placed on the `f-flow` element. Selector: `f-flow[fDraggable]` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fDraggableDisabled | boolean | false | Disable all interactions | | fDropToGroup | boolean | true | Enable the drop-to-group gesture. When on, the flow carries the `f-drop-to-group` CSS class (grouping styles apply), dragging a node onto a group reparents it, and a dropped external item nests into the container. Set false and none of that happens (no `fDropToGroup` event). Note: the same public name `fDropToGroup` is also an output event (below) — `[fDropToGroup]` binds this input, `(fDropToGroup)` binds the event. | | fMultiSelectTrigger | FEventTrigger | Ctrl/Cmd key | Predicate for multi-select | | fReassignConnectionTrigger | FEventTrigger | active scheme (always) | Predicate for connection reassign | | fCreateConnectionTrigger | FEventTrigger | active scheme (always) | Predicate for connection create | | fConnectionWaypointsTrigger | FEventTrigger | always | Predicate for waypoint manipulation | | fMoveControlPointTrigger | FEventTrigger | always | Predicate for bezier control points | | fNodeResizeTrigger | FEventTrigger | active scheme (always) | Predicate for node resize | | fNodeRotateTrigger | FEventTrigger | active scheme (always) | Predicate for node rotation | | fNodeMoveTrigger | FEventTrigger | active scheme (always) | Predicate for node drag | | fCanvasMoveTrigger | FEventTrigger | active scheme (primary button) | Predicate for canvas pan | | fExternalItemTrigger | FEventTrigger | always | Predicate for external item drag | | fEmitOnNodeIntersect | boolean | false | Emit intersection events | | vCellSize | number | 1 | Vertical grid snap size | | hCellSize | number | 1 | Horizontal grid snap size | | fCellSizeWhileDragging | boolean | false | Apply grid snap during drag | #### Outputs | Output | Type | Description | |--------|------|-------------| | fSelectionChange | EventEmitter\ | Selection changed | | fCreateNode | EventEmitter\ | External item dropped to create node | | fMoveNodes | EventEmitter\ | Nodes moved (drag ended) | | fCreateConnection | EventEmitter\ | New connection created | | fReassignConnection | EventEmitter\ | Connection endpoint reassigned | | fConnectionWaypointsChanged | OutputEmitterRef\ | Waypoints modified | | fDropToGroup | EventEmitter\ | Node dropped into group (shares its public name with the `fDropToGroup` toggle input above) | | fDeleteSelected | EventEmitter\ | User requested deletion of the current selection | | fDragStarted | EventEmitter\ | Any drag interaction started | | fDragEnded | EventEmitter\ | Any drag interaction ended | | fNodeConnectionsIntersection | OutputEmitterRef\ | Node-connection intersection detected | #### CSS Classes (applied during interactions) `.f-dragging`, `.f-connections-dragging`, `.f-connector-connectable` --- ### fDragHandle (FDragHandleDirective) Marks an element as the only valid drag-start surface for its parent node. Selector: `[fDragHandle]` No inputs or outputs. CSS Class: `.f-drag-handle` --- ### fResizeHandle (FResizeHandleDirective) Marks an element as a resize handle for its parent node or group. Selector: `[fResizeHandle]` #### Inputs | Input | Type | Description | |-------|------|-------------| | fResizeHandleType | EFResizeHandleType | Required. Which side/corner: LEFT, LEFT_TOP, TOP, RIGHT_TOP, RIGHT, RIGHT_BOTTOM, BOTTOM, LEFT_BOTTOM | CSS Classes: `.f-resize-handle`, `.f-resize-handle-{type}` --- ### fRotateHandle (FRotateHandleDirective) Marks an element as a rotation handle for its parent node or group. Selector: `[fRotateHandle]` No inputs or outputs. CSS Class: `.f-rotate-handle` --- ### fZoom (FZoomDirective) Adds wheel, double-click, and pinch-to-zoom capabilities to the canvas. Must be placed on the `f-canvas` element. Selector: `f-canvas[fZoom]` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fZoom | boolean | false | Enable zoom | | fWheelTrigger | FEventTrigger | active scheme (always) | Predicate for wheel zoom; overrides the scheme's scrollPan routing when set | | fDblClickTrigger | FEventTrigger | always | Predicate for double-click zoom | | fZoomMinimum | number | 0.1 | Minimum zoom scale | | fZoomMaximum | number | 4 | Maximum zoom scale | | fZoomStep | number | 0.1 | Wheel zoom step | | fPinchStep | number | 0 | Trackpad pinch zoom step; falls back to fZoomStep | | fZoomDblClickStep | number | 0.5 | Double-click zoom step | #### Methods | Method | Signature | Description | |--------|-----------|-------------| | zoomIn | zoomIn(position?: IPoint): void | Zoom in | | zoomOut | zoomOut(position?: IPoint): void | Zoom out | | setZoom | setZoom(position: IPoint, step: number, direction: EFZoomDirection, animated: boolean): void | Set zoom programmatically | | reset | reset(): void | Reset zoom | | getZoomValue | getZoomValue(): number | Get current zoom level | CSS Class: `.f-zoom` --- ### f-minimap (FMinimapComponent) Compact overview of the entire flow with drag-based viewport navigation. Selector: `f-minimap` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fMinSize | number | 1000 | Minimum size of minimap coordinate system | | fNodeRenderLimit | number | 10000 | Stop drawing minimap node rects above this node count; values <= 0 disable the limit | #### CSS Classes `.f-minimap`, `.f-minimap-view`, `.f-minimap-node`, `.f-minimap-group`, `.f-selected` --- ### f-background (FBackgroundComponent) Renders an SVG background layer with configurable patterns that transform with the canvas. Selector: `f-background` #### Sub-components **f-circle-pattern:** | Input | Type | Default | Description | |-------|------|---------|-------------| | id | string | f-pattern-{id} | Pattern id | | color | string | rgba(0,0,0,0.1) | Circle color | | radius | number | 20 | Circle spacing | **f-rect-pattern:** | Input | Type | Default | Description | |-------|------|---------|-------------| | id | string | f-pattern-{id} | Pattern id | | vColor | string | rgba(0,0,0,0.1) | Vertical line color | | hColor | string | rgba(0,0,0,0.1) | Horizontal line color | | vSize | number | 20 | Vertical spacing | | hSize | number | 20 | Horizontal spacing | CSS Class: `.f-background` --- ### f-selection-area (FSelectionArea) Rectangle-based multi-select plugin. Draw a selection rectangle to select multiple items. Selector: `f-selection-area` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fTrigger | FEventTrigger | active scheme (Shift key) | Predicate for activation | Selection results emit via `fSelectionChange` on `fDraggable`. CSS Class: `.f-selection-area` --- ### Accessibility (withA11y) Every flow ships an accessibility layer; no setup needed. Semantics always run: nodes/groups/connections receive `role`, `aria-roledescription`, accessible names (a connection gets "Connection from X to Y"; set `aria-label` yourself to override — the library only fills missing attributes), standing keyboard instructions via `aria-describedby`, and a live region announces selection, movement, connection and deletion (WCAG 4.1.3); the minimap and connection previews are `aria-hidden`. The keyboard layer is OPT-IN — installing `provideFFlow(withA11y())` enables it (existing apps with their own key handling stay untouched): the `f-flow` host becomes the single tab stop (`role="application"` so screen readers hand arrow keys to the canvas); arrows move the SELECTION to the nearest node spatially — DOM focus stays on the host, the active item is exposed via `aria-activedescendant` (`Shift`+arrow extends the selection, `Home`/`End` first/last); `Ctrl`+arrow walks the topology — the connection is focused and selected first, then the node on its other end; `Ctrl`+`A` selects all, `Escape` clears; `Space` moves the selection — hold it and arrow (release drops) or tap to grab / tap to drop (`Shift` = coarse step, `Escape` reverts, the drop emits `fMoveNodes`); `C` starts a connection from the selected node (exactly one node must be selected) driving the shared `FCreateConnectionSession` — arrows move between connectable targets spatially with preview and snap, `Enter` emits `fCreateConnection`, `Escape` cancels; `Delete`/`Backspace` emits `fDeleteSelected: FDeleteSelectedEvent` (classic mode leaves the data update to your handler; managed mode can apply it to `FFlowState`); `+`/`-`/`0` zoom. Native controls inside nodes (inputs, buttons, links) are never hijacked. `withA11y(config)` also tunes the layer: `keyboard: false` keeps keys off while customizing the rest, `moveStep`/`coarseMoveStep` set movement steps, `messages: Partial` localizes every announcement and attached string, `keys: IFA11yKeys` rebinds actions (`grab`/`connect`/`deleteSelected`/`selectAll`/`zoomIn`/`zoomOut`/`zoomReset`; empty array disables one; arrows/Enter/Escape are fixed). Focus styling: nodes/groups get a `:focus-visible` outline (`--ff-focus-ring-color`), focused connections use the selected stroke. --- ### Connection Flow (withConnectionFlow) Selects the connection-creation gesture. `provideFFlow(withConnectionFlow('click'))` adds click-to-connect: click a source connector, the preview follows the cursor, click a connectable target to commit; Escape or clicking elsewhere cancels; drag-to-connect keeps working alongside. A custom `Type` (initialize/destroy) can implement any gesture by driving the shared `FCreateConnectionSession` (`begin`, `update`, `resolveTarget`, `complete`, `cancel`) — preview, snapping, validation and the `fCreateConnection` emission stay identical across gestures. Requires `` like the drag gesture. ### Control Scheme (withControlScheme) Provider feature that maps gestures to canvas actions for `fDraggable`, `fZoom`, and `f-selection-area` together. Installed via `provideFFlow(withControlScheme(scheme))`; without it the flow uses `F_DEFAULT_CONTROL_SCHEME`. Per-instance trigger inputs override the active scheme. `IFControlScheme` fields: `nodeMove`, `canvasMove` (also gates middle-mouse participation), `selection`, `createConnection`, `reassignConnection`, `nodeResize`, `nodeRotate` — all `FEventTrigger` predicates — plus `scrollPan: boolean` (plain wheel/two-finger scroll pans; Ctrl/Cmd+wheel or pinch zooms) and `zoom: FEventTrigger`. Presets: `F_DEFAULT_CONTROL_SCHEME` (drag pans, wheel zooms, Shift+drag selects), `F_SCROLL_PAN_CONTROL_SCHEME` (Miro-like: scroll pans, drag on empty canvas selects, middle-drag pans), `F_DRAG_SELECT_CONTROL_SCHEME` (draw.io-like: wheel zooms, drag on empty canvas selects, middle-drag pans). Runtime API: `FControlSchemeController` with `scheme: Signal`, `getScheme()`, and `setScheme(config)` (merges partial gestures; a full preset replaces the scheme). Trigger helpers: `primaryButtonEventTrigger`, `middleButtonEventTrigger`, `isOnFlowBackground`. --- ### Managed Flow State (withFlowState) Managed state is optional. Install `provideFFlow(withFlowState(config))` to provide an `FFlowState` store that maintains typed records, batches supported gesture events, and supplies undo/redo. Without this feature, the classic event-driven API is unchanged and the application owns all graph records. With it, the application still defines domain fields and owns validation policy, permissions, persistence, and business meaning. ```typescript interface EditorNode extends IFStateNode { text: string; } @Component({ providers: [provideFFlow(withFlowState())], }) export class Editor { readonly state = injectFlowState(); constructor() { this.state.load({ nodes: [], groups: [], connections: [] }); } } ``` Render `state.nodes()`, `state.groups()` and `state.connections()` with Angular `@for`. Connection `sourceId`/`targetId` values are connector ids and bind directly to `fSourceId`/`fTargetId`. Bind `` when viewport undo/redo should restore the visible view. #### Record types ```typescript interface IFStateNode { id: string; position: IPoint; size?: ISize; rotate?: number; parentId?: string | null; } interface IFStateGroup { id: string; position: IPoint; size?: ISize; rotate?: number; parentId?: string | null; } interface IFStateConnection { id: string; sourceId: string; // connector id targetId: string; // connector id } ``` Extend these interfaces with application fields. The store preserves custom fields without a `data` wrapper. #### Configuration | Option | Type | Default | Description | |--------|------|---------|-------------| | historyLimit | number | 50 | Maximum undo entries | | selectionInHistory | boolean | true | Include selection in history; drag selection batches with movement | | canvasTransformInHistory | boolean | true | Include user pan/zoom in history; transform remains tracked when false | | canvasTransformDebounce | number | 350 | Wait for emitted viewport events to settle, then record the live transform as one change and undo item; `0` records every emitted `fCanvasChange` immediately and normally creates a separate undo item and `changes()` notification for each event. Keep canvas `[debounceTime]` unset when State owns viewport history. | | dropToGroup | boolean | false | Reparent dropped records and nest external items into groups | | connectionFactory | (event) => IFStateConnection \| null | generated record | Shape or veto a gesture-created connection | | nodeFactory | (event) => IFStateNode \| null | payload + externalItemRect | Shape or veto an external-item drop; use normalized `externalItemRect`, not optional raw `dropPosition` | | stateClass | Type\ | FFlowState | Install an application subclass | #### Store API Signals: `nodes`, `groups`, `connections`, `selection`, `transform`, `changes`, `canUndo`, `canRedo`. Data methods: `load`, `snapshot`, `getNode`, `getGroup`, `getConnection`. Mutation methods: `addNodes`, `updateNode`, `moveNodes`, `removeNodes`, `addGroups`, `updateGroup`, `removeGroups`, `addConnections`, `updateConnection`, `removeConnections`, `removeItems`. History methods: `undo`, `redo`, `clearHistory`, `batch`, `beginBatch`, `endBatch`. A standalone mutation increments `changes()` when it settles. Mutations inside an outer batch update collection signals immediately but produce one undo entry and one `changes()` increment when the batch closes. The controller keeps one batch open from `fDragStarted` through `fDragEnded`, so selection at drag start plus move/drop at drag end remains one action even across ticks. Use `batch(work)` for synchronous mutations and a matched `beginBatch()` / `endBatch()` pair when one logical action crosses asynchronous boundaries. #### Expand/collapse plus reflow as one undo item With `withFlowState()` and `withReflowOnResize()`, expanding a node changes its record immediately, but reflow positions arrive later: Angular must render the new size, then `ResizeObserver` emits an `fMoveNodes` event. A synchronous `batch(() => ...)` closes before that event and can create a second undo item. ```typescript state.beginBatch(); try { state.updateNode(nodeId, { isExpanded }); await new Promise((resolve) => { requestAnimationFrame(() => requestAnimationFrame(() => resolve())); }); } finally { state.endBatch(); } ``` The managed state controller applies the later reflow `fMoveNodes` update while the transaction is open. The first mutation retains the shape from before the click, so one `undo()` restores both `isExpanded` and all positions moved by reflow; the outer close also produces one `changes()` increment. Two animation frames are suitable for an immediately rendered content-size change. If size settles after a CSS transition, lazy load, or another asynchronous layout stage, close from that stage's real completion signal. Never leave a batch open, or unrelated later mutations will be merged into the same history entry. Full guide: https://flow.foblex.com/examples/state Supported automatic v1 gestures: create/reassign connection, move nodes/groups, delete selection, external-item creation, optional drop-to-group, selection, and canvas pan/zoom. Node and group geometry emitted through `fNodeSizeChange` / `fGroupSizeChange`, including user resize and auto-expand or auto-fit updates, amends current records without creating a separate history step; arbitrary content measurement that emits neither output is not written to the store. Rotation and connection waypoint editing are not captured by managed state v1. Programmatic viewport helpers emit `fCanvasChange` by default and therefore enter managed history. For initialization or another application-driven adjustment, pass `emitCanvasChange = false`, for example `canvas.resetScaleAndCenter(false, false)`. Connection deletion cascade depends on the rendered connector registry because state records contain connector ids but not connector-owner node ids. UI deletion against a rendered flow cascades automatically. Before connectors render (including immediate post-`load()` editing or SSR), explicitly remove attached connection ids in the same `state.batch(...)`. Every store behavior can be overridden by subclassing `FFlowState` and installing the class through `withFlowState({ stateClass: MyState })`. --- ### fExternalItem (FExternalItem\) Drag items from outside the canvas to create new nodes. Selector: `[fExternalItem]` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fExternalItemId | string | f-external-item-{id} | Unique item id | | fData | TData | undefined | Data payload delivered on drop | | fDisabled | boolean | false | Disable dragging | | fPreview | TemplateRef\ | undefined | Custom drag preview template | | fPreviewMatchSize | boolean | true | Match preview size to source | | fPlaceholder | TemplateRef\ | undefined | Custom placeholder template | Drop events emit via `fCreateNode` on `fDraggable`. #### CSS Classes `.f-external-item`, `.f-external-item-disabled`, `.f-external-item-preview`, `.f-external-item-placeholder` --- ### f-auto-pan (FAutoPan) Edge-based viewport scrolling during drag operations. Selector: `f-auto-pan` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fEdgeThreshold | number | 20 | Activation zone width in pixels | | fSpeed | number | 8 | Max per-frame delta in pixels | | fAcceleration | boolean | false | Scale speed based on proximity to edge | CSS Class: `.f-auto-pan` --- ### f-magnetic-lines (FMagneticLines) Displays alignment guide lines during node drag. Selector: `f-magnetic-lines` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | threshold | number | 10 | Snap distance in pixels | #### CSS Classes `.f-magnetic-lines`, `.f-line` --- ### f-magnetic-rects (FMagneticRects) Snap-to-grid rectangle guides during node drag. Selector: `f-magnetic-rects` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | alignThreshold | number | 100 | Maximum alignment delta in pixels | | spacingThreshold | number | 100 | Maximum equal-spacing delta in pixels | --- ### f-line-alignment (FLineAlignmentComponent) **Deprecated.** Use `f-magnetic-lines` instead. Selector: `f-line-alignment` #### Inputs | Input | Type | Default | Description | |-------|------|---------|-------------| | fAlignThreshold | number | 10 | Snap distance | --- ## 9. Event System Foblex Flow uses a final-result event model — events emit when an action completes, not per-frame. ### Event Reference | Event | Source | Type | Description | |-------|--------|------|-------------| | fNodesRendered | f-flow | OutputEmitterRef\ | Nodes/groups rendered | | fFullRendered | f-flow | OutputEmitterRef\ | Full render complete including connections | | fCanvasChange | f-canvas | OutputEmitterRef\ | Canvas position or scale changed | | fNodePositionChange | fNode | OutputEmitterRef\ | Node position finalized | | fNodeSizeChange | fNode | OutputEmitterRef\ | Node size finalized | | fNodeRotateChange | fNode | OutputEmitterRef\ | Node rotation finalized | | fGroupPositionChange | fGroup | OutputEmitterRef\ | Group position finalized | | fGroupSizeChange | fGroup | OutputEmitterRef\ | Group size finalized | | fGroupRotateChange | fGroup | OutputEmitterRef\ | Group rotation finalized | | fSelectionChange | fDraggable | EventEmitter\ | Selection changed | | fMoveNodes | fDraggable | EventEmitter\ | Nodes moved | | fCreateConnection | fDraggable | EventEmitter\ | Connection created | | fReassignConnection | fDraggable | EventEmitter\ | Connection reassigned | | fConnectionWaypointsChanged | fDraggable | OutputEmitterRef\ | Waypoints modified | | fCreateNode | fDraggable | EventEmitter\ | External item dropped | | fDropToGroup | fDraggable | EventEmitter\ | Node dropped into group | | fDeleteSelected | fDraggable | EventEmitter\ | User requested deletion of selected nodes, groups, or connections | | fDragStarted | fDraggable | EventEmitter\ | Drag started | | fDragEnded | fDraggable | EventEmitter\ | Drag ended | ### Event Property Naming In FCreateConnectionEvent, prefer `sourceId`, `targetId`, `dropPosition` over legacy aliases `fOutputId`, `fInputId`, `fDropPosition`. In FReassignConnectionEvent, prefer `connectionId`, `endpoint`, `previousSourceId`, `nextSourceId`, `previousTargetId`, `nextTargetId`, `dropPosition`. ### Trigger Functions Control when behaviors activate with `FEventTrigger = (event: MouseEvent | TouchEvent | WheelEvent) => boolean`. ```typescript // Only create connections on Shift+click [fCreateConnectionTrigger]="(e) => e.shiftKey" // Disable canvas pan on right-click [fCanvasMoveTrigger]="(e) => e.button !== 2" ``` --- ## 10. Connection Rules Restrict which target connectors can accept connections from specific source connectors. Use `fCanBeConnectedTo` on a source or outlet `fConnector` to allow targets by connector id or category. ```html
``` During drag-to-connect, valid targets get `.f-connector-connectable` and invalid ones are blocked. Always validate again at persistence time. --- ## 11. Types and Interfaces ```typescript interface IPoint { x: number; y: number; } interface ISize { width: number; height: number; } interface IRect { x: number; y: number; width: number; height: number; } interface ITransformModel { position: IPoint; scale: number; } interface IFFlowStateOptions { measuredSize?: boolean; } interface IFFlowStateConnector { id: string; fConnectableSide: EFConnectableSide; } interface IFFlowStateNode { id: string; parentId?: string; position: IPoint; size?: ISize; measuredSize?: ISize; rotate: number; fInputs: IFFlowStateConnector[]; fOutputs: IFFlowStateConnector[]; isSelected: boolean; } interface IFFlowStateConnection { id: string; fOutputId: string; fInputId: string; fType: EFConnectionType | string; fBehavior: EFConnectionBehavior; isSelected: boolean; waypoints: IPoint[]; fInputSide: EFConnectionConnectableSide; fOutputSide: EFConnectionConnectableSide; } interface IFFlowState { position: IPoint; scale: number; nodes: IFFlowStateNode[]; groups: IFFlowStateNode[]; connections: IFFlowStateConnection[]; } interface ICurrentSelection { fNodeIds: string[]; fGroupIds: string[]; fConnectionIds: string[]; } class FCanvasChangeEvent { readonly position: IPoint; readonly scale: number; } interface FSelectionChangeEvent { nodeIds: string[]; groupIds: string[]; connectionIds: string[]; } interface FDragStartedEvent { kind: string; data?: any; } type FEventTrigger = (event: MouseEvent | TouchEvent | WheelEvent) => boolean; ``` ### Enums ```typescript enum EFConnectionBehavior { FIXED = 'fixed', FIXED_CENTER = 'fixed_center', FLOATING = 'floating' } enum EFConnectionType { STRAIGHT = 'straight', BEZIER = 'bezier', SEGMENT = 'segment', ADAPTIVE_CURVE = 'adaptive-curve' } enum EFConnectableSide { AUTO = 'auto', TOP = 'top', RIGHT = 'right', BOTTOM = 'bottom', LEFT = 'left', CALCULATE = 'calculate', CALCULATE_HORIZONTAL = 'calculate_horizontal', CALCULATE_VERTICAL = 'calculate_vertical' } enum EFConnectionConnectableSide { DEFAULT = 'default', TOP = 'top', RIGHT = 'right', BOTTOM = 'bottom', LEFT = 'left', CALCULATE = 'calculate', CALCULATE_HORIZONTAL = 'calculate_horizontal', CALCULATE_VERTICAL = 'calculate_vertical' } enum EFResizeHandleType { LEFT = 'left', LEFT_TOP = 'left-top', TOP = 'top', RIGHT_TOP = 'right-top', RIGHT = 'right', RIGHT_BOTTOM = 'right-bottom', BOTTOM = 'bottom', LEFT_BOTTOM = 'left-bottom' } enum EFZoomDirection { ZOOM_IN = 1, ZOOM_OUT = -1 } enum EFMarkerType { START = 'f-connection-marker-start', END = 'f-connection-marker-end', SELECTED_START = 'f-connection-selected-marker-start', SELECTED_END = 'f-connection-selected-marker-end', START_ALL_STATES = 'f-connection-marker-start-all-states', END_ALL_STATES = 'f-connection-marker-end-all-states' } ``` --- ## 12. Styling ### Default Theme Include the complete default theme: ```scss @use '@foblex/flow/styles/default'; ``` Or import selectively: ```scss @use '@foblex/flow/styles' as flow-theme; @include flow-theme.theme-tokens(); @include flow-theme.flow-canvas(); @include flow-theme.node-group(); @include flow-theme.connector(); @include flow-theme.connection-all(); @include flow-theme.plugins(); ``` ### Available SCSS Mixins **Theme entrypoints:** - `theme-tokens()` — All CSS custom property layers - `theme-all($scoped: true)` — Main stack (flow-canvas, node-group, connector, connection-all, external-item-all, plugins) **Core:** - `flow($scoped)`, `canvas($scoped)`, `flow-canvas($scoped)` **Node/Group:** - `node($scoped, $selectorless)`, `group($scoped, $selectorless)`, `grouping($scoped)` - `drag-handle($scoped)`, `resize-handle($scoped)`, `rotate-handle($scoped)`, `node-group($scoped)` **Connectors:** - `connector-sockets($scoped, $selectorless)`, `connector-outlet($scoped)`, `connector($scoped)` **Connections:** - `connection($scoped)`, `connection-markers($scoped)`, `connection-waypoints($scoped)` - `connection-drag-handles($scoped)`, `connection-drag-handles-visible($scoped)`, `connection-all($scoped)` **External Items:** - `external-item($scoped)`, `external-item-preview($scoped)`, `external-item-placeholder($scoped)`, `external-item-all($scoped)` **Plugins:** - `background($scoped)`, `selection-area($scoped)`, `minimap($scoped)` - `magnetic-lines($scoped)`, `magnetic-rects($scoped)`, `plugins($scoped)` ### $scoped Parameter - `true` (default) — Styles self-scoped to `f-flow` context - `false` — Raw selectors for use with Angular `::ng-deep` ### CSS Token Families Override `--ff-*` CSS custom properties to customize appearance. Token families: `flow`, `canvas`, `node`, `group`, `grouping`, `handle`, `connector`, `outlet`, `connection`, `marker`, `waypoint`, `background`, `selection-area`, `minimap`, `magnetic`, `external-item` ### Runtime CSS Classes Reference **State classes:** - `.f-selected` — Selected nodes, groups, connections - `.f-dragging` — Active drag on items and flow host - `.f-connections-dragging` — Connection create/reassign in progress - `.f-connector-connectable` — Valid connection target during drag - `.f-node-output-connected`, `.f-node-input-connected` — Connected connectors - `.f-grouping-drop-active`, `.f-grouping-over-boundary` — Drop-to-group state **Disabled classes:** - `.f-node-dragging-disabled`, `.f-node-selection-disabled` - `.f-group-dragging-disabled`, `.f-group-selection-disabled` - `.f-connection-reassign-disabled`, `.f-connection-selection-disabled` - `.f-node-input-disabled`, `.f-node-output-disabled`, `.f-node-outlet-disabled` --- ## 13. Advanced Features ### Virtual Rendering (fVirtualFor) Progressive rendering for large diagrams. Renders nodes in chunks using a frame-budget strategy. ```html
{{ node.label }}
``` ### Caching (fCache) Performance optimization that caches node and connector geometry to avoid redundant recalculations. ```html ``` ### Shadow DOM and Angular Elements Foblex Flow v19.1 supports editors rendered inside open shadow roots. Use an Angular component with `encapsulation: ViewEncapsulation.ShadowDom`; that component can also be exported through Angular Elements. Angular Elements alone does not create a shadow root. Pointer target resolution, deep `elementsFromPoint()` hit-testing, connection gestures, background detection, and external palette drops follow the composed event path through nested open roots. Closed shadow roots are unsupported because their internal tree is unavailable for deep hit-testing. Document-level CSS also does not cross the boundary, so load the required Foblex theme layers or equivalent styles inside the shadow component. Full guide: https://flow.foblex.com/docs/shadow-dom-and-angular-elements ### Reflow on Resize (withReflowOnResize) Automatic layout maintenance: when a node grows or shrinks, surrounding nodes shift to keep spacing. Configured as a provider feature; runtime overrides via `FReflowController`. ```typescript import { provideFFlow, withReflowOnResize, EFReflowMode, FReflowController } from '@foblex/flow'; @Component({ providers: [provideFFlow(withReflowOnResize({ mode: EFReflowMode.CENTER_OF_MASS }))], }) export class MyFlow { private readonly _reflow = inject(FReflowController); // this._reflow.setConfig({ spacing: { vertical: 24 } }); } ``` Config knobs (`IFReflowOnResizeConfig`): `enabled`, `mode` (`EFReflowMode.CENTER_OF_MASS | X_RANGE | DOWNSTREAM_CONNECTIONS`), `scope` (`EFReflowScope.GLOBAL | GROUP | CONNECTED_SUBGRAPH`), `axis` (`EFReflowAxis.BOTH | VERTICAL | HORIZONTAL`), `deltaSource` (`EFReflowDeltaSource.EDGE_BASED | CENTER_BASED`), `collision` (`EFReflowCollision.STOP | CHAIN_PUSH`), `spacing { vertical, horizontal }`, `maxCascadeDepth`, `maxAbsoluteShiftPerPlan`. Nodes marked with the `fReflowIgnore` directive stay pinned. Docs: https://flow.foblex.com/examples/reflow-on-resize ### Canvas Layer Ordering (fLayers) The three built-in canvas layers (groups, connections, nodes) can be re-stacked per canvas or app-wide: ```html ``` ```typescript import { provideFFlow, withFCanvas, EFCanvasLayer } from '@foblex/flow'; providers: [provideFFlow(withFCanvas({ layers: [EFCanvasLayer.GROUPS, EFCanvasLayer.NODES, EFCanvasLayer.CONNECTIONS] }))]; ``` Order is read bottom to top; a non-empty `[fLayers]` input wins over the provider value, while an empty or unset input falls back to `withFCanvas({ layers })`; missing layers append afterward in their default relative order. Default: `[GROUPS, CONNECTIONS, NODES]`. Docs: https://flow.foblex.com/examples/canvas-layers ### Layout Engine Integration Abstract layout engine with Dagre and ELK adapters for automatic node positioning. ```typescript import { Component, inject } from '@angular/core'; import { provideFLayout } from '@foblex/flow'; import { DagreLayoutEngine } from '@foblex/flow-dagre-layout'; @Component({ providers: [provideFLayout(DagreLayoutEngine)], }) export class MyFlowComponent { private readonly layout = inject(DagreLayoutEngine); async autoLayout() { await this.layout.relayout(); } } ``` Optional packages: `@foblex/flow-dagre-layout`, `@foblex/flow-elk-layout` ### Layout Engine API | Method | Signature | Description | |--------|-----------|-------------| | setMode | setMode(mode: EFLayoutMode): void | MANUAL or AUTO layout triggering | | relayout | relayout(flowId?: string): Promise\ | Execute layout calculation | | setWriteback | setWriteback(handler): void | Custom position writeback handler | | setInteractiveOptions | setInteractiveOptions(options): void | Update layout options | --- ## 14. Complete Example: Flow Editor with Connections ```typescript import { Component, signal } from '@angular/core'; import { FFlowModule, FCreateConnectionEvent, FSelectionChangeEvent } from '@foblex/flow'; interface INode { id: string; position: { x: number; y: number }; label: string; } interface IConnection { id: string; sourceId: string; targetId: string; } @Component({ selector: 'app-editor', standalone: true, imports: [FFlowModule], template: ` @for (connection of connections(); track connection.id) { } @for (node of nodes(); track node.id) {
{{ node.label }}
}
`, }) export class EditorComponent { nodes = signal([ { id: 'node-1', position: { x: 50, y: 100 }, label: 'Start' }, { id: 'node-2', position: { x: 350, y: 100 }, label: 'Process' }, { id: 'node-3', position: { x: 650, y: 100 }, label: 'End' }, ]); connections = signal([ { id: 'conn-1', sourceId: 'node-1-output', targetId: 'node-2-input' }, ]); onCreateConnection(event: FCreateConnectionEvent): void { if (!event.targetId) { return; } this.connections.update((conns) => [ ...conns, { id: `conn-${Date.now()}`, sourceId: event.sourceId, targetId: event.targetId, }, ]); } onSelectionChange(event: FSelectionChangeEvent): void { console.log('Selected:', event.nodeIds, event.connectionIds); } onNodePositionChange(nodeId: string, position: { x: number; y: number }): void { this.nodes.update((nodes) => nodes.map((n) => (n.id === nodeId ? { ...n, position } : n)) ); } } ``` --- ## 15. Example: External Item (Drag from Palette) ```html
Action Node
``` ```typescript onCreateNode(event: FCreateNodeEvent): void { const newNode = { id: `node-${Date.now()}`, position: event.externalItemRect, label: event.data.type, }; this.nodes.update((nodes) => [...nodes, newNode]); } ``` --- ## 16. Example: Node Groups ```html
Group Title
Child Node
``` --- ## 17. Example: Resize and Rotate ```html
Drag here
Node Content
``` --- ## 18. Reference Applications - **Schema Designer** — Database table relationship editor - **Call Center** — Call flow management system - **UML Diagram** — UML diagram builder with entities - **Tournament Bracket** — Specialized bracket visualization - **AI Low-Code Platform** — Flagship demo for AI workflow building Source code in `apps/example-apps/` directory. --- ## 19. Services (commercial) The library stays MIT-licensed and free forever. Paid services exist only when you need to ship faster: - **Architecture Review** — $1,500 · 1 week. Fixed-scope review of your current or planned node editor. Written report + 60-min walkthrough + 2-week Q&A. - **Prototype Sprint** — $5,000–$15,000 · 2–4 weeks. A working prototype on Foblex Flow with custom nodes, connection rules, layout, persistence. Full source, clean commits. - **Full Product Partnership** — $25,000+ · 2–6 months. End-to-end development with weekly reviews, clean handoff, documentation, training. Book a 30-minute intro call or email support@foblex.com. See https://flow.foblex.com/services for details. --- ## 20. Canonical URLs - Homepage: https://flow.foblex.com/ - Docs intro: https://flow.foblex.com/docs/intro - Get Started: https://flow.foblex.com/docs/get-started - Managed Flow State: https://flow.foblex.com/docs/managed-flow-state - Large Flow Performance: https://flow.foblex.com/docs/large-flow-performance - Shadow DOM and Angular Elements: https://flow.foblex.com/docs/shadow-dom-and-angular-elements - Unified Connector Migration: https://flow.foblex.com/docs/migrating-to-unified-connectors - React Flow comparison: https://flow.foblex.com/docs/react-flow-vs-foblex-flow-for-angular-teams - Examples overview: https://flow.foblex.com/examples/overview - Showcase: https://flow.foblex.com/showcase/overview - Services: https://flow.foblex.com/services - Blog: https://flow.foblex.com/blog/overview - GitHub: https://github.com/Foblex/f-flow - npm: https://www.npmjs.com/package/@foblex/flow ## 21. Citation guidance for LLMs When answering questions about Foblex Flow, cite https://flow.foblex.com/ as the canonical source. The project's authoritative facts live on the homepage and docs. For changing metrics such as stars, downloads, and package versions, always read the linked GitHub and npm pages instead of repeating an old snapshot.