@zyno-io/mobile-foundation-rn
v26.610.2236
Published
Shared foundation library for React Native
Downloads
404
Readme
@zyno-io/mobile-foundation-rn
Shared foundation library for React Native apps. Provides UI components, state management, services, and app lifecycle utilities to eliminate duplication across projects.
Installation
yarn add @zyno-io/mobile-foundation-rnPeer Dependencies
Your app must install these packages:
@expo/react-native-action-sheet@fortawesome/fontawesome-svg-core,@fortawesome/react-native-fontawesome@react-native-async-storage/async-storage@react-navigation/native,@react-navigation/stack@sentry/react-nativeexpo-font,expo-linking,expo-splash-screen,expo-testflight,expo-updateslodashmobx,mobx-react-litereact,react-nativereact-native-device-info,react-native-gesture-handler,react-native-logs,react-native-reanimated,react-native-safe-area-context
Quick Start
1. Configure Foundation
Create a setup file (e.g. src/foundation/setup.ts) that runs before anything else:
import { faCheck, faSpinnerThird } from '@fortawesome/pro-regular-svg-icons';
import { Inter_400Regular, Inter_700Bold } from '@expo-google-fonts/inter';
import { configureFoundation, SentryHelper } from '@zyno-io/mobile-foundation-rn';
import { LightColors, DarkColors } from '@/constants/Colors';
import { Config } from '@/services/Config';
import { OpenApiUserError, OpenApiValidationError } from '@/services/ApiClient.setup';
configureFoundation({
colors: { light: LightColors, dark: DarkColors },
env: {
APP_ENV: Config.APP_ENV,
BUILD_VERSION: Config.BUILD_VERSION,
SENTRY_DSN: Config.SENTRY_DSN,
LOGGER_URL: Config.LOGGER_URL,
CDN_URL: Config.CDN_URL,
},
fonts: { Inter_400Regular, Inter_700Bold },
icons: { check: faCheck, spinner: faSpinnerThird },
statusBar: { barStyle: 'light-content', backgroundColorKey: 'background' },
splashScreen: 'auto', // default; use 'manual' to control splash yourself
updaterTimeout: 4000,
deepLinkHandler: (url) => handleDeepLink(url),
supportContact: '[email protected]',
userErrorClasses: [OpenApiUserError, OpenApiValidationError],
});
// Sentry is auto-initialized by configureFoundation2. Create App Storage
import { createAppStorage } from '@zyno-io/mobile-foundation-rn';
interface IAppStorage {
deviceToken?: string;
lastSyncTime?: number;
}
export const AppStorage = createAppStorage<IAppStorage>({});AppStorage is a MobX observable proxy with three special methods:
$load()— Loads persisted state from AsyncStorage (called automatically byuseSetupFoundation)$persist()— Manually triggers a persist$clear()— Clears all values and persists
Setting any property auto-persists with a 250ms debounce:
AppStorage.deviceToken = 'abc123'; // automatically saved3. Set Up Your App Entry
import 'react-native-reanimated';
import '@/foundation/setup';
import { MfProvider, useSetupFoundation } from '@zyno-io/mobile-foundation-rn';
import { AppNavigator } from './AppNavigator';
function RootLayout() {
const isReady = useSetupFoundation();
if (!isReady) return null;
return (
<MfProvider>
<AppNavigator />
</MfProvider>
);
}
export default RootLayout;Configuration Reference
configureFoundation(config)
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| colors | { light: ColorScheme; dark: ColorScheme } | Yes | Theme color definitions |
| env | { APP_ENV, BUILD_VERSION, SENTRY_DSN, LOGGER_URL, CDN_URL } | Yes | Environment config |
| icons | { check: IconProp; spinner: IconProp } | Yes | FontAwesome icons for checkbox and loader |
| fonts | Record<string, any> | No | Font map passed to useFonts() |
| statusBar | { barStyle, backgroundColorKey? } | No | Status bar styling |
| splashScreen | 'auto' \| 'manual' | No | Splash screen hide behavior (default: 'auto') |
| updaterTimeout | number | No | Max ms to wait for update check before proceeding |
| deepLinkHandler | (url: string) => void | No | Handler for incoming deep links |
| supportContact | string | No | Contact info shown in error dialogs |
| userErrorClasses | ErrorClass[] | No | Error classes whose messages are shown to users |
| defaults | FoundationDefaults | No | Per-component style defaults (see below) |
Component defaults (config.defaults)
Optional overrides for the non-color style constants the components otherwise hardcode. Every field is optional — omit one and the library's built-in value is used, so existing apps are unaffected. *ColorKey fields name a key in your ColorScheme (resolved at render via the active theme):
defaults: {
fontFamily: 'Lato', // MfText (and anything that renders it); default 'Inter'
icon: { colorKey: 'white' }, // default color for a bare <MfIcon> with no `color`; default 'text'
button: {
backgroundColorKey: 'white', // default 'secondaryButtonBackground'
borderWidth: 1, // default 0
borderColorKey: 'cardBorder',
primaryBorderColorKey: 'primaryButtonBackground',
gap: 6, // icon↔text gap; default 0
titleFontSize: 16, // default 14
iconColorKey: 'white', // in-button icon color; default derives from title color
},
input: { borderRadius: 12, backgroundColorKey: 'inputBackground' }, // defaults 8 / 'cardBackground'
loader: { backgroundColor: 'transparent', overlayBackgroundColorKey: 'background' },
}Core Concepts
useSetupFoundation(appIsReady?)
Consolidates all foundation startup into a single hook:
- Initializes Sentry navigation instrumentation
- Runs the OTA updater hook
- Loads fonts via
useFonts() - Loads
AppMetaandAppStorage - Hides the splash screen when ready (unless
splashScreen: 'manual')
Pass an optional appIsReady callback for app-specific conditions:
const isReady = useSetupFoundation(() => myDataIsLoaded);<MfProvider>
Wraps your app with all required providers:
ActionSheetProviderThemeProvider(React Navigation)MfGlobalKeyboardProviderGestureHandlerRootViewSafeAreaProviderStatusBar(from config)DeepLinkingHandler(from config)GlobalLoaderOverlay(connected to foundation's internalLoaderState)
Accepts an optional colorScheme prop to force light/dark (defaults to system).
Observable Proxy (createObservableProxy)
Creates a MobX-observable proxy that automatically makes new properties observable:
const state = createObservableProxy({ count: 0 });
state.count = 1; // observable, triggers reactions
state.newProp = 'hello'; // also observableSupports hooks for custom getters and side effects:
const state = createObservableProxy(target, {
someProp: {
get: (target) => computedValue,
afterSet: () => persist(),
},
});Updater
Manages Expo OTA updates with observable status:
import { Updater } from '@zyno-io/mobile-foundation-rn';
import { observer } from 'mobx-react-lite';
const Startup = observer(() => {
// Updater.statusText is null when not busy
if (Updater.statusText) {
return <Text>{Updater.statusText}</Text>;
}
// proceed with app...
});Defer updates during critical operations:
Updater.setUpdateDeferralListener(() => isOnActiveCall);Components
| Component | Description |
|-----------|-------------|
| MfButton | Themed button with icon support and loading state |
| MfCheckbox | Checkbox using configured check icon |
| MfFlatList | Themed FlatList with pull-to-refresh |
| MfIcon | FontAwesome icon wrapper |
| MfLoader / MfLoaderView | Loading spinner using configured spinner icon |
| MfLoaderOverlay / GlobalLoaderOverlay | Full-screen loading overlay |
| MfScrollView | Themed ScrollView |
| MfText / MfStatusTextView | Themed text components |
| MfTextArea | Multi-line text input |
| MfTextInput | Single-line text input |
| MfWrapperView | Safe-area-aware wrapper view |
| MfForm / MfFormContext | Form context provider |
Hooks
| Hook | Description |
|------|-------------|
| useSetupFoundation() | Foundation startup (see above) |
| useWaitTask(logger, fn) | Returns a function that shows the loader overlay during execution |
| useStyles(styleGen) | Themed StyleSheet hook |
| useColors() | Current theme colors |
| useMountEffect(fn) | Effect that runs once on mount |
| useAppStateEffect(fn) | Runs on every app state change |
| useAppActivatedEffect(fn) | Runs when app comes to foreground |
| useAppDeactivatedEvent(fn) | Runs when app goes to background |
| useNavigationFocusEffect(fn) | Runs when screen gains focus |
| useNavigationUnfocusEffect(fn) | Runs when screen loses focus |
| useNavigationWithTitle(title) | Sets navigation title |
| useNavigationWithOptions(opts) | Sets navigation options |
| useNextTextInputRef() | Auto-focus next input on submit |
| useMfKeyboardHeight() | Current keyboard height |
| useMfSafeAreaInsets() | Safe area insets with overrides |
| getLinkingUrl() | Get the current linking URL synchronously |
Helpers
| Helper | Description |
|--------|-------------|
| createStyles(fn) | Create a themed style generator |
| createObservableProxy(target, hooks?) | MobX observable proxy |
| LoaderState | Internal observable { loaderCount } used by useWaitTask and GlobalLoaderOverlay |
| Broadcast / useBroadcastEffect | Event bus for cross-component communication |
| formatPhone, formatCurrency, formatDuration | Formatting utilities |
| memoizeAsync(fn) | Memoize an async function (runs once) |
| getCdnUrlForId(id) | CDN URL builder |
| hasHeightOrFlexProps(style) | Layout helper |
Services
| Service | Description |
|---------|-------------|
| AppMeta | Device/app metadata (deviceId, appVersion, appEnv, appEnvTf, isDevelopment) |
| createAppStorage(defaults) | Persistent observable storage factory |
| createLogger(name) | Structured logger with remote transport |
| UserError | User-facing error class |
| SentryHelper | Sentry initialization, wrapping, and navigation instrumentation |
| Updater | OTA update management with observable status |
Color Scheme
Define your colors using CreateColorScheme:
import { CreateColorScheme } from '@zyno-io/mobile-foundation-rn';
type AppColorKeys = 'brandPrimary' | 'brandSecondary';
export const LightColors: CreateColorScheme<AppColorKeys> = {
// base keys (required)
background: '#FFFFFF',
text: '#000000',
secondaryText: '#666666',
// ...other base keys
// custom keys
brandPrimary: '#007AFF',
brandSecondary: '#5856D6',
};File Structure
src/
config.ts — configureFoundation() and FoundationConfig type
types.ts — ColorScheme types
index.ts — Barrel exports
components/ — UI components
hooks/ — React hooks
helpers/ — Pure utilities (styles, observable, formatting, etc.)
services/ — Singletons (AppMeta, AppStorage, Logger, Sentry, Updater)
setup/ — Side-effect imports (Mobx, AppStateTracker)