DevactionUI.CommandPalette (devaction_ui v0.2.3)

Copy Markdown View Source

The ⌘K palette as a library piece: a dialog near the top with a large field, an optional row of scopes (all, pull requests, tasks...), the results in groups with their hints, an "ask the AI" action with the typed text and a footer that teaches the keys. ↑ ↓ move the active row, ↵ opens it, ⌘↵ asks the AI and Esc closes it.

The server owns the search, as in DevactionUI.Autocomplete (whose keyboard hook it shares and whose groups it takes). The LiveView decides when it is there (:if={@open}); it takes the focus in and keeps it inside. The library has no hook for the global ⌘K that opens it: the app listens for the key (a phx-window-keydown or a small hook) and sets the assign. To get the focus back where it was, the opener runs JS.push_focus() before it opens the palette; closing it runs JS.pop_focus().

A group is %{label: "Pull requests", items: [item]} and an item is %{id: "p1", label: "Wrap tithes", to: "/pr/1", hint: "#1", tone: :risk, sub: "main", shortcut: "G P"}. A row goes where to (a LiveView navigation), patch or href says, or sends event with the item's id (a command, such as "create a contract"). hint is a small mono badge colored by tone, sub is a second line under the label and shortcut is the key cap of the item at the right (the ↵ otherwise appears on the active row). The item_icon slot draws a 28px tile with the item's icon and gets the item. Each group is a role="group" named by its label, and the active row has aria-selected; the field's aria-expanded is false when there is no row at all. hint_style: :plain draws the hint as bare mono text in its tone (the number of a pull request).

The scopes are a real role="tablist" of role="tab" buttons (the chosen one has aria-selected and is the only one in the tab order; ← → Home End move to a scope and choose it, and the row scrolls sideways when it does not fit). The first scope is the chosen one while scope is nil.

The palette has the states of a search: with an empty query the caller puts what was opened lately in a group (label: "Recent"); loading shows loading_label (with the loading_icon slot) while the server searches and marks the list busy; and with nothing to show, empty (or the empty_state slot, which gets the query) is centered in the list.

Summary

Functions

palette(assigns)

@spec palette(map()) :: Phoenix.LiveView.Rendered.t()

Attributes

  • id (:string) (required)
  • label (:string) (required) - the name of the dialog, for assistive technology.
  • query (:string) - the text in the field, kept by the caller. Defaults to "".
  • placeholder (:string) - Defaults to nil.
  • search_event (:string) (required) - sent with the text, debounced.
  • debounce (:integer) - milliseconds the field waits before sending. Defaults to 150.
  • close_event (:string) (required)
  • groups (:list) - %{label, items: [%{id, label, to | patch | href | event, hint, hint_style, tone, sub, shortcut}]}. Defaults to [].

  • empty (:string) (required) - shown, centered, when there is no row.
  • loading (:boolean) - the server is searching: shows loading_label and marks the list busy. Defaults to false.
  • loading_label (:string) - what the list says while loading. Defaults to nil.
  • ask_label (:string) - the text of the AI row; no row when nil. Defaults to nil.
  • ask_event (:string) - the event the AI row sends with the text, as q. Defaults to nil.
  • ask_kbd (:string) - the key of the AI row, as a key cap: ⌘↵; none when nil. Defaults to nil.
  • close_key (:string) - the key cap at the end of the field; none when nil. Defaults to "Esc".
  • scopes (:list) - %{value, label} each; none draws no row. Defaults to [].
  • scope (:string) - the value of the chosen scope. Defaults to nil.
  • scope_event (:string) - sent with the value of the scope pressed. Defaults to nil.
  • scope_label (:string) - the name of the scopes, for assistive technology. Defaults to nil.
  • keys (:list) - {keys, what} for the footer: {"↑↓", "move"}. Defaults to [].
  • Global attributes are accepted.

Slots

  • search_icon
  • loading_icon - turning icon before loading_label.
  • empty_state - replaces the empty text; gets the query.
  • item_icon - the icon in the tile of an item; gets the item.