Skip to main content

Helpers

The SDK exports helpers used internally by its components so apps can reuse the same Formik field wrappers, conditional rendering, logger, and telemetry utilities. Import them from @ovok/native/helpers or the package root @ovok/native. Bottom-sheet components remain on their own package and are not re-exported by the SDK root.

Source: src/modules/helpers/index.tsx.

Exports at a glance​

import {
Conditional,
FormField,
FormSelect,
FormDateField,
slog,
configureOvokLogger,
ovokLogger,
configureOvokTelemetry,
sanitizeOvokTelemetryAttributes,
startOvokSpan,
recordOvokMetric,
recordOvokDuration,
addOvokSpanEvent,
emitOvokLog,
withOvokSpan,
withAnimated,
} from "@ovok/native";
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
ExportModule pathSource library
Conditional./conditional.tsxSDK
FormField./form-items/form-field.tsxSDK (wraps react-native-paper TextInput)
FormSelect./form-items/form-select.tsxSDK (wraps react-native-element-dropdown)
FormDateField./form-items/form-date-field.tsxSDK (wraps react-native-modal-datetime-picker)
slog./utils/s-log.tsSDK logger compatibility helper; see Logging.
configureOvokLogger, ovokLogger./utils/sentry-logger.tsConfigurable logger and direct log API; see Logging.
configureOvokTelemetry and telemetry types./utils/telemetry.tsProvider setup; see Telemetry.
sanitizeOvokTelemetryAttributes and telemetry helpers./utils/telemetry.tsSpans, metrics, durations, events, and OTel logs; see Telemetry.
withAnimated./utils/with-animated.tsxSDK (Reanimated HOC bridge)

<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.

See the form helper references and withAnimated for the remaining helper APIs.

<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<any>;
containerStyle?: ViewStyle;
inputRef?: React.Ref<{ focus: () => void }>;
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<any>;
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<any>;
label?: string;
testID?: string;
containerStyle?: ViewStyle;
labelStyle?: TextStyle;
mode?: "date" | "time" | "datetime";
}
<FormDateField name="dateOfBirth" context={FormContext} label="Date of birth" />

Note: every mode is serialized as YYYY-MM-DD; the time component is discarded even when mode is 'time' or 'datetime'. If you need a time or full ISO timestamp, write a separate field wrapper. labelStyle is part of the public type but is not currently applied by the component.

Logging and telemetry​

The helpers module exposes logging and telemetry functions rather than rendered UI components. Use the focused references for their complete signatures and behavior:

  • Logging — slog, configureOvokLogger, and ovokLogger, including console behavior, callback routing, and log-data boundaries.
  • Telemetry — provider adapters, span and metric helpers, the attribute allowlist, and the built-in SDK signal catalog.

The app owns provider and exporter setup. OpenTelemetry peers are optional, and telemetry helpers remain best-effort when no provider is available.

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.ComponentType<AnimatedProps<T>>;
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​

Mount BottomSheetModalProvider from @gorhom/bottom-sheet once at the root when using <PickerSheet> or another bottom-sheet component. It is intentionally not exported from @ovok/native:

import { GestureHandlerRootView } from "react-native-gesture-handler";
import { ThemeProvider as OvokThemeProvider } from "@ovok/native";
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";

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. It is not a public @ovok/native export; install the peer and import it from @gorhom/bottom-sheet when your app uses bottom sheets.