This repository got archived as the packages inside got migrated to a new monorepo: https://github.com/emergence-engineering/emergence-tools
React UI for prosemirror-suggestcat-plugin.
- A slash menu to select and filter AI commands, implemented with prosemirror-slash-menu-react
- An "Ask AI" tooltip that appears when text is selected
- A suggestion overlay to show streaming results and accept/reject them
- A grammar popup to display grammar suggestions with accept, discard, and hint actions
- Import
SlashMenuPluginfromprosemirror-slash-menu - Import
ProsemirrorSuggestcatPluginReactandpromptCommandsfrom this package - Add
SlashMenuPluginandcompletePluginV2to your editor - Add the component next to your editor div
import { SlashMenuPlugin } from "prosemirror-slash-menu";
import { completePluginV2 } from "prosemirror-suggestcat-plugin";
import {
promptCommands,
ProsemirrorSuggestcatPluginReact,
} from "prosemirror-suggestcat-plugin-react";
const Editor: FC = () => {
const [editorState, setEditorState] = useState<EditorState>();
const [editorView, setEditorView] = useState<EditorView>();
const editorRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const state = EditorState.create({
doc: schema.nodeFromJSON(initialDoc),
plugins: [
completePluginV2("<YOUR_API_KEY>"),
SlashMenuPlugin(promptCommands, undefined, undefined, false, true),
],
});
const view = new EditorView(document.querySelector("#editor"), {
state,
dispatchTransaction: (tr) => {
try {
const newState = view.state.apply(tr);
view.updateState(newState);
setEditorState(newState);
} catch (e) {}
},
});
setEditorView(view);
setEditorState(view.state);
return () => {
view.destroy();
};
}, [editorRef]);
return (
<Root>
<StyledEditor id="editor" ref={editorRef} />
{editorView && editorView?.state && (
<ProsemirrorSuggestcatPluginReact
editorView={editorView}
editorState={editorView.state}
/>
)}
</Root>
);
};editorView— ProseMirror EditorVieweditorState— ProseMirror EditorStatedomReference— optional HTMLElement for Popper positioning (defaults to the current selection node)
The GrammarPopup component displays an inline popup for grammar suggestions created by grammarSuggestPlugin. It shows the original text with strikethrough, the suggested replacement, and action buttons to accept, discard, or request an explanation.
import { grammarSuggestPlugin } from "prosemirror-suggestcat-plugin";
import { GrammarPopup } from "prosemirror-suggestcat-plugin-react";
// Add grammarSuggestPlugin to your editor plugins
const state = EditorState.create({
plugins: [
grammarSuggestPlugin("<YOUR_API_KEY>"),
// ...other plugins
],
});
// Render the component alongside your editor
<GrammarPopup
editorView={editorView}
editorState={editorView.state}
apiKey="<YOUR_API_KEY>"
model="cerebras:gpt-oss-120b" // optional
apiEndpoint="/custom" // optional
/>editorView— ProseMirror EditorVieweditorState— ProseMirror EditorStateapiKey— API key used to fetch hint explanationsapiEndpoint— (optional) custom endpoint for hint requestsmodel— (optional) model to use for generating hint explanations
When the cursor is inside a grammar decoration, the popup appears with:
- The original text (red, strikethrough) and the suggested replacement (green)
- Accept (
✓) — applies the suggestion - Discard (
✕) — removes the suggestion without applying - Hint (
?) — fetches an AI explanation of why the change is suggested
import "prosemirror-suggestcat-plugin-react/dist/styles/styles.css";Navigation works with keyboard (arrows, Tab, Enter, Escape) and mouse clicks. The slash menu is powered by prosemirror-slash-menu-react.
This package is intended as a quick way to get a working UI. You can customize it by:
- Providing your own
domReferencefor positioning - Overriding the CSS classes
- Passing your own commands into
SlashMenuPluginto change labels or icons
The command functions themselves must stay the same to work with prosemirror-suggestcat-plugin.
