Skip to content

feat: Ribbon, an Office-style command ribbon - #499

Merged
tannevaled merged 1 commit into
mainfrom
ribbon
Oct 22, 2026
Merged

tannevaled merged 1 commit into
mainfrom
ribbon

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Adds Ribbon, an Office-style command ribbon, and NewCommandAction.

Bibliography (opened): Windows 7 "Ribbons" guidelines (learn.microsoft.com uxguide/cmd-ribbons): scaling "shows the largest valid combination that fits", up to three layouts per group, single-button groups are not folded into a pop-up, groups of 3-5 commands, large icons last to shrink, enhanced tooltips with the shortcut, keytips (Alt, tab letter, command letters, Z-prefixed tips for pop-up groups), split buttons keep the immediate command on the button, the ribbon state persists. WAI-ARIA APG toolbar (Left/Right, Home/End, role toolbar) and tabs (Left/Right wrap, Home/End, automatic activation, tablist/tab, aria-selected).

What it does

  • Tabs -> groups -> controls: button, toggle, split button, drop-down, small gallery; large (icon above text) and small (icon beside) forms.
  • Adaptive collapse by RibbonGroup.Priority: full -> compact -> icon-only -> one pop-up button; lowest priority first, rightmost among equals; a single-control group stops at icon-only. Ribbon.Levels() exposes it.
  • Collapsible: Collapsed() Observable, a chevron, Ctrl+F1, a collapsed tab peeks at its body.
  • Keyboard: tablist + toolbar navigation, Alt+Down / Down opens menus, Escape steps back; keytips on Alt.
  • Tooltips (name + shortcut, then a description) after TooltipDelayMs, driven by Tick.
  • 3:1 for boundaries and the focus ring in light and dark (PopupBorder, ensureContrast), tested on tokens and on rendered pixels across four palettes (one faint dark, one pale light).
  • A11y: toolbar > tablist > tab (selected) + controls (button / checkbox for toggles / expanded-collapsed), with rects for WalkA11y.
  • MVVM: controls are views on an Action; NewCommandAction(id, label, *mvvm.Command) follows CanExecute; the active tab, collapsed, a toggle's checked and a drop-down's selection are mvvm.Observables. Gate entry added.

A host sizes the ribbon with Height(), draws it, and calls DrawPopup last (menus, a peeking body, tooltips and keytips are drawn there).

Tests: 100% per function; layout at every width (monotone, collapse order, ties), keyboard, keytips, contrast, a11y, command binding. A screenshot gallery test writes PNGs when RIBBON_GALLERY_DIR is set (refuses a git work tree).

MINOR release after merge (ghrelease).

🤖 Generated with Claude Code

… small controls)

A Ribbon widget: tabs of groups of controls - large buttons (icon above the
text), small ones (icon beside it), toggles, split buttons, drop-downs and a
small gallery - that scales down by group priority as the width shrinks
(full -> compact -> icon-only -> one pop-up button), collapses to its tab
strip (Ctrl+F1, a chevron, a peeking body), has keytips (Alt), tooltips
carrying the shortcut and a description, keyboard navigation (a WAI-ARIA
tablist and toolbar), and a toolbar/tablist accessibility tree with
rectangles for WalkA11y.

Every control is a view on an Action (label, icon, shortcut, enabled,
visible, run); NewCommandAction makes one from an mvvm.Command, so a
CanExecute change greys every surface. The active tab, the collapsed state, a
toggle's checked state and a drop-down's selection are mvvm.Observables.
Boundaries and the focus ring reach 3:1 against the tab strip and the body in
light and dark palettes (PopupBorder / ensureContrast), checked on tokens and
on rendered pixels.

Ribbon is in the MVVM gate; 100% per-function coverage; layout tests at many
widths (the collapse order), keyboard, keytips, contrast, a11y, command
binding. Windows 7 "Ribbons" guidelines and the WAI-ARIA toolbar/tabs
patterns are cited in the code.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 5caf4a9 into main Oct 22, 2026
1 check passed
@tannevaled
tannevaled deleted the ribbon branch October 22, 2026 08:16
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