Repository navigation
spec(AST-103): optional positions() for grid and fan drops, and attach() for plain elements - #8601
Conversation
…and fan drop positions
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
|
/approve-spec a9e7c1a |
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.
Requesting changes: the positions() direction is owner-approved at this head, but two small fixes to the record are needed first.
- FR1 should say what the
{x, y}values are measured from and which point of a slot they mark, whether they decide the reportedto, the point the card settles on, or both, and what a wrong-length array or a tree does (spec:AST-002FR8 and FR15). - The FR1, FR6–FR8 verification row now fails drops that ignore
positions, but API review, type tests and descriptor checks never perform a drag, so add browser drag tests there or move thepositionsstates into the FR3 row (and drop the stray,,).
After the update, the new head needs a fresh /approve-spec, since a new commit invalidates the current approval.
[Automated review]
| an optional `positions()` that returns each item's drop position as | ||
| `{x, y}`, in item order, for layouts such as a grid or a fanned hand; without | ||
| it, drop positions come from the measured layout and existing calls are | ||
| unchanged; |
There was a problem hiding this comment.
positions() needs its frame and use stated here: what the {x, y} values are measured from (the collection's box, the viewport, the page) and which point of a slot they mark; whether they decide the reported to, the point the card settles on, or both; and what a wrong-length array or a tree does. Without that, callers cannot tell which numbers to return, and the verification row cannot define "a drop that ignores the given positions" (spec:AST-002 FR8, FR15).
| | Contract | Verification | Representative states | Mutation or failure expectation | | ||
| | ------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | FR1, FR6–FR8 | Public-API review, type tests, and descriptor checks | the factory's options; a collection's `reorderable` type; the factory's and List's descriptors | an extra gesture, timing, or animation option, an experimental name or subpath, a missing descriptor, or a second public reorder API, fails | | ||
| | FR1, FR6–FR8 | Public-API review, type tests, and descriptor checks | the factory's options; a collection's `reorderable` type; the factory's and List's descriptors; a fanned hand with custom `positions` and a list without them | an extra gesture, timing, or animation option, an experimental name or subpath, a missing descriptor, or a second public reorder API,, a drop that ignores the given `positions`, or a call without `positions` whose behavior changes, fails | |
There was a problem hiding this comment.
This row now fails drops that ignore positions, but its methods (API review, type tests, descriptor checks) never perform a drag, and the FR3 browser row lists no positions state, so an implementation that ignores positions passes every listed check (architecture:knowledge-contracts INV18). Add browser drag tests here, or move the fanned-hand and no-positions states into the FR3 row. Also, API,, a drop has a stray comma.
|
/approve-spec 05ea461 |
|
/approve-spec f6269a1 |
… the handle's name, the hint, and how a move commits
|
/approve-spec 00b4669 |
|
/approve-spec ef284a3 |
|
That The gate only accepts the exact current head, so post this instead: A new commit invalidates the command, so repeat it after any push. |
There was a problem hiding this comment.
Requesting changes: the positions(), attach() and mouse-and-pen changes to spec:AST-103 are owner-approved at this head and the earlier requested fixes are in, but FR4b's announcements have no route inside a modal dialog the page opens itself. FR4 sends them through the page-body channel, which spec:AST-086 says assistive technology does not hear while a native modal is open, so on a page without React a reorder inside any modal is silent. Please say in FR4b where attach announces while a modal dialog encloses the container (for example, a persistent polite container inside that dialog, as AST-086 FR14 does for Astryx modals), and add that state, one object attached to two containers, and a pen drag to the FR4b verification row. An engineering owner then re-approves the new head with /approve-spec.
[Automated review]
| `attach(container, {items})`, where `items()` returns one | ||
| `{key, element, handle}` per item in order, and it returns `{detach}`. An | ||
| attached container gets FR3's drag, FR4's reorder mode on each handle, and | ||
| their announcements, with no collection component; `positions` and |
There was a problem hiding this comment.
These announcements follow FR4's route (line 178-179): the page-body channel, or an Astryx modal's containers under AST-086 FR14. Inside a modal dialog the page opens itself, AST-086 says the body channel is not exposed and leaves other delivery outside its record, and on a page without React every modal is one the page opens, so a screen-reader user hears no move, refusal or "Done" there. Please say where attach announces while a modal dialog encloses the container, for example a persistent polite container inside that dialog that detach removes, as FR14 shapes it for Astryx modals.
| | FR4 hint | Browser tests with a mouse, a finger, and a keyboard | the hint's axis in vertical, horizontal, and grid collections; each move button and Done; a tap-only reorder; the hint's theme roles | a hint off the keyboard hint's layer, anchoring, or theme roles, buttons that ignore taps or are hidden from assistive technology, a button whose move or announcement differs from its key, focus leaving the handle, or a hint that outlives the mode fails | | ||
| | FR4 two-dimensional | Keyboard and announcement-routing tests on a wrapping card grid, left-to-right and right-to-left | Left and Right across a row end; Up and Down between full rows and into a short last row; announcements with row and column; the hint's four buttons; a resize that changes the column count | a move off reading order, a mirrored direction wrong in right-to-left, a short-row move that is not clamped to its last position, a missing row or column, or a column count read from anything but layout fails | | ||
| | FR4a | Keyboard, mouse, and announcement-routing tests of `start(key)` | `start` from a context-menu item and a toolbar button; a key that is not reorderable, not mounted, or unknown; an object re-created each render; one object on two collections | `start` that does not focus and scroll to the handle, a hint or announcement that differs from the handle's mode, a missing-key call that throws or acts, or a two-collection call without a development warning fails | | ||
| | FR4b | Browser tests of `attach` on plain elements with a mouse, a finger, and the keyboard, and listener counts after `detach` | a drag, a cancelled drag, reorder mode, a fanned layout with `positions`, a move the app applies and one it does not, `detach` mid-drag, a server import, a page in another language, an item element with no accessible name, an item `isReorderable` rejects, a keyless item, `start(key)` on an attached item, a handle with its own `tabindex="-1"` | a missing drag, mode, or announcement on plain elements; a handle without FR4's role, pressed state, or name, one named "Reorder" alone when the item has text, or one outside the Tab order; a rejected or keyless item whose handle is a Reorder toggle or can be dragged; a `start(key)` that does not reach an attached item; a move announced before `items()` reports it, or one the app did not apply left unrefused; a drag or mode still running, or a listener, observer, hint element, handle attribute, or changed tab order left, after `detach`, strings other than the shipped English catalog's, or DOM work at import fails | |
There was a problem hiding this comment.
This row has no attached container inside a modal dialog the page opens, no second container for FR1's new two-container clause (lines 140-143; the FR4a row tests two collections only), and no pen, though FR3 now gives pens their own start (lines 154-155) and this row lists "a mouse, a finger, and the keyboard". Suggest adding those three states, failing an announcement that reaches only the page-body channel, a move between containers or a start without the development warning, and a pen drag that waits for a hold.
|
/approve-spec b7f7715 |
There was a problem hiding this comment.
Recommend approval: the positions(), attach() and mouse-and-pen changes to spec:AST-103 are owner-approved at this head, and the modal-dialog route and the modal, two-container and pen states requested earlier are now in the record. Nothing else blocks; the doubled comma in the FR4b row's failure cell is an optional fix, and any new push needs a fresh /approve-spec from an engineering owner.
[Automated review]
| | FR4 hint | Browser tests with a mouse, a finger, and a keyboard | the hint's axis in vertical, horizontal, and grid collections; each move button and Done; a tap-only reorder; the hint's theme roles | a hint off the keyboard hint's layer, anchoring, or theme roles, buttons that ignore taps or are hidden from assistive technology, a button whose move or announcement differs from its key, focus leaving the handle, or a hint that outlives the mode fails | | ||
| | FR4 two-dimensional | Keyboard and announcement-routing tests on a wrapping card grid, left-to-right and right-to-left | Left and Right across a row end; Up and Down between full rows and into a short last row; announcements with row and column; the hint's four buttons; a resize that changes the column count | a move off reading order, a mirrored direction wrong in right-to-left, a short-row move that is not clamped to its last position, a missing row or column, or a column count read from anything but layout fails | | ||
| | FR4a | Keyboard, mouse, and announcement-routing tests of `start(key)` | `start` from a context-menu item and a toolbar button; a key that is not reorderable, not mounted, or unknown; an object re-created each render; one object on two collections | `start` that does not focus and scroll to the handle, a hint or announcement that differs from the handle's mode, a missing-key call that throws or acts, or a two-collection call without a development warning fails | | ||
| | FR4b | Browser tests of `attach` on plain elements with a mouse, a finger, a pen, and the keyboard, and listener counts after `detach` | a drag, a cancelled drag, reorder mode, a fanned layout with `positions`, a move the app applies and one it does not, `detach` mid-drag, a server import, a page in another language, an item element with no accessible name, an item `isReorderable` rejects, a keyless item, `start(key)` on an attached item, a handle with its own `tabindex="-1"`, a container inside a modal dialog the page opens, one object attached to two containers, a pen drag | a missing drag, mode, or announcement on plain elements; a handle without FR4's role, pressed state, or name, one named "Reorder" alone when the item has text, or one outside the Tab order; a rejected or keyless item whose handle is a Reorder toggle or can be dragged; a `start(key)` that does not reach an attached item; a move announced before `items()` reports it, or one the app did not apply left unrefused; a drag or mode still running, or a listener, observer, hint element, handle attribute, or changed tab order left, after `detach`, strings other than the shipped English catalog's,, an announcement inside a page-opened modal that reaches only the page-body channel, a move between two containers or a `start` there without the development warning, a pen drag that waits for a hold, or DOM work at import fails | |
There was a problem hiding this comment.
Optional: this failure cell has a doubled comma, catalog's,, an announcement; one comma is enough.
|
/approve-spec 8938de1 |
There was a problem hiding this comment.
Requesting changes: the positions(), attach() and pointer changes to spec:AST-103 are owner-approved at this head, but the latest edit split FR3's pen rule by primary pointer without updating the FR4b verification row. That row still fails "a pen drag that waits for a hold", which FR3 now requires of a pen on a coarse primary pointer in attached containers, so please split it as the FR3 row is and bring the description's FR3 bullet and R3 line in line with the record. The doubled comma in the same cell is an optional fix, and the new head will need a fresh /approve-spec from an engineering owner.
[Automated review]
| | FR4 hint | Browser tests with a mouse, a finger, and a keyboard | the hint's axis in vertical, horizontal, and grid collections; each move button and Done; a tap-only reorder; the hint's theme roles | a hint off the keyboard hint's layer, anchoring, or theme roles, buttons that ignore taps or are hidden from assistive technology, a button whose move or announcement differs from its key, focus leaving the handle, or a hint that outlives the mode fails | | ||
| | FR4 two-dimensional | Keyboard and announcement-routing tests on a wrapping card grid, left-to-right and right-to-left | Left and Right across a row end; Up and Down between full rows and into a short last row; announcements with row and column; the hint's four buttons; a resize that changes the column count | a move off reading order, a mirrored direction wrong in right-to-left, a short-row move that is not clamped to its last position, a missing row or column, or a column count read from anything but layout fails | | ||
| | FR4a | Keyboard, mouse, and announcement-routing tests of `start(key)` | `start` from a context-menu item and a toolbar button; a key that is not reorderable, not mounted, or unknown; an object re-created each render; one object on two collections | `start` that does not focus and scroll to the handle, a hint or announcement that differs from the handle's mode, a missing-key call that throws or acts, or a two-collection call without a development warning fails | | ||
| | FR4b | Browser tests of `attach` on plain elements with a mouse, a finger, a pen, and the keyboard, and listener counts after `detach` | a drag, a cancelled drag, reorder mode, a fanned layout with `positions`, a move the app applies and one it does not, `detach` mid-drag, a server import, a page in another language, an item element with no accessible name, an item `isReorderable` rejects, a keyless item, `start(key)` on an attached item, a handle with its own `tabindex="-1"`, a container inside a modal dialog the page opens, one object attached to two containers, a pen drag | a missing drag, mode, or announcement on plain elements; a handle without FR4's role, pressed state, or name, one named "Reorder" alone when the item has text, or one outside the Tab order; a rejected or keyless item whose handle is a Reorder toggle or can be dragged; a `start(key)` that does not reach an attached item; a move announced before `items()` reports it, or one the app did not apply left unrefused; a drag or mode still running, or a listener, observer, hint element, handle attribute, or changed tab order left, after `detach`, strings other than the shipped English catalog's,, an announcement inside a page-opened modal that reaches only the page-body channel, a move between two containers or a `start` there without the development warning, a pen drag that waits for a hold, or DOM work at import fails | |
There was a problem hiding this comment.
FR3 now keeps the hold for "a pen where the primary pointer is coarse" (lines 154-156), and FR4b gives attached containers "FR3's drag" (line 219), but this row still lists one "a pen drag" state and fails "a pen drag that waits for a hold" with no pointer condition. On a tablet with a stylus, a conforming attached handle fails this row, and one that drops the hold passes it. Suggest testing "a pen drag on a fine and on a coarse primary pointer" and failing "a pen drag on a fine primary pointer that waits for a hold, or one on a coarse primary pointer that starts without one", as the FR3 row does. The doubled comma (catalog's,,) in the same cell can go in the same edit.
|
/approve-spec dbef6ed |
There was a problem hiding this comment.
Requesting changes: the positions(), attach() and pointer changes to spec:AST-103 are owner-approved at this head, but attached reorder mode can lose keyboard focus after every move. Because the app applies each move, moving or re-rendering a card drops focus from its grip to the page (Chromium does this for insertBefore and for rebuilt markup), and FR4b neither returns focus to the moved item's handle nor has a verification failure for it, so please add both to FR4b and its row. The positions() grid wording, the wording of the refusal for an unapplied move, and the FR3 row's pen states are smaller fixes for the same push, which will need a fresh /approve-spec from an engineering owner.
[Automated review]
| when both are empty; it puts each handle in the Tab order; a | ||
| rejected item's handle, or a keyless item's, gets none of this and starts no | ||
| drag; `start(key)` reaches attached items as it reaches a collection's; and it renders FR4's hint as an element it owns. A move | ||
| commits when `items()` reports the new order after `onReorder`: `attach` |
There was a problem hiding this comment.
Under FR4b the app applies each move, so it moves or re-renders the card, and a focused grip inside a moved or rebuilt element loses focus to the page (Chromium does this for insertBefore and for rebuilt markup). FR4's "focus stays on the handle" then needs attach to put focus back. Suggest: once items() reports the move, attach focuses the moved key's handle as items() returns it and scrolls it into view, plus a FR4b row state for a move the app applies by moving the card's element and one by re-rendering it, failing focus that is not on the moved handle afterwards.
| returns a reorderable object. `options` carries the change callback, | ||
| `onReorder({ key, to })`, and an optional `isReorderable(key)` predicate; | ||
| `onReorder({ key, to })`, an optional `isReorderable(key)` predicate, and | ||
| an optional `positions()` for layouts such as a grid or a fanned hand. |
There was a problem hiding this comment.
Grids already get their slots from the measured layout (FR4 reads a grid's rows and columns from it, line 173), so naming "a grid" here suggests grid callers need positions(). Suggest naming the layouts the measured layout cannot place, such as cards positioned with transforms in a fanned hand, or "a grid the product places itself".
| announces it and plays the drop then; while a modal dialog encloses the | ||
| container, `attach` announces through a persistent polite container inside | ||
| that dialog, as `spec:AST-086` FR14 shapes it for Astryx modals; and a move whose order has not changed | ||
| by the end of that task is refused and announced, as in FR4. `attach` resolves its strings and number formats as a component outside a |
There was a problem hiding this comment.
FR4's only refusal wording names a rejected end row ("Can't move past Pinned"), which a move the app did not apply does not have, and "that task" names no task. Suggest an example such as "Can't move King of hearts" and "by the end of the task that ran onReorder".
|
/approve-spec 7db5884 |
|
/approve-spec 348392c |
There was a problem hiding this comment.
Recommend approval: the positions(), attach() and pointer changes to spec:AST-103 are owner-approved at this head, they contradict no current record, and the focus-return requirement and verification state requested earlier are in. Nothing else blocks; the doubled comma in the FR4b row's failure cell and the FR3 row's method cell, which does not yet name the pen, are optional fixes, and any new push needs a fresh /approve-spec from an engineering owner.
[Automated review]
| | FR4 hint | Browser tests with a mouse, a finger, and a keyboard | the hint's axis in vertical, horizontal, and grid collections; each move button and Done; a tap-only reorder; the hint's theme roles | a hint off the keyboard hint's layer, anchoring, or theme roles, buttons that ignore taps or are hidden from assistive technology, a button whose move or announcement differs from its key, focus leaving the handle, or a hint that outlives the mode fails | | ||
| | FR4 two-dimensional | Keyboard and announcement-routing tests on a wrapping card grid, left-to-right and right-to-left | Left and Right across a row end; Up and Down between full rows and into a short last row; announcements with row and column; the hint's four buttons; a resize that changes the column count | a move off reading order, a mirrored direction wrong in right-to-left, a short-row move that is not clamped to its last position, a missing row or column, or a column count read from anything but layout fails | | ||
| | FR4a | Keyboard, mouse, and announcement-routing tests of `start(key)` | `start` from a context-menu item and a toolbar button; a key that is not reorderable, not mounted, or unknown; an object re-created each render; one object on two collections | `start` that does not focus and scroll to the handle, a hint or announcement that differs from the handle's mode, a missing-key call that throws or acts, or a two-collection call without a development warning fails | | ||
| | FR4b | Browser tests of `attach` on plain elements with a mouse, a finger, a pen, and the keyboard, and listener counts after `detach` | a drag, a cancelled drag, reorder mode, a fanned layout with `positions`, a move the app applies and one it does not, `detach` mid-drag, a server import, a page in another language, an item element with no accessible name, an item `isReorderable` rejects, a keyless item, `start(key)` on an attached item, a handle with its own `tabindex="-1"`, a container inside a modal dialog the page opens, one object attached to two containers, a pen drag on a fine and on a coarse primary pointer, a move the app applies by moving the item's element and one by re-rendering it | a missing drag, mode, or announcement on plain elements; a handle without FR4's role, pressed state, or name, one named "Reorder" alone when the item has text, or one outside the Tab order; a rejected or keyless item whose handle is a Reorder toggle or can be dragged; a `start(key)` that does not reach an attached item; a move announced before `items()` reports it, or one the app did not apply left unrefused; a drag or mode still running, or a listener, observer, hint element, handle attribute, or changed tab order left, after `detach`, strings other than the shipped English catalog's, an announcement inside a page-opened modal that reaches only the page-body channel, a move between two containers or a `start` there without the development warning, a pen drag on a fine primary pointer that waits for a hold, or one on a coarse primary pointer that starts without one,, focus not on the moved item's handle after a move, or DOM work at import fails | |
There was a problem hiding this comment.
Optional: this failure cell has a doubled comma, starts without one,, focus not on the moved item's handle; one comma is enough.
| | ------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | FR1, FR6–FR8 | Public-API review, type tests, and descriptor checks | the factory's options; a collection's `reorderable` type; the factory's and List's descriptors | an extra gesture, timing, or animation option, an experimental name or subpath, a missing descriptor, or a second public reorder API, fails | | ||
| | FR2 | Bundle and runtime check of a collection with and without the prop | without the prop; with the prop | reorder code in the bundle, a handle, or a reorder listener without the prop fails; the measured cost is recorded in the pull request | | ||
| | FR3 | Browser tests with real touch input and a mouse (`spec:AST-013` FR10) | a hold and drag; a flick; a drop; a cancelled drag; Reduce Motion; a fanned hand with custom `positions`; a list without them; a `positions` array of the wrong length; a tree with `positions`; custom `positions` beside a rejected end row; a pen drag on a fine and on a coarse primary pointer | a drag that starts off the handle, a commit before the drop, two callbacks for one drag, a callback on cancel, travel under Reduce Motion, a drop that ignores `positions` of the right length, a wrong-length array or a tree whose drops do not come from the measured layout, a drop outside the drop range, a mouse drag, or a pen drag on a fine primary pointer that waits for a hold, or a pen drag on a coarse primary pointer that starts without one, or a call without `positions` whose behavior changes fails | |
There was a problem hiding this comment.
Optional: this row's states and failures now include a pen on a fine and on a coarse primary pointer, but its method cell still reads "Browser tests with real touch input and a mouse"; "real touch input, a pen, and a mouse" would match the FR4b row.
|
/approve-spec 348392c |
Decided (Cindy, 2026-10-26, with the public gesture hooks).
User impact
A product can make cards in a grid or a fanned hand reorderable, with drops landing where its own layout puts them. Existing reorderable lists are unchanged.
Change:
spec:AST-103FR1createReorderable({…, positions?: () => {x, y}[]})returns each slot's center in pixels from the collection container's top-left, in item order. It decides the reportedto(the nearest slot) and where a dropped item settles. A wrong-length array, orpositionsin a tree, is ignored.positions, a list without them, a wrong-length array, a tree, a rejected end row, and a pen on a fine and on a coarse primary pointer. It fails each fallback and a pen or mouse drag whose hold does not match FR3.The docs and playing-cards example for
positionsare part of the gesture hooks' done criterion (AST-107 FR5).Writing rubric results
R1 present tense: pass. R2 research: none. R3 verification: the FR3 and FR4b rows carry the new states and failures, the pen split by primary pointer in both.
R4 rejected alternatives: none. R5 change references: none in the record. R6 open questions: none.
FR4b (Cindy 20:38, non-React alternatives):
reorderable.attach(container, {items}) → {detach}, whereitems()returns{key, element, handle}per item. Plain elements get the same drag, reorder mode, and announcements;positionsandisReorderableapply.detachremoves every listener, and creation does no DOM work (SSR-safe).