Repository navigation
Conversation
Touch presentations get one native-feeling behavior by default on every touch device: measured values, compositor motion a finger can catch, recognizer-tracked gestures, two press profiles, Reduce Motion per design:reduced-motion, menus and popovers under a finger (FR26-FR35), and one release decision for every drag that commits (FR36-FR40). Touch motion is themeable through use-named roles, except motion that must stay in step with the on-screen keyboard (AST-099 FR8). The seven current records it amends point to it. Retries #8378, whose review rounds were spent, carrying its last revision plus the keyboard exception and three decisions pending an owner ruling (DEC-5 the generated role table, DEC-6 touch media-query CSS, DEC-7 passive watchers). Co-authored-by: vjeux <197597+vjeux@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
PR Analysis Report
The exact-head preview is not available yet. Generated by PR Enrichment workflow | View current CI run |
There was a problem hiding this comment.
This spec is not ready to approve yet: no engineering owner has approved spec:AST-094 or its amendments to eight current records at this head, and DEC-5 to DEC-7 still read "pending owner ruling". Once those three rulings are settled in the record, an engineering owner (the author included, as one) records the decision by commenting /approve-spec <full head SHA> on this pull request. Whatever that decision, these need fixing first:
- FR29 moves DropdownMenu's released
presentationdefault ('popover') anduseMenuPress's released 500 mslongPressDelayMs, so please name both in FR25 and the Current-state impact and mark the trigger half released inuseMenuPress.spec.md. - DEC-5 to DEC-7 are pending inside a record marked current and accepted, so please name their decider, or mark them and the sentences they settle (FR4, FR13, FR20) as proposed.
- FR4 cites a generated motion role table that
astryx docs motiondoes not contain, so the 17 named roles have no recorded default or source. - FR33 gives no
presentationway back for the ContextMenu lift, unlike FR29 for DropdownMenu. - The DR1 amendment in
docs/design/user-states.mdreplaces the pressed-overlay paint with FR11, which only sets timing, so please keep the paint and move only the timing, as the DR3 amendment does.
[Automated review]
| on FR26–FR28 apply. `presentation="popover"` keeps today's open on a tap; | ||
| the default is unset (`architecture:public-component-api` INV16). The delay and distances are internal values and gain no new props | ||
| (`spec:AST-002` FR3); A `module:DropdownMenu/useMenuPress` caller that sets the released | ||
| `longPressDelayMs` gets that wait in a fixed bar and in a scroll view alike, | ||
| which keeps the released behavior (`spec:AST-017` FR3). |
There was a problem hiding this comment.
This moves two released defaults: DropdownMenu's documented presentation default ('popover') becomes unset, and a useMenuPress caller that leaves longPressDelayMs unset loses the released 500 ms wait. FR25 and the Current-state impact name only Selector's moved default, so please add both.
| (`architecture:theme-tokens` INV3); the generated motion role table | ||
| (`astryx docs motion`) lists every role with its kind and default. The role's default value is |
There was a problem hiding this comment.
astryx docs motion (packages/cli/assets/docs/motion.doc.mjs) has no role table at this head, so the 17 roles named in FR4, FR31 and FR34 have no recorded default or source, which FR2 requires next to each value.
| - **FR33 — A ContextMenu under a finger.** With a finger or pen, the long | ||
| press that opens a ContextMenu MUST NOT close it at the lift, and a press | ||
| outside it follows FR32. On every touch device, a ContextMenu that a held | ||
| finger opens on a block trigger MUST lift the trigger above the page and | ||
| show the menu beside it, with no row lit. A tap outside closes the menu and | ||
| reaches nothing beneath it, and closing returns the trigger to its place. | ||
| Under reduced motion FR8 applies. An inline trigger keeps today's menu, and | ||
| a menu presented as a bottom sheet follows the sheet. |
There was a problem hiding this comment.
FR29 gives DropdownMenu a presentation way back, but FR33 gives none for the ContextMenu lift, and ContextMenu's released default is presentation = 'popover'. Please state which INV16 branch the lift falls under.
| ### DEC-5 — FR4 cites the generated motion role table | ||
|
|
||
| **Reference:** `spec:AST-094/DEC-5` | ||
| **Decider:** pending owner ruling | ||
|
|
||
| FR4 names its roles by use and cites the generated motion role table instead | ||
| of copying it, so a new component table cannot drift from the record. | ||
|
|
||
| ### DEC-6 — CSS keyed on the touch media query counts as after hydration | ||
|
|
||
| **Reference:** `spec:AST-094/DEC-6` | ||
| **Decider:** pending owner ruling | ||
|
|
||
| FR13's "only after hydration" governs a presentation decided in script. A | ||
| style keyed on the literal touch media query conforms: the server and | ||
| hydrating markup are identical, and the browser applies the style at first | ||
| paint. | ||
|
|
||
| ### DEC-7 — A watcher recognizer is passive only | ||
|
|
||
| **Reference:** `spec:AST-094/DEC-7` | ||
| **Decider:** pending owner ruling | ||
|
|
||
| A recognizer that never claims registers only passive listeners (FR20), so | ||
| watching a touch never delays the browser's scroll. |
There was a problem hiding this comment.
These three decisions are pending inside a record marked authority: current and phase: accepted, and the sentences they settle (FR4, FR13, FR20) carry no "proposed" marker. Please name the decider, or mark them proposed as useMenuPress.spec.md does for its pending FR8 and DEC-4.
| or drag ends. Under a finger, a touch presentation's press feedback follows | ||
| `spec:AST-094` FR11's press profiles instead. |
There was a problem hiding this comment.
"Instead" removes the requirement to paint --color-overlay-pressed under a finger, but FR11 only sets when the highlight starts, drops and activates. Suggest: "Under a finger, the overlay's timing follows spec:AST-094 FR11's press profiles", which matches the DR3 amendment below.
| | highlight | DOM focus, or a caller callback | one lit row; focus with `preventScroll` in a menu, `aria-activedescendant` in a picker | focus | `module:DropdownMenu/useMenuPress` | stable | | ||
| | stray-click window | 400 ms, or the next `pointerdown` | how long after a tracked release the browser's click is still swallowed | `MENU_PRESS_STRAY_CLICK_MS` | `module:DropdownMenu/useMenuPress` | stable | | ||
| | settle time | 300 ms | proposed: how long an opening press must last before its release may act | `MENU_PRESS_SETTLE_MS` | `module:DropdownMenu/useMenuPress` | proposed | | ||
| | long-press delay | as `spec:AST-094` FR29 states (none in a fixed bar; 150 ms in a scroll view) | proposed: how long a held finger waits on a trigger before the menu opens (`spec:AST-094` FR29). A caller that sets `longPressDelayMs` gets that wait in a fixed bar and in a scroll view alike, which keeps the released behavior. | `longPressDelayMs` | `module:DropdownMenu/useMenuPress` | proposed | |
There was a problem hiding this comment.
longPressDelayMs shipped in 0.6.6 with a 500 ms default, and AST-094 FR29 calls it released, but this row and the Public contract row still list the trigger half as proposed.
…roposals - FR25 and Current-state impact name the four released defaults FR29 and FR33 move (Selector's adaptive policy, DropdownMenu's and ContextMenu's omitted presentation, useMenuPress's 500 ms longPressDelayMs) and each way back; useMenuPress's trigger half is released; ContextMenu's compatibility note says so. - FR33: presentation="popover" keeps the released ContextMenu without the lift. - FR4 lists its 17 roles with defaults and sources. DEC-5 to DEC-7 and the FR4, FR13 and FR20 sentences they settle are marked proposed. - design:user-states DR1 keeps the pressed overlay; only its timing follows FR11 under a finger. Co-authored-by: vjeux <197597+vjeux@users.noreply.github.com>
|
Three points for the owner's ruling. None of them is in this pull request's diff yet. 1.
2. FR20 and watchers, the part of the earlier amendment that's still open. DEC-7 settles that a watcher registers only passive listeners. FR20 still says that when the browser takes a touch, "active ones are cancelled", which includes an active watcher.
3. The press selection lock, which no record states yet. On a phone, a finger resting on a press-tracked control or cell (a slider, a segmented control, a stepper, a row's checkbox) starts a text selection or opens the loupe. UIKit's controls and cells never do: their labels aren't selectable text; only text views and fields are.
|
There was a problem hiding this comment.
This spec is not ready to approve yet: no engineering owner has approved spec:AST-094 or its amendments to eight current records at this head, and DEC-5 to DEC-7 are still proposed. Please fix the two points below in a new commit; then an engineering owner (the author included, as one) records the decision and the DEC-5 to DEC-7 rulings by commenting /approve-spec <full head SHA> on this pull request.
DropdownMenu.spec.mdandContextMenu.spec.mdstill say the released default is preserved and name nopresentationmigration, while FR25 moves bothpresentationdefaults withpresentation="popover"as the way back; please name that change and its migration in both records.- FR29's open-on-press rule is scoped to every press-model surface, so ContextMenu (whose FR5 now cites FR26–FR30), sub-menu rows and Selector would open on press too; please limit FR29 to the DropdownMenu trigger and have ContextMenu FR5 cite FR26–FR28 and FR30.
[Automated review]
| ## Compatibility and migration | ||
|
|
||
| - Released default: `popover` | ||
| - Released default: `popover`. Under a finger, `spec:AST-094` FR33's lift |
There was a problem hiding this comment.
This line now moves ContextMenu's default under a finger, but the next lines still say defaults are preserved with "Migration decision: none" (lines 49-52), and DropdownMenu.spec.md line 53 still says "Released default preserved: yes" although FR25 moves its default too. Please name the change and presentation="popover" as the migration in both records (spec:AST-017 FR3).
|
|
||
| ### Menus and popovers under a finger | ||
|
|
||
| FR26–FR30 apply to every surface that carries the press model of |
There was a problem hiding this comment.
This scope makes FR29's open-on-press rule apply to ContextMenu, sub-menu rows and Selector's trigger too. ContextMenu FR5 now cites FR26–FR30 while a ContextMenu opens by long press (FR33), and OQ6 says a sub-menu drills in at the lift. Suggest limiting FR29 to the DropdownMenu trigger and citing FR26–FR28 and FR30 from ContextMenu FR5.
|
FR4's two sub-menu springs differ from the ones UIMenu itself uses, and UIKit's own values fit the captured frames better. iOS 26.2 simulator, iPhone 17 Pro, a pull-down menu (Alpha, Beta, Sort By ▸, Delete), every view read per 60 Hz tick, with each
The other springs UIKit starts at those moments ((1, 0.5), (1, 0.3), (1, 0.2)) miss the box by 2 to 8 pt. A free single-spring fit of the same frames lands on the same springs: (0.86, 0.395) and (0.98, 0.41). The frames are listed in the sources of Proposal: FR4 lists |
…gration - FR29's open-on-press rule covers DropdownMenu's trigger only; ContextMenu, sub-menu rows and Selector keep their own opening, and ContextMenu FR5 cites FR26-FR28 and FR30. - DropdownMenu and ContextMenu name the changed default under a finger and its migration, presentation="popover" (AST-017 FR3). Co-authored-by: vjeux <197597+vjeux@users.noreply.github.com>
There was a problem hiding this comment.
This spec is not ready to approve yet: no engineering owner has approved spec:AST-094 or its amendments to eight current records at this head, DEC-5 to DEC-7 are still proposed, and the requests in this pull request's comments for UIKit's own sub-menu springs (FR4) and for FR20 to stop cancelling watchers are not settled in the record. Please fix the point below in a new commit; then an engineering owner (the author included, as one) records the decision and those rulings by commenting /approve-spec <full head SHA> on this pull request.
useMenuPress.spec.md's Compatibility and migration section still names DEC-3 as the only moved default, andDropdownMenu.spec.mdstill calls the change "additive documentation"; please name thelongPressDelayMsmove there, with passinglongPressDelayMsas its migration, and restate DropdownMenu's compatibility class the wayContextMenu.spec.mddoes.
[Automated review]
| | highlight | DOM focus, or a caller callback | one lit row; focus with `preventScroll` in a menu, `aria-activedescendant` in a picker | focus | `module:DropdownMenu/useMenuPress` | stable | | ||
| | stray-click window | 400 ms, or the next `pointerdown` | how long after a tracked release the browser's click is still swallowed | `MENU_PRESS_STRAY_CLICK_MS` | `module:DropdownMenu/useMenuPress` | stable | | ||
| | settle time | 300 ms | proposed: how long an opening press must last before its release may act | `MENU_PRESS_SETTLE_MS` | `module:DropdownMenu/useMenuPress` | proposed | | ||
| | long-press delay | released 500 ms when set; unset, as `spec:AST-094` FR29 states (none in a fixed bar; 150 ms in a scroll view) | how long a held finger waits on a trigger before the menu opens. A caller that sets `longPressDelayMs` gets that wait in a fixed bar and in a scroll view alike, which keeps the released behavior (`spec:AST-094` FR25). | `longPressDelayMs` | `module:DropdownMenu/useMenuPress` | stable | |
There was a problem hiding this comment.
This row moves the hook's released 500 ms default, as spec:AST-094 FR25 says, but the Compatibility and migration section (lines 84-90) still names DEC-3 as the only moved default and gives no migration for this one. Please name the longPressDelayMs move there, with passing longPressDelayMs as its migration (spec:AST-017 FR3).
| `presentation`, released as `'popover'`, follows `spec:AST-094` FR29 (open | ||
| on press) under a finger; `presentation="popover"` keeps the released | ||
| behavior (`spec:AST-094` FR25). Mouse and keyboard are unchanged. | ||
| - Compatibility class: additive documentation; the press-model behavior |
There was a problem hiding this comment.
Line 53 now says the released default is not preserved under a finger, but this line still calls the change additive documentation and places the behavior delta in useMenuPress, while spec:AST-094 FR29 and FR25 own it. Suggest the wording ContextMenu.spec.md uses: the default under a finger changes, with presentation="popover" as the migration.
…nu springs; handoff after a ContextMenu hold - useMenuPress names the longPressDelayMs move and its migration (pass longPressDelayMs: 500); DropdownMenu restates its compatibility class. - FR4: the sub-menu springs take UIKit's own UIMenu values (0.85/0.4 s and 1/0.4 s), measured on the iOS 26.2 simulator, a correction under FR2. - Proposed DEC-7: a watcher is not cancelled when the browser takes the touch; it follows the scroll to the lift. - FR33: after a held finger opens a ContextMenu, the opening finger's handoff applies before FR26-FR28. - FR17: a Lab gesture reports Core's release velocity for the same motion (AST-100 FR1, interaction-modality INV10). Co-authored-by: vjeux <197597+vjeux@users.noreply.github.com>
Its record is under review in its own pull request (meta#8394); this stack no longer carries an older draft of it. Nothing here cites it.
There was a problem hiding this comment.
This spec is not ready to approve yet: no engineering owner has approved spec:AST-094 or its amendments to eight current records at this head, and DEC-5 to DEC-7 are still proposed. Please fix the two points below in a new commit; then an engineering owner (the author included, as one) records the decision, the DEC-5 to DEC-7 rulings and whether architecture:interaction-modality INV10 stands by commenting /approve-spec <full head SHA> on this pull request.
- FR17's new clause that a Lab gesture's access path "follows
spec:AST-017FR21 once that is settled" gives Lab's velocity a second owner beside INV10, whichspec:AST-100FR1 names; please drop it, or amend INV10 here if the owner adopts vjeux's rewrite. - FR19 still says every recognizer that begins must claim its touches through a non-passive listener, which the watcher in proposed DEC-7 and FR20 never does; please exempt watchers there if DEC-7 stands.
[Automated review]
| and its translation excludes that travel. Release velocity is governed by `spec:AST-100`: a Lab gesture | ||
| reports the same release velocity as Core's tracker for the same motion | ||
| (`spec:AST-100` FR1, `architecture:interaction-modality` INV10), and its | ||
| access path follows `spec:AST-017` FR21 once that is settled. |
There was a problem hiding this comment.
This clause gives Lab's velocity path a second owner: spec:AST-100 FR1 already says architecture:interaction-modality INV10 "owns the source in Core and how a Lab component matches it", and INV10 says "Lab cannot import the tracker; a Lab gesture keeps one local tracker". FR21 is current too, and FR4 says the gesture machinery publishes no /experimental subpath. Suggest ending the sentence at "for the same motion (spec:AST-100 FR1, architecture:interaction-modality INV10).", or amending INV10 in this pull request if vjeux's rewrite is adopted.
| touch listener is registered (FR24). A recognizer that begins MUST claim its | ||
| touches by cancelling `touchmove` through a non-passive listener on its | ||
| element. A `touchmove` of a touch no recognizer owns MUST NOT be cancelled, with |
There was a problem hiding this comment.
A watcher that follows the scroll has begun but never claims (proposed DEC-7 and FR20), so this sentence obliges it to cancel touchmove through a blocking listener, which DEC-7 forbids. If DEC-7 stands, suggest: "A recognizer that begins, other than a watcher (DEC-7), MUST claim its touches …".
Supersedes #8378 (whose three review rounds were spent), which superseded #8316 and #8052. It carries vjeux's record, credited as co-author, plus every owner ruling since. The record itself contains no pull request references.
What changed from #8378's last head:
spec:AST-099FR8,architecture:react-component-runtimeINV11).Exact decision needed
Approve
spec:AST-094: touch presentations get one native-feeling behavior by default on every touch device, iOS and Android alike. Open questions: OQ5 (the menu's drift allowance), OQ6–OQ8 (opening a sub-menu without a lift, the opening haptic, a withdrawn tentative open), OQ9 (where a menu sits on a compact touch screen) and OQ10 (a sub-menu with its parent visible). Module-level experimental subpaths are closed: motion and gestures stay internal (FR4). Platform look and feel is a non-goal tracked separately. Release velocity is governed byspec:AST-100.Existing authority searched
component:SelectorDEC-1 (theadaptivequery);spec:AST-013FR3 (an Android Chrome support row);spec:AST-025FR14 (nested scrolling);spec:AST-057(Item's swipe constants and FR2);design:user-statesDR1/DR3;family:buttons;module:DropdownMenu/useMenuPressFR6.module:DropdownMenu/useMenuPressFR4;design:user-statesDR4;spec:AST-043FR1;spec:AST-012FR9 (compact);design:reduced-motion;architecture:public-component-apiINV14, INV16;spec:AST-017FR3, DEC-23;spec:AST-002FR3;architecture:react-component-runtimeINV5/INV7;family:overlay-dismissalAV6.Decision
design:reduced-motionDR2 and DR4.spec:AST-012FR9 compact definition where a presentation depends on size. The touch presentation applies after hydration.presentationchoice. Touch work costs nothing under a fine pointer.spec:AST-100.Rejected alternatives
presentationis the way back, INV16 and DEC-23).Claim scope and non-goals
Evidence and implementation relationship
The values come from UIKit read on the simulator, Apple documentation, WWDC sessions and WebKit's source. Implementation stacks on this record. Implementations: #8078 (menu press and handoff), #8080 (menu grow and collapse), #8187 and #8198 (Popover grow and pan-outside dismissal), #8201 (ContextMenu lift), #7308 (ContextMenu under a finger), #8341 (the release decision), #8220 (sub-menus in place), #8223 (the presentation hold), #8195 (the menu cell profile); #8089 (menu placement on a phone) is OQ9.
Writing rubric results
Scope
architecture:knowledge-contractsINV18).Validation
pnpm check:knowledge: aligned.git diff --check: clean.