Helpers
@ovok/native re-exports a handful of utilities used internally by other components. They're publicly exported so apps can reuse the same Formik field wrappers, conditional rendering, and Sentry-aware logger that the SDK uses itself — no need to redefine them.
Source: src/modules/helpers/index.tsx.
Exports at a glance
import {
Conditional,
FormField,
FormSelect,
FormDateField,
slog,
withAnimated,
BottomSheetModalProvider,
} from "@ovok/native";
| Export | Module path | Source library |
|---|---|---|
Conditional | ./conditional.tsx | SDK |
FormField | ./form-items/form-field.tsx | SDK (wraps react-native-paper TextInput) |
FormSelect | ./form-items/form-select.tsx | SDK (wraps react-native-element-dropdown) |
FormDateField | ./form-items/form-date-field.tsx | SDK (wraps react-native-modal-datetime-picker) |
slog | ./utils/s-log.ts | SDK (wraps @sentry/react-native) |
withAnimated | ./utils/with-animated.tsx | SDK (Reanimated HOC bridge) |
BottomSheetModalProvider | (direct re-export) | @gorhom/bottom-sheet |
<Conditional>
Renders children only when condition is truthy. Cleaner than {cond && <View>...</View>} for multi-line branches and easier to scan in deeply-nested trees.
interface ConditionalProps {
condition: boolean;
children: React.ReactNode;
}
<Conditional condition={isMfaRequired}>
<MfaCodeInput onSubmit={handleMfa} />
</Conditional>
condition === false → returns null. No fallback prop; pair with a sibling for else branches.
<FormField>
A Formik-bound text input. Reads value/error/touched from the Formik context you pass via context and routes change/blur back through the form. Renders react-native-paper's <TextInput mode="outlined"> plus a <HelperText> for errors, with the error message run through react-i18next's t().
interface FormFieldProps extends Omit<TextInputProps, "onChangeText" | "value" | "testID"> {
name: string;
context: React.Context<ReturnType<typeof useFormik>>;
containerStyle?: ViewStyle;
testID?: string;
}
import { useFormik } from "formik";
import * as React from "react";
import { FormField } from "@ovok/native";
const FormContext = React.createContext<ReturnType<typeof useFormik> | null>(null);
function SignInForm() {
const form = useFormik({
initialValues: { email: "" },
onSubmit: async (values) => { /* ... */ },
});
return (
<FormContext.Provider value={form}>
<FormField name="email" context={FormContext} label="Email" />
</FormContext.Provider>
);
}
Error messages are looked up as translation keys, so feed Yup/Zod schemas key names like "validation.email.required" rather than raw English strings.
<FormSelect>
Formik-bound dropdown with an animated floating label. Wraps react-native-element-dropdown's <Dropdown>. Generic on the option type T.
interface FormSelectProps<T extends object> extends Omit<DropdownProps<T>, "data" | "onChange" | "onBlur" | "placeholder"> {
name: string;
context: React.Context<ReturnType<typeof useFormik>>;
label?: string;
options: T[];
labelStyle?: TextStyle;
onChange?: (item: T) => void;
onBlur?: () => void;
}
<FormSelect
name="country"
context={FormContext}
label="Country"
options={countries}
labelField="name"
valueField="code"
/>
The selected value is written via setFieldValue(name, item[valueField]) — so valueField must be a key of T whose value is the discriminator your schema validates.
<FormDateField>
Formik-bound date picker. Wraps react-native-modal-datetime-picker and writes the result back as a YYYY-MM-DD string (via date.toISOString().split('T')[0]). Supports mode: 'date' | 'time' | 'datetime'; default is 'date'.
interface FormDateFieldProps {
name: string;
context: React.Context<ReturnType<typeof useFormik>>;
label?: string;
testID?: string;
containerStyle?: ViewStyle;
labelStyle?: TextStyle;
mode?: "date" | "time" | "datetime";
}
<FormDateField name="dateOfBirth" context={FormContext} label="Date of birth" />
Note: in 'datetime' mode the date is still serialized as YYYY-MM-DD — the time component is discarded. If you need full ISO timestamps, write a separate field wrapper.
slog(error, scope, additionalData?, level?)
Structured logger. In __DEV__ it console.logs; in production it calls Sentry.captureException with the scope + extras.
slog(
error: any,
scope: string,
additionalData?: Record<string, any>,
level?: "error" | "warning" | "info" | "debug",
): void;
try {
await someBleOperation();
} catch (e) {
slog(e, "bt.connect", { deviceSn: device.sn }, "warning");
}
Use the scope argument to grep across logs — it's free text, but consistent prefixes (bt.*, auth.*, fhir.*) pay off later.
withAnimated(Component)
Higher-order component that bridges a React Native Paper class component into a react-native-reanimated animated component. Worked around callstack/react-native-paper#2364 — createAnimatedComponent on a class component requires a class wrapper, which is what this HOC supplies.
const withAnimated: <T extends object>(
WrappedComponent: React.ComponentType<T>,
) => React.ComponentClass<AnimatedProps<T>, any>;
import { Card } from "react-native-paper";
import { withAnimated } from "@ovok/native";
const AnimatedCard = withAnimated(Card);
Use only when a Paper class component needs useAnimatedStyle/useSharedValue. Function components don't need this — Animated.createAnimatedComponent accepts them directly.
BottomSheetModalProvider
Direct re-export of BottomSheetModalProvider from @gorhom/bottom-sheet, surfaced for apps that consume <PickerSheet> or other SDK components that present bottom sheets. Mount once at the root, inside GestureHandlerRootView:
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { BottomSheetModalProvider, ThemeProvider as OvokThemeProvider } from "@ovok/native";
function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<BottomSheetModalProvider>
<OvokThemeProvider theme={themeConfig}>
<YourScreens />
</OvokThemeProvider>
</BottomSheetModalProvider>
</GestureHandlerRootView>
);
}
This is the same provider you'd import from @gorhom/bottom-sheet directly — re-exported here so apps don't need a separate dependency entry just for this single symbol.
Related
- PickerSheet — uses
BottomSheetModalProvider - Sign-In — uses
FormFieldinternally