Repository navigation
spec(useMenuPress): a finger opens a sub-menu by lifting, and a handed-off finger is the opening press (DEC-8) - #8451
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
PR Analysis ReportView Storybook for this PR · View Sandbox for this PR
Generated by PR Enrichment workflow | View current CI run |
|
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 |
There was a problem hiding this comment.
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 | |
There was a problem hiding this comment.
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). | |
There was a problem hiding this comment.
"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.
There was a problem hiding this comment.
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-094FR33) and FR9's held press, so it answers OQ8 for every menu. - Point
spec:AST-094OQ6 and OQ8 at DEC-8, so the system spec no longer lists them as open.
[Automated review]
| 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 |
There was a problem hiding this comment.
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…".
| - **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 |
There was a problem hiding this comment.
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)
…ouch-model proposal dropped
…ter is coarse; mouse handoff moves to FR8; evidence and AR5 verification
… menu opening; AST-094 OQ6 and OQ8 point to DEC-8
be47ffa to
3108132
Compare
|
/approve-spec 3108132 |
There was a problem hiding this comment.
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 | |
There was a problem hiding this comment.
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.
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
module:DropdownMenu/useMenuPress(current): FR1–FR7, FR9 (a finger's opening keyed on the primary pointer), DEC-3; FR8 and DEC-4 proposed (OQ1).spec:AST-094(current): FR26 (the lift acts), FR29 (DropdownMenu opens on press, with the opening finger's handoff;presentation="popover"keeps the tap), FR33 (ContextMenu's held-finger handoff), FR34 (sub-menu drill-in on a compact touch screen); OQ6 (opening a sub-menu without a lift) is open there.Decision
module:DropdownMenu/useMenuPressDEC-8 (Cindy, 2026-10-25, A437 "A for menu"):Rejected alternatives
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
Scope
Validation
pnpm check:knowledge(CI lint)git diff --check