API REFERENCE · UTILITIES
@dojo-ng/rich-text-menu
The caret menu that the mentions and slash-command plugins are built on. It is not a plugin you load directly.
npm install @dojo-ng/rich-text-menu
Inside a plugin's setup(ctx), create a menu from a trigger config and drive it with setOptions. See @dojo-ng/rich-text-mentions for a complete plugin built on this.
import { createEditorMenu } from "@dojo-ng/rich-text-menu";
export const myPlugin = {
name: "at-menu",
setup(ctx) {
const menu = createEditorMenu(ctx, {
match: (text) => { const m = /(^|\s)@(\w*)$/.exec(text); return m ? { start: m.index + m[1].length, query: m[2] } : null; },
onQueryChange: async (q) => menu.setOptions((await fetchPeople(q)).map((p) => ({ value: p.id, label: p.name }))),
onPick: (opt) => ctx.editor.update(() => { /* insert something for opt */ }),
});
return () => menu.dispose();
},
};
What it does
- It shows a
dj-popupand adj-listat the caret, with arrow, Enter, Tab, and Escape navigation, a polite live region, and closing on a click outside, Escape, or blur.
Using it
Call createEditorMenu(ctx, config). The config has three functions:
match(textBeforeCaret)finds the trigger and the query, and returns{ start, query }ornull.onQueryChange(query)fetches or filters, then calls the menu'ssetOptions(options, loading?).onPick(option)runs after the trigger text has been removed.
Also exported
- The the
EditorMenuConfigandMenuMatchtypes, andcomputeMatch(textBeforeCaret, matchFn)for testing a matcher without a browser.
Functions
computeMatch
function computeMatch(textBeforeCaret: string, matchFn: EditorMenuConfig["match"]): {
start: number;
query: string;
} | null;
createEditorMenu
function createEditorMenu(ctx: RichTextContext, config: EditorMenuConfig): EditorMenu;
Types
EditorMenu
interface EditorMenu {
setOptions(options: ListOption[], loading?: boolean): void;
readonly open: boolean;
close(): void;
dispose(): void;
}
EditorMenuConfig
interface EditorMenuConfig {
match(textBeforeCaret: string): {
start: number;
query: string;
} | null;
onQueryChange(query: string): void;
onPick(option: ListOption): void;
pickInUpdate?: boolean;
}
MenuMatch
interface MenuMatch {
start: number;
end: number;
query: string;
}