Skip to content

Add tooltips with shortcut hints to the markdown editor toolbar#5414

Open
FadhlanR wants to merge 2 commits into
mainfrom
markdown-toolbar-shortcuts
Open

Add tooltips with shortcut hints to the markdown editor toolbar#5414
FadhlanR wants to merge 2 commits into
mainfrom
markdown-toolbar-shortcuts

Conversation

@FadhlanR

@FadhlanR FadhlanR commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What & why

The rich-markdown editor toolbar showed plain browser title attributes on hover, which can't render a styled "label + key-command badge". This gives every toolbar item a proper styled tooltip, surfacing the keyboard shortcut where one exists.

Changes

  • packages/base/codemirror-editor.gts — Every toolbar item renders a styled boxel-ui <Tooltip>: the item label, plus a shortcut key badge for items that have a CodeMirror binding — Bold (⌘/Ctrl+B), Italic (⌘/Ctrl+I), Code (⌘/Ctrl+`). A local modKey helper picks on macOS / Ctrl elsewhere, mirroring CodeMirror's Mod-. Shortcut-less items (strikethrough, link, headings, lists, blockquote) and the add-embed / edit-embed buttons get label-only tooltips. The format-button tooltips are suppressed while the control is disabled, so no hint shows until the editor holds focus.
  • packages/boxel-ui/addon/src/components/tooltip/index.gts — Adds an opt-in @disabled arg to Tooltip: when true, hovering the trigger reveals no content. Defaults to the previous always-show behavior, so existing call sites are unchanged.
  • packages/host/app/components/modal-container.gts — Adds opt-in @closeButtonLabel / @closeButtonShortcut args. When a shortcut is supplied, the close button renders the same styled tooltip (suppressed while the close button is disabled, via the new @disabled); the absolute positioning moves to the tooltip trigger wrapper so the overlay anchors to the button. Modals that don't pass a shortcut are unchanged.
  • packages/host/app/components/markdown-embed-chooser/modal.gts — Passes @closeButtonLabel='close' @closeButtonShortcut='ESC', surfacing the already-wired Escape-to-close binding as a tooltip. The chooser now stops the Escape keydown at the modal so it no longer bubbles to the document-level operator-mode handler — previously, closing via Escape (but not via the × button) flipped the underlying card out of edit format, because the modal cleared the has-modal guard before the same event reached that handler.

No new formatting keymap entries are added — only the three shortcuts that already exist in the CodeMirror keymap get badges. Further bindings are a follow-up pending design confirmation.

Testing

  • rich-markdown-field-test — every toolbar item is wrapped in a tooltip trigger; hovering a disabled control (format buttons are disabled until the editor is OS-focused, which headless CI can't grant) reveals no tooltip. ✅
  • codemirror-embed-toolbar-test — the always-enabled Add / Edit embed buttons reveal a label-only tooltip on hover (no shortcut badge). ✅
  • markdown-embed-chooser-modal-test — the close button shows a close ESC tooltip on hover; pressing Escape closes the modal and is stopped at the modal (does not reach the document). ✅
  • eslint and ember-template-lint pass clean across the changed base + host + boxel-ui files.

All affected test modules were also run in the browser against the live dev server and pass.

Note for review

The modal close button's absolute positioning was moved onto the <Tooltip> trigger wrapper (the button itself becomes position: static inside it) so the overlay anchors correctly. Worth a quick visual check that the × still sits flush in the top-right corner.

Screen Recording

Screen.Recording.2026-07-09.at.09.20.53.mov

Ref: CS-11679

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Preview deployments

Host Test Results

    1 files  ± 0      1 suites  ±0   2h 53m 40s ⏱️ + 16m 59s
3 456 tests +39  3 441 ✅ +39  15 💤 ±0  0 ❌ ±0 
3 475 runs  +39  3 460 ✅ +39  15 💤 ±0  0 ❌ ±0 

Results for commit 476c4cd. ± Comparison against earlier commit db871d4.

Realm Server Test Results

    1 files  ± 0      1 suites  ±0   11m 45s ⏱️ +11s
1 806 tests +69  1 806 ✅ +69  0 💤 ±0  0 ❌ ±0 
1 885 runs  +69  1 885 ✅ +69  0 💤 ±0  0 ❌ ±0 

Results for commit 476c4cd. ± Comparison against earlier commit db871d4.

@FadhlanR FadhlanR force-pushed the markdown-toolbar-shortcuts branch 3 times, most recently from d7c16b7 to 94c88e7 Compare July 8, 2026 16:05
Every toolbar item renders a styled boxel-ui tooltip: the item label, plus a
key-command badge (⌘ on macOS, Ctrl elsewhere) for items that have a CodeMirror
binding — Bold, Italic, Code. The add-embed and edit-embed buttons get
label-only tooltips. Tooltips are suppressed while a control is disabled, so the
format buttons surface no hint until the editor holds focus.

Tooltip gains an opt-in @disabled arg (boxel-ui) that hides the content on hover;
it defaults to the previous always-show behavior.

ModalContainer gains opt-in @closeButtonLabel / @closeButtonShortcut args: when a
shortcut is supplied the close button renders the same styled tooltip (suppressed
while the close button is disabled), so the markdown-embed chooser surfaces its
ESC-to-close binding. The chooser stops the Escape at the modal so it no longer
bubbles to the operator-mode handler and flips the card out of edit format.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@FadhlanR FadhlanR force-pushed the markdown-toolbar-shortcuts branch from 94c88e7 to db871d4 Compare July 8, 2026 16:21
@FadhlanR FadhlanR marked this pull request as ready for review July 9, 2026 02:22
@FadhlanR FadhlanR requested a review from a team July 9, 2026 02:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces native title-attribute hover text with styled boxel-ui tooltips across the rich-markdown editor toolbar, and extends the shared <Tooltip> component with an opt-in @disabled arg so disabled controls don’t reveal hints. It also enhances the modal close button to optionally show the same “label + shortcut badge” tooltip and fixes Escape handling in the embed chooser modal so it doesn’t bubble to the document.

Changes:

  • Add styled tooltips (with optional shortcut badges) to CodeMirror editor toolbar controls, suppressing tooltip display while formatting controls are disabled.
  • Extend boxel-ui <Tooltip> with @disabled to prevent showing tooltip content.
  • Add optional close-button tooltip args to ModalContainer, and stop Escape propagation in the markdown embed chooser modal; add/extend integration tests accordingly.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/base/codemirror-editor.gts Wrapes toolbar items (including embed actions) in <Tooltip> blocks and adds shortcut badge support + styling.
packages/boxel-ui/addon/src/components/tooltip/index.gts Adds @disabled support via a showContent gate for rendering tooltip content.
packages/host/app/components/modal-container.gts Adds @closeButtonLabel / @closeButtonShortcut and renders close button inside a tooltip when provided.
packages/host/app/components/markdown-embed-chooser/modal.gts Stops Escape keydown propagation before closing; opts into close-button tooltip with close + ESC.
packages/host/tests/integration/components/rich-markdown-field-test.gts Adds coverage that disabled format controls don’t reveal tooltip content on hover.
packages/host/tests/integration/components/codemirror-embed-toolbar-test.gts Asserts add/edit embed controls show label-only tooltips (no shortcut badge).
packages/host/tests/integration/components/markdown-embed-chooser-modal-test.gts Asserts close button tooltip shows close + ESC, and Escape closes without reaching document.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 116 to 126
@action
private handleKeydown(event: Event) {
if ((event as KeyboardEvent).key === 'Escape') {
// Own the Escape here: stop it before it reaches the document-level
// operator-mode handler, which would otherwise flip the card out of edit
// format once closing this modal has cleared the `has-modal` guard.
event.preventDefault();
event.stopPropagation();
this.handleClose();
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Kept event: Event with the cast. The handler is wired via {{on 'keydown' ...}}, and this repo's Glint typing for the on modifier provides (event: Event) — typing the param as KeyboardEvent fails ember-tsc (TS2345, handler not assignable to (event: Event) => void). Casting is the established convention for keydown handlers here (e.g. file-chooser/modal.gts, card-chooser/modal.gts, indexed-file-tree.gts).

Comment on lines +1703 to +1706
border-radius: var(--boxel-border-radius-xs, 4px);
background: rgb(0 0 0 / 35%);
color: #939393;
font-family: inherit;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Done in 476c4cd — now color: var(--boxel-450, #939393). --boxel-450 is #919191, visually indistinguishable, and #939393 stays as the fallback.

Comment on lines +223 to +228
padding: 0 var(--boxel-sp-5xs);
border-radius: var(--boxel-border-radius-xs, 4px);
background: rgb(0 0 0 / 35%);
color: #939393;
font-family: inherit;
font-size: 0.9em;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Done in 476c4cd — now color: var(--boxel-450, #939393). --boxel-450 is #919191, visually indistinguishable, and #939393 stays as the fallback.

Replace the hard-coded #939393 badge text color in the markdown toolbar
and modal-container tooltips with the --boxel-450 token (same value),
keeping #939393 as the fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants