PhiaUi.Collab.CollabPresence (phia_ui v0.1.17)

Copy Markdown View Source

Phoenix.Presence wrapper for collaborative editing sessions.

Provides standardized user presence tracking with cursor positions, typing indicators, and idle detection. Compatible with the presence_avatars and connection_status PhiaUI components.

Setup

Configure the PubSub name in your config:

config :phia_ui, :collab_pubsub, MyApp.PubSub

Add PhiaUi.Collab.Supervisor to your supervision tree — it starts the required Registry and DynamicSupervisor. This Presence module must also be started in your supervision tree (it runs its own tracker):

children = [
  PhiaUi.Collab.Supervisor,
  PhiaUi.Collab.CollabPresence
]

Topic Convention

Use "collab:room:<room_id>" as the presence topic to match the channel topic convention used by PhiaUi.Editor.CollabChannel.

User Metadata

Each tracked user carries standardized metadata:

  • :name — display name (default "Anonymous")
  • :color — hex color for cursor/avatar (default "#6366F1")
  • :avatar_url — optional avatar image URL
  • :cursor%{x: number, y: number} or nil
  • :typing — boolean typing indicator
  • :idle_since — UTC datetime when user became idle, or nil
  • :joined_at — UTC datetime when user was first tracked

Summary

Functions

Callback implementation for Phoenix.Presence.fetch/2.

Callback implementation for Phoenix.Presence.list/1.

Mark a user as idle.

Returns a formatted list of online users compatible with the presence_avatars component.

Callback implementation for Phoenix.Presence.track/3.

Track a user in a collaboration room.

Returns only users who are currently typing.

Callback implementation for Phoenix.Presence.untrack/2.

Update the cursor position for a tracked user.

Set or clear the typing indicator for a user.

Returns the count of distinct online users in the topic.

Types

user_meta()

@type user_meta() :: %{
  name: String.t(),
  color: String.t(),
  avatar_url: String.t() | nil,
  cursor: map() | nil,
  typing: boolean(),
  idle_since: DateTime.t() | nil,
  joined_at: DateTime.t()
}

Functions

child_spec(opts)

fetch(topic, presences)

Callback implementation for Phoenix.Presence.fetch/2.

fetchers_pids()

get_by_key(topic, key)

Callback implementation for Phoenix.Presence.get_by_key/2.

list(topic)

Callback implementation for Phoenix.Presence.list/1.

mark_idle(topic, user_id)

@spec mark_idle(String.t(), String.t()) :: {:ok, binary()} | {:error, term()}

Mark a user as idle.

Sets idle_since to the current UTC time and clears the typing flag.

online_users(topic)

@spec online_users(String.t()) :: [map()]

Returns a formatted list of online users compatible with the presence_avatars component.

Each user map contains: :id, :name, :color, :avatar_url, :status, :cursor, :typing. The :status field is "online" or "idle" based on the idle_since metadata.

track(socket, key, meta)

Callback implementation for Phoenix.Presence.track/3.

track(pid, topic, key, meta)

Callback implementation for Phoenix.Presence.track/4.

track_user(topic, user_id, meta)

@spec track_user(String.t(), String.t(), map()) :: {:ok, binary()} | {:error, term()}

Track a user in a collaboration room.

Normalizes the provided metadata into the standard presence schema. Missing fields receive sensible defaults.

Parameters

  • topic — the presence topic (e.g., "collab:room:doc-123")
  • user_id — unique user identifier (string)
  • meta — user metadata map; recognized keys: :name, :color, :avatar_url

Examples

iex> CollabPresence.track_user("collab:room:doc-1", "user-42", %{name: "Alice", color: "#EF4444"})
{:ok, _ref}

typing_users(topic)

@spec typing_users(String.t()) :: [map()]

Returns only users who are currently typing.

untrack(socket, key)

Callback implementation for Phoenix.Presence.untrack/2.

untrack(pid, topic, key)

Callback implementation for Phoenix.Presence.untrack/3.

update(socket, key, meta)

Callback implementation for Phoenix.Presence.update/3.

update(pid, topic, key, meta)

Callback implementation for Phoenix.Presence.update/4.

update_cursor(topic, user_id, cursor)

@spec update_cursor(String.t(), String.t(), map()) ::
  {:ok, binary()} | {:error, term()}

Update the cursor position for a tracked user.

Also clears the idle state, since cursor movement implies activity.

Parameters

  • topic — the presence topic
  • user_id — the user whose cursor moved
  • cursor — a map with position data (e.g., %{x: 120, y: 340})

update_typing(topic, user_id, typing?)

@spec update_typing(String.t(), String.t(), boolean()) ::
  {:ok, binary()} | {:error, term()}

Set or clear the typing indicator for a user.

Parameters

  • topic — the presence topic
  • user_id — the user who started or stopped typing
  • typing?true when typing, false when stopped

user_count(topic)

@spec user_count(String.t()) :: non_neg_integer()

Returns the count of distinct online users in the topic.