Rich text / foldkit-mixins-richtext
The slash menu
What opens a menu, what it offers, and what Enter sends are the editor's
(foldkit-richtext-dom's README explains slashQuery, slashEntries, and slashMenu), and
they are re-exported here so the chrome and the editor share one vocabulary. This package adds
the two things the editor cannot: the keys that move the highlight, and the view.
import { slashEntries, slashMenuView, slashMove } from 'foldkit-mixins-richtext'
// The catalogue as the caller's Messages.
const entries = slashEntries(message => edited(message))
// Where ArrowDown moves the highlight: the primitive's rule, shared with any other list.
const next = slashMove(entries, 'see /head', model.editor.menuIndex, 'ArrowDown', modifiers)
// The view, placed only while `slashMenu` says a query is open.
slashMenuView<Message>()(
{ entries, textBefore: RichText.textBefore(document, caret), index: model.editor.menuIndex },
h,
)slashMove returns the index a key moves the highlight to, or undefined for a key that moves
nothing, and it starts from what the menu highlights now rather than a remembered index, so a
query that narrowed past the old one does not move from a position no one can see. The keys
are the application's to handle, because only it knows the caret: ArrowUp/Down, Home/End, and
Escape in OnKeyDownPreventDefault while a query is open, writing the index to
editor.menuIndex. Enter is not: the editor's update resolves it against that index.
Each item carries data-entry (its id), role="menuitem", aria-current="true" on the
highlighted one, and its entry's Message on click, and draws the entry's icon (when the set
below has it), label and description. Under / alone the entries sit under their groups'
headings; a query lists the best matches first, without headings, and one that matches nothing
says "No matches". Outside a query the view draws nothing.
| Slot | Capability | Renders |
|---|---|---|
root | Container | the menu's wrapper |
list | Collection | the list of matches |
heading | Container | a group's name, before its first entry |
item | Interactive | one entry, per match |
icon | Container | the entry's icon |
label | Container | the entry's label |
description | Container | the line under the label |
empty | Container | "No matches" |