facett-menu — the overlay menu system + Elm menu Facet
Class:
design· What it IS: oneCommandset surfaced three ways — right-click context menus, a fuzzy command palette overlay (Ctrl-K), and dropdown menu bars — plus [MenuView], the canonical facett-ElmFacetwrapping a menubar + palette so it drops into aFacetDeckand is driven headlessly by JSON. Sibling how-to:guide.md. This file states only what the crate is.
Function axis
- f0 — the crate: a uniform, theme-aware layer that sits above any facet; the house rule it enforces is that nothing is pointer-only — every action is reachable by right-click, by typing in the palette, and by id from code/test.
- f1 — the action-as-data: [
Command] (id·label·group·keywords· optionalshortcuthint /iconglyph ·enabled).ids are ownedStrings so a runtime source (e.g.facett_app::NavModel) builds them, not just literals.Commandis serde-round-trippable so it lives inside a serializable model. - f2 — the fuzzy matcher: [
fuzzy_score] (subsequence, with contiguous-run and word-start bonuses and a span penalty) and [rank] (best-first, disabled filtered, ties keep registry order via a stable sort). Public so a host or test reproduces exactly what the palette would show. - f3 — the three immediate-mode surfaces: [
context_menu] / [attach_context_menu], [menu_bar], and the floating [CommandPalette] (scrim + centered search box + keyboard-navigable, wrapping list). Each is a free primitive a host splices anywhere. - f4 — the Elm
Facet: [MenuView] —MenuState/Msg/Effect/update/pureviewbridged toFacetviaimpl_facet_via_elm!, so it is headless-drivable (update_json/state_json) and paints a menubar + palette in egui.
The Elm split (f4)
- Model — [
MenuState]: thecommandsregistry,palette_open, the palettequery+ highlightedcursor, andlast_selected(the id the host was last asked to run).commandslives in the model so a driver can read — and a host can hot-swap — the whole action set. - Msg — every input, externally-tagged serde so a driver posts JSON:
OpenPalette·ClosePalette·SetQuery(String)·MoveCursor(i32)(wraps within the hit list) ·SelectHighlighted(Enter) ·Select(String)(by id) ·SetCommands(Vec<Command>)(host hot-swap).updateis the ONLY mutation path. - Effect — [
Effect::Selected(id)]: a menu does no I/O; selecting a command hands the host itsidand the host owns what running it means. - view — a pure
&self → Vec<Msg>: paints the menubar and (when open) the palette overlay over local buffers, and returns theMsgs it produced; theimpl_facet_via_elm!bridge applies them throughupdate.
Introspection (the robot seam)
state_json is richer than the raw model (Form 3, custom_state_json): it adds the live hits — the ids the palette would show for the current query — so a robot proves the fuzzy filter narrowed without rendering. update_json deserializes a Msg straight through update. The robot test drives the full loop headless: open → type filter → assert hits → select → assert Effect::Selected.
Constraints
- Theme-aware, nothing hardcoded — every surface reads the facett
Theme(panel_bg/panel_stroke/accent/glow/text/text_dim); the selected palette row gets an accent underline + a layeredglowbloom. - Self-contained, no network — deps are only
facett-core(theme + Elm),egui,serde/serde_json. The optionaltestmatrixfeature turns each surface'sfunctional_status(...)self-report into a nornir warehouse row; compiled OUT of the default build. - Additive —
MenuViewis layered on top of the existing free surfaces; the immediate-modeCommand/menu_bar/CommandPaletteAPI thatfacett-app's NavModel bridge and menubar already use is unchanged.