Skip to content

feat: add advanced keyboard shortcuts#196

Merged
ocavue merged 3 commits into
prosekit:masterfrom
maccman:claude/stoic-lichterman-6b025f
Jul 2, 2026
Merged

feat: add advanced keyboard shortcuts#196
ocavue merged 3 commits into
prosekit:masterfrom
maccman:claude/stoic-lichterman-6b025f

Conversation

@maccman

@maccman maccman commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

What

Ports the editor-scoped keyboard behaviors from the v1 Reflect editor, per the porting doc's recommended list:

  • Alt-ArrowUp / Alt-ArrowDown — new move-block.ts. Moves the list item under the caret together with its nested children (via prosemirror-flat-list's createMoveListCommand), and falls back to swapping a plain top-level block with its previous/next sibling so the shortcut behaves uniformly outside lists. The caret stays inside the moved block. No-op inside table cells (row swapping is deliberately out of scope) and at document edges.
  • [ over a selection — extends wikilink-trigger.ts. Typing [ over a non-empty single-block selection replaces it with [[selection (brackets left open, caret at the end) so the wikilink menu opens with the selection as the query. Guards: a selection already starting with [[ falls through (never [[[), a leading single [ is stripped so a second tap converges, and a bare [ on an empty caret still types literally. Mod-Shift-k keeps its existing behavior via the same command with allowEmpty, and both now decline inside code blocks.
  • Mod-Enter follows the link under the caret — new follow-link.ts. Resolves the wikilink, tag, or Markdown link at the caret (wikilink → tag → link) and fires the same onWikilinkClick / onTagClick / onLinkClick handlers a click does, with the KeyboardEvent as event. Off a link the key falls through, so the existing checkbox-task cycle on Mod-Enter is untouched — the plugin runs at Priority.high, ahead of every keymap binding, and returns false when there is nothing to follow. The click payload event types widen to MouseEvent | KeyboardEvent.
  • Mod-Shift-7/8/9 — ordered / bullet / task list toggles in the list keymap (Google-Docs semantics via toggleList: same kind unwraps, a different kind converts in place, a non-list block wraps). Resolved through the physical digit key, so layouts where Shift+digit types punctuation still work.
  • Escape collapses a non-empty selection — new escape-collapse.ts, bound at Priority.low so the autocomplete menus (which bind Escape at the highest priority) keep dismissing themselves first; a React test verifies an open wikilink menu closes without disturbing the text and only a second press touches the selection.

The EDITOR_KEY_BINDINGS table and the README shortcuts table document all the new bindings (plus the previously missing Mod-Shift-k entry).

Why

These are the most-missed structural edits from the v1 editor — reordering a bullet without cut/paste, linking a selected phrase in two keystrokes, and following links without the mouse. Editor-level bindings belong here in meowdown; the host app only sees the existing click-handler props.

Notes for review

  • The Mod-Enter conflict with the task-rotate cycle is the subtle part: follow-link.test.ts covers both sides (on-link follows and leaves the markdown untouched; off-link in the same task item rotates it), plus the modifier guard so Mod-Shift-Enter keeps rotating circle tasks even on a link.
  • The list-toggle tests press the physical [Digit7..9] keys to exercise prosemirror-keymap's keyCode fallback for shifted digits. Verified under Chromium locally; worth watching under WebKit in CI.
  • No new React props: Mod-Enter reuses the existing onWikilinkClick/onTagClick/onLinkClick threading, installed only when a handler is present.

Testing

  • 34 new tests across move-block.test.ts, wikilink-trigger.test.ts, follow-link.test.ts, escape-collapse.test.ts, and extensions to list.test.ts / wikilink-menu.test.tsx, including markdown round-trip assertions.
  • Full suite: 66 files, 1092 passed (17 pre-existing expected failures). tsc -b, eslint, oxfmt, and knip all clean.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jul 2, 2026

Copy link
Copy Markdown

@maccman is attempting to deploy a commit to the ocavue's projects Team on Vercel.

A member of the Team first needs to authorize it.

@pkg-pr-new

pkg-pr-new Bot commented Jul 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/prosekit/meowdown/@meowdown/core@196
npm i https://pkg.pr.new/prosekit/meowdown/@meowdown/react@196

commit: 1c6d12b

Adds the meowdown-scoped keyboard behaviors from the v1 editor:

- Alt-ArrowUp/Down moves a list item with its nested children, or swaps
  a plain top-level block with its neighbor (no-op inside tables)
- Typing [ over a selection wraps it into an open wikilink ([[query)
  with the menu searching it; a bare [ still types literally
- Mod-Enter follows the wikilink/tag/link under the caret through the
  same handlers a click uses, falling through to the task cycle off-link
- Mod-Shift-7/8/9 toggle ordered/bullet/task lists (same kind unwraps)
- Escape collapses a non-empty selection, at low priority so open menus
  keep owning the key

The click payload event types widen to MouseEvent | KeyboardEvent, and
the key-bindings table and README document the new shortcuts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@maccman maccman force-pushed the claude/stoic-lichterman-6b025f branch from c2d5ea8 to dade0b7 Compare July 2, 2026 06:11
@maccman maccman requested a review from ocavue July 2, 2026 07:12
Exercises the two untested branches of the block-move fallback: a
NodeSelection from the block handle moves the node and keeps it
selected, and a caret inside a blockquote moves the whole blockquote.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ocavue ocavue changed the title feat: port v1 editor keyboard shortcuts feat: add more keyboard shortcuts Jul 2, 2026
@ocavue ocavue changed the title feat: add more keyboard shortcuts feat: add advanced keyboard shortcuts Jul 2, 2026
@ocavue ocavue merged commit 49dfc87 into prosekit:master Jul 2, 2026
10 checks passed
@ocavuebot ocavuebot mentioned this pull request Jul 2, 2026
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.

2 participants