npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@funkit/connect-rn

v1.0.4

Published

React Native bindings for @funkit/connect. Re-exports the headless @funkit/connect-core logic; the RN platform halves (Restyle theme, WebView Swapped transport, Transfer/Swapped screens, logging) land in later releases.

Readme

@funkit/connect-rn

React Native bindings for Funkit Connect. This README is for working on the package. For integrating the SDK into an app (install, peer dependencies, FunkitProvider API, DepositFlowConfig), see the client integration guide — maintained in Notion. To run the SDK on a simulator/device, use the with-expo playground.

Architecture

@funkit/connect-rn is the React Native half of a three-package split. The headless business logic lives once in @funkit/connect-core and is shared by web and RN, so the two platforms can't drift:

| Package | Role | | --- | --- | | @funkit/connect-core | Headless, platform-agnostic — domains, utils, query/Statsig hooks, theme factories, FunLogger. No DOM, vanilla-extract, or wagmi under src/**. | | @funkit/connect | Web presentation halves (.tsx, vanilla-extract, Dialog/portals, iframe transport, wagmi identity). | | @funkit/connect-rn | This package — the RN presentation halves over core. |

The platform halves this package supplies (mirroring connect's web halves):

  • a local Shopify Restyle theme + useFunkitTheme() / useColorScheme()
  • FunLogger wired to a React Native log transport
  • WebViewSwappedTransport + the Swapped screen
  • the managed Add money → Transfer / UDA → QR flow

Core stays platform-agnostic by depending on contracts that each platform implements: IdentityProvider (web wraps wagmi; RN takes host props), SwappedTransport (web <iframe>; RN WebView), and LogTransport (web Datadog browser-logs; RN console). The customer theme is a plain ThemeVars object from core that RN maps to a Restyle theme via toRestyleTheme(tokens).

Public surface. index.ts re-exports core plus an explicit, named set of RN symbols (no barrels): the provider, the useFunkitCheckout entry hook, theme tokens/adapter/primitives, and config types. The screens, Statsig RN bindings, log transports, identity context, and transfer hooks are internal (mirroring @funkit/connect, which exports none of them). When adding a public export, wire it explicitly in index.ts.

Peer dependencies

These are declared as peer dependencies (not bundled), so the host app links a single copy and controls the native-module versions. Editing peerDependencies in package.json is a public-API change — bump it deliberately and add a changeset (a peer bump is a major change for consumers).

The authoritative list lives in package.json (peerDependencies / peerDependenciesMeta) — it's intentionally not duplicated here so it can't drift. Adding a peer dependency is a consumer-facing decision: every integrator must install it. Before adding one:

  • Pick it carefully. Prefer a widely-used, well-maintained library — ideally one (nearly) every customer already depends on — over a niche package that adds install burden for everyone. A peer dep is a tax on all consumers.
  • Update the client docs. A new peer dep changes the install/setup steps integrators follow, so the client integration guide (Notion) must be updated in the same change.
  • Native modules need extra care. A native peer (iOS/Android native code, vs JS-only) can't be linked by the host without a rebuild, carries version compatibility constraints against the RN core, and may be absent in some runtimes. Treat it as a heavier commitment than a JS-only dep.
  • Prefer Expo-Go-bundled native modules. When a native peer is needed, prefer one already bundled in Expo Go (see Expo Go compatibility) so the SDK keeps working in the playground without a custom dev build. This is a preference, not a hard requirement — if a non-bundled native module is genuinely needed, make it optional + lazy + guarded with a host override (the way clipboard is).
  • Don't depend on the Expo SDK. "Bundled in Expo Go" is a convenience for our playground, not an assumption about consumers — many integrate via bare React Native, not Expo. Prefer a framework-agnostic RN library over one that needs the Expo SDK (the expo package) installed to work, so it runs either way. An expo-* name isn't itself a red flag — those modules are published by Expo but run fine in bare RN; the concern is a library that genuinely requires the Expo runtime, like @expo/ui. For example, @gorhom/bottom-sheet is preferred over @expo/ui's bottom sheet.

Expo Go compatibility

connect-rn is designed to run in Expo Go (no custom dev build needed) — this is what lets the with-expo playground preview the flow in Expo Go. Keep new code Expo-Go-safe.

Every native peer the SDK relies on is either bundled in Expo Go for the target SDK (react-native-reanimated, react-native-gesture-handler, react-native-webview, react-native-svg, react-native-safe-area-context, AsyncStorage) or JS-only (@gorhom/bottom-sheet, react-native-qrcode-svg). Two deliberate choices keep it that way:

  • Clipboard is optional, lazy, and guarded. @react-native-clipboard/clipboard is a bare-RN native module not in Expo Go. src/transfer/clipboard.ts only import()s it when a copy actually happens (never at startup) inside a try/catch — so in Expo Go, where getEnforcing('RNCClipboard') would throw, a copy degrades to a no-op + warning rather than crashing. A host injects its own writer via FunkitProvider's copyToClipboard (e.g. expo-clipboard), and that override runs instead, so the throwing path never executes.
  • No react-native-device-info. src/statsig/statsigMetadata.ts vendors the Statsig metadata adapter with the react-native-device-info dependency removed (it's a native module that needs a dev build). The app-version / device-model fields are left undefined; systemName and locale are read from RN's built-in Platform / NativeModules (no extra native dep). Geo/IP resolution uses plain fetch.

Contributor rule: don't add a hard top-level import of a bare-RN native module that Expo Go doesn't bundle. If you genuinely need one, make it optional + lazily imported + guarded with a host-injectable override, the way clipboard is.

Local development

No root shortcut exists for this package — use the pnpm --filter form (or cd packages/connect-rn and drop the filter).

pnpm --filter @funkit/connect-rn build         # esbuild bundle + typecheck
pnpm --filter @funkit/connect-rn build:watch   # rebuild on change
pnpm --filter @funkit/connect-rn dev           # build:watch + type-gen watch in parallel
pnpm --filter @funkit/connect-rn typecheck     # tsc --noEmit
pnpm --filter @funkit/connect-rn lint          # oxlint (lint:fix to auto-fix)
pnpm --filter @funkit/connect-rn storybook     # web Storybook on http://localhost:7007

Typical inner loop when changing the SDK and watching it in the app: run pnpm --filter @funkit/connect-rn dev in one terminal and pnpm --filter with-expo start in another. Metro watches the whole monorepo, so SDK edits hot-reload in the playground.

Testing

Tests run with Vitest in the node environment (no DOM — native modules are stubbed). Components mount with react-test-renderer + act(), not React Testing Library.

pnpm --filter @funkit/connect-rn test                # run once
pnpm --filter @funkit/connect-rn test -- --watch     # watch mode
pnpm --filter @funkit/connect-rn test -- test/providers/FunkitProvider.test.tsx  # one file
  • Config: vitest.config.ts. Setup: test/setup.ts (stubs global fetch, enables IS_REACT_ACT_ENVIRONMENT).
  • Native-module stubs live in test/*.stub.ts(x) (react-native, react-native-svg, react-native-reanimated, @gorhom/bottom-sheet, clipboard, webview, qrcode). Pulling in a new native module? Add a stub or the import fails under node.
  • Mock at the @funkit/api-base edge — never mock internal hooks (useTransferInit, etc.). Snapshot tests may mock internal hooks to freeze inputs. See the repo TESTING.md.

Fonts

connect-rn's theme renders text in the system UI font by default (SF on iOS, Roboto on Android) at two weights: 400 (regular) and 500 (medium). There is no semibold/bold in the token set. The default needs no font assets — it works out of the box.

connect-rn is font-agnostic: it ships no typeface and no font preset. To render in a custom font (the Fun Mobile design uses Inter), supply your own fonts tokens and register the matching font files (see "Rendering in a custom font" below).

connect-rn does not — and cannot — load fonts itself. A JS-only React Native library has no way to register a font with the native font manager: fonts are either bundled and linked natively (iOS UIAppFonts / Android assets/fonts) or loaded at runtime through a native module such as expo-font. Both live in the host app, not in this package.

Rendering in a custom font

To render in a custom font instead of the system default, set fonts on your tokens and register the matching font files.

You can't select a custom font's weight via fontWeight in React Native/Expo: Android matches custom fonts by exact family-name string, and a font loaded at runtime registers one native typeface per name — so fontWeight: '500' on a custom Inter family is silently ignored. connect-rn therefore expresses weight through the family name (set family + a per-weight familySuffix), and the host registers each cut under its own name — e.g. Inter-Regular and Inter-Medium. Use fontFamilyForWeight(...) to resolve those names so you don't hardcode them.

Define the font tokens in your host app, load the files before rendering <FunkitProvider> (if a name is missing, that text falls back to the system font), and build your theme with them. Example with Expo (expo-font + @expo-google-fonts/inter):

import { useFonts, Inter_400Regular, Inter_500Medium } from '@expo-google-fonts/inter'
import {
  type FunkitFontTokens,
  fontFamilyForWeight,
  lightTokens,
  toRestyleTheme,
} from '@funkit/connect-rn'

// Host-owned: weight lives in the family name (RN/Expo can't pick a cut via
// fontWeight). cssWeight is kept for the Swapped WebView (CSS) theme.
const interFonts: FunkitFontTokens = {
  family: 'Inter',
  weights: {
    base: { familySuffix: 'Regular', cssWeight: '400' },
    medium: { familySuffix: 'Medium', cssWeight: '500' },
  },
}

const themes = {
  light: toRestyleTheme({ ...lightTokens, fonts: interFonts }),
  // …dark likewise
}

export default function App() {
  const [fontsLoaded] = useFonts({
    [fontFamilyForWeight(interFonts, 'base')]: Inter_400Regular, // 'Inter-Regular'
    [fontFamilyForWeight(interFonts, 'medium')]: Inter_500Medium, // 'Inter-Medium'
  })
  if (!fontsLoaded) return null // or a splash screen
  return <FunkitProvider themes={themes} {...}>{/* … */}</FunkitProvider>
}