import React from 'react';
import { type StyleProp, type ViewStyle } from 'react-native';
import { type DarkColors } from './appearance';
import type { UnitOption } from './units';
import { type MultipleChoice, type ScreenCondition } from './logic';
import { type VariableFormat, type VariableValue } from './variables';
import { type FlowTest, type ScreenExperiment } from './experiment';
export type { VariableValue } from './variables';
export type EdgeInsets = {
    top?: number;
    right?: number;
    bottom?: number;
    left?: number;
};
export type AxisInsets = {
    vertical?: number;
    horizontal?: number;
};
export type ScreenTheme = {
    background?: string;
    showImage?: boolean;
    showProgress?: boolean;
    showTitle?: boolean;
    showSubtitle?: boolean;
    showButton?: boolean;
    showSkip?: boolean;
    showBack?: boolean;
    showTerms?: boolean;
    showLoader?: boolean;
    showChecklist?: boolean;
    showCharts?: boolean;
    showProof?: boolean;
    gap?: number;
    margin?: number | AxisInsets;
    headerPadding?: number | EdgeInsets;
    bodyPadding?: number | EdgeInsets;
    footerPadding?: number | EdgeInsets;
    headerMargin?: AxisInsets;
    bodyMargin?: AxisInsets;
    footerMargin?: AxisInsets;
    align?: 'left' | 'center' | 'right';
    text?: string;
    muted?: string;
    primary?: string;
    buttonPadding?: number | EdgeInsets;
    buttonRadius?: number;
    cardPadding?: number | EdgeInsets;
    cardRadius?: number;
    cardBackground?: string;
    imageFit?: 'cover' | 'contain' | 'fill';
    imageWidthMode?: 'fill' | 'fixed';
    imageHeightMode?: 'fill' | 'fixed';
    imageWidth?: number;
    imageHeight?: number;
    imageRadius?: number;
    imagePadding?: number | EdgeInsets;
    imageMargin?: AxisInsets;
    imageBorderWidth?: number;
    imageBorderColor?: string;
    /** 'background' fills the screen behind the content, under a tinted overlay. */
    imagePlacement?: 'inline' | 'background';
    imageMotion?: 'none' | 'float' | 'rock' | 'pulse' | 'drift';
    /** Shows an inline image or video inside a phone mockup. */
    imageFrame?: 'none' | 'iphone' | 'android';
    overlayColor?: string;
    overlayOpacity?: number;
    overlayStyle?: 'solid' | 'gradient';
    /** Dark-mode color overrides; anything left out is derived from the light colors. */
    dark?: DarkColors;
    /** Order of parts in the header and body. Missing parts fall back to their default section. */
    arrangement?: {
        header: LayoutPart[];
        body: LayoutPart[];
    };
    /** Which zone each section sits in. Defaults: header top, footer bottom, body bottom on full-photo screens and top otherwise. */
    headerAlign?: SectionAlign;
    bodyAlign?: SectionAlign;
    footerAlign?: SectionAlign;
    headerHorizontalAlign?: 'left' | 'center' | 'right';
    bodyHorizontalAlign?: 'left' | 'center' | 'right';
    footerHorizontalAlign?: 'left' | 'center' | 'right';
    partOffsets?: Partial<Record<LayoutPart | 'button' | 'skip' | 'terms', {
        x: number;
        y: number;
    }>>;
    progress?: 'above' | 'below';
    progressStyle?: 'segments' | 'bar' | 'dots';
    skipLabel?: string;
    backLabel?: string;
    termsLabel?: string;
    termsUrl?: string;
    font?: string;
    bodyFont?: string;
    titleSize?: number;
    bodySize?: number;
    titleWeight?: 400 | 500 | 700;
    titleUnderline?: boolean;
    subtitleBold?: boolean;
    subtitleUnderline?: boolean;
    motion?: Partial<Record<MotionPart, PartMotion>>;
};
export type MotionPart = 'image' | 'progress' | 'title' | 'subtitle' | 'answers' | 'cards' | 'button' | 'skip' | 'back' | 'terms';
export type PartMotion = {
    enter: 'fade' | 'rise' | 'slide' | 'pop';
    duration?: number;
    delay?: number;
};
export type ScreenChart = {
    id: string;
    kind: 'bar' | 'line' | 'donut';
    title: string;
    points: {
        label: string;
        value: number;
    }[];
    hidden?: boolean;
    motion?: PartMotion;
};
export type LayoutPart = 'back' | 'progress' | 'image' | 'loader' | 'title' | 'subtitle' | 'answers' | 'proof' | 'checklist' | 'charts';
/** Every action except next and complete reaches onAction so the app can make the native request. */
export type ScreenAction = 'next' | 'complete' | 'requestNotifications' | 'showPaywall' | 'requestTracking' | 'requestLocation' | 'requestCamera' | 'requestPhotos' | 'requestMicrophone' | 'requestContacts' | 'requestHealth' | 'requestBiometrics' | 'requestReview' | 'signUp' | `custom:${string}`;
/** What onAction returns: nothing or true moves on, false keeps the person on the screen. A Promise makes the flow wait for it. */
export type ActionResult = void | boolean;
export type Testimonial = {
    quote: string;
    author: string;
    detail?: string;
    stars?: number;
};
export type Appearance = 'light' | 'dark' | 'system';
export type SectionAlign = 'top' | 'center' | 'bottom';
export type FlowScreen = {
    id: string;
    kind: 'Welcome' | 'Question' | 'Feature' | 'Permission' | 'Paywall';
    title: string;
    subtitle: string;
    button: string;
    accent: string;
    answerType?: 'text' | 'singleChoice' | 'positionPicker' | 'photo';
    options?: string[];
    positionPicker?: {
        positions: {
            id: string;
            label: string;
            x: number;
            y: number;
        }[];
        maxSelections: number;
        background?: string;
        height?: number;
        cornerRadius?: number;
        hotspotShape?: 'circle' | 'rounded' | 'chip';
        hotspotSize?: 'small' | 'medium' | 'large';
    };
    photoInput?: {
        sources?: ('camera' | 'library')[];
        analysis?: boolean;
        analysisVariable?: string;
    };
    /** Choice questions: allow several picks. The answer joins them with ", ". */
    multiple?: MultipleChoice;
    /** Saves this answer under a name later copy can use as {name} or {name|fallback}. */
    variable?: string;
    /** How the saved answer is shown when recalled: a currency for money, a style for dates. */
    variableFormat?: VariableFormat;
    /** Show this screen only when an earlier choice question's answer matches. */
    showIf?: ScreenCondition;
    /** Optional emoji aligned with `options`. Missing or blank means that choice is text only. */
    optionIcons?: string[];
    /** Entry hints for written answers, e.g. a number with a unit. */
    /** Entry for written answers. Wheel: min/max/step/initial. Date: min/max are years; the answer is YYYY-MM-DD. Country: the answer is the English name. */
    input?: {
        format: 'text' | 'number' | 'wheel' | 'date' | 'country';
        unit?: string;
        placeholder?: string;
        min?: number;
        max?: number;
        step?: number;
        initial?: number; /** Other units people can switch to; answers stay in the base unit. */
        units?: UnitOption[];
    };
    /** A "preparing your plan" moment: a ring fills while each step is checked off. */
    loader?: {
        steps: string[];
        duration?: number;
        autoAdvance?: boolean;
        color?: string;
        trackColor?: string;
        textColor?: string;
    };
    /** Benefits shown with check marks. */
    checklist?: {
        items: string[];
        color?: string;
        textColor?: string;
    };
    /** Two or more images shown as an auto-advancing carousel; `illustration` mirrors the first. */
    carousel?: {
        images: string[];
        interval?: number;
        autoplay?: boolean;
    };
    illustration?: string;
    imageVariable?: string;
    action?: ScreenAction;
    /** Social proof: a star rating, short testimonials, and a stat line. */
    proof?: {
        rating?: {
            score: number;
            count?: string;
            label?: string;
        };
        testimonials?: Testimonial[];
        stat?: string;
    };
    /** A/B test: other versions of this screen's copy or image. Each session sees one version for the whole flow. */
    experiment?: ScreenExperiment;
    buttonStyle?: 'filled' | 'outline' | 'text';
    theme?: ScreenTheme;
    translations?: Record<string, ScreenCopy>;
    charts?: ScreenChart[];
};
export type ScreenCopy = {
    title?: string;
    subtitle?: string;
    button?: string;
    options?: string[];
    skipLabel?: string;
    backLabel?: string;
    termsLabel?: string;
};
export type OnboardingFlow = {
    schemaVersion: 1;
    id: string;
    version: number;
    updatedAt: string;
    appearance?: Appearance; /** For the {app_name} variable. */
    appName?: string;
    screens: FlowScreen[]; /** A whole-onboarding A/B test; `screens` is version A. */
    experiment?: FlowTest<FlowScreen>;
};
type Props = {
    flowId: string;
    /** The app's publishable key (`oy_pub_…`) from the studio. It's meant to ship inside the app, so it can live in source code. */
    apiKey: string;
    baseUrl: string;
    fallbackFlow: OnboardingFlow;
    /** TestFlight and other release builds should pass `testing` explicitly; development builds default to `development`. */
    analyticsEnvironment?: 'development' | 'testing' | 'production';
    /** Locale key for translated screen copy, e.g. `fr-CA` or `es`. */
    locale?: string;
    /** `details.variables` holds every saved answer as a typed value (raw value, unit or currency, and the text shown), keyed by variable name. */
    onComplete?: (answers: Record<string, string>, details: {
        variables: Record<string, VariableValue>;
        photos: Record<string, PhotoSelection>;
    }) => void;
    /** `values` lists every pick for multiple-choice questions, or the single answer otherwise. */
    onAnswer?: (screen: FlowScreen, answer: string, values: string[], variable?: VariableValue, photo?: PhotoSelection) => void;
    /** Opens the app's native camera or photo library, then optionally uploads/analyzes it. Return a local URI for preview and a durable reference for later screens. */
    onPhotoRequest?: (screen: FlowScreen, source: 'camera' | 'library') => Promise<PhotoSelection | null>;
    /** Optional app-owned AI step. Return concise result text; the host app owns provider credentials and image handling. */
    onPhotoAnalyze?: (screen: FlowScreen, photo: PhotoSelection) => Promise<string | null>;
    /**
     * Runs for every action except next and complete. Return a Promise to make the flow wait (the button shows a spinner):
     * resolving to false, or rejecting, keeps the person on the screen. `details` holds the answers so far, e.g. to save them to a new account.
     */
    onAction?: (action: NonNullable<FlowScreen['action']>, screen: FlowScreen, details: {
        answers: Record<string, string>;
        variables: Record<string, VariableValue>;
    }) => ActionResult | Promise<ActionResult>;
    /** Overrides the flow's appearance. 'system' follows the device setting. */
    appearance?: Appearance;
    /** Saves progress on the device so a person who leaves the app (e.g. to sign up in a browser) comes back to the same screen. Defaults to true. */
    resume?: boolean;
    /**
     * Draws the videos a flow can use in place of images, e.g. with expo-video. It should fill `style`, loop, and stay muted.
     * Without it, a video slot shows the screen's illustration color.
     */
    renderVideo?: (video: OnboardingVideo) => React.ReactNode;
};
export type PhotoSelection = {
    uri: string;
    reference?: string;
    analysis?: string;
};
export type OnboardingVideo = {
    uri: string;
    resizeMode: 'cover' | 'contain' | 'stretch';
    style: StyleProp<ViewStyle>;
};
export declare function Onboarding({ flowId, apiKey, baseUrl, fallbackFlow, locale, onComplete, onAction, onAnswer, onPhotoRequest, onPhotoAnalyze, appearance, analyticsEnvironment: configuredAnalyticsEnvironment, resume, renderVideo }: Props): React.JSX.Element;
//# sourceMappingURL=index.d.ts.map