Skip to content

fix: Keep teleported item in sync with collapsed content - #595

Merged
MatiPl01 merged 3 commits into
mainfrom
fix/portal-collapsible-teleport-size
Jul 8, 2026
Merged

fix: Keep teleported item in sync with collapsed content#595
MatiPl01 merged 3 commits into
mainfrom
fix/portal-collapsible-teleport-size

Conversation

@MatiPl01

@MatiPl01 MatiPl01 commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Description

When a grid is wrapped in Sortable.PortalProvider and its items collapse on drag (e.g. onDragStart shrinks them), the teleported active item stayed at its pre-collapse (large) size instead of shrinking with the rest.

The portal pushed a one-shot snapshot of the item cell into the outlet and relied on a first-update setTimeout to re-push it. That deferred re-push raced the collapse re-render, so the teleported copy could keep rendering the pre-collapse content.

This drives teleportation from a React state flag instead, with two effects that are intentionally kept separate:

  • one hides the source item while teleported and clears the outlet on teardown;
  • one keeps the outlet in sync with the current cell whenever the item node changes.

Keeping the source-hiding independent of the content re-push matters: because the rendered cell changes identity when the item collapses, folding both into a single effect would toggle the source item's hidden state on every re-push and leave the underlying item visible under the teleported copy. Split, the teleported copy tracks the live (collapsed) content while the source stays hidden, with no timer.

The now-unused isTeleported was also dropped from the portal context (this rework was its only consumer).

Testing

Verified on the iOS fabric example (New Arch) with the built-in Collapsible Items example under Sortable.PortalProvider (enabled via the bottom-bar settings) and a dedicated portal + collapsible screen:

  • Dragging an item teleports a shrunk copy that matches the collapsed content; it grows back and reorders on drop.
  • The source item is hidden throughout the drag (no duplicate under the floating copy).
  • Reverting only this change makes the same drag teleport a large copy with stale content.

typecheck, lint, and test pass; a store regression test is included.

@MatiPl01 MatiPl01 self-assigned this Jul 8, 2026
@vercel

vercel Bot commented Jul 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
react-native-sortables-docs Ignored Ignored Preview Jul 8, 2026 10:57pm

@MatiPl01
MatiPl01 force-pushed the fix/portal-collapsible-teleport-size branch 2 times, most recently from 090ea23 to 29cc4b1 Compare July 8, 2026 10:39
The portal teleport pushed a one-shot snapshot of the item cell and relied on a first-update setTimeout to re-push it, which raced the collapse re-render and could leave the teleported active item stuck at its pre-collapse size. Drive teleportation from a React state flag instead: one effect hides the source item while teleported (and clears the outlet on teardown), and a separate effect keeps the outlet in sync with the current cell whenever the item node changes. Keeping the source-hiding independent of the content re-push is deliberate - it means a collapsible item shrinks its teleported copy without ever revealing the source item underneath. Also drop the now-unused isTeleported from the portal context.
@MatiPl01
MatiPl01 force-pushed the fix/portal-collapsible-teleport-size branch from 29cc4b1 to 763aa48 Compare July 8, 2026 10:55
MatiPl01 added 2 commits July 9, 2026 00:11
The mounted source cell of a teleported item is hidden with `left: 9999`.
On Fabric that layout offset is transiently defeated during auto-scroll's
per-frame commits, so the source card shows behind the teleported copy and
the two separate as the list auto-scrolls. Add a static `opacity: 0`
alongside the offset (a non-layout prop that survives the commit timing;
`left` still covers the Old Architecture), plus a render test that drives a
teleport and asserts the hidden source is marked hidden and carries the
opacity.
Drop the memoized renderTeleportedItemCell, the manual push effect, and the
context-provider nesting from ActiveItemPortal. A small declarative Teleport
component pushes the cell into the outlet (re-pushing on change, so a collapsing
item stays in sync), and TeleportedItemCell now owns the CommonValues/Item
context wrappers it renders under. ActiveItemPortal goes from 8 hooks to 6 and
reads top to bottom; behaviour is unchanged - the source-hide stays keyed on the
teleported flag and the teardown state updates batch into one commit.
@MatiPl01
MatiPl01 merged commit 1fbcf9e into main Jul 8, 2026
11 checks passed
@MatiPl01
MatiPl01 deleted the fix/portal-collapsible-teleport-size branch July 8, 2026 23:20
MatiPl01 pushed a commit that referenced this pull request Jul 23, 2026
# [1.10.0](v1.9.4...v1.10.0) (2026-07-23)

