Repository navigation
Run 54 React Native and Expo libraries on macOS, and add real pointer input to the e2e driver - #531
Merged
Merged
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
MMKV builds on macOS with Spark's Nitro patches, but its default store was ~/Documents/mmkv, the user's TCC-protected Documents folder shared by every app. A patch moves it to Application Support under SparkNamespace(), like Spark's other app data. Optional pins in patches/dependencies.json apply a patch when the app itself installs the pinned version; other versions stay unpatched. Adds a Kitchen Sink MMKV screen and a driver flow covering typed values, listeners, persistence across launches and clearState.
Unistyles 3.6.0 ships only a UIKit native runtime. Its optional patch adds a macOS podspec platform and an AppKit runtime: the main window's size and backing scale, appearance changes for adaptive themes, and RTL. Insets, bars and the keyboard report zero on desktop. Adds a Kitchen Sink Unistyles screen, with the Babel plugin scoped to it, and a driver flow that flips the app appearance and sees the theme follow.
Quick Crypto already targets macOS and its OpenSSL has a macOS slice, but fastpbkdf2 includes <endian.h>, which macOS lacks; the patch uses <machine/endian.h> as Mac Catalyst does. Its peer Quick Base64 declares only iOS, so macOS skipped linking it and the first import failed; its patch adds the macOS platform. Adds a Kitchen Sink security screen and a driver flow checking hashes, HMAC, PBKDF2, AES-GCM, random values and WebCrypto digest vectors.
Nitro Fetch's URLSession client compiles for AppKit, but its podspec declares only iOS and tvOS. The patch adds macOS, runs launch prefetches on NSApplicationDidFinishLaunching, and gives its URLCache an absolute directory under the app's namespaced Caches folder: the relative diskPath put Cache.db in the process's working directory on macOS. Adds a Kitchen Sink networking screen that asserts the native client is present (the JS otherwise falls back to global fetch) and a driver flow.
Blur is UIKit only, and without ios.componentProvider in its codegen config RN 0.83 never registers its Fabric components. The patch declares both components and adds AppKit BlurView and VibrancyView on NSVisualEffectView materials, with light/dark styles mapped to appearances and the reduced-transparency fallback. blurAmount has no AppKit equivalent. Adds a Kitchen Sink blur screen and a driver flow checking registration, layout and vibrancy children.
Worklets Core's native code is platform-neutral, but its podspec declares only iOS; the patch adds macOS. The Kitchen Sink adds the worklet Babel plugin and the three Babel plugins it requires, which Expo SDK 55 apps no longer carry. Adds a Kitchen Sink screen and a driver flow running a worklet context, a shared value and a call back to the main runtime.
CocoaPods skips a pod whose podspec lists platforms without macOS, but
codegen still registered the library's Fabric components and TurboModules.
The registry then mapped them to classes that were never built, and the app
crashed at launch inserting nil into the component dictionary
(react-native-fast-image). Spark's macOS native selection now excludes
those codegen libraries from the macOS Podfile only; iOS and Android builds
reading the shared react-native.config.js and Expo autolinking settings
keep them.
The podspec check reads the platforms assignment itself, singular
s.platform or plural s.platforms, in either :osx => or osx: syntax, so
react-native-gesture-handler (platforms { ios: ..., osx: ... }) stays in.
FastImage's native view is UIKit only. Its optional patch adds a macOS entry that renders FastImage and FastImageBackground with React Native's Image: sources, objectFit, tint, placeholders while loading, load events, reload and preload. Cache APIs resolve not ok. onLoad reports the size from Image.getSize, since React Native macOS scales a 1x image's load size by the screen's. Adds a Kitchen Sink screen and an offline driver flow.
The profiler's Hermes module has no UIKit code, but its podspec lists only iOS. The patch adds macOS and writes traces to the app's namespaced Caches folder: on a Mac, the root of ~/Library/Caches is shared by every app. Adds a Kitchen Sink devtools screen and a driver flow that profiles busy JavaScript and reads the trace back.
prepareNativePatches returned an optional pin it declined to patch (another version installed), so non-desktop autolinking still forced that copy. Record a package only once its version matches the pin. Also call the MMKV check's file a file.
ATTrackingManager exists on macOS 11, but react-native-tracking-transparency lists only iOS, checks UIApplication's state before prompting, and its JavaScript returns unavailable off iOS. The patch adds macOS with AppKit's activation check and lets macOS reach the native module. Adds a Kitchen Sink security screen and a driver flow reading the status.
Skia 2.14 supports macOS upstream and needs no Spark patch. Adds a Kitchen Sink screen and a driver flow that read back an on-screen Canvas and an offscreen raster surface by pixel. The Worklets Core Babel plugin, applied app-wide, rewrote Skia's worklets and read its optional Reanimated proxy at load, so the app never rendered. The Kitchen Sink now applies that plugin only to its Worklets Core demo.
Writing the patch receipt reformats a dependency's package.json as two-space JSON, so a package.json hunk that matched a tab-indented upstream file failed on every later preparation. Normalize package.json before applying hunks, so patches target one form.
Blurhash is UIKit only and its codegen config names no component provider, so RN 0.83 never registered its view. The patch declares the provider and adds AppKit support: an NSView showing the decoded image as layer contents, NSImage decoding and encoding, and resize modes as contents gravity. Adds a Kitchen Sink screen and a driver flow that decode a Blurhash in the native view and encode a local image.
Its iOS-only native module is absent on macOS, and the JavaScript read a property of it at import, so importing the library threw. The patch reads it optionally, so desktop reports a 0 radius. Adds a Kitchen Sink screen and a driver flow.
Nitro SQLite supports macOS upstream and links beside Spark's OP-SQLite, since its SQLite symbols are prefixed. Adds a Kitchen Sink storage screen and a driver flow covering parameterized, batched and async queries.
OSLogStore's current-process scope exists on macOS 12, but the library's podspec lists only iOS and only its iOS bindings call native. The patch adds macOS 12 to the podspec and a macOS entry using the iOS bindings. Adds a Kitchen Sink devtools screen and a driver flow that read back a console marker from the unified log.
Nitro ZXing is C++ on top of VisionCamera 5 and Nitro Image, which Spark already builds for macOS; its podspec only lacked the platform. Adds a Kitchen Sink media screen and a driver flow that scan a QR code from a still image.
Safe Area Context 5.6.2 supports macOS upstream; no patch is needed. Adds a Kitchen Sink windows screen and a driver flow checking the provider's frame and insets and SafeAreaView layout.
expo-keep-awake builds on macOS but did nothing there: activation compiled to a no-op and isActivated returned false. The patch holds a ProcessInfo activity that disables idle display and system sleep while activated. Adds a Kitchen Sink screen and a driver flow that find the power assertion in pmset while active and not after deactivating.
Screens' native containers are UIKit only, but callers that enable them (such as React Navigation's native stack) rendered the missing native components on macOS. The patch adds macOS entries that re-export each component's web implementation, which uses plain views. Adds a Kitchen Sink screen and a driver flow checking active, inactive and stack screens.
Reanimated 4.2.1 and Worklets 0.7.4 support macOS upstream; no patch is needed. Adds a Kitchen Sink screen and a driver flow checking a timing animation's finished callback and UI-thread frame callbacks.
Gesture Handler 2.30.0 supports macOS upstream; no patch is needed. Adds a Kitchen Sink screen and a driver flow checking that the native module and button are registered and a GestureDetector mounts. Pointer gestures are checked by hand.
native-stack's native view relies on UIKit header configs, which draw nothing on macOS, so stack screens had no header or back button. The patch gives macOS the JavaScript stack view web uses, which draws headers with @react-navigation/elements. Core and bottom tabs work unchanged. Adds a Kitchen Sink screen and a driver flow navigating a stack forward and back and switching tabs.
Quick Crypto's BLAKE3 guards drop the NEON source and x86 SIMD symbols only for the x86_64 iOS simulator, so an x86_64 macOS build failed to compile and link. The patch adds the same settings for macosx x86_64. The Kitchen Sink's PBKDF2 vector now runs 4096 iterations.
Nitro Fetch keeps its launch-prefetch queue in the nitro_fetch_storage defaults suite and its encryption key under a fixed Keychain service. On a Mac both are shared by every app using the library, and the queue can hold request headers. The patch suffixes both with the app's namespace, as it already does for the URL cache.
App Tracking Transparency does nothing on the Mac: the status is always not-determined and requests never prompt. Unpatched, the library imports and reports unavailable, which is the accurate answer, so the native build added nothing.
…ings The library's native module is iOS and Android only, so importing it threw on macOS. A Mac has no software keyboard, so its macOS entries now use the package's own no-op web bindings. Kitchen Sink renders the provider, a keyboard-aware scroll view and the toolbar, with a driver flow.
Sentry's native module builds for macOS, but its replay mask views compile only with UIKit while codegen still registers them, so the app aborted at launch on a nil component class. On macOS they are now plain containers. Kitchen Sink captures an error and checks its stack trace and native macOS context without sending it, with a driver flow.
expo-router runs on macOS without a patch through React Navigation and the react-native-screens patch. Kitchen Sink mounts ExpoRoot on a small route folder whose home route pushes a dynamic route with a search param, with a driver flow.
react-native-graph 1.4.0 builds its line paths with Skia 1's mutable SkPath methods, which Skia 2 removed, so its graphs threw on render. The patch builds them with Skia.PathBuilder instead. Kitchen Sink renders a static and an animated graph with a gradient fill, with a driver flow.
Keep-awake always releases its tag, polls pmset instead of sleeping, and tolerates the assertion development builds already hold. The drawer counts onClose only after it opens, since it reports a close on mount. The bottom sheet retries its snap until the sheet has measured itself. The pressable demo gets the GestureHandlerRootView its native button requires.
The catalog golden still showed 6 populated areas from before the library screens were added; it now matches the current catalog's counts and screens.
A blurhash, thumbhash, SF Symbol or ImageRef source rendered nothing and fired no load events, so a screen waiting on onLoadEnd or onError waited forever. Such a source now reports onLoadStart, onError and onLoadEnd once. Sources also keep their width, height and scale, so a require()d @2x asset draws at its point size rather than at 1x.
The macOS stand-in rebuilt object sources from uri and headers alone, so a source's scale was lost and a @2x image drew at 1x, and a placeholder given as { uri, headers } fell through to defaultSource and never showed. Sources now keep width, height and scale, and uri placeholders load.
The date was applied before minimumDate and maximumDate, and NSDatePicker clamps its date whenever the limits move, so one update changing the value and both limits left the picker on a clamped date that JavaScript never heard about. The limits now apply first, and the date is set after any change to either.
…sing Without NSLocationWhenInUseUsageDescription, expo-location calls RCTFatal, which Debug builds swallow and Release builds throw, so a Release app terminated on its first permission check. On macOS it now logs an error and reports denied, as Debug did. The docs named NSLocationUsageDescription, which CoreLocation and expo-location never read; they now name the WhenInUse key.
The animated LineGraph wraps itself in a GestureDetector, which throws without a GestureHandlerRootView in development builds, so the screen showed the error in a dev Kitchen Sink. The e2e driver bundles with __DEV__ off, which hid it.
Fourteen patched podspecs declared macOS 11 or 12, below Spark's macOS 14 floor. Masked View in particular uses macOS 14's CADisplayLink and only built because the Podfile raised every pod's deployment target. They now declare 14.0.
Driver windows are never shown, so an external CGWindow lookup cannot find one for a real click. Add an opt-in --pointer backend using the existing testID lookup and an external CGEventPostToPid helper. Encode the events in the window-owning process so AppKit preserves the window-local hit point. Show the window without presentation animation and let the gesture demo accept its first background click on macOS. Missing input-posting permission fails immediately without a prompt. **Test plan** Focused native protocol, pointer backend and existing driver backend checks passed. Scoped strict TypeScript checking passed. ✅ Debug arm64 Kitchen Sink build via heavy, -jobs 6, no signing. ✅ Real native mouse-view probe observed one down and one up callback. ✅ Gesture-handler and drawer-layout flows via --backend driver --pointer: GestureDetector's successful tap callback and drawer open/close were observed, including a screenshot showing tap. The console remained locked.
An unknown window or a non-finite point now fails at once with E_NO_WINDOW or E_INVALID_ARGUMENT, as capture does, instead of waiting and reporting E_NOT_SETTLED.
…ettles tapOn passed no timeout, so the driver's fixed 5 s settle wait applied and E_NOT_SETTLED failed the step. It now waits up to the step's timeout in slices under the driver's reply limit, re-resolving the target between them, and taps once the timeout is spent, as it did before the settle wait. pointerEvents with timeoutMs 0 skips the wait.
…ation Main now requires every active pin to resolve to a prepared package. An optional pin that finds another installed version stays unpatched on purpose, so it no longer fails that check.
…ws outside the gate The 50 library checks this branch adds pass on the driver backend, so the release gate now blocks on them. The gesture-handler and pressable-pointer flows need --pointer, which the gate does not accept, so they move to e2e/pointer/flows/ and run with bun run gate:pointer before a release.
@react-native-community/blur and the other native libraries this branch adds have no Windows implementation yet, so the Windows build excludes them like the rich text libraries. Windows support comes on a separate branch.
The sidebar catalog counts changed as library screens were added, the title bar tint changed slightly, and in Arabic the Dock screen title is now translated and the sidebar uses the Latin digits the shell pins.
jmeistrich
force-pushed
the
feat/desktop-libs-macos-land-v2
branch
from
November 1, 2026 11:08
e065b89 to
4633699
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces #530 (rebased onto main after #529 merged).
This branch (
e065b890) has the same tree as #530 (99c74c64) except main's three test-only commits from #529 (package-distribution, runner-package-manager and windows-nitro-native tests). The device evidence below comes from #530's SHAs. One065b890, typecheck, 13 scoped Vitest files (99/99), e2e validate and e2e lint all pass.This makes 54 libraries that the Kitchen Sink adds for macOS build and work there. 35 have version-pinned Spark patches, plus Quick Base64 as a support library; the rest work without a patch, and that is now verified. Each library gets a row in
docs/external-libraries.md, a Kitchen Sink screen and a macOS e2e flow. The PR also adds opt-in real mouse input to the e2e driver. Windows support is in a separate branch.Behavior changes
~/Documents/mmkv· now:~/Library/Application Support/<namespace>/mmkv, with no migration · when: macOS, react-native-mmkv 4.3.2.docs/external-libraries.md.--pointeronly: the target window is shown and the app activated, then restored at flow end or disconnect. Requires an Accessibility grant. The release gate rejects--pointer, and default runs are unchanged.Changes
patches/dependencies.jsonaddsoptionalpins. A pin on another installed version stays unpatched and also passes the "every active pin was prepared" check. Patching handles tab-indented manifests and exports maps that hidepackage.json.--source-dir __dir__touse_native_modules!, and patched pods declare macOS 14.bun run e2e:run <flow> --backend driver --pointersends real Quartz mouse events fortapOn. Each tap waits for mounted UI to settle within the step timeout. Seedocs/test-driver.md#real-pointer-input-macos.gesture-handlerandpressable-pointerneed real clicks (--pointer), so they live ine2e/pointer/outside the gate and run withbun run gate:pointerin the pre-release checklist.windows.autolinking.excludelist until the Windows work lands separately.Verification
Run on
a2531141:bun run typecheck: passes.e2e-coverage, release-gate dialog flows). The other,kitchen-sink's Windows rich-text test, comes from a stale localnode_modulespatch; a fresh install has not been tried.bun run e2e:validateandbun run e2e:lint: 0 problems (79 flows).bun.lockagrees with every workspace manifest (static check).macOS, on
a2531141plus the gate commits (99c74c64):e2e:run e2e/flows --backend driver: 72 pass, 23 fail, 4 skip; every failure uses a step the driver backend does not support yet, or was a stale dock golden (now updated, 4/4 pass).bun run gate:pointer(gesture-handler, pressable-pointer with--pointer): 2/2 pass.Not run: Windows, Intel macOS, the full test suite locally (CI runs it).