Repository navigation
Conversation
…ter stays the touch hit layer Under a finger, an interactive row's `::after` is its invisible hit layer (List FR10, listRow.stylex.ts). The surface a row an update slides across others rides on was the same pseudo-element, so the two merged: the hit layer took the surface's colour and its `pointer-events: none`. The surface is now an inset shadow across the row's padding box, which paints in the same place (over the row's background, under the press layer and the content, inside the divider) with no pseudo-element. The proof reads the shadow's colour instead of the layer's.
…es its recognizers, and the group keeps answering afterwards Under a fine pointer the host is not installed, so usesTouchEvents keeps its initial true, and a group press's own touch pointermove and pointerup went down the touch-pairing path and returned: the finger's moves and lift never reached the group, its contact stayed in the arena, and the group answered no press after it, a mouse's included. The group press now feeds its own events through the pointer path for every pointer type. Test (failing first): under a fine pointer a finger tap on a group recognizes, and a mouse tap afterwards does too.
… are all passive spec:AST-094 FR20: a watcher registers only passive listeners, but a watcher-only page still got the host's cancelable document touchend and its contextmenu and window click listeners. The document touchend is now passive until an enabled claimer (a recognizer that claims touches, or a consumer) is attached, and the contextmenu and click listeners are on only then, swapped as attachments change. The new test (a lone watcher leaves no cancelable document or window listener; a claiming pan brings the three) fails on the previous head.
…r watchers) into the host line The host keeps this PR's isRtlElement and its fingers held before a recognizer begins (a kept press, a scroll-edge pan), beside meta#8061's view size and meta#8309's pointer-events finger lookup. meta#8589's claimer check counts only participants active on this pointer (isActive, isConsumerActive), and a group press's click listener now stays while a claimer keeps it installed. The browser spec keeps the fine-pointer describe beside the FR18-FR22 real-touch states.
…'s passive-only watcher listeners) into the arena fixes The host-owner changeset keeps this PR's own listeners for the scroll lock and finger-scroll watch, and adds meta#8336's scroll-edge hold.
A List row's target is its pressable root (Item's `li`), not the control inside it: that inner button, link or checkbox is only the label column, inside the row's padding. Without the root among the interactive elements, a row's watch measures the next row through that inner control, 10 px away instead of 2, and both 36 px rows grow 4 px into the 2 px gap, overlapping by 6 px. With it, each takes 1 px and the two areas meet in the gap.
…tree expansion change
…list updates change
…inter reaches its recognizers) as a dependency
…s the diagonal pocket and lets keyboard clicks through - The live watch read neighbours within 22 px only, but two small targets reach each other from up to 44 px apart: two 8 px dots 24 px apart kept 18 px of growth toward each other. It reads within the minimum size now. - A wide target and a tall one, diagonally, could each stay short of the other's half of the gap on one axis yet meet at full growth (32 x 32 beside 40 x 24: 4 x 4 px). A neighbour now also counts when the two full areas meet. - The one-shot click swallower lets a keyboard or assistive-technology activation (detail 0) through, and a cancelled touch (pointercancel) disarms it, so a touch the browser took for a scroll leaves nothing armed. - A second watch of an element starts as visible as the first, so it hears its insets. Each fix has a test that fails on the previous head.
Main's meta#8521 is its head 25b468c squashed, which this pull request already carries: every file it touches is byte-identical to 25b468c. In the two files that conflicted (the motion README and animator.ts), the resolution is this side's version, main's merged meta#8521 with this pull request's later work on top. Nothing of main is dropped.
… control's label included The guard ended on its click, a cancelled touch, or the next press on the control itself; a tap on the control's own label lands outside it, so a touch that ended with neither a click nor a cancel could leave the label's click to the input swallowed. While armed, the guard now also listens for the next pointerdown anywhere in the document. The test's label-tap case fails on the previous head.
A List row's target is its pressable root (Item's `li`), not the control inside it: that inner button, link or checkbox is only the label column, inside the row's padding. Without the root among the interactive elements, a row's watch measures the next row through that inner control, 10 px away instead of 2, and both 36 px rows grow 4 px into the 2 px gap, overlapping by 6 px. With it, each takes 1 px and the two areas meet in the gap.
The note's reword joined its next sentence onto one long line; it now wraps like the rest of the file. No code change.
Rows move by transform (an update's slide, a swipe, edit mode's slide), and the shared touch hit area measures them as they stand in one frame: during a removal it re-measured a frame into the motion and wrote fractional insets, a layout and a paint in the middle of a compositor-only motion. A measurement that arrives while the row's list has a finite animation running or held is now dropped, and once those animations end the row is watched afresh, so its insets are taken at rest.
…w press release change
…inst a fine pointer astracat's 13:21Z review: the finger-target case capped every hint button, Done included, below 44 px, which neither shows that no control grows for a finger (spec:AST-094 FR42) nor allows a button that is larger by itself. It now opens the same hint where the primary pointer is fine and requires each button to add the same space around what it shows (its glyph, or its text's width and line) under both pointers; the theme's type scale may set larger text for a coarse pointer, which the comparison leaves out. The invisible hit layer still only grows, up to 44 px or the button's own size. Failing-first: with a coarse-only 2 px of block padding on the buttons, the old cap passed and this case fails (Move up adds 4 px of height).
…e touch target size from the theme) under the reorder values
astracat's 13:19Z review: the browser proofs read only the order a drop leaves, and the story's moveKey is idempotent, so an onReorder called twice for one drop passed them, while spec:AST-103 FR3 asks for one call per drag and none for a cancelled one. The List stories count the moves their onReorder reports on the list (data-moves); the touch drop and the mouse drop each add exactly one, and a cancelled drag adds none. Failing-first: with the engine reporting each drop twice, the touch and mouse drop proofs failed (expected 1, received 2); the cancel proof passed, as it should.
PR Analysis Report
View Storybook for this PR · View Sandbox for this PR Generated by PR Enrichment workflow | View current CI run |
There was a problem hiding this comment.
This needs an engineering owner's decision before it can be approved: List's every-pointer reorder cites spec:AST-094 FR43, which is not on main yet (it is proposed in #8646), while the current FR19 attaches no recognizer where the primary pointer is fine. An engineering owner needs to identify the governing spec for this behavior, including whether a finger's flick may stop on the handle on touchscreen laptops where spec:AST-103 FR3 says it still scrolls, and records the decision by commenting /approve-spec af760b20424a59f6bb7ea2b326ab1f6741ad1aa9 on this pull request; the author, as an engineering owner, may do so. Independently of that decision:
- The diff against
maincarries the whole stack (261 files, about 47,800 lines), so land #8139, #8337, #8140, #8665 and #8666 first and rebase until this pull request shows only its own commit. ListReorderHandle.tsxsetstouch-action: noneunder a fine pointer, which drops the pinch-zoomspec:AST-094FR18 keeps, whilepinch-zoomwould still stop a pen's pan.- List's docs and release note (
List.tsx,List.doc.mjs,createReorderable.doc.mjs,.changeset/list-reorderable.md) still say a flick on the handle scrolls and do not mention pens.
[Automated review]
| // A pen drags at once where the primary pointer is fine, as a mouse does, | ||
| // since the handle allows it no pan there; where it is coarse, the handle | ||
| // keeps the page's pan, so a pen holds as a finger does (an iPad Pencil's | ||
| // touches are claimable; spec:AST-094 FR43, FR18). | ||
| useIsomorphicLayoutEffect( | ||
| () => controller.attachMouse(!isTouch), | ||
| [controller, isTouch], | ||
| ); |
There was a problem hiding this comment.
This effect changed (it now depends on isTouch and admits pens), and its comment explains pens but names no external system. architecture:react-component-runtime INV3 asks a new or changed Effect to name what it synchronizes: here the list's pointer listeners that attachMouse adds and its returned detach removes.
| '@astryxdesign/core': patch | ||
| --- | ||
|
|
||
| [feat] `createReorderable({onReorder, isReorderable})` makes a collection's reorder behavior, and `List` takes it as `reorderable`: each `ListItem` with an `itemKey` gets a reorder handle at its end, and each committed move calls `onReorder({key, to})` once, with the row's key and its index after the move. On a touch screen a finger held still on a handle picks up its row the way an iOS table's reorder control does (a flick on it still scrolls): the row stays in its place, dimmed, while a copy of it follows the finger and an accent line marks where it would land; the other rows stay still, the page scrolls near the edges, and on release the rows rearrange, gliding to their new places. A mouse drags a handle at once with the same copy and line, and rows take their places without motion; a cancelled drag puts everything back at once. Without a drag, a click, Space or Enter on a handle turns on reorder mode for its row: each arrow key moves it a place at once, announced with its place and neighbours, and Escape or another activation ends the mode, keeping the moves. The object's `start(key)` enters the same mode from the app's own UI, such as a row's context menu. A List without `reorderable` loads none of the reorder code. |
There was a problem hiding this comment.
The description relies on this release note, but with the own commit a flick on the handle no longer scrolls on a touchscreen laptop, and a pen drags at once there and holds where the primary pointer is coarse; this note still says "a flick on it still scrolls" and names only a mouse's immediate drag.
|
Posted by Cindy's agent on her behalf: closed and reopened only to restart this PR's CI on the current workflow after tonight's queue-wide cancel; nothing in the PR changed. |
… hold A divided List row keeps its dividers while it is pressed, as it does today, and Core keeps no selection hold: products show a row kept selected through ListItem's isSelected. This removes the touch press's divider hiding (its ListItem styles, docs, changeset, tests and browser proofs) and the selection hold (selectionHold.ts, its held press state in the shared press code, its internal deselect constants, the row focus-return lines, story, changeset and proofs). The shared test helpers, the press-coverage guard and the press release's own clock stay. Co-authored-by: Christopher Chedeau <vjeuxx@gmail.com>
…tion hold) as a dependency Co-authored-by: Christopher Chedeau <vjeuxx@gmail.com>
The previous merge left List.tsx's hasDividers JSDoc unresolved and the List stories empty. This restores the stories (without the selection hold demo) and the plain hasDividers line. Co-authored-by: Christopher Chedeau <vjeuxx@gmail.com>
There was a problem hiding this comment.
This needs an engineering owner's decision before it can be approved: with spec:AST-094 FR43 now on main the every-pointer reorder has its spec, but on a touchscreen laptop the handle's touch-action: none gives a pen its drag without a hold by stopping a finger's flick from the handle, while spec:AST-103 FR3 asks for both. An engineering owner records which wins: commenting /approve-spec 85a30f173854866a1a0735180e5b75fb32f16c8d on this pull request keeps the pen's drag as written, and otherwise the handle has to keep the flick; the author may record it as an engineering owner. Independently of that decision:
- The diff against
maincarries at least 18 other open pull requests (252 files, about 45,600 lines) and no longer merges cleanly (TreeList), so land the stack and rebase until only this pull request's own commit remains. ListReorderHandle.tsxdrops the pinch-zoomspec:AST-094FR18 keeps;pinch-zoomin place ofnonewould still stop a pen's pan.- The carried
hasAnimatedChangesshould be theanimatedLayouthandleList.spec.mdFR12 specifies, and List's docs and release note still say a flick on the handle scrolls.
[Automated review]
| * Off by default; with a mouse nothing moves. | ||
| * @default false | ||
| */ | ||
| hasAnimatedChanges?: boolean; |
There was a problem hiding this comment.
Current List.spec.md FR12 says "List MUST take an animatedLayout handle (spec:AST-105 FR1)", and AST-105 FR5 has the glide apply "under every pointer, a mouse included". This boolean animates only under a finger and sits beside the useAnimatedLayout hook main already exports, so a caller who adopts it holds an API the record does not have. Taking FR12's animatedLayout handle instead keeps one public shape.
| if (target.closest('button, a, input, select, textarea')) { | ||
| return; | ||
| } | ||
| if (onClick == null && href != null && !isLinkRoot) { |
There was a problem hiding this comment.
This forwards any click in a link row's box to its anchor, under every pointer, so a mouse click in a ListItem row's padding, which did nothing before, now navigates (the new Item.test.tsx case asserts it with a plain click). List.spec.md FR10 grows the target only under a coarse pointer and says "A fine pointer keeps today's hit target". Forwarding only from the coarse-pointer hit area would keep a mouse's target as it was.
| * development). On an object passed to two collections, it starts the | ||
| * mode in the one mounted last. | ||
| */ | ||
| start(key: TKey): void; |
There was a problem hiding this comment.
start is the object's only method, and the options carry only onReorder and isReorderable. Current spec:AST-103 FR4b says "The object exposes attach(container, {items})", and FR1 gives the options "an optional positions()"; FR6 makes the object stable from its first release, which this pull request is.
meta#8360's gesture host With meta#8106 on meta#8360's foundation, the gesture host takes a finger from pointer events where it can: mounting two reorderable lists on a touch screen now puts a pointerdown listener on the document, and no touch listener until a press. The test asked for touch listeners only, so it found none (expected 0 to be greater than 0). It now counts touch and pointer listeners, as meta#8683's version of it already does, and still requires every one of them to go when the lists unmount.
Depends on #8140, and carries #8665 and #8666 (the every-pointer gesture host and its pen test driver). Review only this PR's change, its one commit: vjeux/astryx@8d0e69a...df13e2c
Why
People reorder with whatever they hold: a finger on a laptop's touch screen, a pen, or a mouse. The List reorder's touch hold worked only where the main pointer is a finger, and a pen always had to hold first, even on a desktop.
What led to it
This is part of the UIKit-parity program, which makes Astryx's components behave like their iOS counterparts on touch screens.
spec:AST-094FR43, now merged, makes gestures work for every pointer, and has a mouse, trackpad or pen start a reorder by dragging the handle without a hold. Here:Options and tradeoffs
The handle's
touch-actioncould benoneeverywhere,manipulationeverywhere, or depend on the main pointer.nonebreaks the phone's flick-to-scroll;manipulationlets a pen pan the page instead of dragging.Why this choice
It depends on the main pointer:
noneon a desktop, so a pen stroke can't become a pan, andmanipulationon a phone, so a flick still scrolls. Wheel autoscroll, mouse press feedback and removing the row-menu stopgap stay in their own PRs.How to check it
In Storybook
Core/List:I ran the browser and unit tests for each step, and all pass; each one failed first. WebKit skips the pen cases, since its driver has no pen. Two reds come from elsewhere:
touch-support-bundle, which #8671 fixes, andpr-rtl, main's newer RTL test from 0472c4e.Evidence
The List reorder's browser tests.
Stack (merge in this order): … → #8139 → #8337 → #8140 → #8665 → this.