Repository navigation
Conversation
… (spec:AST-094 FR43) A drag from the edge band begins a screen-edge pan for a finger only, unless the caller allows another pointer. The mouse and pen case fails until the recognizer defaults to touches.
… FR19, FR24, DEC-21) Recognizers and press consumers attach for a mouse, a pen and a finger alike. Where the primary pointer is fine, each element with an enabled recognizer or consumer keeps one passive pointerdown listener and the page has none: a press on it (a mouse's primary button, a pen, or a finger) installs the host's page listeners until that press's contacts end. The action group's own fine-pointer path folds into this one, so a group is served like every attachment. - touch-action is written for every pointer, a kept press's manipulation too (FR18); the element's blocking touchmove stays a coarse pointer's, so under a fine one the element keeps its one listener (FR24). - A press consumer takes a mouse press as a press (DEC-21): no feedback-only mode; PressTracker brakes only a finger's press (FR11). - The screen-edge pan allows touches only unless its caller allows another pointer (FR43). - perEventPointer is accepted and does nothing; the fine-pointer warning goes. Tests that encoded the coarse-only design now state FR43's; a finger's pointerdown comes before its touchstart in them, as in a browser.
…th real mouse drags (spec:AST-094 FR43, FR24) Under a desktop's mouse the host still writes touch-action, leaves the page no listener while idle and warns for nothing; a real mouse drag pans both the bare page's pan and the fixture's horizontal pan, and the page's touch listeners are gone again after the release.
…(spec:AST-094 FR18, DEC-13) A screen-edge pan attached to a stack container, as wide as the screen, with a touch 4 px from its edge: inside the 40.2 px band the pan decides at UIKit's 15 px whatever the element's width, and then tracks the travel past it. From several edges too. Both fail while a wider element decides at FR19's 10 px.
…'s width (spec:AST-094 FR18, DEC-13) FR18: inside the 40.2 px band a screen-edge pan decides at UIKit's 15 px screen-edge hysteresis; outside it the author's scrolling is untouched and FR19's 10 px governs every other claim. The pan decided at 10 px on any element wider than the band, so NavigationStack's edge pan, attached to the stack container, began 5 px early. The edge zone still decides only the touch-action; a touch outside every band still fails at once. The two cases that pinned the 10 px decision go.
… 15 px whatever the element's width) into the experimental touch exports
…er's move keeps that finger until it lifts) into the experimental touch exports
…than the band (spec:AST-094 FR18, DEC-22) FR18 as amended in meta#8631 (DEC-22): the band's pan-x claim and 15 px start hold only where the screen-edge pan is attached to an element within the band; on an element that reaches beyond it, whose touch-action cannot claim per touch, a touch in the band decides at FR19's 10 px like every other claim. This restores the 10 px decision 3d85c30 removed and keeps 15 px on an element within the band. The cases pin DEC-22 both ways (a wide element with a touch at x=4 begins at 10, an in-band strip at 15, and from several edges at 10 on a wide element); the 10 px cases fail on 3d85c30.
…an the edge band decides at 10 px again, DEC-22) into the experimental touch exports
…t reads its end before the arena's reset) into facebook#8336
The case walked ContextMenu, DropdownMenu, useLongPress and useMenuPress's imports and failed on the UIKit gestures table: it kept that table out of the menus' bundles, the lazy design the no-lazy-load ruling and direct imports retire. The long-press numbers keep one source, still pinned by the table, recognizer and hooks case and by the hooks reaching longPress.ts.
# Conflicts: # .github/workflows/ci.yml
…xposes no ontouchstart is taken once Chromium fixes ontouchstart when the page is created, so turning touch emulation on later sends Touch Events without it: the host reads Pointer Events for the finger and must not read its Touch Events too. A one-finger long press fails here, the finger tracked twice.
…from their pointer events install() reads a finger from its pointer events when the window has no ontouchstart, but the four touch handlers still took the Touch Events a browser sends anyway (Chromium after touch emulation turns on), tracking the finger twice, so a one-finger long press never recognized. Each touch handler now returns while usesTouchEvents is false, after noting the fingers down, as install()'s comment promised.
…ter events) into meta#8320
…ter events) into meta#8293
…ter events) into meta#8356
…ter events) into meta#8358
…age's selection The drag selection hold cleared the page's selection when any mouse or pen contact was claimed, but an action group's press claims at its pointerdown, before it has moved or selected anything, so a plain click on a group's button left its Copy or Cut with nothing to act on. A claim before any movement now keeps the page's selection: the hold still refuses a new one, and puts the page's back over a selection that appears while it runs. A claim after movement clears what its drag selected, as before (spec:AST-094 FR41). The case before the new one now waits for its hold to end a task after the lift, so no hold outlives that test.
…t every pointer does - GestureHost's header, the gestures README and coarsePointer.ts no longer describe the coarse-only host: a finger or a pen takes the touch-down lock under any primary pointer, a kept press's finger is kept during a fine pointer's press too, and recognizers attach for every pointer while the page listeners last a press (spec:AST-094 FR19, FR24, FR41, FR43). - The fine-pointer selection case asserted the replaced rule and passed only because it read iOS WebKit's inline lock without iOS WebKit: it now asserts the lock a fine pointer's finger and pen take, and that a mouse takes none. - FR41's sentence and its verification row say that a press claimed at its own pointerdown, before it moves, keeps the page's selection, while a drag that moved before its claim loses what it selected.
|
This needs an owner's call on wheel input. FR43 says a pan takes wheel and trackpad scrolling, with no exception. This slider takes none, so a scroll over it stays the page's, as over a native range input; taking it would let a page scroll change a value by accident. The options: amend FR43 to exclude a control's thumb, or give the slider wheel input. My pick is the FR43 amendment. |
…ion, in the present tense The sentence said a drag that moved before its claim loses the selection it started, but the hold clears the page's selection then, whatever made it; and an unclaimed mouse drag kept "today's" behavior, a phrase that ages. It now says a claim after movement clears the page's selection, a press claimed at its own pointerdown keeps it, and an unclaimed mouse drag keeps its released behavior.
meta#8665's review fixes: an armed press under a fine pointer brings the claiming listeners, keeps a kept press's finger and goes when the page hides; a press claimed at its own pointerdown keeps the page's selection; FR41 says what a claimed drag does with the selection; meta#8360's input-stream notes. The merge is clean.
…r path Each case fails on this head: - Under Reduce Motion a release's momentum keeps moving and a track tap sets its value at once, both at full opacity (design:reduced-motion DR2: a throw's momentum is direct movement; an in-place value change applies at once). The thumb cross-fades both today. - Range thumbs closer than their touch targets split the gap, so a finger on the lower thumb's exposed side takes the lower thumb (spec:AST-094 FR42). Today the upper thumb's 48 px target covers it. - A valueDisplay change that remounts the thumbs keeps their gestures. Today the new touch targets have none. - A finger's drag moves the thumb even when the owner renders nothing, its position written straight to the thumb (spec:AST-094 FR9). Today the thumb moves only through the owner's render. The pen case now advances the frames before it asserts, so it checks what a pen's tap on the track does: it sets the value on its lift, as a finger's does.
…s gap, remounts, and a drag off the render path - Under Reduce Motion a release's coast plays as momentum (the animator's decay), so it keeps moving, and a tap on the track sets its value at once: design:reduced-motion DR2 calls a throw's momentum direct movement and an in-place value change immediate. Neither cross-fades now. - Each thumb's touch target grows to UISlider's 48 pt, but on the side facing a range's other thumb only to half the gap between them (spec:AST-094 FR42), computed in container units so it needs no layout read. A finger on the lower thumb no longer drags the upper one. - The thumbs' gestures re-attach when a valueDisplay change wraps or unwraps the thumbs in their value tooltips, which mounts new targets. - Each move of a drag writes the thumb's and the fill's positions straight to their translates (spec:AST-094 FR9), with onChange still reported per value; the parts go back to the stylesheet when the interaction ends, and a finished interaction no longer hands back the parts of one still being dragged. - The Effects that hand the controller its model and parts getter, and the one that disposes it, name what they synchronize (architecture:react-component-runtime INV3).
…EC-4) AST-094 FR13 leaves each component's touch presentation to its own record. FR6 records Slider's: under a coarse primary pointer a thumb takes a finger or a pen through UISlider's 48 pt target, clamped to half the gap facing a range's other thumb; a drag moves the value by the finger's travel past the 10 px threshold with no render per move; the release coasts on UISlider's measured spring; a tap on the track sets the value on lift; and Reduce Motion follows DR2. FR5's interaction ends, under a finger, when the coast settles. DEC-4 records the decision, with no prop to restore the released behavior.
… thumb A mouse's first 12 px straight across a horizontal slider, then 60 px along it: the thumb should move by the 60 px, since a mouse has no page scroll to yield to. Today the thumb's pan, limited to the travel's direction, fails on the first movement, and the thumb never moves.
…thumb The thumb's pan was limited to the travel's direction for every pointer, so a mouse drag whose first 10 px ran across the travel failed it and the thumb never moved. A mouse now has a pan of its own that claims in any direction after the same 10 px, and the value follows the drag's travel along the axis, counted from the threshold's projection on it. A finger and a pen keep the pan limited to the travel, so a swipe across the track still scrolls the page.
…se drag Slider.doc.mjs said a mouse keeps the pointer behavior, the changeset counted listeners, and the primary-click comment named a pen rule the gesture host does not apply. They now describe the mouse drag, past the same 10 px in any direction, and the primary click. component:Slider FR6 covers every pointer (spec:AST-094 FR43): a mouse drag tracks past the same threshold in any direction, a press on the track sets the value where a primary click lands, and a scroll over the slider stays the page's.
Inside a scrolling sheet a wheel or trackpad scroll over a slider goes to the sheet, not the page, so the record, the docs, the changeset and the controller's comments say it goes to the scroll under the slider, as spec:AST-094 FR43's exception for a control's thumb does.
…ame window Both 'a dip held before its first frame lands once the hold is …' proofs waited for no running animation, then one frame and a timeout, assuming the next step starts within a frame. The dip lands on a timer due on the call's own clock, though, and the proofs passed only because the evaluate round trips covered the gap: in WebKit on a loaded box the window closed first and the proof read the element mid-dip (opacity 0, translate none; reproduced 1 in 4 with the round trips removed). They now wait on the call's own finished, then on the browser's own animations still running or waiting for their first frame, and read nothing from the animator.
…ment at once and settles then A Reduce Motion dip whose landing runs more than its whole fade back in late (a hold released long after the dip was due) played a 1 ms opacity animation, which WebKit keeps pending until its next frame, and settled the call on a 1 ms timer: the call's finished could resolve while the element still showed opacity 0. The animator's notes say the element appears at once there. Fails now: the landing plays one opacity animation and the call has not settled.
…element at once and settles A Reduce Motion landing that runs at least the whole fade back in late had nothing left of the cross-fade, but still played a 1 ms opacity animation and settled the call 1 ms later. WebKit keeps that animation pending until its next frame, so the call's finished could resolve with the element still at opacity 0. Such a landing now writes the end opacity at once (handing a borrowed one back to the stylesheet), plays nothing, and settles the call then, as the animator's notes say.
|
Pushed ce50d06, answering the Oct 28 review point by point:
|
There was a problem hiding this comment.
Approval waits on an engineering owner: the slider's thumb pans take no wheel or trackpad scroll, which AST-094 FR43 on main still requires of a pan until the amendment in #8905 lands, and the new every-pointer clause in component:Slider FR6 needs owner approval. An engineering owner records the decision by landing that FR43 amendment and commenting /approve-spec ce50d067e2324902a7f6c0b5c3db9669531a3ded here, or by rejecting the exception so the thumb's pan takes wheel input; the author may do so if they are an engineering owner. Whatever that decision, these changes are needed:
- Rebase once #8190, #8665, #8676, #8666, #8671 and #8360 land, so the diff against
mainholds only this change (36,403 authored lines today; its own ten commits touch about 715). - A mouse drag that starts diagonally counts up to 2.9 px of the 10 px threshold when the pan begins (
sliderTouchController.ts:531-534); subtract the travel the recognizer swallowed and add a diagonal test. - A pen under a fine pointer now lifts, coasts and sets the value on a track tap's lift, which FR6, the docs and the description do not describe.
- Add
## Writing rubric resultsfor the two edited records, asAGENTS.mdasks of a record pull request.
[Automated review]
| interaction.beganOffset = interaction.isMouse | ||
| ? distance > 0 | ||
| ? (pan.hysteresis * along) / distance | ||
| : 0 |
There was a problem hiding this comment.
The mouse pan begins once either axis reaches 10 px (a square in PanGestureRecognizer.tryBegin), but this subtracts the projection of a 10 px circle, so a 45° start counts about 2.9 px of threshold travel at once, against AST-094 FR17 (“its translation excludes that travel”). Subtracting what the recognizer swallowed, Math.sign(along) * Math.min(Math.abs(along), pan.hysteresis), keeps straight starts as they are; a diagonal test would pin it.
| | FR3 | Filled range, tick marks, mark labels, and adjacent text value display are stable rendered parts without their own current Slider target. | Current source and public docs | Verified current asymmetry; not ratified as policy | | ||
| | FR4 | Label and status presentation continue to use Field and FieldStatus; value tooltips continue to use Tooltip. | Current source and focused tests | Verified composition boundary | | ||
| | FR5 | `onChangeEnd` fires once when an interaction ends — a pointer drag or track press is released or cancelled (under a finger, once the release's coast settles; FR6), or a keyboard step (arrow, Page, Home, End) completes — and carries the value the owner renders after its synchronous response to that interaction's `onChange` calls, including any clamp, snap, or rejection; it never carries a value Slider emitted that the owner did not render. A range reports both values the same way. | Maintainer decision (DEC-3) | Approved | | ||
| | FR6 | Under a coarse primary pointer, after hydration (`spec:AST-094/FR13`), each thumb takes a finger or a pen through an invisible touch target of UISlider's measured 48 pt; on the side facing a range's other thumb it grows only to half the gap between them (`spec:AST-094/FR42`). A drag on a thumb moves the value by the finger's travel past `spec:AST-094/FR19`'s 10 px threshold over the track's length, writing each move to the thumb with no component render (`spec:AST-094/FR9`). The release coasts on UISlider's measured spring toward 0.4 of the momentum projection. A tap on the track sets the value when the finger lifts; a swipe across the track scrolls the page. Under reduced motion the thumb does not grow, a tap's value applies at once, and the coast continues (`design:reduced-motion/DR2`). Under every other pointer (`spec:AST-094/FR43`) a mouse drag on a thumb moves the value the same way, past the same threshold in any direction; a press on the track sets the value where a primary click lands; and a wheel or trackpad scroll over the slider goes to the scroll under it. | UIKit measurements (`motion/uikit/slider`) and maintainer decision (DEC-4) | Approved | |
There was a problem hiding this comment.
This clause covers a mouse, but under a fine primary pointer a pen now takes the finger path: Slider.tsx leaves every pen press to the gesture host, so a pen on a thumb lifts and coasts and a pen press on the track sets the value only when its tap ends. AST-017 FR59 asks for the owner decision on a new fine-pointer feel in this record, so the pen needs a sentence here (or the mouse path).
Depends on #8190 (which carries #8671) and #8676 (which carries #8665 and #8666). Review only this PR's change: vjeux/astryx@93e4ce4...ce50d06 (it also shows the parents' newer commits: #8676's last two, #8671 and #8360's animator fix)
User need
Part of Astryx's UIKit-parity work (
spec:AST-094): #8190 made a Slider under a finger track like iOS's UISlider, but on a desktop a mouse drag still jumped the value to the pointer. FR43 asks gestures to work for every pointer.Problem and solution fit
Current specification
spec:AST-094FR43, FR19, FR24 and DEC-21; #8905 adds FR43's exception for a control's thumb.component:SliderFR6 (from #8190) now covers every pointer.Public delta and caller burden
No API change. Size (
component-size.js, base to head): the Slider import's JavaScript 85.1 → 85.2 KB gzip, CSS unchanged.Design and alternatives
Left to the owner (
component:Slider, per FR13; today's behavior stays): a lift on a mouse press, a coast after its release, a track press that sets the value on release.Evidence
The test plan below, run in Chromium and WebKit.
Scope
Testing
In Storybook (Slider › Default), with a mouse:
Run on this head, locally (fork pull requests start no CI): steps 1, 3 and 4 are browser tests in Chromium and WebKit (the ctrl-click a unit test), each failing before its change and passing now; the full core suite, typecheck, lint, the builds and
pnpm check:knowledgepass. #8671 per-component bundle check, carried through #8190, passes here.Writing rubric results