@aranova/tracking-react 0.24.1 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,366 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, CSSProperties, InputHTMLAttributes, ChangeEvent, FocusEvent } from 'react';
3
+ import { G as GtagEnvironmentMap, M as MetaPixelEnvironmentMap, h as ConsentState, f as ConsentChoiceState, g as ConsentSource, T as TrackingParams, b as TrackingEnvironment, k as PhoneConfig, P as ParsedPhone, l as PhoneDisplayFormat } from './phone-utils-BVzSNBf1.js';
4
+ import { T as TrackingConfigReference, C as ConversionConfig } from './tracking-config-runtime-BnUlS_Ae.js';
5
+ import { N as TriggerRegistryConfig, Q as TypedTrackingClient } from './ingest-typed-C-SPiigr.js';
6
+ import { CountryCode } from 'libphonenumber-js';
7
+ import 'zod';
8
+ import 'src';
9
+
10
+ /**
11
+ * Legacy opt-in-era consent banner.
12
+ *
13
+ * @deprecated PERMANENTLY INERT since consent v2 (opt-out model): it renders
14
+ * only while consent is `pending`, and the effective state is never `pending`
15
+ * anymore, so this component always returns `null`. Tracking is on by default;
16
+ * replace the banner with a footer "cookie preferences" control built on
17
+ * {@link useCookiePreferences} (see the package README). Kept exported so
18
+ * existing integrations keep compiling; scheduled for removal.
19
+ */
20
+ interface ConsentBannerProps {
21
+ /** Body text. Defaults to the standard cookies-for-ad-performance message. */
22
+ message?: ReactNode;
23
+ /** Optional bold title above the body text. */
24
+ title?: ReactNode;
25
+ /** Label for the accept button. Default: `"Accept"`. */
26
+ acceptLabel?: string;
27
+ /** Label for the decline button. Default: `"Decline"`. */
28
+ declineLabel?: string;
29
+ /** Optional link inline with the message (e.g. to a privacy policy). */
30
+ policyHref?: string;
31
+ /** Visible text for {@link policyHref}. Default: `"Learn more"`. */
32
+ policyLabel?: string;
33
+ /**
34
+ * Fires after the consent state is persisted + propagated to gtag. Useful
35
+ * for emitting your own analytics event on the choice.
36
+ */
37
+ onAccept?: () => void;
38
+ onDecline?: () => void;
39
+ /** Where the banner docks. Default: `"bottom"`. */
40
+ position?: "top" | "bottom";
41
+ /**
42
+ * Visual theme. `"auto"` follows `prefers-color-scheme`. Default: `"light"`.
43
+ */
44
+ theme?: "light" | "dark" | "auto";
45
+ /** Class added to the outer wrapper for additional styling hooks. */
46
+ className?: string;
47
+ /** Inline style overrides applied to the outer wrapper after the defaults. */
48
+ style?: CSSProperties;
49
+ }
50
+ /**
51
+ * @deprecated Permanently inert since consent v2 — always renders `null`
52
+ * because the effective consent state is never `pending`. Use a footer
53
+ * control built on {@link useCookiePreferences} instead. See
54
+ * {@link ConsentBannerProps} for details.
55
+ */
56
+ declare function ConsentBanner({ message, title, acceptLabel, declineLabel, policyHref, policyLabel, onAccept, onDecline, position, theme, className, style, }?: ConsentBannerProps): ReactNode;
57
+
58
+ /**
59
+ * Props for the combined ad-platform tag loader.
60
+ *
61
+ * Every field is optional and independent: pass the Google fields, the Meta
62
+ * fields, or both. For each platform a labelled `*Ids` map (ALL loaded) takes
63
+ * precedence over the single `*Id` shortcut.
64
+ */
65
+ interface AdPlatformTrackingProps {
66
+ /** Single Google Ads tag id, e.g. `AW-123456789`. */
67
+ gtagId?: string;
68
+ /** Labelled Google Ads tag map — ALL loaded; wins over `gtagId`. */
69
+ gtagIds?: GtagEnvironmentMap;
70
+ /** R2-authoritative Google tracking config. When set, static gtagId(s) are ignored. */
71
+ trackingConfig?: TrackingConfigReference;
72
+ /** Fire a Google page view from this standalone loader. Leave false when using TrackingProvider. */
73
+ standalonePageView?: boolean;
74
+ /** Single Meta Pixel id, e.g. `123456789012345`. */
75
+ metaPixelId?: string;
76
+ /** Labelled Meta Pixel map — ALL loaded; wins over `metaPixelId`. */
77
+ metaPixelIds?: MetaPixelEnvironmentMap;
78
+ }
79
+ /**
80
+ * Client component that loads the configured ad-platform tags — the Google tag
81
+ * (`gtag`) and/or the Meta Pixel (`fbq`) — each with the visitor's effective
82
+ * consent applied as the default (opt-out model). One mount handles both
83
+ * platforms; omit a platform's props to skip it. Renders nothing.
84
+ *
85
+ * On React you usually don't need this at all — `<TrackingProvider>` already
86
+ * accepts the same `gtagId/gtagIds` + `metaPixelId/metaPixelIds` props. Use this
87
+ * standalone component when you want the ad tags WITHOUT the event-ingest SDK.
88
+ */
89
+ declare function AdPlatformTracking({ gtagId, gtagIds, trackingConfig, standalonePageView, metaPixelId, metaPixelIds, }: AdPlatformTrackingProps): null;
90
+
91
+ /**
92
+ * Props for the Google Ads tracking component.
93
+ *
94
+ * Accepts either a single `gtagId` (legacy) or a labelled `gtagIds` map
95
+ * where ALL entries are loaded simultaneously via `gtag('config', ...)`.
96
+ */
97
+ type GoogleAdsTrackingProps = {
98
+ gtagId: string;
99
+ gtagIds?: undefined;
100
+ } | {
101
+ gtagId?: undefined;
102
+ gtagIds: GtagEnvironmentMap;
103
+ };
104
+ /**
105
+ * Client component that loads Google Ads gtag with the visitor's effective
106
+ * consent applied as the Consent Mode default (opt-out model — granted unless
107
+ * an unexpired stored decline exists).
108
+ *
109
+ * Render once near the application root when the client site runs paid Google
110
+ * Ads. The component renders nothing.
111
+ */
112
+ declare function GoogleAdsTracking(props: GoogleAdsTrackingProps): null;
113
+
114
+ /**
115
+ * Read the captured Google Ads click id from first-party cookies.
116
+ *
117
+ * Returns `null` during SSR and before the client has mounted.
118
+ */
119
+ declare function useGclid(): string | null;
120
+ /**
121
+ * Read all captured attribution parameters from first-party cookies.
122
+ *
123
+ * Values are loaded after mount, so the initial render returns all `null`s.
124
+ */
125
+ declare function useTrackingParams(): TrackingParams;
126
+ /** Options for {@link useCookiePreferences}. */
127
+ interface UseCookiePreferencesOptions {
128
+ /** Days an explicit decline is honored. Defaults to 90. */
129
+ declineTtlDays?: number;
130
+ }
131
+ /**
132
+ * The headless cookie-preferences surface returned by
133
+ * {@link useCookiePreferences}.
134
+ */
135
+ interface UseCookiePreferencesResult {
136
+ /** Effective consent — `granted` unless an unexpired explicit decline exists. */
137
+ state: ConsentChoiceState;
138
+ /** `default` = no valid explicit choice stored; `explicit` = visitor chose. */
139
+ source: ConsentSource;
140
+ /** True when the visitor has made no (valid, unexpired) explicit choice. */
141
+ isDefault: boolean;
142
+ isGranted: boolean;
143
+ isDenied: boolean;
144
+ /** ISO timestamp of the explicit choice; null for the default state. */
145
+ updatedAt: string | null;
146
+ /** ISO expiry of an unexpired decline; null otherwise. */
147
+ expiresAt: string | null;
148
+ /** Explicitly opt out of ad tracking (honored for 90 days by default). */
149
+ optOut: () => void;
150
+ /** Explicitly opt in (never expires). */
151
+ optIn: () => void;
152
+ /** Clear the explicit choice — back to default-granted. */
153
+ reset: () => void;
154
+ }
155
+ /**
156
+ * Headless cookie-preferences hook for the opt-out consent model (consent v2).
157
+ *
158
+ * Tracking is ON by default; this hook is how each client site wires its own
159
+ * footer "Cookie preferences" control (button, dialog, toggle — the packages
160
+ * ship no consent UI). State stays in sync with actions from other components
161
+ * in the same tab (via `onConsentChange`) and other tabs (via `storage`
162
+ * events).
163
+ *
164
+ * ```tsx
165
+ * function CookiePreferences() {
166
+ * const { isDenied, optOut, optIn } = useCookiePreferences();
167
+ * return isDenied ? (
168
+ * <button onClick={optIn}>Enable ad measurement</button>
169
+ * ) : (
170
+ * <button onClick={optOut}>Opt out of ad measurement</button>
171
+ * );
172
+ * }
173
+ * ```
174
+ */
175
+ declare function useCookiePreferences(options?: UseCookiePreferencesOptions): UseCookiePreferencesResult;
176
+ /**
177
+ * Read the current visitor consent state.
178
+ *
179
+ * @deprecated Since consent v2 (opt-out model) the state is never `pending`.
180
+ * Use {@link useCookiePreferences} — it exposes the effective state plus
181
+ * `source` so you can tell a default grant from an explicit one.
182
+ */
183
+ declare function useConsentState(): ConsentState;
184
+ /**
185
+ * Result shape of the deprecated {@link useConsent} hook.
186
+ *
187
+ * @deprecated Use {@link UseCookiePreferencesResult} via
188
+ * {@link useCookiePreferences}. `isPending` is always `false` since consent v2.
189
+ */
190
+ interface UseConsentResult {
191
+ state: ConsentState;
192
+ isPending: boolean;
193
+ isGranted: boolean;
194
+ isDenied: boolean;
195
+ accept: () => void;
196
+ decline: () => void;
197
+ reset: () => void;
198
+ }
199
+ /**
200
+ * Legacy opt-in-era consent hook.
201
+ *
202
+ * @deprecated Since consent v2 tracking defaults ON (opt-out model): the state
203
+ * is never `pending`, so banner UIs gated on `isPending` never render. Use
204
+ * {@link useCookiePreferences} for footer "cookie preferences" controls.
205
+ * `accept` / `decline` still work and map to `optIn` / `optOut`.
206
+ */
207
+ declare function useConsent(): UseConsentResult;
208
+
209
+ interface CreateTrackingOptions<TRegistry extends TriggerRegistryConfig> {
210
+ /**
211
+ * Public tracking API key issued for this business.
212
+ *
213
+ * This key is safe to expose in browser code. Abuse is bounded by the
214
+ * server-side origin allowlist and rate limits.
215
+ */
216
+ apiKey: string;
217
+ /**
218
+ * Tracking endpoint base URL, usually ending in `/tracking`.
219
+ *
220
+ * The client posts events to `${endpoint}/events`.
221
+ */
222
+ endpoint: string;
223
+ /**
224
+ * Trigger registry. Determines which events the SDK fires automatically
225
+ * and which ones the consumer can fire manually via `trackEvent()`.
226
+ * `automatic.page_view` is required — every tracking install needs it.
227
+ */
228
+ triggers: TRegistry;
229
+ /**
230
+ * Deployment environment label reported in session context.
231
+ *
232
+ * Does not affect which gtag IDs are loaded — all configured IDs are
233
+ * loaded simultaneously. This value is purely for event tagging so the
234
+ * dashboard can filter by environment.
235
+ */
236
+ environment?: TrackingEnvironment;
237
+ /**
238
+ * When true, the typed client validates every `trackEvent()` metadata
239
+ * payload through the Zod schema before forwarding. Errors are thrown
240
+ * loudly. Leave off in prod; turn on in dev to catch shape bugs early.
241
+ */
242
+ debug?: boolean;
243
+ /**
244
+ * Phone-field display + default-country config, read by `usePhoneField` /
245
+ * `<PhoneField>`. Display is customizable; the transmitted value is always E.164.
246
+ */
247
+ phone?: PhoneConfig;
248
+ /**
249
+ * GAP28 / unified-goal: enable real-time on-site conversion firing. When set, the SDK
250
+ * fetches the per-business config from `cdnUrl` (optional offline `baked` fallback) and
251
+ * AUTOMATICALLY fires `gtag('event','conversion')` for any automatic event-goal
252
+ * (scroll/time/page-view/…) whose trigger threshold a detector crosses. Omit to keep events
253
+ * analytics-only. (Sale + manual-event firing lives in the server/browser sales client.)
254
+ */
255
+ conversionConfig?: {
256
+ cdnUrl: string;
257
+ baked?: ConversionConfig | null;
258
+ };
259
+ /**
260
+ * R2-authoritative config reference — `ARANOVA_TRACKING_CONFIG` from
261
+ * `tracking-cli gen`. Wins over `conversionConfig`. The object URL is composed
262
+ * from `businessId` + `environment` against the production CDN; spread in a
263
+ * `cdnBaseUrl` to read it from somewhere else, e.g.
264
+ * `{ ...ARANOVA_TRACKING_CONFIG, cdnBaseUrl: import.meta.env.VITE_ARANOVA_CDN_BASE_URL }`.
265
+ */
266
+ trackingConfig?: TrackingConfigReference;
267
+ }
268
+ interface TrackingProviderProps {
269
+ /**
270
+ * Optional Google Ads tag id, for example `AW-123456789`.
271
+ *
272
+ * If omitted and `gtagIds` is also omitted, no gtag script is loaded.
273
+ */
274
+ gtagId?: string;
275
+ /**
276
+ * Labelled map of Google Ads tag IDs. ALL are loaded simultaneously.
277
+ * When provided, `gtagId` is ignored.
278
+ */
279
+ gtagIds?: GtagEnvironmentMap;
280
+ /** Optional Meta Pixel id, for example `123456789012345`. */
281
+ metaPixelId?: string;
282
+ /**
283
+ * Labelled map of Meta Pixel IDs. ALL are loaded simultaneously.
284
+ * When provided, `metaPixelId` is ignored.
285
+ */
286
+ metaPixelIds?: MetaPixelEnvironmentMap;
287
+ /**
288
+ * Application tree that should have access to the scoped tracking client.
289
+ */
290
+ children: ReactNode;
291
+ }
292
+ interface CreateTrackingResult<TRegistry extends TriggerRegistryConfig> {
293
+ /**
294
+ * Provider component that initializes the page-level tracking client.
295
+ *
296
+ * Mount this once near the root of the React tree.
297
+ */
298
+ TrackingProvider: (props: TrackingProviderProps) => ReactNode;
299
+ /**
300
+ * Hook that returns the registry-typed tracking client.
301
+ *
302
+ * Import this hook from your local tracking module, not directly from the
303
+ * package root, so TypeScript preserves your trigger registry.
304
+ */
305
+ useTracking: () => TypedTrackingClient<TRegistry>;
306
+ }
307
+ declare function createTracking<TRegistry extends TriggerRegistryConfig>(options: CreateTrackingOptions<TRegistry>): CreateTrackingResult<TRegistry>;
308
+
309
+ /** Resolve the effective phone config (provider value or built-in defaults). */
310
+ declare function usePhoneConfig(): {
311
+ defaultCountry: CountryCode;
312
+ display: PhoneDisplayFormat;
313
+ };
314
+ interface UsePhoneFieldOptions {
315
+ defaultValue?: string;
316
+ /** Overrides the provider's `defaultCountry`. */
317
+ country?: CountryCode;
318
+ /** Overrides the provider's `display` (applied to the settled value on blur). */
319
+ display?: PhoneDisplayFormat;
320
+ /** Notified with the canonical E.164 (or `null`) on every change. */
321
+ onValueChange?: (e164: string | null) => void;
322
+ }
323
+ interface PhoneInputProps {
324
+ value: string;
325
+ onChange: (event: ChangeEvent<HTMLInputElement>) => void;
326
+ onBlur: (event: FocusEvent<HTMLInputElement>) => void;
327
+ type: "tel";
328
+ inputMode: "tel";
329
+ autoComplete: "tel";
330
+ }
331
+ interface PhoneFieldApi {
332
+ /** Display value for the `<input>` (live `AsYouType` while typing). */
333
+ value: string;
334
+ /** Canonical E.164 — what gets transmitted. `null` while invalid/incomplete. */
335
+ e164: string | null;
336
+ isValid: boolean;
337
+ /** Validation message, surfaced only after blur with non-empty invalid input. */
338
+ error: string | null;
339
+ parsed: ParsedPhone;
340
+ /** Spread onto an `<input>`: pre-wires value/onChange/onBlur/type/inputMode/autoComplete. */
341
+ inputProps: PhoneInputProps;
342
+ }
343
+ /** Headless phone field — the client owns the markup. */
344
+ declare function usePhoneField(opts?: UsePhoneFieldOptions): PhoneFieldApi;
345
+ interface PhoneFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "value" | "onChange"> {
346
+ country?: CountryCode;
347
+ /** Controlled display value. */
348
+ value?: string;
349
+ /** Uncontrolled initial value. */
350
+ defaultValue?: string;
351
+ /** Receives the native change event (RHF `register().onChange` or your own); the
352
+ * event's `target.value` is already `AsYouType`-formatted. */
353
+ onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
354
+ /** Receives the canonical E.164 (or `null`) on every change. */
355
+ onE164Change?: (e164: string | null) => void;
356
+ }
357
+ /**
358
+ * Batteries-included phone input. Composes identically with react-hook-form
359
+ * `{...register('phone')}` and with controlled state — the `AsYouType` +
360
+ * mutate-`e.target.value`-before-`onChange` technique lives inside, so RHF and
361
+ * controlled parents both receive the formatted value, and the wire value stays
362
+ * E.164.
363
+ */
364
+ declare const PhoneField: react.ForwardRefExoticComponent<PhoneFieldProps & react.RefAttributes<HTMLInputElement>>;
365
+
366
+ export { AdPlatformTracking, type AdPlatformTrackingProps, ConsentBanner, type ConsentBannerProps, type CreateTrackingOptions, type CreateTrackingResult, GoogleAdsTracking, type GoogleAdsTrackingProps, PhoneField, type PhoneFieldApi, type PhoneFieldProps, type PhoneInputProps, type TrackingProviderProps, type UseConsentResult, type UseCookiePreferencesOptions, type UseCookiePreferencesResult, type UsePhoneFieldOptions, createTracking, useConsent, useConsentState, useCookiePreferences, useGclid, usePhoneConfig, usePhoneField, useTrackingParams };