# Helpers

Canonical page: https://docs.ovok.com/native-sdk/guide/components/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 [#exports-at-a-glance]

```ts
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";
```

| 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 logger compatibility helper; see [Logging](/native-sdk/guide/components/helpers/logging). |
| `configureOvokLogger`, `ovokLogger` | `./utils/sentry-logger.ts` | Configurable logger and direct log API; see [Logging](/native-sdk/guide/components/helpers/logging). |
| `configureOvokTelemetry` and telemetry types | `./utils/telemetry.ts` | Provider setup; see [Telemetry](/native-sdk/guide/components/helpers/telemetry). |
| `sanitizeOvokTelemetryAttributes` and telemetry helpers | `./utils/telemetry.ts` | Spans, metrics, durations, events, and OTel logs; see [Telemetry](/native-sdk/guide/components/helpers/telemetry). |
| `withAnimated`               | `./utils/with-animated.tsx`            | SDK (Reanimated HOC bridge) |

## `<Conditional>` [#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.

```ts
interface ConditionalProps {
  condition: boolean;
  children: React.ReactNode;
}
```

```tsx
<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](/native-sdk/guide/components/helpers/forms/) and [`withAnimated`](/native-sdk/guide/components/helpers/with-animated) for
the remaining helper APIs.

## `<FormField>` [#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()`.

```ts
interface FormFieldProps extends Omit<TextInputProps, "onChangeText" | "value" | "testID"> {
  name: string;
  context: React.Context<any>;
  containerStyle?: ViewStyle;
  inputRef?: React.Ref<{ focus: () => void }>;
  testID?: string;
}
```

```tsx
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>` [#formselect]

Formik-bound dropdown with an animated floating label. Wraps `react-native-element-dropdown`'s `<Dropdown>`. Generic on the option type `T`.

```ts
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;
}
```

```tsx
<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>` [#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'`.

```ts
interface FormDateFieldProps {
  name: string;
  context: React.Context<any>;
  label?: string;
  testID?: string;
  containerStyle?: ViewStyle;
  labelStyle?: TextStyle;
  mode?: "date" | "time" | "datetime";
}
```

```tsx
<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 [#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](/native-sdk/guide/components/helpers/logging) — `slog`, `configureOvokLogger`, and `ovokLogger`, including
  console behavior, callback routing, and log-data boundaries.
- [Telemetry](/native-sdk/guide/components/helpers/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)` [#withanimatedcomponent]

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](https://github.com/callstack/react-native-paper/issues/2364) — `createAnimatedComponent` on a class component requires a class wrapper, which is what this HOC supplies.

```ts
const withAnimated: <T extends object>(
  WrappedComponent: React.ComponentType<T>,
) => React.ComponentType<AnimatedProps<T>>;
```

```tsx
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` [#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`:

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

## Related [#related]

- [PickerSheet](/native-sdk/guide/components/picker-sheet/) — uses `BottomSheetModalProvider`
- [Sign-In](/native-sdk/guide/components/auth/sign-in/) — uses `FormField` internally
