@copyfactory/alpine-flow - npm explorer
`

#### The $nodes magic

A $nodes magic is also exposed should you want to know what the registered nodes currently are.

The $nodes magic returns an object where the keys are the registry
names and the values an object of the registered node Element and it's config.

By default all x-node are registered in the default registry. You can specify which registries your nodes belong to
by adding a modifier.

`html

x-data="editor = flowEditor({
nodeTypes: $nodes.customRegistryName,
// more config
})"
>
`

---

$3

#### Configuration

Below are the available config options and defaults when initializing a new flowEditor.

| Name | Type | Description | Default |
|-------------------|-----------|------------------------------------------------------------------------------------------------------------|----------------------------------------|
| nodeTypes |
Object | The types of nodes available in the editor. The default is to use the components registered with x-node. | $nodes.default |
| nodes |
Array | The initial nodes to populate the editor. | [] |
| edges |
Array | The initial edges to populate the editor. | [] |
| viewport |
Object | The viewport positioning to set | {x:0, y:0,zoom:1} |
| zoomOnWheelScroll |
Boolean | Whether to enable zooming on wheel scroll. The default is to panOnScroll. | false |
| zoomOnPinch |
Boolean | Whether to enable zooming on pinch gestures | true |
| panOnScroll |
Boolean | Whether to enable panning on scroll | true |
| panOnScrollSpeed |
Number | The speed of panning on scroll | 0.5 |
| panOnDrag |
Boolean | Whether to enable panning on drag | true |
| dagreConfig |
Object | The settings to use with Dagre. 'rankdir', 'nodesep' and 'ranksep' is supported. | {rankdir:'TB', nodesep:50, ranksep:50} |
| minZoom |
Number | The minimum allowed zoom level | 0.5 |
| maxZoom |
Number | The maximum allowed zoom level | 2 |
| zoomDuration |
Number | The duration of zoom animation in milliseconds. | 100 |
| toolbarClasses |
String | The CSS classes to add to the toolbar. | 'bottom left' |
| toolbarBtnClasses |
String | The CSS classes to add to the toolbar buttons. | '' |
| backgroundClasses |
String | The CSS classes for the background. | 'dots' |

Example usage

`html
x-data="editor = flowEditor({
nodes: [{id: 1, type: 'myCustomNode', data: {foo: 'bar'}}],
minZoom: 1,
maxZoom: 2,
// more config
})"
>
`

#### Methods

Below are the public methods for using the flowEditor.

---

##### editor.hasNodes()

Returns:

- (boolean): Returns true if the editor has nodes, otherwise false.

Example:

`javascript
editor.hasNodes();
`

---

##### editor.hasNoNodes()

Returns true if the editor has no nodes, otherwise false.

Example:

`javascript
editor.hasNoNodes();
`

---

##### editor.addNode(_incompleteNode_, _dependsOn_=null)

Adds a node to the flow editor.

Parameters:

- incompleteNode (Object): The incomplete node to be added.
-
dependsOn (Array|null, optional): The node IDs on which the new node depends. Defaults to null.

Example:

`javascript
let newNode = {
id: 'my-node-id',
type: 'myNode',
data: { foo: 'bar' },
};

editor.addNode(newNode, [anotherNode.id]);
`

---

##### editor.deleteNode(_nodeId_, _dependsOn_=null)

Delete a node from the graph along with its edges.

Parameters:

- nodeId (string): The ID of the node.
-
strategy (string): preserve (the default) tries to keep as many nodes as possible while deleting. all removes all descendants of the input node.

Example:

`javascript
// Suppose you had a graph of nodes: '1 -> 2 -> 3'
editor.deleteNode('2', 'preserve');
// by deleting node 2 the new nodes would be: '1 -> 3' since we can repoint node '1' to node '3'.

