Rich text / foldkit-mixins-richtext

The command palette

The slash menu's catalogue, searched from a field of its own instead of typed into the document. Whether it is open, its query, and its highlighted index are the application's, as { query, index } | null in its Model.

ts
import { commandPalette, slashEntries } from 'foldkit-mixins-richtext'

const commands = slashEntries(event => Message.ChoseCommand({ event }))

model.palette === null
  ? h.empty
  : commandPalette<Message>()(
      {
        id: 'commands',
        entries: commands,
        query: model.palette.query,
        index: model.palette.index,
        changed: (query, index) => Message.ChangedPalette({ query, index }),
        closed: Message.ClosedPalette(),
      },
      h,
    )

Typing sends changed(query, 0); ArrowUp and ArrowDown send changed(query, next), wrapping; Home and End stay the field's. Enter and a click send the entry's own Message, which is why the entries are wrapped: the application's ChoseCommand closes the palette and hands event to the editor. Enter with nothing matching sends nothing, and Escape sends closed. The field is a combobox whose aria-activedescendant names the highlighted option, so id must be unique on the page. Opening the palette on a chord and moving focus into it are the application's.

SlotCapabilityRenders
rootContainerthe palette, role="dialog"
inputTextInputthe search field, role="combobox"
listCollectionthe matches, role="listbox"
optionInteractiveone entry, data-entry and aria-selected