UNPKG

@datanova/react

Version:

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

1 lines 31 kB
{"version":3,"sources":["../src/index.ts","../package.json","../src/createDatanova.ts","../src/providers/DatanovaProvider.tsx","../src/hooks/useDatanova.ts","../src/hooks/useVariant.ts","../src/components/TrackPageView.tsx","../src/components/TrackClick.tsx","../src/components/TrackImpression.tsx","../src/components/TrackSubmit.tsx","../src/components/TrackChange.tsx","../src/components/Experiment.tsx"],"names":["name","version","createDatanova","keyOrServices","datanova","Datanova","DatanovaEventsService","DatanovaExperimentsService","__name","DatanovaContext","createContext","DatanovaProvider","value","children","jsx","useDatanova","context","useContext","useVariant","experimentId","client","state","setState","useState","useEffect","cancelled","fetchVariant","__async","variant","err","TrackPageView","eventName","properties","trackPageView","TrackClick","trackClick","isValidElement","originalOnClick","cloneElement","event","TrackImpression","threshold","triggerOnce","trackImpression","InView","inView","TrackSubmit","trackSubmit","originalOnSubmit","TrackChange","trackChange","originalOnChange","__spreadProps","__spreadValues","Experiment","control","variantContent","loadingContent","errorContent","data","isLoading","error","Fragment"],"mappings":"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","file":"index.mjs","sourcesContent":["export type {\n Event,\n EventsService,\n ExperimentsService,\n SDKConfig,\n Variant,\n} from '@datanova/browser';\nexport {\n EventType,\n ConsoleEventsService,\n DatanovaEventsService,\n DatanovaExperimentsService,\n NoopEventsService,\n RandomExperimentsService,\n generateAnonymousId,\n} from '@datanova/browser';\n\nexport { createDatanova } from './createDatanova';\nexport { useDatanova } from './hooks/useDatanova';\nexport { useVariant } from './hooks/useVariant';\nexport { DatanovaProvider } from './providers/DatanovaProvider';\nexport {\n TrackPageView,\n TrackClick,\n TrackImpression,\n TrackSubmit,\n TrackChange,\n Experiment,\n type TrackPageViewProps,\n type TrackClickProps,\n type TrackImpressionProps,\n type TrackSubmitProps,\n type TrackChangeProps,\n} from './components';\n","{\n \"name\": \"@datanova/react\",\n \"version\": \"1.7.0\",\n \"description\": \"React SDK for event tracking and A/B testing with Datanova\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.mjs\",\n \"require\": \"./dist/index.js\"\n }\n },\n \"sideEffects\": false,\n \"files\": [\n \"dist/\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"NODE_ENV=production tsup\",\n \"dev\": \"NODE_ENV=development tsup --watch\",\n \"lint\": \"eslint src\",\n \"tc\": \"tsc --noEmit\",\n \"format\": \"prettier --write src\",\n \"test\": \"vitest\",\n \"test:ui\": \"vitest --ui\",\n \"test:coverage\": \"vitest --coverage\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/d0-datanova/react-sdk.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/d0-datanova/react-sdk/issues\"\n },\n \"homepage\": \"https://github.com/d0-datanova/react-sdk#readme\",\n \"keywords\": [\n \"analytics\",\n \"ai\",\n \"data-analyst\",\n \"react\",\n \"react-hooks\",\n \"event-tracking\",\n \"ab-testing\"\n ],\n \"author\": \"\",\n \"license\": \"MIT\",\n \"peerDependencies\": {\n \"react\": \">=16.8.0\"\n },\n \"dependencies\": {\n \"@datanova/browser\": \"2.0.0\",\n \"react-intersection-observer\": \"^9.16.0\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.30.1\",\n \"@semantic-release/changelog\": \"^6.0.3\",\n \"@semantic-release/commit-analyzer\": \"^13.0.1\",\n \"@semantic-release/git\": \"^10.0.1\",\n \"@semantic-release/release-notes-generator\": \"^14.0.3\",\n \"@testing-library/jest-dom\": \"^6.6.3\",\n \"@testing-library/react\": \"^16.3.0\",\n \"@testing-library/user-event\": \"^14.6.1\",\n \"@types/node\": \"^24.0.12\",\n \"@types/react\": \"^19.1.8\",\n \"@vitest/ui\": \"^3.2.4\",\n \"conventional-changelog-conventionalcommits\": \"^9.0.0\",\n \"eslint\": \"^9.30.1\",\n \"happy-dom\": \"^18.0.1\",\n \"prettier\": \"^3.6.2\",\n \"react\": \"^19.1.0\",\n \"semantic-release\": \"^24.2.6\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.8.3\",\n \"typescript-eslint\": \"^8.36.0\",\n \"vitest\": \"^3.2.4\"\n }\n}\n","import {\n Datanova,\n DatanovaEventsService,\n DatanovaExperimentsService,\n EventsService,\n ExperimentsService,\n} from '@datanova/browser';\nimport { name, version } from '../package.json';\n\n// Overload signatures\nexport function createDatanova(apiKey: string): Datanova;\nexport function createDatanova(config: {\n eventsService?: EventsService;\n experimentsService?: ExperimentsService;\n}): Datanova;\n\n/**\n * Create and initialize a Datanova client for React applications\n * @param keyOrServices - Either an SDK key string or configuration object\n * @returns Initialized Datanova instance\n * @example\n * ```javascript\n * import { createReactDatanova } from '@datanova/react';\n *\n * // Simple usage with API key\n * const client = createReactDatanova(\"YOUR_SDK_KEY\");\n *\n * // Advanced usage with custom services\n * const client = createReactDatanova({\n * eventsService: new DatanovaEventsService(\"YOUR_SDK_KEY\"),\n * experimentsService: new DatanovaExperimentsService(\"YOUR_SDK_KEY\")\n * });\n * ```\n */\nexport function createDatanova(\n keyOrServices:\n | string\n | {\n eventsService?: EventsService;\n experimentsService?: ExperimentsService;\n }\n): Datanova {\n const datanova = new Datanova();\n\n if (typeof keyOrServices === 'string') {\n datanova.init({\n eventsService: new DatanovaEventsService(keyOrServices),\n experimentsService: new DatanovaExperimentsService(keyOrServices),\n context: {\n library: {\n name,\n version,\n },\n },\n });\n } else {\n datanova.init({\n eventsService: keyOrServices.eventsService,\n experimentsService: keyOrServices.experimentsService,\n context: {\n library: {\n name,\n version,\n },\n },\n });\n }\n\n return datanova;\n}\n","'use client';\n\nimport { ReactNode, createContext } from 'react';\nimport { Datanova } from '@datanova/browser';\n\n/**\n * Props for the DatanovaProvider component\n */\ninterface DatanovaProviderProps {\n value: Datanova;\n children: ReactNode;\n}\n\nexport type DatanovaContextValue = Datanova;\n\nexport const DatanovaContext = createContext<DatanovaContextValue | null>(null);\n\n/**\n * Provider component that provides Datanova tracking methods to child components.\n * Must be placed at the root of your component tree.\n *\n * @remarks\n * The DatanovaProvider uses React Context to make the Datanova instance available\n * throughout your application. Initialize the Datanova instance outside of your\n * component tree to prevent re-initialization on re-renders.\n *\n * @example\n * Basic usage with SDK key:\n * ```jsx\n * import { createReactDatanova, DatanovaProvider } from '@datanova/react';\n *\n * // Simple initialization with SDK key\n * const datanova = createReactDatanova(\"your-sdk-key\");\n *\n * function App() {\n * return (\n * <DatanovaProvider value={datanova}>\n * <YourApp />\n * </DatanovaProvider>\n * );\n * }\n * ```\n *\n * @example\n * Advanced usage with custom services:\n * ```jsx\n * import { createReactDatanova, DatanovaProvider } from '@datanova/react';\n * import { DatanovaEventsService, DatanovaExperimentsService } from '@datanova/browser';\n *\n * // Custom configuration with specific services\n * const datanova = createReactDatanova({\n * eventsService: new YourEventsService(),\n * experimentsService: new YourExperimentsService()\n * });\n *\n * function App() {\n * return (\n * <DatanovaProvider value={datanova}>\n * <YourApp />\n * </DatanovaProvider>\n * );\n * }\n * ```\n *\n * @example\n * Development usage with ConsoleEventsService:\n * ```jsx\n * import { createReactDatanova, DatanovaProvider } from '@datanova/react';\n * import { ConsoleEventsService } from '@datanova/browser';\n *\n * // Use ConsoleEventsService for development/debugging\n * const datanova = createReactDatanova({\n * eventsService: new ConsoleEventsService()\n * });\n *\n * function App() {\n * return (\n * <DatanovaProvider value={datanova}>\n * <YourApp />\n * </DatanovaProvider>\n * );\n * }\n * ```\n *\n * @param props - The provider props\n * @param props.value - The Datanova instance to provide to child components\n * @param props.children - The child components that will have access to the Datanova instance\n */\nexport function DatanovaProvider({ value, children }: DatanovaProviderProps) {\n return <DatanovaContext.Provider value={value}>{children}</DatanovaContext.Provider>;\n}\n","'use client';\n\nimport { useContext } from 'react';\nimport { DatanovaContext } from '../providers/DatanovaProvider';\n\n/**\n * Hook to access Datanova analytics tracking methods.\n * Must be used within a DatanovaProvider component.\n *\n * @returns Object containing track, trackClick, trackPageView, trackImpression, trackSubmit, trackChange, identify, and reset methods\n *\n * @example\n * ```jsx\n * import { useDatanova } from '@datanova/react';\n *\n * function MyComponent() {\n * const { trackClick, identify, reset } = useDatanova();\n *\n * const handleClick = () => {\n * trackClick('Button Clicked', { buttonId: 'submit' });\n * };\n *\n * const handleLogin = (userId, plan) => {\n * // Simple identify with just userId\n * identify(userId);\n *\n * // Or with user properties (v1.7.0+)\n * identify(userId, { plan });\n * };\n *\n * const handleLogout = () => {\n * reset();\n * };\n *\n * return <button onClick={handleClick}>Track Event</button>;\n * }\n * ```\n *\n * @throws {Error} If used outside of a DatanovaProvider\n */\nexport function useDatanova() {\n const context = useContext(DatanovaContext);\n\n if (!context) {\n throw new Error('useDatanova must be used within a DatanovaProvider');\n }\n\n return {\n trackClick: context.trackClick,\n trackPageView: context.trackPageView,\n trackImpression: context.trackImpression,\n trackSubmit: context.trackSubmit,\n trackChange: context.trackChange,\n identify: context.identify,\n reset: context.reset,\n };\n}\n","'use client';\n\nimport { useContext, useEffect, useState } from 'react';\nimport { Variant } from '@datanova/browser';\nimport { DatanovaContext } from '../providers/DatanovaProvider';\n\ntype ExperimentState =\n | { isLoading: true; data: undefined; error: null }\n | { isLoading: false; data: Variant; error: null }\n | { isLoading: false; data: 'control'; error: Error };\n\n/**\n * Hook to get and track A/B test experiment variants.\n * Automatically tracks experiment exposure and manages loading/error states.\n *\n * SSR-safe: During server-side rendering, this hook returns null\n * to avoid hydration mismatches. The actual variant is fetched client-side.\n *\n * @param experimentId - The numeric ID of the experiment\n * @returns Object containing variant, loading state, and error\n *\n * @example\n * ```jsx\n * import { useVariant } from '@datanova/react';\n *\n * function MyComponent() {\n * const { loading, data, error } = useVariant({ experimentId: 20 });\n *\n * if (loading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <div>\n * {data === 'variant' ? (\n * <NewFeature />\n * ) : (\n * <OldFeature />\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useVariant({ experimentId }: { experimentId: number }): ExperimentState {\n const client = useContext(DatanovaContext);\n const [state, setState] = useState<ExperimentState>({\n isLoading: true,\n data: undefined,\n error: null,\n });\n\n useEffect(() => {\n if (!client) {\n setState({\n isLoading: false,\n data: 'control',\n error: new Error('useVariant must be used within a DatanovaProvider'),\n });\n return;\n }\n\n let cancelled = false;\n\n async function fetchVariant() {\n try {\n setState({ isLoading: true, data: undefined, error: null });\n const variant = await client!.getVariant(experimentId);\n\n if (!cancelled) {\n setState({\n isLoading: false,\n data: variant,\n error: null,\n });\n }\n } catch (err) {\n if (!cancelled) {\n setState({\n isLoading: false,\n data: 'control',\n error: err instanceof Error ? err : new Error('Failed to load experiment'),\n });\n }\n }\n }\n\n if (typeof window !== 'undefined') {\n fetchVariant();\n } else {\n setState({ isLoading: false, data: 'control', error: null });\n }\n\n return () => {\n cancelled = true;\n };\n }, [experimentId, client]);\n\n return state;\n}\n","'use client';\n\nimport { useEffect } from 'react';\nimport { useDatanova } from '../hooks/useDatanova';\n\n/**\n * Props for the TrackPageView component\n */\nexport interface TrackPageViewProps {\n /** Event name to track when the component mounts */\n eventName: string;\n /** Optional properties to include with the event */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Component that tracks a page view event when it mounts.\n * The browser SDK automatically captures page metadata like URL, title, and referrer.\n *\n * @example\n * ```jsx\n * import { TrackPageView } from '@datanova/react';\n *\n * function HomePage() {\n * return (\n * <>\n * <TrackPageView eventName=\"Home Page Viewed\" />\n * <h1>Welcome to our site</h1>\n * </>\n * );\n * }\n * ```\n *\n * @example\n * ```jsx\n * // With additional properties\n * function ProductPage({ productId }) {\n * return (\n * <>\n * <TrackPageView\n * eventName=\"Product Page Viewed\"\n * properties={{ productId, category: 'electronics' }}\n * />\n * <ProductDetails />\n * </>\n * );\n * }\n * ```\n */\nexport function TrackPageView({ eventName, properties }: TrackPageViewProps) {\n const { trackPageView } = useDatanova();\n\n useEffect(() => {\n trackPageView(eventName, properties);\n }, [eventName, properties, trackPageView]);\n\n return null;\n}\n","'use client';\n\nimport { MouseEvent, ReactElement, cloneElement, isValidElement } from 'react';\nimport { useDatanova } from '../hooks/useDatanova';\n\n/**\n * Props for the TrackClick component\n */\nexport interface TrackClickProps {\n children: ReactElement<{ onClick?: (event: MouseEvent) => void }>;\n /** Event name to track when the element is clicked */\n eventName: string;\n /** Optional properties to include with the event */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Component that tracks click events on its child element.\n * Wraps a single React element and tracks when it's clicked, preserving any existing onClick handler.\n *\n * @example\n * ```jsx\n * import { TrackClick } from '@datanova/react';\n *\n * function CTAButton() {\n * return (\n * <TrackClick eventName=\"CTA Clicked\" properties={{ location: 'header' }}>\n * <button onClick={() => console.log('Original handler')}>\n * Get Started\n * </button>\n * </TrackClick>\n * );\n * }\n * ```\n *\n * @throws {Error} If children is not a valid React element\n */\nexport function TrackClick({ children, eventName, properties }: TrackClickProps) {\n const { trackClick } = useDatanova();\n\n if (!isValidElement(children)) {\n throw new Error('TrackClick must be used with a valid React element');\n }\n\n const originalOnClick = children.props.onClick;\n\n const handleClick = (event: MouseEvent) => {\n trackClick(eventName, properties);\n if (originalOnClick) {\n originalOnClick(event);\n }\n };\n\n return cloneElement(children, { onClick: handleClick });\n}\n","'use client';\n\nimport { ReactNode } from 'react';\nimport { InView } from 'react-intersection-observer';\nimport { useDatanova } from '../hooks/useDatanova';\n\n/**\n * Props for the TrackImpression component\n */\nexport interface TrackImpressionProps {\n children: ReactNode;\n /** Event name to track when the element comes into view */\n eventName: string;\n /** Optional properties to include with the event */\n properties?: Record<string, unknown>;\n /** Percentage of element that must be visible to trigger (0-1). Default: 0.5 (50%) */\n threshold?: number;\n /** Whether to track only the first impression. Default: true */\n triggerOnce?: boolean;\n}\n\n/**\n * Component that tracks when its children come into the viewport using Intersection Observer.\n * Useful for tracking impressions of content blocks, images, or any visual elements.\n *\n * @example\n * ```jsx\n * import { TrackImpression } from '@datanova/react';\n *\n * function HeroSection() {\n * return (\n * <TrackImpression eventName=\"Hero Section Viewed\">\n * <section className=\"hero\">\n * <h1>Welcome to Our Product</h1>\n * <p>Start your journey today</p>\n * </section>\n * </TrackImpression>\n * );\n * }\n * ```\n *\n * @example\n * ```jsx\n * // Track when 80% of element is visible, multiple times\n * <TrackImpression\n * eventName=\"Product Card Viewed\"\n * properties={{ productId: '123' }}\n * threshold={0.8}\n * triggerOnce={false}\n * >\n * <ProductCard />\n * </TrackImpression>\n * ```\n *\n * @example\n * ```jsx\n * // Track lazy-loaded content\n * <TrackImpression\n * eventName=\"Comments Section Viewed\"\n * threshold={0.1} // Track when just 10% is visible\n * >\n * <LazyComments />\n * </TrackImpression>\n * ```\n */\nexport function TrackImpression({\n children,\n eventName,\n properties,\n threshold = 0.5,\n triggerOnce = true,\n}: TrackImpressionProps) {\n const { trackImpression } = useDatanova();\n\n return (\n <InView\n onChange={(inView) => {\n if (inView) {\n trackImpression(eventName, properties);\n }\n }}\n threshold={threshold}\n triggerOnce={triggerOnce}\n >\n {children}\n </InView>\n );\n}\n","'use client';\n\nimport { FormEvent, ReactElement, cloneElement, isValidElement } from 'react';\nimport { useDatanova } from '../hooks/useDatanova';\n\n/**\n * Props for the TrackSubmit component\n */\nexport interface TrackSubmitProps {\n children: ReactElement<{ onSubmit?: (event: FormEvent) => void }>;\n /** Event name to track when the form is submitted */\n eventName: string;\n /** Optional properties to include with the event */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Component that tracks submit events on form elements.\n * Wraps a form element and tracks when it's submitted, preserving any existing onSubmit handler.\n *\n * @example\n * ```jsx\n * import { TrackSubmit } from '@datanova/react';\n *\n * function ContactForm() {\n * return (\n * <TrackSubmit eventName=\"Contact Form Submitted\" properties={{ type: 'inquiry' }}>\n * <form onSubmit={(e) => { e.preventDefault(); console.log('Form submitted'); }}>\n * <input type=\"email\" name=\"email\" required />\n * <button type=\"submit\">Submit</button>\n * </form>\n * </TrackSubmit>\n * );\n * }\n * ```\n *\n * @throws {Error} If children is not a valid React element\n */\nexport function TrackSubmit({ children, eventName, properties }: TrackSubmitProps) {\n const { trackSubmit } = useDatanova();\n\n if (!isValidElement(children)) {\n throw new Error('TrackSubmit must be used with a valid React element');\n }\n\n const originalOnSubmit = children.props.onSubmit;\n\n const handleSubmit = (event: FormEvent) => {\n trackSubmit(eventName, properties);\n originalOnSubmit?.(event);\n };\n\n return cloneElement(children, { onSubmit: handleSubmit });\n}\n","'use client';\n\nimport { ReactElement, cloneElement, isValidElement } from 'react';\nimport { useDatanova } from '../hooks/useDatanova';\n\n/**\n * Props for the TrackChange component\n */\nexport interface TrackChangeProps {\n children: ReactElement<{ onChange?: (value: unknown) => void }>;\n /** Event name to track when the element value changes */\n eventName: string;\n /** Optional properties to include with the event */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Component that tracks change events on form elements.\n * Wraps a form element (select, input, etc.) and tracks when its value changes,\n * preserving any existing onChange handler.\n *\n * @example\n * ```jsx\n * import { TrackChange } from '@datanova/react';\n *\n * function FilterForm() {\n * return (\n * <TrackChange eventName=\"Date Filter Changed\" properties={{ filter: 'date' }}>\n * <select onChange={(e) => console.log('Selected:', e.target.value)}>\n * <option value=\"7d\">Last 7 days</option>\n * <option value=\"30d\">Last 30 days</option>\n * </select>\n * </TrackChange>\n * );\n * }\n * ```\n *\n * @throws {Error} If children is not a valid React element\n */\nexport function TrackChange({ children, eventName, properties }: TrackChangeProps) {\n const { trackChange } = useDatanova();\n\n if (!isValidElement(children)) {\n throw new Error('TrackChange must be used with a valid React element');\n }\n\n const originalOnChange = children.props.onChange;\n\n const handleChange = (\n event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement> | unknown\n ) => {\n let value: unknown;\n\n if (event && typeof event === 'object' && 'target' in event) {\n value = (event as React.ChangeEvent<HTMLInputElement>).target.value;\n } else {\n value = event;\n }\n\n trackChange(eventName, {\n ...properties,\n value,\n });\n originalOnChange?.(event);\n };\n\n return cloneElement(children, { onChange: handleChange });\n}\n","'use client';\n\nimport { ReactNode } from 'react';\nimport { useVariant } from '../hooks/useVariant';\n\ninterface ExperimentProps {\n /** The numeric ID of the experiment */\n experimentId: number;\n /** Content to show for the control variant */\n control: ReactNode;\n /** Content to show for the variant */\n variant: ReactNode;\n /** Optional content to show while loading */\n loading?: ReactNode;\n /** Optional content to show on error */\n error?: ReactNode;\n}\n\n/**\n * Component for declarative A/B testing.\n * Automatically handles experiment assignment and tracks exposure.\n *\n * @example\n * ```jsx\n * import { Experiment } from '@datanova/react';\n *\n * function HomePage() {\n * return (\n * <Experiment\n * experimentId={20}\n * control={<OldHero />}\n * variant={<NewHero />}\n * />\n * );\n * }\n * ```\n *\n * @example With loading and error states\n * ```jsx\n * <Experiment\n * experimentId={20}\n * control={<OldCheckout />}\n * variant={<NewCheckout />}\n * loading={<CheckoutSkeleton />}\n * error={<OldCheckout />} // Fallback to control on error\n * />\n * ```\n */\nexport function Experiment({\n experimentId,\n control,\n variant: variantContent,\n loading: loadingContent,\n error: errorContent,\n}: ExperimentProps) {\n const { data, isLoading, error } = useVariant({ experimentId });\n\n if (isLoading) {\n return <>{loadingContent ?? null}</>;\n }\n\n if (error) {\n return <>{errorContent ?? control}</>;\n }\n\n const content = data === 'variant' ? variantContent : control;\n\n return <>{content}</>;\n}\n"]}