Skip to content

Fire @press on nested text runs - #52

Open
gwleuverink wants to merge 2 commits into
NativePHP:mainfrom
trailhead-labs:fix/nested-text-press
Open

Fire @press on nested text runs#52
gwleuverink wants to merge 2 commits into
NativePHP:mainfrom
trailhead-labs:fix/nested-text-press

Conversation

@gwleuverink

@gwleuverink gwleuverink commented Aug 15, 2026

Copy link
Copy Markdown

Fixes NativePHP/mobile-air#339. A <text @press> inside another <text> rendered fine but taps did nothing. A standalone <text @press> worked.

The PHP side turned out to be innocent. The nested run crosses the wire with a live on_press callback id, and firing that callback from the test suite runs the handler. Press handling on native is attached per node view by NodeGestureModifier, and the text renderers never create views for their text children. They fold them into one attributed string, so the onPress sitting on the run node was never read. Same on both platforms.

The fix uses each platform's inline link mechanism, which already hit-tests taps inside a wrapped paragraph, and calls the same sendPressEvent every other renderer here calls. PHP receives an ordinary press. No core changes, no wire changes.

On Android every span emitted under a pressable run gets its own LinkAnnotation.Clickable, so annotation ranges stay flat instead of nesting when a pressable sits inside a pressable. I carry the run's own text decoration into the link styles, because with styles = null Compose underlined the range like a hyperlink.

On iOS the innermost @press travels down through RunContext, pressable runs get a custom scheme run.link, and composedBody intercepts it with an OpenURLAction. Real URLs still fall through to the system. The run's explicit foregroundColor keeps the authored color instead of the link tint.

Both platforms resolve the press target the same way, down through the run context: a styled sub-run inside a pressable run stays tappable, and the innermost @press wins. Long-press and the other gesture callbacks stay out of scope here, link annotations are tap-only primitives, and wiring those needs a different mechanism. Today they silently do nothing on runs, same as @press did before this.

Verified with a counter screen on both:

before after
Android emulator nested stayed 0 nested=3 from 3 taps
iOS simulator nested stayed 0 nested=6 from 6 taps

Styling checked too: authored color and weight survive, no underline, no accent tint.

Press inside press is verified as well, on both platforms: a tap on the inner pressable fires only the inner handler, the outer one fires on its own words, innermost wins. On Android that was outer=2 inner=2 from exactly two taps on each region, on iOS the same by hand.

No automated test in here, and that's deliberate. Native::test() passes on the broken build, it dispatches by callback id against the PHP tree and never touches a renderer, so it can't see this class of bug. A real regression test needs to drive the native side.

Jump ships these renderers precompiled, so the fix reaches the reporter with the next Jump release, not with a composer update.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nested native:text elements do not trigger @press events

1 participant