Skip to content

spec(useMenuPress): a finger opens a sub-menu by lifting, and a handed-off finger is the opening press (DEC-8) - #8451

Merged
cixzhang merged 4 commits into
mainfrom
spec/menu-press-touch-model
Oct 25, 2026
Merged

cixzhang merged 4 commits into
mainfrom
spec/menu-press-touch-model

Conversation

@cixzhang

@cixzhang cixzhang commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Exact decision needed

How a finger opens a sub-menu row, how a handed-off finger behaves, and how a menu's open is announced, in module:DropdownMenu/useMenuPress.

Existing authority searched

Decision

module:DropdownMenu/useMenuPress DEC-8 (Cindy, 2026-10-25, A437 "A for menu"):

  • FR10: a finger released on a sub-menu row opens it (AST-094 FR26; drill-in is FR34's); a finger resting on it never opens it; a slide onto an open flyout picks there. This answers AST-094 OQ6, which can close by pointing here.
  • FR11: a pointer handed to the menu as it opens is the opening press; a finger picks after the handoff distance as AST-094 FR33 counts it; a mouse follows FR8's settle rule.
  • AR5: a finger opens the menu once and nothing withdraws an open; a screen reader hears one open and one close. AST-094 OQ8 can close by pointing here.
  • FR9 is unchanged (it cites AST-094 FR29 and FR19). The touch-model concept from feat(ContextMenu): a finger held until the menu opens slides onto an action and picks it #8133 is not recorded.

Rejected alternatives

  • Opening a sub-menu when a finger rests on its row.

Claim scope and non-goals

FR10, FR11, AR5 and DEC-8 only. Mouse press-to-open (FR8, DEC-4, OQ1), haptics, and AST-094 itself are unchanged.

Writing rubric results

  • R1 narration: none.
  • R2 research in the record: none.
  • R3 evidence naming a change: none; verification names test states.
  • R4 rejected alternatives over one line or outside a decision: none; one line inside DEC-8.
  • R5 pull request or issue references remaining: none.
  • R6 ruled open questions still listing options: none.

Scope

  • This PR contains specification records only.
  • It records observable behavior and preserves equivalent internal implementations.
  • Any named internal mechanism is intentionally public, names its dependent caller/system, and explains why an equivalent implementation would not satisfy the contract.
  • Verification states the evidence layer and failure signal without prescribing CI job/workflow topology.
  • It records one intentional durable decision, not a rescue for a separable tagalong.
  • The canonical knowledge owner, affected current claims, and overlapping open work are named; any ownership collision is resolved or called out for human decision.
  • Adjacent API, visual, accessibility, composition, and implementation facts remain outside scope unless this exact decision depends on them.
  • Public text and artifacts contain no internal Meta context.

Validation

  • pnpm check:knowledge (CI lint)
  • Prettier
  • git diff --check

@vercel

vercel Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
astryx Ready Ready Preview Oct 25, 2026 10:09pm UTC

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 25, 2026
@astracat-bot

astracat-bot Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Oct 25, 2026, 10:31 PM UTC

@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Oct 25, 2026
@cixzhang cixzhang changed the title spec(useMenuPress): proposed: a finger's touch model, sub-menu rows, and handed-off pointers spec(useMenuPress): a finger opens a sub-menu by lifting, and a handed-off finger is the opening press (DEC-8) Oct 25, 2026
@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

View Storybook for this PR · View Sandbox for this PR

Current run: The current change has no visual or preview-producing scope. Visual checks are not applicable; preview links are not shown.


Generated by PR Enrichment workflow | View current CI run

@cixzhang

Copy link
Copy Markdown
Contributor Author

Posted by Cindy's agent on her behalf.

Cindy's decision: under a finger, a sub-menu row opens only when the finger lifts on it; a finger resting on it never opens it. This closes spec:AST-094 OQ6. FR11 (the handoff, per AST-094 FR33) and AR5 (one open, one close) are settled with it, and AR5 lets AST-094 OQ8 close. Her /approve-spec follows at the head CodeBunny clears.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval of FR10, FR11, AR5 and DEC-8 in useMenuPress.spec.md waits on an engineering owner's decision: these are new requirements, and no owner has approved this head yet. An engineering owner records that decision by commenting /approve-spec c83aa21fd3d8566f28dafd3f1271b7dfc67356d4 on this pull request, and the author may do so as an engineering owner. Independently, FR11 needs a pointer condition: as written it makes a finger wait 10 px where the primary pointer is fine, while unchanged FR9 lets that long-pressed finger pick at once.

  • Begin FR11's finger sentence with "Where the primary pointer is coarse," as FR1–FR3 and FR7 do, and move its mouse clause to FR8, which is still proposed.
  • The readiness row's "jsdom evidence is complete" no longer holds for FR10's resting case, FR11 and AR5, and AR5's verification row should name the observed open and close rather than what a screen reader hears.

[Automated review]

| FR8 | On a mouse a DropdownMenu trigger MUST open its menu on press-down (button 0, no Control), and a drag from the trigger into the menu that releases over an enabled row MUST act on it. The opening gesture's release MUST act only if the pointer entered the menu or the press lasted the settle time; otherwise nothing acts and the menu stays open. Pressing the trigger of an open menu MUST close it and MUST NOT reopen it in the same gesture. | Proposed DEC-4; `DropdownMenu.test.tsx` press model suite, `menuPressGesture.test.ts` trigger states | proposed; pending owner review |
| FR9 | Where the primary pointer is coarse, opening a menu from its trigger under a finger and the opening finger's handoff are governed by `spec:AST-094` FR29. Where it is fine, a finger keeps the released behavior (`spec:AST-094` FR19): a tap on the trigger opens the menu through its click, and a press held on the trigger for the long-press delay opens the menu with the finger down, prevents the default of the finger's later `touchmove`s until the gesture ends, and continues under FR1–FR4. | `spec:AST-094` FR29 | as `spec:AST-094` states |
| FR10 | A finger released on a sub-menu's row MUST open that sub-menu, as the row's own click would (the lift acts, `spec:AST-094` FR26; on a compact touch screen an `adaptive` row drills in, FR34); a finger resting on the row MUST NOT open it. A finger that slides from a row onto the rows of an open flyout picks there under ORD1. | DEC-8; `DropdownMenuSubMenu.test.tsx` press cases | verify |
| FR11 | A pointer that went down elsewhere, such as a context menu's long press, and is handed to the menu as it opens MUST be the opening press. A finger picks only after the handoff distance, counted from the first position the menu sees after it opened as `spec:AST-094` FR33 counts it, and its lift before that acts on nothing and leaves the menu open; a mouse follows FR8's settle rule. | DEC-8; `useMenuPress.test.tsx` continuation suite | verify |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

FR11 names no pointer condition, so it also covers a finger where the primary pointer is fine. There, FR9 (unchanged) lets the long-pressed finger "continue under FR1–FR4", so a lift on a row within 10 px picks; FR11 says it picks nothing. Suggest opening the finger sentence with "Where the primary pointer is coarse," as FR1–FR3 and FR7 do, and moving "a mouse follows FR8's settle rule" into FR8, which is still proposed (OQ1).

| Behavior | The row under the pointer when it is RELEASED is the row that acts; the highlight follows a held mouse; a mouse released outside closes the menu; the browser's stray click for a tracked gesture never acts; the menu root declares `touch-action` by overflow. Where the primary pointer is coarse, a finger or pen's press follows `spec:AST-094` FR26–FR30; where it is fine, FR1–FR7 and FR9 here apply to it. PROPOSED (FR8, DEC-4): a mouse opens a DropdownMenu on press-down, with a settle rule on the opening release. |
| End-user impact | A finger that lands on one menu row and lifts on another acts on the second, once, instead of on the first; a drag inside an open menu picks where it lets go; a mouse that lets go outside dismisses, a finger does not. PROPOSED: a mouse can press the trigger, drag into the menu and let go on a row in one gesture. Opening under a finger is `spec:AST-094` FR29's. Keyboard behavior and sub-menu hover are unchanged. |
| Builder impact | None for consumers of the five surfaces: they mount the model themselves. A component CAN adopt this model only when it meets the eligibility criteria below, and its component contract MUST explicitly name this module and the governed surfaces before mounting `useMenuPress`. The builder supplies an enabled-row selector and a `touch-action` declaration. |
| Compatibility/readiness | Additive public hook; existing consumer props unchanged; shipped keyboard behavior unchanged. Shipped-behavior changes: DEC-3 (current; a mouse released outside a menu dismisses it) and PROPOSED DEC-4 (a mouse opens the menu on press rather than click; under a finger, `spec:AST-094` FR29). jsdom evidence is complete and real-Chromium evidence covers the touch pan, the finger slide and its stray click; iOS WebKit evidence is not required for this module. Authority: current for FR1–FR7, DEC-3, DEC-6, DEC-7 (`cixzhang`, 2026-10-02) and FR10, FR11, AR5, DEC-8 (`cixzhang`, 2026-10-25); FR8 and DEC-4 are proposed in this change and await the same owner (OQ1). |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"jsdom evidence is complete" no longer holds once FR10, FR11 and AR5 are added: at this head no test covers a finger resting on a sub-menu row or a handed-off finger, and useMenuPress.test.tsx has no continuation suite yet. Suggest saying those three await their evidence.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval of FR10, FR11, AR5 and DEC-8 in useMenuPress.spec.md waits on an engineering owner's decision: they are new requirements, and no owner has approved this head yet. An engineering owner records that decision by commenting /approve-spec be47ffa1c1033905c3eb822866d527f5a31be49f (or the full SHA of a later head), and the author may do so as an engineering owner; because an exact-head approval can auto-merge this spec-only pull request, land these fixes first and approve that head:

  • DEC-8 still says every handed-off finger waits for the handoff distance; add FR11's "where the primary pointer is coarse", since unchanged FR9 lets a fine-pointer long press pick at once.
  • AR5 lists only DropdownMenu's openings; cover a context menu opened by a long press (spec:AST-094 FR33) and FR9's held press, so it answers OQ8 for every menu.
  • Point spec:AST-094 OQ6 and OQ8 at DEC-8, so the system spec no longer lists them as open.

[Automated review]

Comment on lines +320 to +323
finger that is still choosing. A finger handed to a menu as it opens, such as
the long press that opened a context menu, is that menu's opening press: it
picks once it has travelled the handoff distance, so the press that opened the
menu never picks by itself. A finger opens a menu once, and nothing withdraws

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This sentence still applies the handoff distance to every handed-off finger, while FR11 now limits it to where the primary pointer is coarse and unchanged FR9 lets a fine-pointer long-pressed finger pick at once under FR1–FR4. Suggest: "…is that menu's opening press: where the primary pointer is coarse, it picks once it has travelled the handoff distance…".

Comment on lines +222 to +223
- **AR5 — One open, one close.** A finger opens the menu once, as
`spec:AST-094` FR29 states or through a tap's click, and nothing withdraws

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

spec:AST-094 FR29 covers DropdownMenu's trigger only, so this list leaves out the ContextMenu long press (AST-094 FR33) that FR11 names, and FR9's held press. Suggest "A finger opens a menu once, however it opens it, and nothing withdraws an open", so AR5 answers OQ8 for every menu a held finger opens.

…handed-off pointers, one open and one close (FR9 replacement, FR10, FR11, AR5)
…ter is coarse; mouse handoff moves to FR8; evidence and AR5 verification
… menu opening; AST-094 OQ6 and OQ8 point to DEC-8
@cixzhang
cixzhang force-pushed the spec/menu-press-touch-model branch from be47ffa to 3108132 Compare October 25, 2026 22:02
@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec 3108132

@github-actions github-actions Bot added spec-auto-merge Auto-merge was enabled by the spec owner gate and removed needs:spec-owner-review Current knowledge records await owner approval labels Oct 25, 2026

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This spec change is ready to land: FR10, FR11, AR5 and DEC-8 in useMenuPress.spec.md, with the AST-094 OQ6 and OQ8 pointers, are approved by an engineering owner for this head and agree with the current touch rules in AST-094, and the earlier DEC-8, AR5 and AST-094 fixes are all in. Two optional touch-ups, neither blocking: the description's scope line still says FR8 and AST-094 are unchanged, and FR11's Basis names a useMenuPress.test.tsx continuation suite that does not exist yet, so a later edit could say FR11 still needs a jsdom case as well as the real-browser one.

[Automated review]

| FR8 | On a mouse a DropdownMenu trigger MUST open its menu on press-down (button 0, no Control), and a drag from the trigger into the menu that releases over an enabled row MUST act on it. The opening gesture's release MUST act only if the pointer entered the menu or the press lasted the settle time; otherwise nothing acts and the menu stays open. Pressing the trigger of an open menu MUST close it and MUST NOT reopen it in the same gesture. A mouse pointer handed to the menu as it opens (FR11) follows the same settle rule. | Proposed DEC-4; `DropdownMenu.test.tsx` press model suite, `menuPressGesture.test.ts` trigger states | proposed; pending owner review |
| FR9 | Where the primary pointer is coarse, opening a menu from its trigger under a finger and the opening finger's handoff are governed by `spec:AST-094` FR29. Where it is fine, a finger keeps the released behavior (`spec:AST-094` FR19): a tap on the trigger opens the menu through its click, and a press held on the trigger for the long-press delay opens the menu with the finger down, prevents the default of the finger's later `touchmove`s until the gesture ends, and continues under FR1–FR4. | `spec:AST-094` FR29 | as `spec:AST-094` states |
| FR10 | A finger released on a sub-menu's row MUST open that sub-menu, as the row's own click would (the lift acts, `spec:AST-094` FR26; on a compact touch screen an `adaptive` row drills in, FR34); a finger resting on the row MUST NOT open it. A finger that slides from a row onto the rows of an open flyout picks there under ORD1. | DEC-8; `DropdownMenuSubMenu.test.tsx` press cases | verify |
| FR11 | A pointer that went down elsewhere, such as a context menu's long press, and is handed to the menu as it opens MUST be the opening press. Where the primary pointer is coarse, a finger picks only after the handoff distance, counted from the first position the menu sees after it opened as `spec:AST-094` FR33 counts it, and its lift before that acts on nothing and leaves the menu open. | DEC-8; `useMenuPress.test.tsx` continuation suite | verify |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Non-blocking: useMenuPress.test.tsx has no continuation suite yet; its suites are tracking inside the menu, one gesture one activation, release outside and cancellation, the trigger, and edge autoscroll, and none hands off a pointer. A later edit could say in the readiness row that FR11 still needs a jsdom case as well as the real-browser one.

@cixzhang
cixzhang merged commit e36bd2e into main Oct 25, 2026
57 checks passed
@github-actions
github-actions Bot deleted the spec/menu-press-touch-model branch October 26, 2026 06:31

This branch was successfully deployed

1 active deployment
Preview — 31081321 Deployed Oct 25, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. spec-auto-merge Auto-merge was enabled by the spec owner gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant