feat(examples): add configurable-toolbar Custom UI example (SD-2929)#3159
feat(examples): add configurable-toolbar Custom UI example (SD-2929)#3159caio-pizzol wants to merge 4 commits intomainfrom
Conversation
The smallest example that proves how to build your own toolbar with superdoc/ui. Three built-in commands (bold, italic, underline) wired per-id via ui.commands.<id>.observe, plus one custom command via ui.commands.register on the same surface. Body-only fixture, no framework. Linked from the Custom UI > Toolbar and commands docs page. Single concept per the examples rules: one custom toolbar, one registered custom command, no theming, no comments, no track changes.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db1ad57d8b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| id: 'example.insertClause', | ||
| execute: ({ superdoc: sd }) => { | ||
| const editor = sd?.activeEditor; | ||
| const target = ui.selection.getSnapshot().selectionTarget; |
There was a problem hiding this comment.
Preserve selection before executing insertClause
execute reads ui.selection.getSnapshot().selectionTarget at click time, but clicking a toolbar button moves focus off the editor and can clear the live selection first; this is already modeled in create-super-doc-ui tests (ui.selection.capture survives a later selection clear). In that path target becomes null and Insert clause silently no-ops even though the button was enabled just before the click. Capture the target before focus shifts (e.g., pointerdown/mousedown with preventDefault) or otherwise preserve the selection used for execution.
Useful? React with 👍 / 👎.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Inline links from toolbar-and-commands.mdx and custom-commands.mdx pointing at examples/editor/custom-ui/configurable-toolbar/. Same plain-link pattern used by the selection-capture link PR (#3143). The example teaches both halves of the surface (built-in command binding + ui.commands.register), so both docs pages get a callout.
|
📖 Docs preview: https://superdoc-caio-sd-2929-configurable-toolbar.mintlify.app |
Clicking a toolbar button steals focus from the editor on mousedown, which can collapse the live selection before the click handler runs. For built-in commands the buttons could end up disabled mid-click; for the custom Insert clause command, ui.selection.getSnapshot() .selectionTarget would return null and the insert silently no-ops. Add a mousedown preventDefault on every toolbar button to keep the editor focused while the click is dispatched. Same trick the built-in toolbar uses internally. Caught by the bot reviewer on #3159.
The smallest example that proves how to build your own toolbar with
superdoc/ui. Three built-in command buttons (bold, italic, underline) wired per-id viaui.commands.<id>.observe(...), plus one custom command viaui.commands.register(...)on the same surface. Body-only fixture, no framework.Linked from Custom UI > Toolbar and commands. Single concept per the examples rules in
dx-comms/architecture/examples-and-demos.md: one custom toolbar, one registered custom command, no theming / comments / track changes / mode toggle.The custom command (
example.insertClause) reads the current selection target fromui.selection.getSnapshot().selectionTargetand inserts a fixed snippet viaeditor.doc.insert(...)at that target.getStatedisables the button when the editor isn't ready or there's no positional selection, so the toolbar reads consistently across built-ins and customs.Verified:
pnpm install;pnpm --filter superdoc build;pnpm exec tsc --noEmitclean; dev server boots onhttp://localhost:5173/. Manifest entry, README link, andcustom-uimatrix inci-examples.ymlupdated.