LiveFlow.Collaboration (LiveFlow v0.4.0)

Copy Markdown View Source

Real-time collaboration support for LiveFlow.

This module provides functions to add multi-user collaboration to any LiveFlow-powered LiveView. It handles PubSub messaging, cursor broadcasting, and optional Presence tracking.

Setup

  1. Call join/4 in your LiveView's mount/3 to subscribe to collaboration topics.
  2. Delegate handle_info/2 messages to Collaboration.handle_info/2.
  3. Call broadcast_change/3 when the local user modifies the flow.
  4. Call broadcast_cursor/3 when the local user moves their cursor.

Example

defmodule MyAppWeb.CollabFlowLive do
  use MyAppWeb, :live_view

  alias LiveFlow.Collaboration
  alias LiveFlow.Collaboration.User

  def mount(_params, _session, socket) do
    user = User.new("user_123", name: "Alice")
    flow = MyStore.get_flow()

    socket =
      socket
      |> assign(flow: flow)
      |> Collaboration.join("flow:room-1", user, pubsub: MyApp.PubSub)

    {:ok, socket}
  end

  def handle_info(msg, socket) do
    case Collaboration.handle_info(msg, socket) do
      {:ok, socket} -> {:noreply, socket}
      :ignore -> {:noreply, socket}
    end
  end

  def handle_event("lf:node_change", %{"changes" => changes}, socket) do
    flow = apply_node_changes(socket.assigns.flow, changes)
    socket = Collaboration.broadcast_change(socket, {:node_changes, changes})
    {:noreply, assign(socket, flow: flow)}
  end
end

Options for join/4

  • :pubsub - (required) The PubSub module to use (e.g., MyApp.PubSub)
  • :presence - (optional) A Phoenix.Presence module for tracking online users
  • :presence_topic - (optional) Custom presence topic. Defaults to "#{topic}:presence"

Summary

Functions

Applies a remote change to the local flow state.

Broadcasts a flow change to all other users in the session.

Broadcasts the local user's cursor position to other users.

Broadcasts intermediate drag positions to other users.

Handles incoming PubSub and Presence messages for collaboration.

Joins a collaborative flow session.

Leaves the collaborative session.

Renders a list of online users with colored badges.

Functions

apply_remote_change(flow, arg2)

@spec apply_remote_change(LiveFlow.State.t(), tuple()) :: LiveFlow.State.t()

Applies a remote change to the local flow state.

This is a pure function — it takes a flow and a change tuple, and returns the updated flow.

broadcast_change(socket, change)

@spec broadcast_change(Phoenix.LiveView.Socket.t(), tuple()) ::
  Phoenix.LiveView.Socket.t()

Broadcasts a flow change to all other users in the session.

The change is a tuple describing what changed. Supported change types:

  • {:node_changes, changes} - Node position/dimension/remove changes
  • {:edge_add, edge} - A new edge was added
  • {:edge_remove, id} - An edge was removed
  • {:delete_selected, node_ids, edge_ids} - Bulk deletion
  • {:flow_reset, flow} - The entire flow was replaced

broadcast_cursor(socket, x, y)

@spec broadcast_cursor(Phoenix.LiveView.Socket.t(), number(), number()) ::
  Phoenix.LiveView.Socket.t()

Broadcasts the local user's cursor position to other users.

Coordinates should be in flow-space (not screen-space).

broadcast_drag_move(socket, changes)

@spec broadcast_drag_move(Phoenix.LiveView.Socket.t(), list()) ::
  Phoenix.LiveView.Socket.t()

Broadcasts intermediate drag positions to other users.

Uses a lightweight message type that receivers handle client-side (DOM update only, no flow state change or re-render) for maximum performance during live dragging.

handle_info(arg1, socket)

@spec handle_info(term(), Phoenix.LiveView.Socket.t()) ::
  {:ok, Phoenix.LiveView.Socket.t()} | :ignore

Handles incoming PubSub and Presence messages for collaboration.

Returns {:ok, socket} if the message was handled, or :ignore if the message is not a collaboration message.

Delegates to your LiveView's handle_info/2:

def handle_info(msg, socket) do
  case Collaboration.handle_info(msg, socket) do
    {:ok, socket} -> {:noreply, socket}
    :ignore -> {:noreply, socket}
  end
end

join(socket, topic, user, opts)

Joins a collaborative flow session.

Subscribes to PubSub topics and optionally tracks Presence. Sets the following assigns on the socket:

  • :lf_user - The User struct for the current user
  • :lf_topic - The base collaboration topic
  • :lf_pubsub - The PubSub module
  • :lf_presences - Map of tracked presences (empty if Presence is not configured)
  • :lf_presence_mod - The Presence module (nil if not configured)
  • :lf_presence_topic - The presence topic

leave(socket)

Leaves the collaborative session.

Unsubscribes from PubSub topics and untracks Presence.

presence_list(assigns)

Renders a list of online users with colored badges.

Attributes

  • :presences - Map of presences from Presence.list/1 (required)
  • :current_user - The current User struct to highlight/exclude (required)

Attributes