Repository navigation
Conversation
Cases for a LayoutPanel that takes a useResizable region's own props: it is measured before the collapse commits and plays from the edge facing its ResizeHandle, on every collapse and open, a controlled isCollapsed and a drag past the threshold, with nothing for a drag that reopens it, the first render or a plain resize. A hand-built object, a pane at the hook's size alone, and a LayoutPanel at the hook's size beside a handle given the props show no slide. Two cases for the shared edge reveal: a conceal keeps the padding and overflow the element was laid out with and puts back the element's own values once the motion ends, and it keeps the scroll offset, which a reveal that reverses it scrolls back to. These cases fail until the next commit.
…ery pointer A LayoutPanel given a useResizable region's own props hands its element to the region, and the region's internal factory plays `spec:AST-105` FR9's edge reveal as it collapses or opens, under every pointer (FR5). It measures in the commit that renders the change, before the DOM changes, and plays once the pane renders its new size. A pointer drag that reopens the pane follows the pointer instead, which the ResizeHandle given the props reports to the region. The slide picks no timing of its own: it follows the shared animated-layout module. No prop, option, export or type changes. The panel lends its element from a layout Effect instead of its callback ref, both to the region and to a ResizeHandle that finds it beside it. At width 0 the panel tells the scroll-region hook it does not scroll, which changes that hook's ref. React then runs every merged ref again, so a lend in the callback ref was taken back and given again mid-collapse, which landed the slide before it played. While the shared edge reveal holds a concealing element at the extent it was laid out at, it now also keeps the element's padding, overflow and scroll offset as laid out, and puts back the element's own values once the motion ends. A LayoutPanel at width 0 drops its padding and stops scrolling in the collapsing commit, so without that its children jumped by the padding and a scrolled panel jumped to its top as the slide began. A reveal that reverses a conceal scrolls back to where the conceal kept it.
…nd open The `resizable` description, in English, Chinese and dense form, says that a panel given the hook's own value slides closed and open from the edge facing its ResizeHandle, and that a hand-built object does not. A `[feat]` changeset describes the slide.
…le in Chromium and WebKit Real-browser proof on new stories: a start and an end panel given the hook's value slide closed and open with the content beside them, through a toggle, a controlled isCollapsed, a double-click, the grow arrow and Enter. A drag reopens a pane under the pointer, and a hand-built object collapses without a slide. Focus moves to the handle as a pane collapses. The slide proof captures its moments by seeking the paused motion. Nothing inside a sliding pane moves, and a scrolled pane keeps its scroll offset as it slides closed. The pane's shown edge stays where the motion leaves it beside the handle: a panel without a divider overlaps its handle by its collapse spacing only while open.
… list the slide as missing The implementation gaps for the pane slide (Resizable FR8, LayoutPanel FR7) close, and the current-state notes drop them. FR8 and FR7 keep their cell widths, so no other row re-pads: each gap sentence becomes a sentence of the same length, which says that a panel at the hook's size beside the handle does not slide. The verification rows name the paths the browser spec drives and the unit cases for the rest.
…takes the handle At every captured moment of a closing and an opening slide, on both sides, a press at the handle's middle where it shows must land on the handle. A drag that starts there 40 ms into a closing slide, with the motion held, must take the handle and reopen the pane. Both fail until the next commit: the gliding content beside the handle takes the press.
A slide translates the handle and the content beside it. A translate makes the handle a stacking context, which traps the grab zone's own z-index inside it, and the content, later in the document and translated too, stacked above the zone. So a finger that landed on the handle mid-slide pressed the content, the browser took the pan, and the drag never started. The handle now carries z-index 2 itself, as an overlay handle already does. At rest nothing changes: 22 stories with handles give identical screenshots and hit tests.
…nd the lift decides a close Past the maximum, and under the minimum, the pane follows the pointer with resistance and springs back to the limit after the lift. A drag past the collapse threshold closes only on its lift, and a flick toward closing closes from above it; anything else returns to the minimum. The close plays the settle spring from the release velocity. The unit cases and the paneSlide cases fail until the next commit: today the edge stops at each limit, and the pane collapses mid-drag.
…nd the lift decides a close Past the maximum, and under the minimum, the pane follows the pointer through core's shared rubber band, over the region's basis, and the reported size runs past the limit by what the band shows. The resize gesture now hands the lift's velocity to the region. After the lift the size springs back to the limit on the settle spring from that velocity, and a new press catches it where it shows. A drag no longer collapses the pane mid-way: the lift closes it when the pointer is past the collapse threshold, or released fast enough to come to rest past it, and the close slides on the settle spring from the release velocity. The slide takes that spring through a release glide the layout animation now accepts for one frame. Reduce Motion still lands both at once.
…ose decided on the lift FR8 adds the pull past either limit, through core's shared rubber band, its spring back on springs.settle from the release velocity, and the close a lift makes past collapsedSize, or a flick whose projected rest is past it, on the same spring. A drag no longer collapses mid-way, and a press on the handle mid-slide takes the handle. The collapse state row, its verification row, the collapsedSize docs and the hook's callback note say the lift decides. A changeset records it.
…size runs past one While a pull rubber-bands past a limit, the region reports the size it shows, past the bound. The separator's aria-valuenow must stay at the bound. This case fails until the next commit.
…ize runs past one aria-valuenow is the size clamped to the separator's bounds, so a pull that rubber-bands past a limit announces the limit, as before. The collapsed case already used the minimum, and keeps it.
A per-frame trace after the lift records the pane's laid-out width and the handle's drawn middle. The pane must keep the width it was pulled to until it takes the maximum, once, while the edge passes the places between. The spring-back stepped from script lays out 30 widths, so this case fails until the next commit.
The spring-back no longer steps the pane's size from script each frame. It commits the bound once, and the pane's edge reveal plays the change on the settle spring from the release velocity, as the close does. A conceal holds the pane at the width it was pulled to, clips it and rides the content beside it; a reveal below the minimum opens to it. A finger that catches it mid-glide starts from the size it shows.
FR8 has a press on the Handle where it shows mid-slide take the Handle. On iOS WebKit that press lands on content until animated-layout glides resolve their hit position, so Current-state impact names the gap.
A grab on the Handle where it shows mid-slide takes it on iOS WebKit too: the grab zone stays above the gliding content. So Current-state impact no longer lists the gap.
…'s tempo At tempo 1.5 a lift's close and spring-back must take 1.5 times as long as the settle spring. This case fails until the next commit.
…s tempo The close and the spring-back after a lift resolve `springs.settle` for the row, so a theme's tempo times them like every other spring role.
A panel sized by the region's `size`, with no pane lent to the region, has no rubber band: it stops at the maximum and does not jump back on the lift. This case fails until the next commit.
The overshoot past a limit reaches the region's size only while a LayoutPanel lends its pane, whose edge springs back on the shared glide. A panel at the hook's size alone stops at the limit, as before, so nothing jumps back on the lift. The pointer's raw size is now `pointerSize`.
…zableProps `ResizableProps._onResizeEnd` keeps main's signature. The hook keeps a module-private map from its props to an end that takes the release velocity, and the ResizeHandle ends a drag through `endResizeAt`, which the package does not export. A hand-built props object ends without a velocity.
The rubber band and its spring-back play when a LayoutPanel renders the pane. A pane rendered at the hook's size alone stops at the limit, under AST-094 FR5. The changeset says the same.
The `@output` headers of `resizablePane.ts`, `animatedLayout.boundary.test.ts` and `animatedLayout.edge.test.ts`, and `resolveMotion`'s description, ran past INV29's sentence length. Each now says one thing per sentence.
… no reflow Each frame of a pull past either limit and its spring-back, the pane keeps its laid-out width, its button keeps its size, and the edge stands at most 8 px past the limit. The content beside never overlaps the drawn pane. These cases fail until the next commit: the pane is laid out 71 px past the maximum, and its button jumps 359 -> 288 px at the end.
…eflow The overshoot past a limit no longer reaches the region's size. The pane keeps its laid-out size, and its edge is drawn past the limit: the pane stretches from its far edge on the compositor, and the handle and the content beside it move with the edge. The rubber band's extent is 8 px, so the edge moves at most that far. After the lift the drawing springs back on the settle spring from the release velocity, with no layout. A finger catches it where it shows.
…t closes FR8 records the cap and that the pane's content keeps its size past a limit, and that only the lift closes the pane. The reported size keeps to the limits. The changeset says the same.
`captureMotion` and `holdMotionAt` gave a change 1 s to start its motion, then decided nothing animates. Under load a commit can land later. They now wait, frame by frame, until a motion starts or the handle says the collapse state changed, then two more frames for a later commit.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
The Resizable entry now carries the gesture system's velocity tracker (1,653 B, via ResizeHandle and the resize gesture): the lift's close and the handle's spring-back start from the release velocity. INV13 lists velocity tracking among the gaps that components reach directly, so the bundle test lists Resizable among the imports that use a gesture, with that reason. It failed with the Resizable entry unlisted.
FR8's longer cells left three tables in the Resizable spec unpadded: the public concepts, the behavioral and layout contract, and the verification map. Prettier re-pads them; no cell text changes.
|
/approve-spec 94cdeb8 |
There was a problem hiding this comment.
Approved pending CI: CI has not run on this head yet because the pull request is a draft; it runs once the pull request is marked ready for review.
An engineering owner approved the spec changes at this head, and no blocking findings remain. The diff includes #9989's slide, and #10333 is built on this pull request's previous head, so restack it to keep the stack's size exemption.
Non-blocking:
- Miss: the public
collapsedSizeJSDoc (useResizable.ts:72) still says "dragging triggers collapse", while only a drag's lift collapses at this head; "Size in px under which a drag's lift collapses the region." matches the docs this pull request already updated. - Still open from the last review: the comment at
separatorAttributes.ts:58describes a size past the bound, which no longer happens now that only the handle is drawn past a limit; "The value stays inside the bounds." says what the clamp does. - The earlier note about the release close's
linear()easing is withdrawn: the slide's keyframes are sampled per frame, so it stays on the compositor.
[Automated review]
|
/approve-spec c4a095b |
There was a problem hiding this comment.
Approved. A pull past a resizable LayoutPanel's limit now bands at most about 8 px and springs back, a collapsible region closes only on the lift, and the panel slides closed and open. An engineering owner approved every rewritten record at this head, and CI passes.
This head only merges #9989's refreshed branch; this pull request's own changes are the same as at the last review, and #9989's slide is part of this diff.
Non-blocking, still open:
- The
collapsedSizeJSDoc inuseResizable.tsstill says "dragging triggers collapse"; only the lift collapses now ("Size in px under which a drag's lift collapses the region"). - The comment above
aria-valuenowinseparatorAttributes.tssays a pull past a limit shows a size beyond it, but the value stays clamped ("The value stays inside the bounds").
#10333 still builds on this pull request's previous head, so the declared stack lines up again once it is rebased.
[Automated review]
|
/approve-spec 20b42fa |
There was a problem hiding this comment.
This pull request is reviewed as part of its stack; see the review on #10333.
Stack: #9989 → #10292 → #10333
Behavior module: the resize controller's limits and lift.
User need
A pull past a resizable LayoutPanel's limit stops dead, reading as a bug; crossing the collapse threshold closes it mid-drag.
Problem and solution fit
collapsedSize, or a flick resting below it; other lifts return to the minimum.Try it: #10333 (stacked): 81e's grip band, snaps settling on lift, drag-to-open feedback.
Current specification
component:ResizableFR8,component:LayoutPanelFR7,spec:AST-105FR4, FR9 and DEC-2, andspec:AST-094FR45.Authority: Owner direction, Nov 5 2026 (Cindy): "rubber band at the limits on both sides, so hitting a limit doesn't read as a bug"; Owner direction, Nov 6 2026 (Cindy): "the extra length of the rubber band should ideally not affect the widths of the content but be kind of treated as just extending the handle and overlapping a bit"; Owner direction, Nov 6 2026 (Cindy): "rubber-band travel for a panel resize is at most about 8 px; the panel closes only on release"; Specs decision, Nov 5 2026: snap-to-close decided on lift, with resistance below the minimum; Specs decisions, Nov 6 2026: the band is every pointer's; an arrow key at a limit doesn't band; "A gesture's release settles on
spec:AST-094's spring from its release velocity; curve tokens govern glides that no gesture releases." For every pointer: Cindy's decision on #8783, Oct 31 2026, verbatim: "edge reveal A".Public delta and caller burden
No prop, option or export; size, persistence and ARIA keep to the limits. Resizable's entry gains the velocity tracker (+1,653 B). Changeset:
[feat].Design and alternatives
springs.settle.Evidence
Writing rubric results
Over
component:Resizable(FR8; the Collapse row),spec:AST-105(FR4/DEC-2 carve-out; FR9; two rows) andspec:AST-094(FR45's exception). R3: rows name tests. R1, R2, R4–R6: none.Scope
Testing
On #9989's head fa3bfea (main 3bd058c): #9989's 13 rubber-band and lift-close commits from before the split, cards 81c and 81d, the owner's handle-only overshoot, FR8's records, the re-grab hold mid-close, the closing slide from the drawn handle, AST-105's carve-out, AST-094's matching exception, and two CI fixes. No try-it commit is in this history.
paneSlidein Chromium (28) and in WebKit under the CI profile (28).gestures/VelocityTracker.ts, +1,653 B); it was red with Resizable unlisted. Prettier re-pads the Resizable spec's three tables (public concepts, behavioral and layout contract, verification map): whitespace only, no cell text changes.