### Bug Fixes

* Add item zIndex preserving based on the order of items ([#534](#534)) ([fb0be4e](fb0be4e)), closes [#36877](https://github.com/MatiPl01/react-native-sortables/issues/36877)
* allow scrolling the ScrollView from draggable items on web ([#574](#574)) ([74879ed](74879ed)), closes [#545](#545)
* Balance onTouchesUp on Sortable.Touchable long press ([#594](#594)) ([f977567](f977567))
* Deduplicate expo example native modules for expo-doctor ([#590](#590)) ([e5af169](e5af169)), closes [#589](#589)
* disable dragging for fixed-order and non-draggable handles ([#598](#598)) ([8ed2e81](8ed2e81))
* dragging stops after a screen is detached and re-attached (gesture-handler v3) ([#573](#573)) ([c70a14f](c70a14f)), closes [#349](#349) [react-native-gesture-handler#3560](https://github.com/react-native-gesture-handler/issues/3560) [#349](#349) [#349](#349)
* Item can settle on another item's slot after a rapid re-order ([#591](#591)) ([9d63817](9d63817)), closes [#586](#586)
* Item position drift on slow web container resize ([#562](#562)) ([8973115](8973115))
* Keep npm version from walking yarn workspaces during release ([#609](#609)) ([0d8d869](0d8d869))
* Keep Sortable.Grid measurements when revealed after react-freeze ([#572](#572)) ([609c73c](609c73c)), closes [#519](#519) [#36877](https://github.com/MatiPl01/react-native-sortables/issues/36877)
* keep Sortable.Touchable onTouchesUp firing on web ([#596](#596)) ([8529fa8](8529fa8)), closes [#594](#594)
* Keep Sortable.Touchable tap and long press working on teleported items ([#602](#602)) ([3efb111](3efb111))
* Keep teleported item in sync with collapsed content ([#595](#595)) ([1fbcf9e](1fbcf9e))
* New-Arch grid mount crash in the example and unrunnable expo example ([#589](#589)) ([01aa1a8](01aa1a8))
* Respect Sortable.Flex alignItems before items are measured ([#560](#560)) ([5c84117](5c84117)), closes [#258](#258)
* Restore tap and long press on teleported items ([#599](#599)) ([e73117b](e73117b))
* Sortable.Touchable crash on gesture-handler v3 (onActivate not a worklet) ([#587](#587)) ([4b3007e](4b3007e))
* Support react-native-gesture-handler 3.x types ([#553](#553)) ([83754e0](83754e0))
* Support react-native-reanimated 4.5 / worklets 0.10 ([#566](#566)) ([828c6d6](828c6d6)), closes [/github.com//issues/552#issuecomment-4634261543](https://github.com//github.com/MatiPl01/react-native-sortables/issues/552/issues/issuecomment-4634261543) [#552](#552)

### Features

* Add react-native-pulsar as a top-priority haptics adapter ([#568](#568)) ([642e734](642e734))
* Auto-detect expo-haptics when available ([#558](#558)) ([a0d7602](a0d7602)), closes [#554](#554)
* Reverse items stacking order  ([#535](#535)) ([14c7d82](14c7d82)), closes [#36877](https://github.com/MatiPl01/react-native-sortables/issues/36877)

### Performance Improvements

* Drive active item position from a single reaction ([#586](#586)) ([c498091](c498091)), closes [#584](#584)
@MatiPl01

Copy link
Copy Markdown
Owner Author

馃帀 This PR is included in version 1.10.0 馃帀

The release is available on:

Your semantic-release bot 馃摝馃殌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant