UNPKG

@datanova/react

Version:

React SDK for event tracking and A/B testing with Datanova

451 lines (439 loc) 13.6 kB
import { Datanova, EventsService, ExperimentsService, Variant } from '@datanova/browser'; export { ConsoleEventsService, DatanovaEventsService, DatanovaExperimentsService, Event, EventType, EventsService, ExperimentsService, NoopEventsService, RandomExperimentsService, SDKConfig, Variant, generateAnonymousId } from '@datanova/browser'; import * as react_jsx_runtime from 'react/jsx-runtime'; import * as react from 'react'; import { ReactNode, ReactElement, MouseEvent, FormEvent } from 'react'; declare function createDatanova(apiKey: string): Datanova; declare function createDatanova(config: { eventsService?: EventsService; experimentsService?: ExperimentsService; }): Datanova; /** * Hook to access Datanova analytics tracking methods. * Must be used within a DatanovaProvider component. * * @returns Object containing track, trackClick, trackPageView, trackImpression, trackSubmit, trackChange, identify, and reset methods * * @example * ```jsx * import { useDatanova } from '@datanova/react'; * * function MyComponent() { * const { trackClick, identify, reset } = useDatanova(); * * const handleClick = () => { * trackClick('Button Clicked', { buttonId: 'submit' }); * }; * * const handleLogin = (userId, plan) => { * // Simple identify with just userId * identify(userId); * * // Or with user properties (v1.7.0+) * identify(userId, { plan }); * }; * * const handleLogout = () => { * reset(); * }; * * return <button onClick={handleClick}>Track Event</button>; * } * ``` * * @throws {Error} If used outside of a DatanovaProvider */ declare function useDatanova(): { trackClick: (eventName: string, properties?: Record<string, unknown>) => void; trackPageView: (eventName: string, properties?: Record<string, unknown>) => void; trackImpression: (eventName: string, properties?: Record<string, unknown>) => void; trackSubmit: (eventName: string, properties?: Record<string, unknown>) => void; trackChange: (eventName: string, properties?: Record<string, unknown>) => void; identify: (userId: string, properties?: Record<string, unknown>) => void; reset: () => void; }; type ExperimentState = { isLoading: true; data: undefined; error: null; } | { isLoading: false; data: Variant; error: null; } | { isLoading: false; data: 'control'; error: Error; }; /** * Hook to get and track A/B test experiment variants. * Automatically tracks experiment exposure and manages loading/error states. * * SSR-safe: During server-side rendering, this hook returns null * to avoid hydration mismatches. The actual variant is fetched client-side. * * @param experimentId - The numeric ID of the experiment * @returns Object containing variant, loading state, and error * * @example * ```jsx * import { useVariant } from '@datanova/react'; * * function MyComponent() { * const { loading, data, error } = useVariant({ experimentId: 20 }); * * if (loading) return <div>Loading...</div>; * if (error) return <div>Error: {error.message}</div>; * * return ( * <div> * {data === 'variant' ? ( * <NewFeature /> * ) : ( * <OldFeature /> * )} * </div> * ); * } * ``` */ declare function useVariant({ experimentId }: { experimentId: number; }): ExperimentState; /** * Props for the DatanovaProvider component */ interface DatanovaProviderProps { datanova: Datanova; children: ReactNode; } /** * Provider component that provides Datanova tracking methods to child components. * Must be placed at the root of your component tree. * * @remarks * The DatanovaProvider uses React Context to make the Datanova instance available * throughout your application. Initialize the Datanova instance outside of your * component tree to prevent re-initialization on re-renders. * * @example * Basic usage with SDK key: * ```jsx * import { createReactDatanova, DatanovaProvider } from '@datanova/react'; * * // Simple initialization with SDK key * const datanova = createReactDatanova("your-sdk-key"); * * function App() { * return ( * <DatanovaProvider datanova={datanova}> * <YourApp /> * </DatanovaProvider> * ); * } * ``` * * @example * Advanced usage with custom services: * ```jsx * import { createReactDatanova, DatanovaProvider } from '@datanova/react'; * import { DatanovaEventsService, DatanovaExperimentsService } from '@datanova/browser'; * * // Custom configuration with specific services * const datanova = createReactDatanova({ * eventsService: new YourEventsService(), * experimentsService: new YourExperimentsService() * }); * * function App() { * return ( * <DatanovaProvider datanova={datanova}> * <YourApp /> * </DatanovaProvider> * ); * } * ``` * * @example * Development usage with ConsoleEventsService: * ```jsx * import { createReactDatanova, DatanovaProvider } from '@datanova/react'; * import { ConsoleEventsService } from '@datanova/browser'; * * // Use ConsoleEventsService for development/debugging * const datanova = createReactDatanova({ * eventsService: new ConsoleEventsService() * }); * * function App() { * return ( * <DatanovaProvider datanova={datanova}> * <YourApp /> * </DatanovaProvider> * ); * } * ``` * * @param props - The provider props * @param props.datanova - The Datanova instance to provide to child components * @param props.children - The child components that will have access to the Datanova instance */ declare function DatanovaProvider({ datanova, children }: DatanovaProviderProps): react_jsx_runtime.JSX.Element; /** * Props for the TrackPageView component */ interface TrackPageViewProps { /** Event name to track when the component mounts */ eventName: string; /** Optional properties to include with the event */ properties?: Record<string, unknown>; } /** * Component that tracks a page view event when it mounts. * The browser SDK automatically captures page metadata like URL, title, and referrer. * * @example * ```jsx * import { TrackPageView } from '@datanova/react'; * * function HomePage() { * return ( * <> * <TrackPageView eventName="Home Page Viewed" /> * <h1>Welcome to our site</h1> * </> * ); * } * ``` * * @example * ```jsx * // With additional properties * function ProductPage({ productId }) { * return ( * <> * <TrackPageView * eventName="Product Page Viewed" * properties={{ productId, category: 'electronics' }} * /> * <ProductDetails /> * </> * ); * } * ``` */ declare function TrackPageView({ eventName, properties }: TrackPageViewProps): null; /** * Props for the TrackClick component */ interface TrackClickProps { children: ReactElement<{ onClick?: (event: MouseEvent) => void; }>; /** Event name to track when the element is clicked */ eventName: string; /** Optional properties to include with the event */ properties?: Record<string, unknown>; } /** * Component that tracks click events on its child element. * Wraps a single React element and tracks when it's clicked, preserving any existing onClick handler. * * @example * ```jsx * import { TrackClick } from '@datanova/react'; * * function CTAButton() { * return ( * <TrackClick eventName="CTA Clicked" properties={{ location: 'header' }}> * <button onClick={() => console.log('Original handler')}> * Get Started * </button> * </TrackClick> * ); * } * ``` * * @throws {Error} If children is not a valid React element */ declare function TrackClick({ children, eventName, properties }: TrackClickProps): ReactElement<{ onClick?: (event: MouseEvent) => void; }, string | react.JSXElementConstructor<any>>; /** * Props for the TrackImpression component */ interface TrackImpressionProps { children: ReactNode; /** Event name to track when the element comes into view */ eventName: string; /** Optional properties to include with the event */ properties?: Record<string, unknown>; /** Percentage of element that must be visible to trigger (0-1). Default: 0.5 (50%) */ threshold?: number; /** Whether to track only the first impression. Default: true */ triggerOnce?: boolean; } /** * Component that tracks when its children come into the viewport using Intersection Observer. * Useful for tracking impressions of content blocks, images, or any visual elements. * * @example * ```jsx * import { TrackImpression } from '@datanova/react'; * * function HeroSection() { * return ( * <TrackImpression eventName="Hero Section Viewed"> * <section className="hero"> * <h1>Welcome to Our Product</h1> * <p>Start your journey today</p> * </section> * </TrackImpression> * ); * } * ``` * * @example * ```jsx * // Track when 80% of element is visible, multiple times * <TrackImpression * eventName="Product Card Viewed" * properties={{ productId: '123' }} * threshold={0.8} * triggerOnce={false} * > * <ProductCard /> * </TrackImpression> * ``` * * @example * ```jsx * // Track lazy-loaded content * <TrackImpression * eventName="Comments Section Viewed" * threshold={0.1} // Track when just 10% is visible * > * <LazyComments /> * </TrackImpression> * ``` */ declare function TrackImpression({ children, eventName, properties, threshold, triggerOnce, }: TrackImpressionProps): react_jsx_runtime.JSX.Element; /** * Props for the TrackSubmit component */ interface TrackSubmitProps { children: ReactElement<{ onSubmit?: (event: FormEvent) => void; }>; /** Event name to track when the form is submitted */ eventName: string; /** Optional properties to include with the event */ properties?: Record<string, unknown>; } /** * Component that tracks submit events on form elements. * Wraps a form element and tracks when it's submitted, preserving any existing onSubmit handler. * * @example * ```jsx * import { TrackSubmit } from '@datanova/react'; * * function ContactForm() { * return ( * <TrackSubmit eventName="Contact Form Submitted" properties={{ type: 'inquiry' }}> * <form onSubmit={(e) => { e.preventDefault(); console.log('Form submitted'); }}> * <input type="email" name="email" required /> * <button type="submit">Submit</button> * </form> * </TrackSubmit> * ); * } * ``` * * @throws {Error} If children is not a valid React element */ declare function TrackSubmit({ children, eventName, properties }: TrackSubmitProps): ReactElement<{ onSubmit?: (event: FormEvent) => void; }, string | react.JSXElementConstructor<any>>; /** * Props for the TrackChange component */ interface TrackChangeProps { children: ReactElement<{ onChange?: (value: unknown) => void; }>; /** Event name to track when the element value changes */ eventName: string; /** Optional properties to include with the event */ properties?: Record<string, unknown>; } /** * Component that tracks change events on form elements. * Wraps a form element (select, input, etc.) and tracks when its value changes, * preserving any existing onChange handler. * * @example * ```jsx * import { TrackChange } from '@datanova/react'; * * function FilterForm() { * return ( * <TrackChange eventName="Date Filter Changed" properties={{ filter: 'date' }}> * <select onChange={(e) => console.log('Selected:', e.target.value)}> * <option value="7d">Last 7 days</option> * <option value="30d">Last 30 days</option> * </select> * </TrackChange> * ); * } * ``` * * @throws {Error} If children is not a valid React element */ declare function TrackChange({ children, eventName, properties }: TrackChangeProps): ReactElement<{ onChange?: (value: unknown) => void; }, string | react.JSXElementConstructor<any>>; interface ExperimentProps { /** The numeric ID of the experiment */ experimentId: number; /** Content to show for the control variant */ control: ReactNode; /** Content to show for the variant */ variant: ReactNode; /** Optional content to show while loading */ loading?: ReactNode; /** Optional content to show on error */ error?: ReactNode; } /** * Component for declarative A/B testing. * Automatically handles experiment assignment and tracks exposure. * * @example * ```jsx * import { Experiment } from '@datanova/react'; * * function HomePage() { * return ( * <Experiment * experimentId={20} * control={<OldHero />} * variant={<NewHero />} * /> * ); * } * ``` * * @example With loading and error states * ```jsx * <Experiment * experimentId={20} * control={<OldCheckout />} * variant={<NewCheckout />} * loading={<CheckoutSkeleton />} * error={<OldCheckout />} // Fallback to control on error * /> * ``` */ declare function Experiment({ experimentId, control, variant: variantContent, loading: loadingContent, error: errorContent, }: ExperimentProps): react_jsx_runtime.JSX.Element; export { DatanovaProvider, Experiment, TrackChange, type TrackChangeProps, TrackClick, type TrackClickProps, TrackImpression, type TrackImpressionProps, TrackPageView, type TrackPageViewProps, TrackSubmit, type TrackSubmitProps, createDatanova, useDatanova, useVariant };