Repository navigation
Conversation
… s of wall clock
The two proofs that a Reduce Motion dip held before its first frame
still lands (after the hold is finished, and after it is resumed) polled
the box for 2 s of wall clock. On a loaded machine the page's main
thread ran the dip's next step late and the poll ran out first: one
WebKit run read {opacity: 0, translate: 'none'} with four WebKit
containers on the box, then passed in 530 ms on a rerun. They now wait
until the box runs no animation, on the animations' own finished
promises (including the fade back in the dip starts when its fade out
ends), and then assert the landed state. The test's own timeout still
bounds them.
With a 2.5 s main-thread block induced right after the release, both
proofs failed before this change (Timeout 2000ms exceeded while waiting
on the predicate) and pass after, 3 runs each in Chromium.
… element moves from under the pointer (spec:AST-094 FR43) The wheel listener sat on the recognizer's element only, so once a pan moved its element out from under a still cursor, the next steps landed on what was under it, went unprevented, and the gesture ended early: of six 16 px trackpad steps, two moved the card. Fails until a wheel gesture is latched to the recognizer that took it, as a browser latches a scroller.
… it (spec:AST-094 FR43, FR24) As a browser latches a scroller: from the claim until the gesture ends, a capture wheel listener on the document hands the host every step first, wherever it lands, so a pan whose element moves from under a still cursor keeps the gesture and every step stays prevented. It goes when the gesture ends (100 ms after its last wheel), and at once when every recognizer that took it has left: a detached, disabled or cancelled taker gives the rest of the gesture back to the page. A page listener only during a gesture.
…input drivers) into the base of the every-pointer follow-up # Conflicts: # packages/core/src/motion/README.md
…s attach for every pointer, and the pan's allowed pointer, a finger, is what keeps a mouse and a pen off (spec:AST-094 FR43, spec:AST-057 FR6, AR2)
…rag (real Chromium) or a pen never moves it, a finger's pointer events come with its touches, and the dismissing tap's click goes to the click guard (spec:AST-094 FR43, spec:AST-057 FR6, AR2)
…first lift event, its pointerup or its touchend, whichever the gesture host releases on (spec:AST-094 FR43)
…oes, and so does a mouse wheel's horizontal notch (spec:AST-057 FR4, DEC-7)
…r under the pointer could scroll for it (spec:AST-094 FR43, FR19) A pull to refresh sits on the content, inside the scroller it pulls: the host checked only the scrollers between the pointer and the pan's element, so with scroll input allowed it would take any vertical wheel over the content, mid-scroll or scrolling down from the top, and break native scrolling. A finger's scroll-edge rule reads every scroller under it, the page included, and so must a wheel's. And touch-action narrows only a finger's pan: content with touch-action none still scrolls its owner with a wheel. Both cases fail until the wheel reads the same chain.
…er under the pointer (spec:AST-094 FR43, FR19) The wheel gesture now reads the scrollers under the pointer as a finger's probe does, its own scroll owner and the page included, with overscroll-behavior ending the chain, but without touch-action, which narrows only a finger's pan (createNativeScrollProbe takes readsTouchAction: false). beginWheel leaves a wheel to the page when a scroll-edge pan's scrollers could still scroll for it, before anything is prevented, and the wheel contact carries the probe, so the pan's own scroll-edge check reads the same chain at its first move. Other pans keep the rule for the scrollers between the pointer and their element.
…ss (spec:AST-094 FR43, FR24) A pan with no pointer types and scroll input allowed, such as a pull's wheel-only pan beside its finger pan, still armed its element for a press where the primary pointer is fine: a pointerdown listener for a recognizer no pointer can start. Fails until arming counts only recognizers that take a pointer.
…t for a press (spec:AST-094 FR43, FR24) Where the primary pointer is fine, an element is armed for a press while an enabled recognizer or consumer on it could take one. A recognizer whose allowedPointerTypes is empty takes only scroll input, so it no longer arms one: its element keeps the wheel listener alone.
…e pointer, and no menu observes the pointer query (useMenuPress FR9; spec:AST-094 FR24) Where the primary pointer is fine, a finger held on a DropdownMenu trigger keeps the released behavior, whose tolerance is 10 px on each axis: an (8, 8) settle opened the menu, and the long press's distance rule now cancels it. And every useMenuPress caller, each menu and sub-menu, subscribed to (pointer: coarse) though only the trigger reads it, when its press starts. Both fail until the trigger takes its tolerance at the press.
…rts, and no menu observes the pointer query (spec:AST-094 FR29, FR24; useMenuPress FR9) Every useMenuPress caller, each menu and sub-menu, subscribed to (pointer: coarse) through useSyncExternalStore, though only the trigger's held finger reads it. The trigger now reads the pointer as its press starts and hands useLongPress that press's tolerance (start's new tolerance argument): FR29's 13px drift where the primary pointer is coarse, the long press's own 10px where it is fine, as the released behavior keeps (on each axis, with #8358's measure). A changeset declares the 13px a finger now gets on phones and tablets.
…entation says useLongPress documents its tolerance as movement past moveCancelPx on either axis, a released contract, and ContextMenu's measured hold and the menu trigger's released behavior keep it. This pull request had changed it to a distance, which cancels a (9, 9) drift the contract keeps. Fails until the measure is the documented one again.
…ocumented; only the defaults have one source useLongPress documents movement past moveCancelPx on either axis, and its callers keep that: ContextMenu's measured hold is per axis, and the menu trigger's released behavior keeps the hook's tolerance (useMenuPress FR9). The defaults, 500ms and 10px, still come from the long-press recognizer's table, which measures its own tolerance as a distance, as UIKit's does. The changeset now says what this is: one source for the numbers, no behavior change; useLongPress.doc.mjs was right all along.
…and a scroller inside a shadow tree from what the wheel landed on (spec:AST-094 FR43) scrollsBy compared Math.abs(scrollLeft) against left-to-right bounds, so at a right-to-left scroller's start (scrollLeft 0) it read a scroll right as the scroller's and a scroll left as nobody's, handing the pan the wheels the scroller should get. And the wheel's target at a shadow host's listener is the host itself, so a scroller inside its shadow tree, between the pointer and the pan, went unseen. Both fail until the host reads them.
…nd the scrollers under what it landed on (spec:AST-094 FR43) scrollsBy reads scrollLeft against the scroller's own range: from 0 to the overflow left to right, from minus the overflow to 0 right to left, where a scroll right moves it toward 0. beginWheel walks, probes and records the wheel from landedOn, the composed path's first element, so a scroller inside a shadow tree between the pointer and the pan counts.
…adow root; a claimed touch's moves are cancelled where fingers come from pointer events With targets from the composed path, a finger inside an open shadow root sits below the scroller only along the flat tree, which Node.contains does not follow: a scroll under it did not take it, and its flick did not arm the scroll brake. And where the host reads fingers from pointer events (inputMode 'auto' with no ontouchstart), the blocking touchmove found no finger for a claimed pan's touch, so its moves went to the page. Three cases fail until the host compares along the flat tree and finds that finger; a fourth pins a finger scroll inside a shadow root.
… tree; a claimed touch finds its pointer finger wherever fingers come from pointer events containsAlongFlatTree walks parentAcrossShadow, so a finger inside an open shadow root, now that targets come from the composed path, counts as under a scroller outside it: a scroll there takes it, its flick arms the scroll brake, and a touch there brakes. cancelIfClaimed matches a touch to its pointer finger whenever the host reads fingers from pointer events, not only under inputMode 'pointer-events', so a claimed pan's moves are cancelled where a browser that exposes no ontouchstart still sends Touch Events.
…t tree, and a claimed touch finds its pointer finger wherever fingers come from pointer events) into #8320
…ame flick only delayed the row)
…s its default scroll types
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
…open row only closes within a gesture (row-follow)
There was a problem hiding this comment.
This preview can't be approved as it stands: it changes established row-swipe behavior and carries far more than its own change. Rows no longer take a mouse's horizontal wheel, which AST-057 FR4 and DEC-7 require, and trackpad pans now release at momentum onset or still, which AST-094 FR43 does not state; an engineering owner needs to settle that rescope and update those records, recording the decision by commenting /approve-spec <full head SHA> on this pull request (the author may do so as an engineering owner). Whatever is decided:
- Carry only the 339-line own change (for example against the #8690 branch); the compare view holds about 54,000 lines of unmerged base pull requests.
- After the release at momentum onset, the remaining momentum reaches the page because the taker check in
GestureHost.tsruns before the absorb branch, and that release reads 0 px/s. - Three carried tests (the trackpad end and speed cases in
wheel.test.tsand the mouse-wheel notch case inItem.test.tsx) contradict this head and were not updated.
[Automated review]
| // (DEC-7) through the pan's default scroll input (FR43): the same | ||
| // contact, moving with the content. | ||
| allowedPointerTypes: ['touch', 'pen'], | ||
| allowedScrollTypes: ['continuous'], |
There was a problem hiding this comment.
With continuous only, a mouse's horizontal wheel (a 100 px notch classifies as discrete) no longer swipes the row. AST-057 FR4 and DEC-7 say it must, the comment at lines 1249-1251 still says it does, and Item.test.tsx:1299-1306 expects it. This needs an engineering owner's decision on the FR43 rescope before it can stay.
| gesture != null && | ||
| gesture.ids.length > 0 && | ||
| gesture.step == null && | ||
| !this.wheelHasTaker(gesture) |
There was a problem hiding this comment.
Once the follow mode ends the contact at momentum onset (line 2095), the taker has ended, so this check hands the next wheel to the page (ids: [], no preventDefault) before the follow.lifted branch at line 2016 can absorb it. The remaining momentum, and a new swipe started inside it, scroll whatever is under the pointer. Adding !gesture.follow?.lifted here, as gesture.step == null does for the step mode, keeps the gesture.
| f.lifted = true; | ||
| f.heldX = 0; | ||
| f.heldY = 0; | ||
| this.arena.ended([{id: gesture.ids[0], x: gesture.x, y: gesture.y, time}]); |
There was a problem hiding this comment.
The decaying wheels before this were held, not moved, so the release is stamped about three wheels (about 48 ms at 16 ms per wheel) after the last moved sample. That is past the 40 ms stillness window in VelocityTracker.releases, so it reads 0 px/s, not the fingers' speed the comment promises, and a quick flick decides by position alone. Stamping the release at the last applied move's time keeps the speed.
|
|
||
| type Row = {gap: number; mode: number; dx: number; dy: number; wdx: number | null; wdy: number | null; kind: string}; | ||
|
|
||
| function classify(e: WheelEvent): string { |
There was a problem hiding this comment.
This copies scrollTypeOf from GestureHost.ts and has already drifted: with no wheelDelta it reports "older rule" instead of applying the 120-tick and notch rules. Its Effect at lines 37-51 attaches a listener a callback ref could own. As a preview-only story it is best dropped before anything merges.
There was a problem hiding this comment.
This preview can't be approved as it stands: it changes established row-swipe behavior and carries far more than its own change. Rows no longer take a mouse's horizontal wheel (AST-057 FR4, DEC-7), trackpad-driven rows play their own unmeasured spring and dead zone (AST-094 FR1), and trackpad pans now release when momentum is read to start, or still, which AST-094 FR43 does not state. An engineering owner needs to settle that rescope and update those records, recording the decision by commenting /approve-spec <full head SHA> on this pull request; the author may do so as an engineering owner. Whatever is decided:
- Carry only the roughly 500-line own change, for example against the #8690 branch; the compare view holds about 54,000 lines of the stack underneath.
- After the release at momentum onset, the remaining momentum still reaches the page, and that release carries 0 px/s.
- The new wheel splitter also splits ctrl-wheel pinches, and mouse-wheel and pinch gestures now end at 180 ms instead of 100 ms.
- Eight carried tests in
wheel.test.tsandItem.test.tsxfail at this head.
[Automated review]
| if ( | ||
| gesture != null && | ||
| gesture.ids.length > 0 && | ||
| gesture.step == null && | ||
| !this.wheelHasTaker(gesture) | ||
| ) { |
There was a problem hiding this comment.
After the follow mode ends the pan's contact at the read lift (line 2101), this check finds no taker and hands the rest of the gesture to the page, so the momentum is never prevented and the f.lifted branch at 2083-2085 never runs. A probe at this head: the five wheels after the release were not prevented. Adding !gesture.follow?.lifted to this condition keeps the momentum absorbed.
| f.lifted = true; | ||
| f.heldX = 0; | ||
| f.heldY = 0; | ||
| this.arena.ended([{id: gesture.ids[0], x: gesture.x, y: gesture.y, time}]); |
There was a problem hiding this comment.
The four shrinking wheels before this were held, not moved, so this release is stamped 64 ms after the last applied move and reads 0 px/s (a probe pan at 750 px/s ends at 0). A quick trackpad flick then opens a row only past half the panel (AST-057 FR5). Stamping the release at the last applied move's time keeps its speed.
| if (seg.boundary != null) { | ||
| this.lastBoundary = seg.boundary; | ||
| if (gesture != null) { | ||
| this.endWheel(time); | ||
| gesture = null; | ||
| } |
There was a problem hiding this comment.
This ends any live wheel gesture at a splitter boundary, a ctrl-wheel pinch included: a pinch that slows for four wheels and then reverses is split, and in a probe its scale fell from 1.865 to 0.984. Pushing only pan wheels, or ignoring boundaries for kind === 'pinch', keeps a pinch whole.
| gesture.step != null && !gesture.step.committed | ||
| ? WHEEL_STEP_CARRY_MS | ||
| : gesture.follow?.endMs ?? WHEEL_FOLLOW_END_V_MS, |
There was a problem hiding this comment.
For a gesture without follow mode (a mouse wheel's notches, a ctrl-wheel pinch) the end timer is now 180 ms, while the quiet-gap check (1998-2001) and the end stamp (2448) keep WHEEL_END_MS (100). wheel.test.ts:486 and :611 fail on it. Keeping gesture.follow?.endMs ?? WHEEL_END_MS here restores the 100 ms end.
| // ============================================================================= | ||
|
|
||
| /** Scratch: a trackpad drag tracks and settles on a quick, critically damped spring. */ | ||
| const TRACKPAD_SPRING = {mass: 1, stiffness: 1600, damping: 80}; |
There was a problem hiding this comment.
A trackpad-driven row tracks and settles on this spring (about four times faster than the measured swipeActions.tracking and settle) with an 8 px dead zone instead of the measured 25 px hysteresis (lines 1134, 1179). AST-094 FR1 asks every component playing the same motion to use the measured value, and FR2 asks a guess to be labelled with its measurement, so this needs an owner's decision or the measured values.
…end; 180 ms is for trackpad pans only
…he fingers' speed (stamped at their last move); unit case
There was a problem hiding this comment.
This preview can't be approved as it stands: it changes established row-swipe behavior and carries far more than its own change. Rows no longer take a mouse's horizontal wheel (AST-057 FR4, DEC-7) and trackpad-driven rows play their own unmeasured spring and dead zone (AST-094 FR1), while trackpad pans now release at momentum onset or still after a pause, which AST-094 FR43 does not state; an engineering owner needs to settle that rescope and update those records, recording the decision by commenting /approve-spec <full head SHA> on this pull request (the author may do so as an engineering owner). Whatever the decision, a trackpad flick's momentum still reaches the page after the release, the wheel splitter also splits ctrl-wheel pinches, six of the branch's own tests contradict this head, and the preview should carry only its own change rather than the whole stack beneath it.
[Automated review]
| if ( | ||
| gesture != null && | ||
| gesture.ids.length > 0 && | ||
| gesture.step == null && | ||
| !this.wheelHasTaker(gesture) |
There was a problem hiding this comment.
After the follow mode ends the pan's contact at the read lift (line 2106), this check finds no taker and hands the rest of the gesture to the page (ids: [], no preventDefault), so a trackpad flick's momentum scrolls whatever is under the pointer and the absorb branch at line 2085 never runs. Adding !gesture.follow?.lifted to this condition would keep the momentum with the lifted gesture.
| if (seg.boundary != null) { | ||
| this.lastBoundary = seg.boundary; | ||
| if (gesture != null) { | ||
| this.endWheel(time); | ||
| gesture = null; | ||
| } |
There was a problem hiding this comment.
This ends any live wheel gesture at a splitter boundary, a ctrl-wheel pinch included: a pinch that slows over four wheels and then reverses, speeds up or pauses 50 ms is split, and the new pinch starts again at scale 1. Pushing only pan wheels to the splitter, or ignoring boundaries for kind === 'pinch', would keep pinches whole.
| // A trackpad's scroll releases at its last wheel, with its speed: its | ||
| // momentum arrives as more wheel. A mouse wheel's notches release still, | ||
| // past the velocity's stillness interval, so position alone decides | ||
| // where a pan settles (the coordinator's ruling; FR43 is silent). |
There was a problem hiding this comment.
This says a trackpad's scroll releases at its last wheel with its speed, but a followed pan's idle end is stamped follow.endMs (220 or 180 ms) later and releases still (line 2456). Worth rewording with the code.
| // (`spec:AST-057` FR4, FR6, AR2). A trackpad's horizontal scroll and | ||
| // a mouse wheel's horizontal notches swipe it as a finger does | ||
| // (DEC-7) through the pan's default scroll input (FR43): the same | ||
| // contact, moving with the content. | ||
| allowedPointerTypes: ['touch', 'pen'], | ||
| allowedScrollTypes: ['continuous'], |
There was a problem hiding this comment.
With continuous only, a mouse's horizontal wheel (a 100 px notch classifies as discrete) no longer swipes the row, which AST-057 FR4 and DEC-7 require, while the comment above still says the notches swipe it. This is part of the rescope that waits on an owner decision.
| const now = e.timeStamp; | ||
| const legacy = e as WheelEvent & {wheelDeltaX?: number; wheelDeltaY?: number}; | ||
| const horizontal = Math.abs(e.deltaX) > Math.abs(e.deltaY); | ||
| const seg = segmenter.push(now, horizontal ? e.deltaX : e.deltaY, horizontal ? 220 : 180); |
There was a problem hiding this comment.
This idle is hard-coded to 220/180 ms for every gesture, while the host now passes 100 ms for mouse wheels and pinches (GestureHost.ts:2036-2037); with the copied classifier above, the probe can disagree with the host it is meant to show. Calling the host's own rules, or dropping the preview story, avoids the drift.
Preview build only, for a live trackpad check of the AST-094 FR43 rescope proposed on #8676. Do not merge, review or land; it closes after the check.
core-item--swipe-actions