Skip to content

Android view props, the onboarding redesign, and root scripts that cover both packages - #5

Merged
ronickg merged 3 commits into
mainfrom
fix/android-view-props
Sep 21, 2026
Merged

ronickg merged 3 commits into
mainfrom
fix/android-view-props

Conversation

@ronickg

@ronickg ronickg commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Three commits that were sitting uncommitted after the last session.

Android: Hybrid Views were getting none of their base view props. From React Native 0.86, a Nitro Hybrid View on Android received no backgroundColor, border*, transform, opacity, testID or accessibility props, silently. Nitro's ViewComponentDescriptor::cloneProps never calls initializeDynamicProps, the only writer of Props::rawProps, which is the map Android serialises to Java. The patch adds the call back. Filed upstream as margelo/nitro#1656, fix in margelo/nitro#1655. A tripwire test reads the installed Nitro source and fails if the patch stops applying or React Native moves the call. The example gets a two-box repro screen (plain View vs Hybrid View, same style, the rotation is the giveaway).

The onboarding flow reads as an onboarding, not as a test harness. Progress rail instead of "Step 2 / 4", the question as a headline, one button per step, the keyboard timeline folded away behind "Show timeline". Shared header chrome for the three pushed steps, header hidden on the sheet. Every testID unchanged. Also ignores native/ (UIKit / SwiftUI / Android reference apps for keyboard comparison) and example/.recordings/.

The root scripts only knew about one of the two packages. bun run test at the root ran only the rolling-number suite. Now specs, build, typecheck, test and test:cpp fan out over packages/*. Verified: root test runs both suites (13 + 96 pass), root typecheck is clean for both.

Left out on purpose: a debug edit to example/src/harness.tsx (red border, green fill, an 8° rotation on the shared field style) that was a hand-check for the view-props bug, not something to land.

🤖 Generated with Claude Code

Ronald Goedeke and others added 3 commits September 21, 2026 18:23
From React Native 0.86 a Nitro Hybrid View on Android received no
backgroundColor, no border*, no transform, no opacity, no testID and no
accessibility props, while iOS was fine. There is no error to go with it:
React Native never sees the prop, so it never warns.

On Android those props only reach the view through Props::rawProps, a
folly::dynamic that is serialised to Java and handed to
ViewManager.updateProperties. The one thing that fills that map is
initializeDynamicProps, which React Native calls at the end of
ConcreteComponentDescriptor::cloneProps. Nitro overrides cloneProps to
use its cached copy constructor and, as shipped in 0.37.1, never makes
that call. The map stays empty and every style prop disappears.

The patch adds the call back. Filed upstream as margelo/nitro#1656 with
the fix in margelo/nitro#1655; drop the patch, the patchedDependencies
entry and the tripwire test once a release contains it.

The tripwire (NitroViewProps.test.tsx) reads the installed Nitro source
and fails if the patch stops being applied - a version bump, a fresh
install without patches - and separately if React Native moves the call,
in which case the patch needs rewriting rather than reapplying. The
example gets a two-box repro screen so the symptom can be seen on a
device rather than inferred.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The four keyboard screens exist to compare NitroInput with TextInput
through a realistic flow, and they looked like the harness they are:
"Step 2 / 4" in grey, every field inside a captioned card, the keyboard
timeline taking half the screen, a navigation title competing with the
question.

Now each step is a progress rail, the question as a headline with one
line under it, the field, and one button. The timeline is still there -
it is the reason the screens exist - but folded away behind "Show
timeline", so the flow reads as the thing it imitates. The three pushed
steps share their chrome through one options object: no title, a
minimal back chevron, no header hairline. The search sheet hides its
header, since the sheet's grabber is the chrome, and its Done button
names what was picked. The details form focuses its first field on
mount, like the email step already did. Every testID is unchanged, so
the recorded flows still run.

The native reference apps under native/ (UIKit, SwiftUI, Android views
and Compose, the same four screens for comparing keyboard behaviour) and
the screen recordings under example/.recordings/ are ignored: reference
material, like the *-INTERNALS.md notes, not part of the library.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every root script routed to packages/react-native-nitro-rolling-number,
so `bun run test` at the root never ran the input package's suite, and
plain `bun test` at the root ran bun's own runner against jest files and
reported failures that were not there. Both packages are live - the
example imports both - so the scripts now fan out over packages/* with
bun's --filter, and test:cpp joins them since both packages have one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ronickg
ronickg merged commit 9d9343c into main Sep 21, 2026
1 check passed
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.

1 participant