Skip to content

feat(hub-ui): assign keyboard shortcuts to dock group members - #282

Open
SaKaNa-Y wants to merge 2 commits into
devframes:mainfrom
SaKaNa-Y:feat/dock-group-shortcuts
Open

feat(hub-ui): assign keyboard shortcuts to dock group members#282
SaKaNa-Y wants to merge 2 commits into
devframes:mainfrom
SaKaNa-Y:feat/dock-group-shortcuts

Conversation

@SaKaNa-Y

@SaKaNa-Y SaKaNa-Y commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Resolves the "dock group members can never be assigned keyboard shortcuts" problem discussed in vitejs/devtools#501, following the approach @antfu proposed there: when a shortcut hits a group entry with no defaultChildId, the command palette offers the sub-docks so the flow stays keyboard-driven.

Two independent halves, one commit each.

fix: nested commands were unbindable

Every consumer of the command tree walked a single level of children. Dock group members sit two levels below the Docks command, so they had no row in Settings → Shortcuts to bind, no entry in the keybinding collector to fire, and no id the dispatcher could resolve. That depth-1 ceiling is the literal cause of "can never be assigned".

Traversal now lives in one place: walkCommands visits the tree depth-first with a 'skip'/'stop' visitor signal, shared by findCommandDeep, collectAllKeybindings, the shortcut-settings rows, and the palette's root flatten. filterCommandsByWhen keeps its own recursion, since it rebuilds a cloned tree per level.

The ceiling was also stated in the public type: children on both DevframeServerCommandInput and DevframeClientCommand documented "Two levels max (parent → children)". Both now read "nested arbitrarily deep", so the JSDoc a consumer hovers matches what the tree actually accepts.

The palette's flatten and drill-down stack move to state/palette.ts. showInPalette: 'without-children' now prunes a whole subtree rather than one level, and a row carries its full path for search while displaying only its immediate parent.

feat: activating a group no longer guesses a member

A group has no view of its own, so activating one by id used to fall back to whichever member came first. A group whose members are peers has no member worth picking.

Activating a group now opens an unambiguous target directly — the author's defaultChildId, or a lone visible member. With several peer members it opens the palette drilled into that group. Pressing the same shortcut again closes the palette; stepping back to the root list unscopes it, so the shortcut drills back in rather than toggling.

CommandsContext gains openPalette(atCommandId?) and paletteScopeId. Members hang directly off their group in the command tree — the dock rail's sub-category dividers have no counterpart there, since a category is not something you can run. A group with no visible member and no reachable defaultChildId registers no command at all.

switchEntry is unchanged, so boot restore and hub:docks:activate behave as before, and clicking a group button still opens the member popover.

Picking a member through the scoped palette also raises it into the recent-dock slot from #305, with no extra wiring: that feature watches the selection rather than the dock rail's click handlers, so a keyboard-driven pick lands in the same slot a popover pick does.

Verification

Rebased onto main at fa37a62. pnpm lint, pnpm typecheck (38/38) and pnpm build (27/27) are clean. Tests: 121 files, 1333 passing, 14 skipped, 0 failing.

Two @devframes/plugin-code-server tests still fail on my machine — a test fixture's temp-file handoff (ENOENT … Temp\dcs-dump-*\hashed) that doesn't work on Windows. Confirmed unrelated: checked out main at fa37a62 with this branch absent and got the identical 2 failed | 11 passed. They sit outside pnpm test's scope either way.

New specs: state/keybindings.test.ts (traversal, skip/stop, deep lookup), state/palette.test.ts (showInPalette pruning, path/parent titles, scope-trail degradation), and group-activation cases in state/context.test.ts. New stories: Commands/Palette → ScopedToGroup, Views/Builtin/Settings → DeeplyNestedShortcuts.

Docs: an "Activating a group" section and a "Nested commands" section in the hub guide, plus the openPalette / paletteScopeId surface in the client-context table. New prose and comments follow the Terms vocabulary from #298 (dock rail, a devframe rather than a bare "host").

@vercel

vercel Bot commented Aug 22, 2026

Copy link
Copy Markdown

@SaKaNa-Y is attempting to deploy a commit to the NuxtLabs Team on Vercel.

A member of the Team first needs to authorize it.

@SaKaNa-Y
SaKaNa-Y marked this pull request as draft August 22, 2026 03:55
Every consumer of the command tree walked a single level of `children`, so
anything deeper was unreachable: a dock group's members had no row in the
shortcut settings to bind, no entry in the keybinding collector to fire, and
no id the dispatcher could resolve.

Traversal now lives in one place. `walkCommands` visits the tree depth-first
with a `'skip'`/`'stop'` visitor signal, and `findCommandDeep`,
`collectAllKeybindings`, the shortcut settings rows and the palette's root
flatten all share it. `filterCommandsByWhen` keeps its own recursion since it
rebuilds a cloned tree per level.

The palette's flatten and drill-down stack move to `state/palette.ts`, where
`showInPalette: 'without-children'` prunes a whole subtree rather than one
level, and a row carries its full path for search while displaying only its
immediate parent. Shortcut rows indent by nesting level instead of a boolean.
A group has no view of its own, so activating one by id — its shortcut, a
palette pick, an RPC activation — used to fall back to whichever member
happened to come first. That picked for the user, and a group whose members
are peers has no member worth picking.

Activating a group now opens an unambiguous target directly: the author's
`defaultChildId`, or a lone visible member. With several peer members it opens
the command palette drilled into that group, so the choice stays with the user
and the group is reachable by keyboard alone. Pressing the same shortcut again
closes the palette; stepping back to the root list unscopes it, so the
shortcut drills back in rather than toggling.

`CommandsContext` gains `openPalette(atCommandId?)` and `paletteScopeId`.
Members hang directly off their group in the command tree — the dock bar's
sub-category dividers have no counterpart there, since a category is not
something you can run. A group with no visible member and no reachable
`defaultChildId` registers no command at all.

`switchEntry` is unchanged, so boot restore and `hub:docks:activate` behave
as before.
@SaKaNa-Y
SaKaNa-Y force-pushed the feat/dock-group-shortcuts branch from b8e9a78 to cb369f0 Compare August 27, 2026 08:36
@SaKaNa-Y
SaKaNa-Y marked this pull request as ready for review August 27, 2026 08:46
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.

1 participant