Lists, trees and boards that people reorder: sortable_list/1,
tree/1, board/1, and tree_picker/1 to choose a place in a tree.
import Narabe.Components
<.sortable_list id="tasks" items={@streams.tasks} on_move="move">
<:item :let={task}>{task.title}</:item>
</.sortable_list>
<.tree id="pages" items={@pages} on_move="move" rules={[nest: true, max_depth: 6]} filter />
<.board id="sprint" columns={@columns} cards={@cards} on_move="move_card" move_columns>
<:column :let={column}>{column.name}</:column>
<:card :let={card}>{card.title}</:card>
</.board>
<.tree_picker field={@form[:folder_id]} items={@folders} />Items move with a mouse, a finger (a short hold), or the keyboard (Space
lifts, the arrows move, Space drops); several move together when
multiple. A drop moves them in the page at once and sends on_move
to the LiveView (or to phx-target), with the move as Narabe.Move.parse/2
reads it:
%{"v" => 1, "ids" => ["7"], "parent" => nil, "after" => "3", "before" => "9", "index" => 2}Reply {:reply, %{ok: true}, socket} to keep it, or %{error: "..."}
to put the items back (Narabe.Live.reply/1 makes the reply from what
Narabe.Ecto.move/4 returned). A refused move tells the person why.
The items are structs or maps; the component reads their id from :id
and a label for screen readers from :name, :title or :label, or
from the functions item_id and item_label. A list's items may be a
stream.
The lists need the Narabe hook in the LiveSocket and the Narabe CSS
(see the README).
Summary
Functions
A board: columns of cards that people move within a column and across
them, and, with move_columns, columns that move too. A kanban, a
sprint, a pipeline.
A list that people reorder: tasks, a playlist, a menu's links.
A tree that people reorder and nest: pages, folders and files, an outline.
A field of a form that chooses an item of a tree: a folder to move
files to, a parent page, a category. It posts the item's id, as a
<select> would; disabled items are shown and not offered (the item
being moved, and those under it).
Functions
A board: columns of cards that people move within a column and across
them, and, with move_columns, columns that move too. A kanban, a
sprint, a pipeline.
columns are in their order; cards are flat, each with its column's
id (card_column, :column_id by default), in their order. A card's
move says its new column as parent; a column's move has "columns" => true.
Rules about kinds apply with the column's kind as the parent's
(column_kind), so a column may refuse some cards (accepts).
Attributes
id(:string) (required) - the element's id, and the list's in its events.label(:string) - the accessible name of the whole. Defaults tonil.on_move(:string) - the event of a move; without it, nothing moves. Defaults tonil.on_select(:string) - the event of a change of the selected items:%{"v" => 1, "ids" => [...]}. Defaults tonil.rules(:any) - what may go where:Narabe.Rules, its options, or a schema withuse Narabe.Ordered. Defaults tonil.multiple(:boolean) - whether several items are selected and moved together. Defaults tofalse.handle(:boolean) - whether items drag by their handle only (a finger still holds them anywhere). Defaults tofalse.readonly(:boolean) - no moves, only focus and selection. Defaults tofalse.locale(:string) - the language of the words (Narabe.Messages). Defaults to"en".messages(:map) - other words, by the keys ofNarabe.Messages.keys/0. Defaults to%{}.item_id(:any) - an item's id: a key or a function. Defaults to:id.item_label(:any) - an item's label, for screen readers and the filter: a key or a function. Defaults tonil.item_kind(:any) - an item's kind, for the rules: a key or a function. Defaults tonil.item_locked(:any) - why an item may not move (a string), or nil: a key or a function. Defaults tonil.issho(:list) - the list's room with Issho (Narabe.Issho):[instance: MyApp.Issho, document: "board:7/cards"]. Defaults tonil.user(:any) - the person, withissho. Defaults tonil.class(:any) - Defaults tonil.columns(:list) (required) - the columns, in their order.cards(:list) (required) - the cards, flat, in their order.card_column(:any) - a card's column id: a key or a function. Defaults to:column_id.column_id(:any) - Defaults to:id.column_label(:any) - Defaults tonil.column_kind(:any) - Defaults tonil.move_columns(:boolean) - whether the columns move too. Defaults tofalse.- Global attributes are accepted. Supports all globals plus:
["phx-target"].
Slots
column- a column's header, given the column as:let; its label by default.item- a card's content, given the card as:let; its label by default.card- the same asitem.actions- buttons a finger swipes into view (a phone), given the card as:let.footer- the end of each column (an "Add a card" button), given the column as:let.
A list that people reorder: tasks, a playlist, a menu's links.
items is a list or a stream (@streams.tasks). With a stream, insert
and delete as usual; after a move, Narabe.Live.stream_move/4 puts the
item in its new place for every other viewer.
Attributes
id(:string) (required) - the element's id, and the list's in its events.label(:string) - the accessible name of the whole. Defaults tonil.on_move(:string) - the event of a move; without it, nothing moves. Defaults tonil.on_select(:string) - the event of a change of the selected items:%{"v" => 1, "ids" => [...]}. Defaults tonil.rules(:any) - what may go where:Narabe.Rules, its options, or a schema withuse Narabe.Ordered. Defaults tonil.multiple(:boolean) - whether several items are selected and moved together. Defaults tofalse.handle(:boolean) - whether items drag by their handle only (a finger still holds them anywhere). Defaults tofalse.readonly(:boolean) - no moves, only focus and selection. Defaults tofalse.locale(:string) - the language of the words (Narabe.Messages). Defaults to"en".messages(:map) - other words, by the keys ofNarabe.Messages.keys/0. Defaults to%{}.item_id(:any) - an item's id: a key or a function. Defaults to:id.item_label(:any) - an item's label, for screen readers and the filter: a key or a function. Defaults tonil.item_kind(:any) - an item's kind, for the rules: a key or a function. Defaults tonil.item_locked(:any) - why an item may not move (a string), or nil: a key or a function. Defaults tonil.issho(:list) - the list's room with Issho (Narabe.Issho):[instance: MyApp.Issho, document: "board:7/cards"]. Defaults tonil.user(:any) - the person, withissho. Defaults tonil.class(:any) - Defaults tonil.items(:any) (required) - the items, in their order: a list or a stream.- Global attributes are accepted. Supports all globals plus:
["phx-target"].
Slots
item- an item, given as:let; its label by default.actions- buttons a finger swipes into view (a phone), given the item as:let.
A tree that people reorder and nest: pages, folders and files, an outline.
items is flat, as the database has it: each with its parent's id
(item_parent, :parent_id by default), in their order. The tree shows
each under its parent (Narabe.Tree.rows/2); a deep tree is fine.
Rows open and close with a click on their arrow, or Left and Right. With
on_expand, an item with children not loaded yet (item_children)
sends %{"v" => 1, "id" => id} as it opens: add its children to items.
With filter, a box above the tree shows the items that match, and
their ancestors. With on_rename, F2 or a double click on a label
renames the item in place and sends %{"v" => 1, "id" => id, "name" => name}.
On a phone, a tree shows as a tree, or one level at a time with
phone={:drill}.
Attributes
id(:string) (required) - the element's id, and the list's in its events.label(:string) - the accessible name of the whole. Defaults tonil.on_move(:string) - the event of a move; without it, nothing moves. Defaults tonil.on_select(:string) - the event of a change of the selected items:%{"v" => 1, "ids" => [...]}. Defaults tonil.rules(:any) - what may go where:Narabe.Rules, its options, or a schema withuse Narabe.Ordered. Defaults tonil.multiple(:boolean) - whether several items are selected and moved together. Defaults tofalse.handle(:boolean) - whether items drag by their handle only (a finger still holds them anywhere). Defaults tofalse.readonly(:boolean) - no moves, only focus and selection. Defaults tofalse.locale(:string) - the language of the words (Narabe.Messages). Defaults to"en".messages(:map) - other words, by the keys ofNarabe.Messages.keys/0. Defaults to%{}.item_id(:any) - an item's id: a key or a function. Defaults to:id.item_label(:any) - an item's label, for screen readers and the filter: a key or a function. Defaults tonil.item_kind(:any) - an item's kind, for the rules: a key or a function. Defaults tonil.item_locked(:any) - why an item may not move (a string), or nil: a key or a function. Defaults tonil.issho(:list) - the list's room with Issho (Narabe.Issho):[instance: MyApp.Issho, document: "board:7/cards"]. Defaults tonil.user(:any) - the person, withissho. Defaults tonil.class(:any) - Defaults tonil.items(:list) (required) - the items, flat, in their order.item_parent(:any) - an item's parent's id: a key or a function. Defaults to:parent_id.item_children(:any) - whether an item has children not loaded yet: a key or a function. Defaults tonil.expanded(:list) - the ids of the items open at first. Defaults to[].on_expand(:string) - the event of an item opened whose children are not loaded. Defaults tonil.on_rename(:string) - the event of a rename; without it, no renaming. Defaults tonil.filter(:boolean) - whether a box filters the items. Defaults tofalse.phone(:atom) - how the tree shows on a phone. Defaults to:tree. Must be one of:tree, or:drill.- Global attributes are accepted. Supports all globals plus:
["phx-target"].
Slots
item- an item's content, given the item as:let; its label by default.actions- buttons a finger swipes into view (a phone), given the item as:let.
A field of a form that chooses an item of a tree: a folder to move
files to, a parent page, a category. It posts the item's id, as a
<select> would; disabled items are shown and not offered (the item
being moved, and those under it).
<.tree_picker field={@form[:parent_id]} items={@pages} disabled={[@page.id]} />On a phone it shows one level at a time unless phone={:tree}.
Attributes
id(:string) - Defaults tonil.field(Phoenix.HTML.FormField) - the form's field. Defaults tonil.name(:string) - Defaults tonil.value(:any) - Defaults tonil.label(:string) - Defaults tonil.items(:list) (required) - the items, flat, in their order.item_id(:any) - Defaults to:id.item_label(:any) - Defaults tonil.item_kind(:any) - Defaults tonil.item_parent(:any) - Defaults to:parent_id.item_children(:any) - Defaults tonil.disabled(:list) - ids that may not be chosen (and the items under them). Defaults to[].expanded(:list) - the ids open at first; by default, the chosen item's ancestors. Defaults tonil.on_expand(:string) - Defaults tonil.filter(:boolean) - Defaults totrue.phone(:atom) - Defaults to:drill. Must be one of:tree, or:drill.rules(:any) - Defaults tonil.locale(:string) - Defaults to"en".messages(:map) - Defaults to%{}.class(:any) - Defaults tonil.- Global attributes are accepted. Supports all globals plus:
["phx-target"].
Slots
item