# Connections

::alert
This guide is based on the [Basic](https://retejs.org/docs/guides/basic) guide. It is recommended to review it for a comprehensive understanding of this guide.
::

::references
  :::ref-guide
  ---
  link: /docs/guides/validation#connections-validation
  title: Validation
  ---
  :::

  :::ref-example{link="/examples/chatbot" title="Chatbot"}
  :::
::

This guide provides a more detailed exploration of the functionalities offered by the rete-connection-plugin plugin, enabling user interaction with connections.

When a user clicks on a socket, the connection that trails behind the cursor is referred to as a pseudo-connection, which is is an object with an additional property `isPseudo: true`.

## Presets

You may have already seen the following preset usage, which allows users to add connections by clicking/pressing on an input/output socket and clicking/releasing on an output/input socket:

```ts
connection.addPreset(ConnectionPresets.classic.setup())
```

which is equivalent to the code below:

```ts
import { ClassicFlow } from 'rete-connection-plugin'

connection.addPreset(() => new ClassicFlow())
```

If the input socket is already connected, clicking or pressing on it will remove the connection and substitute it with a pseudo-connection.

### Custom preset

If you prefer an alternative method for adding connections, you can make use of `BidirectFlow`. In this mode, adding a node is done by clicking on the input/output socket and dragging the pseudo-connection onto a socket of the opposite type.

```ts
import { ClassicFlow } from 'rete-connection-plugin'

connection.addPreset(() => new BidirectFlow())
```

Additionally, utilizing the initial socket data, you have the option to select a specific flow or disable interaction with a particular socket altogether

```ts
connection.addPreset(({ nodeId, side, key }) => {
  if (isReadonly(nodeId, side, key)) return undefined
  if (usesBidirect(nodeId, side, key)) return new BidirectFlow()
  return new ClassicFlow()
})
```

If the existing workflows don't meet your needs, you have the option to implement your own solution by referencing [the source code](https://github.com/retejs/connection-plugin/blob/next/src/flow/builtin/bidirect.ts){rel="nofollow"} of the existing ones.

## Enhanced behavior

Enhancing the behavior of existing presets can involve tracking the events `connectionpick` and `connectiondrop`

```ts
connection.addPipe(context => {
  if (context.type === 'connectionpick') { // when the user clicks on the socket
    const { socket } = context.data
  }
  if (context.type === 'connectiondrop') { // when the user clicks on the socket or any area
    const { socket, initial, created } = context.data
  }
  return context
})
```

The `connectionpick` event can be prevented

```ts
connection.addPipe(context => {
  if (context.type === 'connectionpick') {
    if (readonly) return
  }
  return context
})
```

## User-created connection

By default, when a user creates connections using the UI, the plugin adds the connection as an object, rather than an instance of a class, such as `ClassicPreset.Connection`. If you want to customize the process of adding these connection, specify the `makeConnection` option in `ClassicFlow` or `BidirectFlow`.

```ts
import { getSourceTarget } from 'rete-connection-plugin'

connection.addPreset(() => new ClassicFlow({
  makeConnection(from, to, context) {
    const [source, target] = getSourceTarget(from, to) || [null, null];
    const { editor } = context;

    if (source && target) {
      editor.addConnection(
        new MyConnection(
          editor.getNode(source.nodeId),
          source.key,
          editor.getNode(target.nodeId),
          target.key
        )
      );
      return true; // ensure that the connection has been successfully added
    }
  }
}))
```

Additionally, the usage of `getSourceTarget` is essential in this case, as the `from` and `to` options carry data about the initial and final sockets, which might not necessarily match the output and input sockets.

## Configure connection start/end positions

Every connection is associated with a starting and ending point, directly connected to a socket (excluding pseudo-connections where end point depends on the cursor position). By default, the right side of the output socket serves as the starting point, while the left side of the input socket serves as the starting point. Modifying the socket size will cause a shift in the starting/ending point of the connection.

To configure the start and end positions of the connection, you can provide `getDOMSocketPosition` with these offset coordinates relative to the socket center. This method is used by default when the `socketPositionWatcher` option is not specified.

```ts
import { getDOMSocketPosition } from 'rete-render-utils'

render.addPreset(Presets.classic.setup({
  socketPositionWatcher: getDOMSocketPosition({
    offset({ x, y }, nodeId, side, key) {

      return {
        x: x + 10 * (side === 'input' ? -1 : 1),
        y: y
      }
    },
  })
}))
```

In this scenario, socket position calculation relies on DOM elements. There are cases when such an approach may prove inefficient due to performance or other implementation nuances (for instance, in the [LOD example](https://retejs.org/examples/lod) where displaying connections is required even when the actual sockets are not present in the DOM).

In order to make use of your calculation approach for connection start/end positions, you can extend the abstract class `BaseSocketPosition` and implement the `calculatePosition` method.

```ts
import { BaseSocketPosition } from 'rete-render-utils'

type Position = { x: number, y: number }
type Side = 'input' | 'output'

export class ComputedSocketPosition<S extends Schemes, K> extends BaseSocketPosition<S, K> {
  async calculatePosition(nodeId: string, side: Side, key: string): Promise<Position | null> {
    if (!this.area) return null

    return {
      x: side === 'input' ? 0 : getNodeWith(nodeId)
      y: 0
    }
  }
}

render.addPreset(Presets.classic.setup({
  socketPositionWatcher: new ComputedSocketPosition()
}))
```

where `calculatePosition` is expected to return the position relative to the node's position, or `null` if it cannot be calculated