Skip to content

refactor(core): replace menu-viewport-transition with menu-viewport#1579

Closed
sampotts wants to merge 12 commits into
feat/transition-lifecyclefrom
feat/menu-viewport
Closed

refactor(core): replace menu-viewport-transition with menu-viewport#1579
sampotts wants to merge 12 commits into
feat/transition-lifecyclefrom
feat/menu-viewport

Conversation

@sampotts
Copy link
Copy Markdown
Collaborator

@sampotts sampotts commented May 21, 2026

Refs #1533
Refs #1577

Summary

Replace menu-viewport-transition with createMenuViewport for nested menu panel sizing and root/submenu view transitions.

Changes

  • Introduce menu-viewport.ts and DOM measure helpers
  • Wire transitioning state through core menu, popover, and dismiss-layer bindings
  • Add submenu trigger controller foundation for nested menu navigation

Pointer activation

Menu items and submenu triggers are div role="menuitem" surfaces with custom click handlers, not native buttons. Handlers guard with if (event.button !== 0) return before selecting or pushing a submenu.

A mouse click is usually primary-button only, but the check is deliberate: it limits activation to primary pointer input (ARIA menu model), prevents preventDefault() on submenu clicks from suppressing non-primary browser defaults if a stray click ever fires, and mirrors the same primary-button filter used on pointer events elsewhere. Keyboard activation (Enter, Space, ArrowRight) uses separate key handlers.

See internal/design/ui/menus.md → Accessibility → Pointer activation.

Testing

  • pnpm -F @videojs/core test src/dom/ui/menu/tests/menu-viewport.test.ts src/dom/ui/menu/tests/create-menu.test.ts
  • pnpm -F @videojs/html test src/ui/menu/tests/menu-element.test.ts
  • pnpm -F @videojs/react test src/ui/menu/tests/menu.test.tsx

Note

Medium Risk
Refactors core menu navigation/transition coordination (viewport sizing, focus restoration, popup grouping) across DOM/React/HTML implementations; regressions could affect menu open/close behavior and nested submenu animations.

Overview
Replaces menu-viewport-transition with a new createMenuViewport() implementation that measures stacked menu panels, drives --media-menu-width/height, and coordinates a persistent root panel transition while submenus enter/exit.

Updates menu transition and lifecycle handling: createMenuViewTransition now tracks transitioning, supports persistent panels, exposes reset(), and uses scheduleTransitionSettle() (added to dom/ui/transition) to clear transition attrs once animations/visual completion settle.

Refines menu behavior for nested menus and interactions: root vs submenu popup-group coordination is formalized (shared group by default, isolated groups for nested menus without an explicit group), navigation stack reset is deferred until close completes, trigger focus restoration is guarded to avoid stealing focus during deferred reopen/peer menu interactions, and highlight/navigation now syncs to the keyboard event target when hover highlight differs.

Aligns React/HTML menu parts with the new model: root views use data-menu-view-id="root" and persistent attrs, submenus register with the parent viewport via registerSubmenuView, menu items/back buttons/submenu triggers gate activation to primary pointer (event.button === 0) and add pointer-enter highlight behavior; introduces dom/utils/measure and a SubmenuTriggerController for consistent submenu trigger wiring.

Reviewed by Cursor Bugbot for commit 7ab5440. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v10-sandbox Ready Ready Preview, Comment May 21, 2026 10:28am

Request Review

Comment thread packages/core/src/dom/ui/menu/menu-viewport.ts
Comment thread packages/core/src/dom/ui/transition.ts
Comment thread packages/html/src/ui/menu/submenu-trigger-controller.ts
Comment thread packages/html/src/ui/menu/menu-element.ts Outdated
Comment thread packages/react/src/ui/menu/menu-view.tsx
Comment thread packages/core/src/dom/ui/menu/create-menu.ts Outdated
Comment thread packages/core/src/dom/ui/menu/create-menu.ts
sampotts and others added 8 commits May 21, 2026 16:05
Introduce createMenuViewport for nested menu panel sizing and view
transitions, add DOM measure helpers, and wire transitioning state through
core menu and popover bindings.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Explain why menuitem click handlers check event.button before activation.

Co-authored-by: Cursor <cursoragent@cursor.com>
Register submenu views once instead of every update cycle, and invalidate
viewport transition settle callbacks on destroy.

Co-authored-by: Cursor <cursoragent@cursor.com>
HTML menus register the viewport host before child views connect, so the
initial syncRoot pass can miss the root panel and leave sizing CSS vars unset.
Re-measure on open after child custom elements mount.

Co-authored-by: Cursor <cursoragent@cursor.com>
Settings menus register two submenu panels; bindChild previously replaced
the active subscription so viewport transitions never ran for the first
panel. Track bindings per view, restore the root panel when returning from
a submenu, and animate initial open height via syncRoot.

Co-authored-by: Cursor <cursoragent@cursor.com>
Introduce the helper alongside menu viewport sizing so the transition
lifecycle PR stays focused on createTransition while viewport code can
wait for layout and animation settle.

Co-authored-by: Cursor <cursoragent@cursor.com>
…olves

Lazy-create root panel transitions when parentMenu is known, register
menu content after parent context is available, and skip redundant
submenu view sync when navigation state is unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
Only skip redundant navigation sync in updateAsSubmenu; still apply
transition attrs when phase changes without a navigation update.

Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve the base popup group on each delegated call so submenu
open/close stays on the shared root group, and treat an explicit
group resolver returning undefined as a dedicated createPopupGroup().

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread packages/html/src/ui/menu/menu-back-element.ts
Match other menu surface handlers by ignoring non-primary clicks on
MenuBack in HTML and React.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread packages/react/src/ui/menu/menu-trigger.tsx
Match MenuItem and MenuBack by ignoring non-primary pointer buttons
before invoking consumer handlers or opening the submenu.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7ab5440. Configure here.

override disconnectedCallback(): void {
super.disconnectedCallback();
this.#cleanupRegistration?.();
this.#cleanupRegistration = null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Back button uses wrong ARIA role as menu item

Medium Severity

The back button is now registered as a navigable menu item via menu.registerItem(this), making it participate in ArrowUp/ArrowDown keyboard cycling. However, it retains role="button" (explicit in HTML, implicit via <button> in React). Items inside a role="menu" container are expected to have role="menuitem" per WAI-ARIA. This combination breaks the ARIA ownership model and may confuse assistive technology during keyboard navigation.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7ab5440. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant