With Issho, a picker shows who else is choosing in it: the people of the room who have it open, each in their color, and the option each is on. An agent that changes a value goes to the picker, opens it and moves to the option before the value lands, so that the people see it choose.
A picker's value is not shared here: it is the value of the document that holds it (a page's property, a row, a form), which your app saves and shares as it does. Erabi carries only who is choosing, and where.
The picker
<.select
field={@form[:status]}
options={@statuses}
issho={[instance: MyApp.Issho, document: "page:42/status"]}
user={@current_user}
/>issho takes the keys of every component of the family (Issho.Join):
the picker's document names it in its room (the part before the first
"/", so the pickers of a page share its people), and the LiveView joins
the room for it. user is the person, as Issho.Actor says them. Add
Issho to your deps ({:issho, "~> 0.4"}) and on_mount Issho.Live to the
LiveView.
What people see
- On the field: the avatars of the others who have the picker open, and a ring in the color of the one choosing; its title says "Ada is choosing", and a screen reader hears it once.
- In the list, when they open it too: the option each one is on, marked with their avatar.
- When the list is closed on their screen: a peek of it, read-only, with the other's option tinted in their color, moving as they move. It goes when they close the list.
One at a time
A picker is chosen in by one person at a time. The one who opens its
list holds its lock until they close it, or leave: on the others'
screens, the picker says who is choosing, does not open (a nudge, and a
screen reader hears who), and shows the peek. If two open it at the
same moment, the one who opened it first keeps it on every screen, and
the other's list closes with the reason. An agent holds the lock while
it chooses, and does not choose while someone else holds it
({:error, {:locked, key}}).
lock: false in issho turns the locks off: everyone may open the
picker at once, and each sees the others' options marked in their list.
The lock is the people's way of not choosing over each other, not a check: a form still posts, and the app's document keeps the last value saved.
Pointers
With Issho's pointers on the page, a person's pointer over an option is
that option on every screen, and an agent's pointer goes to it
(Erabi.Issho's places, by the option's value).
An agent
An agent's tool changes the value as the app does, in its own document, and lets the people see it choose first:
def call(%{"status" => status}, ctx) do
{:ok, participant} = Issho.Tool.Context.join(ctx, "page:42")
Erabi.Issho.choose(participant, "page:42/status", status, fn ->
Pages.set_property(page, :status, status)
end)
endErabi.Issho.choose/5 goes to the picker (its list opens on the screens
that show it), then to the option, waits a moment there (:pace, 500
ms), runs the function, and leaves the picker. For a picker of several,
give the values: it goes to each in turn. The agent moves only for
someone who sees the picker, within Issho's time budget
(Issho.Motion); else the value lands at once.