# `Masu.Presence`
[🔗](https://github.com/hattoriai/masu/blob/v0.1.0/lib/masu/presence.ex#L1)

Who else has a grid open, and where they are: the people of a grid,
with `Phoenix.Presence`.

    <.data_grid
      id="orders"
      source={Order}
      repo={Repo}
      changeset={&Order.changeset/2}
      live={{MyApp.PubSub, "orders"}}
      presence={MyAppWeb.Presence}
      user={%{id: @current_user.id, name: @current_user.name}}
    >

The grid shows the other people who have it open (their avatars above
it), the cell each of them is on (a line in their color, with their
name), the cell each of them is editing (which the others cannot edit
meanwhile), and the rows they save, which flash in their color.

## Setting up

`presence` is your app's `Phoenix.Presence` module, on the same PubSub
as the grid's `live` topic (`mix phx.gen.presence` makes one):

    defmodule MyAppWeb.Presence do
      use Phoenix.Presence, otp_app: :my_app, pubsub_server: MyApp.PubSub
    end

and it must be started in your supervision tree, after the PubSub. The
grid needs `live` (the people of a grid are those of its topic) and the
`Masu.Live` hook.

## The user

`user` is a map: `id` (required), `name`, and, if you have them,
`color` (a CSS color) and `avatar` (an image's URL). A person with no
color gets one of a palette of eight, by their id, the same in every
browser.

The people are those of other users: a person who has the grid open in
two tabs does not see themselves.

## Places, not positions

Each person has their own order, filters and search, so a place is a
row's id and a column's key, not a row's index: a person sees another's
line on the cell of that row wherever it is in their own order, and not
at all when their filters leave the row out.

## The look

The avatars are HEEx: give the grid a `:person` slot to draw them with
your own component; it gets each person as a map with `:id`, `:name`,
`:color`, `:avatar`, `:initials`, `:cell`, `:range`, `:editing`, `:view`
and `:top`. Each avatar is a button that follows the person: the grid
shows their order, filters and search (unless their grid has
`share_view={false}`) and keeps their place in view:

    <:person :let={person}>
      <.avatar src={person.avatar} name={person.name} ring={person.color} />
    </:person>

The lines and labels on the cells are drawn by the browser: they are
`.masu-peer` and `.masu-peer-label` elements with the person's color in
`--masu-peer-color` (see the Theming guide), and `configure/1` of the
bundle draws the label with a function of your own.

## Editing at the same time

A cell that someone is editing shows it, and does not open an editor
for anyone else: an advisory lock, as a database's. The guarantee is the
server's: an edit of a cell that changed meanwhile is refused (see the
Editing guide).

# `person`

```elixir
@type person() :: %{
  id: String.t(),
  name: String.t() | nil,
  color: String.t(),
  avatar: String.t() | nil,
  initials: String.t(),
  cell: [term()] | nil,
  range: map() | nil,
  editing: boolean(),
  view: map() | nil,
  top: term()
}
```

A person who has the grid open.

# `color`

```elixir
@spec color(map()) :: String.t()
```

The color of a user: their own `color`, or one of a palette of eight by
their id, the same in every browser.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