editor.deleteNode('2', 'all');
// would delete all dependents on 2 onwards.
// by deleting node 2 the new nodes would be: '1' since we delete node '2' and all dependants on node '2' (node '3') in this case.
`

---

##### editor.getNodeById(_nodeId_)

Gets a node by its ID.

Parameters:

- nodeId (string): The ID of the node.

Returns:

- (Node|null): The node with the given ID, or null if not found.

Example:

`javascript
let myNode = editor.getNodeById('my-node-id');
console.log(myNode);
`

---

##### editor.findParents(_nodeId_)

Get the parent nodes of a given nodeId.

Parameters:

- nodeId (string): The ID of the node.

Returns:

- (Array): An array of nodes.

Example:

`javascript
let nodes = editor.findParents('my-node-id');
console.log(nodes);
`

---

##### editor.findChildren(_nodeId_)

Get the children nodes of a given nodeId.

Parameters:

- nodeId (string): The ID of the node.

Returns:

- (Array): An array of nodes.

Example:

`javascript
let nodes = editor.findChildren('my-node-id');
console.log(nodes);
`

---

##### editor.findDescendantsOfNode(_nodeId_)

Recursively searches nodes for all descendents of a given nodeId.

Parameters:

- nodeId (string): The ID of the node.

Returns:

- (Array): An array of nodeIds.

Example:

`javascript
let nodeIds = editor.findDescendantsOfNode('my-node-id');
console.log(nodes);
`

---

##### editor.zoomOut(_zoomStep = 1 / 1.2_)

Zooms out the viewport.

Parameters:

- zoomStep (number, optional): The factor to zoom out. Defaults to 1 / 1.2.

Example:

`javascript
editor.zoomOut();
`

---

##### editor.zoomIn(_zoomStep = 1.2_)

Zooms in the viewport.

Parameters:

- zoomStep (number, optional): The factor to zoom in. Defaults to 1.2.

Example:

`javascript
editor.zoomIn();
`

---

##### editor.setViewportToCenter(_paddingY = 0.1, paddingX = 0.3_)

Sets the viewport of the canvas to center the content so that all nodes are in view.

Parameters:

- paddingY (number, optional): The vertical padding as a percentage of canvas height. Defaults to 0.1.
-
paddingX (number, optional): The horizontal padding as a fraction of canvas width. Defaults to 0.3.

Returns:

- (Object): The plain object representation of the viewport.

Example:

`javascript
editor.setViewportToCenter();
`

---

##### editor.setViewport(_x=0, y=0, zoom=1_)

Sets the viewport based on X/Y and zoom level.

Parameters:

- x (number, optional): The new X. Defaults to 0.
-
y (number, optional): The new Y. Defaults to 0.
-
zoom (number, optional): The new zoom. Defaults to 1.

Returns:

- (Object): The plain object representation of the viewport.

Example:

`javascript
editor.setViewPort(100, 100, 1.5);
`

---

##### editor.toObject()

Converts the flow editor to a plain object to save to the DB.

Returns:

- (Object): The nodes, edges and viewport.

Example:

`javascript
let flowObject = editor.toObject();
console.log(flowObject);
// {
// nodes: [];
// edges: [];
// viewport: {};
// };

let newEditor = flowEditor(flowObject);
`

---

Events

You can hook into events using the normal Alpine syntax of @event-name.

All events emitted by Alpine Flow will have the prefix flow-.

---

$3

Dispatched when the editor has finished its first load.

Event detail

`js
event = $event.detail;
console.log(event);
// {data: true}
`

---

$3

Dispatched when a new node is rendered.

Event detail

`js
event = $event.detail;
console.log(event);
// {data: 'node-id'}
`

---

$3

Dispatched when nodes have been deleted.

Event detail

`js
event = $event.detail;
console.log(event);
// {data: [deletedNodeId1, deletedNodeId2]}
``

---

Dependencies

Alpine flow depends on the following:

1. Dagre - For node layout and positioning.
2. D3-Zoom - For zooming and panning the editor.

// todo - can i just append to a single observer
// and only trigger rerender once instead of X per changed nodes?

// todo also look at x-intersect for rendering/not rendering nodes that are out of the viewport. Could save?
// todo find better way of creating the html, find performance wins with observer setting and throttling?
// todo add resizable as a node feature (resizable={'south', 'north', 'vertical' etc.}
// todo add minimap feature? Implement using canvas? How to allow for config?
// todo fix the event firing
// todo support left to right node layout.
// todo autocenter the viewport on adding/removing nodes
// todo We are now using one Resize Observer for all nodes and batch update the changes that come from the observer.
// todo - so much good stuff here: https://github.com/xyflow/xyflow/issues/723
// todo consider using the 'x-html' directive is probably not regarded as safe.
// todo how do I figure out how to 'build' js strings better/faster?
// todo HOW I DO TESTS???
// todo eval how we can let users define maybe using data-attrs in flowEditor div? Imagine being able to
// define a bunch of 'mini-map' buttons by adding 'data-flow-btn' or another directive?
// to the element and we teleport to the right area?
// or even other areas like minimap/buttons/links/poweredby etc by teleporting to diff sections.
// data-flow-location.top-right etc maybe or just another directive with config for location?