@bacano/sdk 1.1.19 → 1.2.1

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.
package/react/forms.js CHANGED
@@ -1,13 +1,27 @@
1
1
  // libs/sdk/src/react/forms.tsx
2
2
  import {
3
3
  useCallback as useCallback2,
4
- useEffect as useEffect2,
4
+ useEffect as useEffect3,
5
5
  useId,
6
- useMemo,
7
- useRef as useRef2,
6
+ useMemo as useMemo2,
7
+ useRef as useRef3,
8
8
  useState as useState2
9
9
  } from "react";
10
10
 
11
+ // libs/sdk/src/errors.ts
12
+ var WebsiteError = class extends Error {
13
+ code;
14
+ status;
15
+ retryAfterSeconds;
16
+ constructor(message, code = "WEBSITE_ERROR", options) {
17
+ super(message);
18
+ this.name = "WebsiteError";
19
+ this.code = code;
20
+ this.status = options?.status ?? null;
21
+ this.retryAfterSeconds = options?.retryAfterSeconds ?? null;
22
+ }
23
+ };
24
+
11
25
  // libs/sdk/src/react/form-field-control.tsx
12
26
  import { jsx, jsxs } from "react/jsx-runtime";
13
27
  function BacanoFormFieldControl(props) {
@@ -96,8 +110,110 @@ function BacanoFormFieldControl(props) {
96
110
  );
97
111
  }
98
112
 
99
- // libs/sdk/src/react/hooks.ts
100
- import { useCallback, useContext, useEffect, useRef, useState } from "react";
113
+ // libs/sdk/src/react/form-sections.tsx
114
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
115
+ function FormFields(props) {
116
+ return props.fields.map((field) => {
117
+ const controlId = `${props.idPrefix}-${field.key}`;
118
+ const value = props.values[field.key] ?? (field.type === "checkbox" ? false : field.type === "multi_select" ? [] : "");
119
+ return /* @__PURE__ */ jsxs2("div", { className: props.classNames?.field, children: [
120
+ /* @__PURE__ */ jsx2(
121
+ "label",
122
+ {
123
+ id: `${controlId}-label`,
124
+ htmlFor: field.type === "radio" ? void 0 : controlId,
125
+ className: props.classNames?.label,
126
+ children: field.label
127
+ }
128
+ ),
129
+ /* @__PURE__ */ jsx2(
130
+ BacanoFormFieldControl,
131
+ {
132
+ field,
133
+ id: controlId,
134
+ value,
135
+ className: props.classNames?.input,
136
+ onChange: (nextValue) => props.onChange(field.key, nextValue)
137
+ }
138
+ ),
139
+ field.helpText ? /* @__PURE__ */ jsx2("p", { className: props.classNames?.helpText, children: field.helpText }) : null
140
+ ] }, field.key);
141
+ });
142
+ }
143
+ function FormSections(props) {
144
+ return props.sections.map((section) => /* @__PURE__ */ jsxs2("section", { className: props.classNames?.section, children: [
145
+ /* @__PURE__ */ jsx2("h3", { className: props.classNames?.sectionTitle, children: section.title }),
146
+ section.description ? /* @__PURE__ */ jsx2("p", { className: props.classNames?.sectionDescription, children: section.description }) : null,
147
+ /* @__PURE__ */ jsx2(
148
+ FormFields,
149
+ {
150
+ fields: section.fields,
151
+ idPrefix: props.idPrefix,
152
+ values: props.values,
153
+ classNames: props.classNames,
154
+ onChange: props.onChange
155
+ }
156
+ )
157
+ ] }, section.key));
158
+ }
159
+
160
+ // libs/sdk/src/react/form-tracking.ts
161
+ import { useContext, useEffect, useMemo, useRef } from "react";
162
+
163
+ // libs/sdk/src/marketing/interactions.ts
164
+ function newMarketingEventId() {
165
+ return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `evt_${Date.now()}_${Math.random().toString(16).slice(2)}`;
166
+ }
167
+
168
+ // libs/sdk/src/marketing/form-interactions.ts
169
+ function createFormInteractionTracker(getRuntime, formKey) {
170
+ let visible = false;
171
+ let started = false;
172
+ let attempt = null;
173
+ const completedSteps = /* @__PURE__ */ new Set();
174
+ function emit(eventName, context = {}) {
175
+ try {
176
+ getRuntime().track({ eventName, formKey, ...context });
177
+ } catch {
178
+ }
179
+ }
180
+ return {
181
+ setVisible(next) {
182
+ if (next && !visible && getRuntime().enabled) emit("form_open");
183
+ visible = next;
184
+ },
185
+ start() {
186
+ if (started || !getRuntime().enabled) return;
187
+ started = true;
188
+ emit("form_start");
189
+ },
190
+ stepComplete(stepKey) {
191
+ if (completedSteps.has(stepKey) || !getRuntime().enabled) return;
192
+ completedSteps.add(stepKey);
193
+ emit("form_step_complete", { stepKey });
194
+ },
195
+ beginSubmit() {
196
+ if (attempt) return false;
197
+ attempt = newMarketingEventId();
198
+ emit("form_submit_attempt", { eventId: attempt });
199
+ return true;
200
+ },
201
+ fail(errorCategory) {
202
+ if (!attempt) return;
203
+ emit("form_submit_error", { eventId: attempt, errorCategory });
204
+ attempt = null;
205
+ },
206
+ complete(result) {
207
+ if (!attempt) return;
208
+ if (result?.accepted && typeof result.responseId === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
209
+ result.responseId
210
+ )) {
211
+ emit("form_submit_success", { eventId: result.responseId });
212
+ }
213
+ attempt = null;
214
+ }
215
+ };
216
+ }
101
217
 
102
218
  // libs/sdk/src/react/context-registry.ts
103
219
  import { createContext } from "react";
@@ -125,6 +241,37 @@ function getOrCreateReactContext(key, defaultValue) {
125
241
  return context;
126
242
  }
127
243
 
244
+ // libs/sdk/src/react/marketing-context.ts
245
+ var NOOP_MARKETING_RUNTIME = {
246
+ enabled: false,
247
+ track: () => void 0,
248
+ captureAttribution: () => null,
249
+ getAttribution: () => null,
250
+ destroy: () => void 0
251
+ };
252
+ var BacanoMarketingContext = getOrCreateReactContext(
253
+ "bacano-marketing-v1",
254
+ NOOP_MARKETING_RUNTIME
255
+ );
256
+
257
+ // libs/sdk/src/react/form-tracking.ts
258
+ function useBacanoFormTracking(formKey, options = {}) {
259
+ const runtime = useContext(BacanoMarketingContext);
260
+ const current = useRef(runtime);
261
+ current.current = runtime;
262
+ const tracker = useMemo(
263
+ () => createFormInteractionTracker(() => current.current, formKey),
264
+ [formKey]
265
+ );
266
+ useEffect(() => {
267
+ tracker.setVisible((options.visible ?? true) && runtime.enabled);
268
+ }, [tracker, options.visible, runtime.enabled]);
269
+ return tracker;
270
+ }
271
+
272
+ // libs/sdk/src/react/hooks.ts
273
+ import { useCallback, useContext as useContext2, useEffect as useEffect2, useRef as useRef2, useState } from "react";
274
+
128
275
  // libs/sdk/src/react/context.ts
129
276
  var BacanoReactContext = getOrCreateReactContext("bacano-client-v1", {
130
277
  client: null,
@@ -134,11 +281,11 @@ var BacanoReactContext = getOrCreateReactContext("bacano-client-v1", {
134
281
 
135
282
  // libs/sdk/src/react/hooks.ts
136
283
  function useBacanoState() {
137
- return useContext(BacanoReactContext);
284
+ return useContext2(BacanoReactContext);
138
285
  }
139
286
 
140
287
  // libs/sdk/src/react/forms.tsx
141
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
288
+ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
142
289
  var EMPTY_FORM_FIELDS = [];
143
290
  var EMPTY_FORM_SECTIONS = [];
144
291
  var EMPTY_FORM_STEPS = [];
@@ -151,30 +298,34 @@ function useBacanoForm(formKey, options) {
151
298
  const enabled = options?.enabled ?? true;
152
299
  const initialForm = options?.initialForm?.key === formKey ? options.initialForm : null;
153
300
  const [form, setForm] = useState2(initialForm);
154
- const formRef = useRef2(initialForm);
301
+ const formRef = useRef3(initialForm);
302
+ const requestVersion = useRef3(0);
155
303
  const [loading, setLoading] = useState2(enabled && !initialForm);
156
304
  const [error, setError] = useState2(null);
157
305
  const load = useCallback2(
158
306
  async (force = false) => {
159
307
  if (!enabled || !client) return;
308
+ const version = ++requestVersion.current;
160
309
  setLoading(formRef.current === null);
161
310
  setError(null);
162
311
  try {
163
312
  const nextForm = await client.forms.getDefinition(formKey, { force });
313
+ if (version !== requestVersion.current) return;
164
314
  formRef.current = nextForm;
165
315
  setForm(nextForm);
166
316
  } catch (loadError) {
317
+ if (version !== requestVersion.current) return;
167
318
  if (!formRef.current) setForm(null);
168
319
  setError(
169
320
  loadError instanceof Error ? loadError : new Error(String(loadError))
170
321
  );
171
322
  } finally {
172
- setLoading(false);
323
+ if (version === requestVersion.current) setLoading(false);
173
324
  }
174
325
  },
175
326
  [client, enabled, formKey]
176
327
  );
177
- useEffect2(() => {
328
+ useEffect3(() => {
178
329
  if (!enabled) {
179
330
  formRef.current = null;
180
331
  setForm(null);
@@ -183,76 +334,38 @@ function useBacanoForm(formKey, options) {
183
334
  return;
184
335
  }
185
336
  if (client) void load();
337
+ return () => {
338
+ requestVersion.current += 1;
339
+ };
186
340
  }, [client, enabled, load]);
187
341
  return {
188
- form,
189
- loading: enabled && form === null && (clientLoading || loading),
342
+ form: enabled ? form?.key === formKey ? form : initialForm : null,
343
+ loading: enabled && form?.key !== formKey && !initialForm && (clientLoading || loading),
190
344
  error: clientError ?? error,
191
345
  refresh: async () => load(true)
192
346
  };
193
347
  }
194
- function FormFields(props) {
195
- return props.fields.map((field) => {
196
- const controlId = `${props.idPrefix}-${field.key}`;
197
- const value = props.values[field.key] ?? (field.type === "checkbox" ? false : field.type === "multi_select" ? [] : "");
198
- return /* @__PURE__ */ jsxs2("div", { className: props.classNames?.field, children: [
199
- /* @__PURE__ */ jsx2(
200
- "label",
201
- {
202
- id: `${controlId}-label`,
203
- htmlFor: field.type === "radio" ? void 0 : controlId,
204
- className: props.classNames?.label,
205
- children: field.label
206
- }
207
- ),
208
- /* @__PURE__ */ jsx2(
209
- BacanoFormFieldControl,
210
- {
211
- field,
212
- id: controlId,
213
- value,
214
- className: props.classNames?.input,
215
- onChange: (nextValue) => props.onChange(field.key, nextValue)
216
- }
217
- ),
218
- field.helpText ? /* @__PURE__ */ jsx2("p", { className: props.classNames?.helpText, children: field.helpText }) : null
219
- ] }, field.key);
220
- });
221
- }
222
- function FormSections(props) {
223
- return props.sections.map((section) => /* @__PURE__ */ jsxs2("section", { className: props.classNames?.section, children: [
224
- /* @__PURE__ */ jsx2("h3", { className: props.classNames?.sectionTitle, children: section.title }),
225
- section.description ? /* @__PURE__ */ jsx2("p", { className: props.classNames?.sectionDescription, children: section.description }) : null,
226
- /* @__PURE__ */ jsx2(
227
- FormFields,
228
- {
229
- fields: section.fields,
230
- idPrefix: props.idPrefix,
231
- values: props.values,
232
- classNames: props.classNames,
233
- onChange: props.onChange
234
- }
235
- )
236
- ] }, section.key));
237
- }
238
- function BacanoForm(props) {
348
+ function BacanoFormInstance(props) {
239
349
  const reactId = useId();
240
350
  const idPrefix = `${props.formKey}-${reactId.replace(/:/g, "")}`;
241
351
  const { client } = useBacanoState();
242
352
  const { form, loading, error } = useBacanoForm(props.formKey, {
243
353
  initialForm: props.initialForm
244
354
  });
245
- const [values, setValues] = useState2({});
355
+ const [internalValues, setValues] = useState2({});
246
356
  const [step, setStep] = useState2(0);
247
357
  const [submitting, setSubmitting] = useState2(false);
248
358
  const [submitted, setSubmitted] = useState2(false);
249
359
  const [submissionError, setSubmissionError] = useState2(null);
250
360
  const [honeypot, setHoneypot] = useState2("");
251
- const idempotencyKey = useRef2(crypto.randomUUID());
361
+ const tracking = useBacanoFormTracking(props.formKey, {
362
+ visible: (props.visible ?? true) && !loading && form?.status === "ACTIVE" && !submitted
363
+ });
364
+ const idempotencyKey = useRef3(crypto.randomUUID());
252
365
  const fields = form?.definition.fields ?? EMPTY_FORM_FIELDS;
253
366
  const sections = form?.definition.sections ?? EMPTY_FORM_SECTIONS;
254
367
  const steps = form?.definition.steps ?? EMPTY_FORM_STEPS;
255
- const fieldKeys = useMemo(
368
+ const fieldKeys = useMemo2(
256
369
  () => new Set(
257
370
  [
258
371
  ...fields,
@@ -265,7 +378,12 @@ function BacanoForm(props) {
265
378
  ),
266
379
  [fields, sections, steps]
267
380
  );
268
- useEffect2(() => {
381
+ const values = Object.fromEntries(
382
+ Object.entries(props.values ?? internalValues).filter(
383
+ ([key]) => fieldKeys.has(key)
384
+ )
385
+ );
386
+ useEffect3(() => {
269
387
  setStep(0);
270
388
  setValues(
271
389
  (current) => Object.fromEntries(
@@ -277,23 +395,37 @@ function BacanoForm(props) {
277
395
  setHoneypot("");
278
396
  idempotencyKey.current = crypto.randomUUID();
279
397
  }, [fieldKeys, form?.version]);
280
- if (loading) return /* @__PURE__ */ jsx2(Fragment, { children: props.loadingFallback ?? null });
398
+ if (loading) return /* @__PURE__ */ jsx3(Fragment, { children: props.loadingFallback ?? null });
281
399
  if (error && !form)
282
- return /* @__PURE__ */ jsx2(Fragment, { children: props.errorFallback?.(error) ?? props.unavailableFallback ?? null });
283
- if (!form) return /* @__PURE__ */ jsx2(Fragment, { children: props.unavailableFallback ?? null });
400
+ return /* @__PURE__ */ jsx3(Fragment, { children: props.errorFallback?.(error) ?? props.unavailableFallback ?? null });
401
+ if (!form) return /* @__PURE__ */ jsx3(Fragment, { children: props.unavailableFallback ?? null });
284
402
  if (form.status === "PAUSED") {
285
- return /* @__PURE__ */ jsx2("div", { className: props.classNames?.message, "data-bacano-form-unavailable": true, children: props.unavailableFallback ?? form.definition.unavailableMessage });
403
+ return /* @__PURE__ */ jsx3("div", { className: props.classNames?.message, "data-bacano-form-unavailable": true, children: props.unavailableFallback ?? form.definition.unavailableMessage });
286
404
  }
287
405
  if (submitted) {
288
- return /* @__PURE__ */ jsx2("div", { className: props.classNames?.message, "data-bacano-form-success": true, children: form.definition.successMessage });
406
+ return /* @__PURE__ */ jsx3("div", { className: props.classNames?.message, "data-bacano-form-success": true, children: form.definition.successMessage });
289
407
  }
290
408
  const isMultiStep = steps.length > 0;
291
409
  const activeStep = isMultiStep ? steps[step] : null;
292
410
  const isLastStep = !isMultiStep || step === steps.length - 1;
293
- const setFieldValue = (key, value) => setValues((current) => ({ ...current, [key]: value }));
411
+ const setFieldValue = (key, value) => {
412
+ if (value !== "" && value !== false && (!Array.isArray(value) || value.length > 0))
413
+ tracking.start();
414
+ const nextValues = { ...values, [key]: value };
415
+ setValues(nextValues);
416
+ props.onValuesChange?.(nextValues);
417
+ };
294
418
  const submit = async (event) => {
295
419
  event.preventDefault();
420
+ if (submitting || submitted) return;
421
+ if (isLastStep && !tracking.beginSubmit()) return;
422
+ if (!event.currentTarget.checkValidity()) {
423
+ if (isLastStep) tracking.fail("validation");
424
+ event.currentTarget.reportValidity();
425
+ return;
426
+ }
296
427
  if (!isLastStep) {
428
+ if (activeStep) tracking.stepComplete(activeStep.key);
297
429
  setStep((current) => current + 1);
298
430
  return;
299
431
  }
@@ -301,8 +433,12 @@ function BacanoForm(props) {
301
433
  setSubmissionError(null);
302
434
  try {
303
435
  let responseId = null;
436
+ let officialResult;
304
437
  if (props.onSubmit) {
305
- await props.onSubmit(values, form);
438
+ officialResult = await props.onSubmit(values, form);
439
+ if (officialResult && !officialResult.accepted)
440
+ throw new Error(officialResult.message);
441
+ responseId = officialResult?.responseId ?? null;
306
442
  } else {
307
443
  if (!client) throw new Error("Bacano client is not ready");
308
444
  const result = await client.forms.submitResponse({
@@ -314,11 +450,16 @@ function BacanoForm(props) {
314
450
  honeypot
315
451
  });
316
452
  if (!result.accepted) throw new Error(result.message);
453
+ officialResult = result;
317
454
  responseId = result.responseId;
318
455
  }
456
+ tracking.complete(officialResult);
319
457
  setSubmitted(true);
320
458
  props.onSubmitted?.(responseId);
321
459
  } catch (submitError) {
460
+ tracking.fail(
461
+ submitError instanceof WebsiteError && submitError.code === "NETWORK_ERROR" ? "network" : "rejected"
462
+ );
322
463
  setSubmissionError(
323
464
  submitError instanceof Error ? submitError : new Error(String(submitError))
324
465
  );
@@ -326,15 +467,16 @@ function BacanoForm(props) {
326
467
  setSubmitting(false);
327
468
  }
328
469
  };
329
- return /* @__PURE__ */ jsxs2(
470
+ return /* @__PURE__ */ jsxs3(
330
471
  "form",
331
472
  {
473
+ noValidate: true,
332
474
  className: props.classNames?.root,
333
475
  "data-bacano-form": form.key,
334
476
  "data-bacano-form-version": form.version,
335
477
  onSubmit: (event) => void submit(event),
336
478
  children: [
337
- /* @__PURE__ */ jsxs2(
479
+ /* @__PURE__ */ jsxs3(
338
480
  "div",
339
481
  {
340
482
  "aria-hidden": "true",
@@ -346,8 +488,8 @@ function BacanoForm(props) {
346
488
  clip: "rect(0 0 0 0)"
347
489
  },
348
490
  children: [
349
- /* @__PURE__ */ jsx2("label", { htmlFor: `${form.key}-company-website`, children: "Empresa" }),
350
- /* @__PURE__ */ jsx2(
491
+ /* @__PURE__ */ jsx3("label", { htmlFor: `${form.key}-company-website`, children: "Empresa" }),
492
+ /* @__PURE__ */ jsx3(
351
493
  "input",
352
494
  {
353
495
  id: `${form.key}-company-website`,
@@ -361,12 +503,12 @@ function BacanoForm(props) {
361
503
  ]
362
504
  }
363
505
  ),
364
- /* @__PURE__ */ jsx2("h2", { className: props.classNames?.title, children: form.name }),
365
- form.description ? /* @__PURE__ */ jsx2("p", { className: props.classNames?.description, children: form.description }) : null,
366
- activeStep ? /* @__PURE__ */ jsxs2("section", { className: props.classNames?.step, "data-bacano-form-step": true, children: [
367
- /* @__PURE__ */ jsx2("h3", { className: props.classNames?.stepTitle, children: activeStep.title }),
368
- activeStep.description ? /* @__PURE__ */ jsx2("p", { className: props.classNames?.stepDescription, children: activeStep.description }) : null,
369
- /* @__PURE__ */ jsx2(
506
+ /* @__PURE__ */ jsx3("h2", { className: props.classNames?.title, children: form.name }),
507
+ form.description ? /* @__PURE__ */ jsx3("p", { className: props.classNames?.description, children: form.description }) : null,
508
+ activeStep ? /* @__PURE__ */ jsxs3("section", { className: props.classNames?.step, "data-bacano-form-step": true, children: [
509
+ /* @__PURE__ */ jsx3("h3", { className: props.classNames?.stepTitle, children: activeStep.title }),
510
+ activeStep.description ? /* @__PURE__ */ jsx3("p", { className: props.classNames?.stepDescription, children: activeStep.description }) : null,
511
+ /* @__PURE__ */ jsx3(
370
512
  FormFields,
371
513
  {
372
514
  fields: activeStep.fields,
@@ -376,7 +518,7 @@ function BacanoForm(props) {
376
518
  onChange: setFieldValue
377
519
  }
378
520
  ),
379
- /* @__PURE__ */ jsx2(
521
+ /* @__PURE__ */ jsx3(
380
522
  FormSections,
381
523
  {
382
524
  sections: activeStep.sections,
@@ -386,8 +528,8 @@ function BacanoForm(props) {
386
528
  onChange: setFieldValue
387
529
  }
388
530
  )
389
- ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
390
- /* @__PURE__ */ jsx2(
531
+ ] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
532
+ /* @__PURE__ */ jsx3(
391
533
  FormFields,
392
534
  {
393
535
  fields,
@@ -397,7 +539,7 @@ function BacanoForm(props) {
397
539
  onChange: setFieldValue
398
540
  }
399
541
  ),
400
- /* @__PURE__ */ jsx2(
542
+ /* @__PURE__ */ jsx3(
401
543
  FormSections,
402
544
  {
403
545
  sections,
@@ -408,8 +550,8 @@ function BacanoForm(props) {
408
550
  }
409
551
  )
410
552
  ] }),
411
- /* @__PURE__ */ jsxs2("div", { className: props.classNames?.actions, children: [
412
- isMultiStep && step > 0 ? /* @__PURE__ */ jsx2(
553
+ /* @__PURE__ */ jsxs3("div", { className: props.classNames?.actions, children: [
554
+ isMultiStep && step > 0 ? /* @__PURE__ */ jsx3(
413
555
  "button",
414
556
  {
415
557
  type: "button",
@@ -417,7 +559,7 @@ function BacanoForm(props) {
417
559
  children: "Anterior"
418
560
  }
419
561
  ) : null,
420
- /* @__PURE__ */ jsx2(
562
+ /* @__PURE__ */ jsx3(
421
563
  "button",
422
564
  {
423
565
  type: "submit",
@@ -427,7 +569,7 @@ function BacanoForm(props) {
427
569
  }
428
570
  )
429
571
  ] }),
430
- submissionError ? /* @__PURE__ */ jsx2(
572
+ submissionError ? /* @__PURE__ */ jsx3(
431
573
  "div",
432
574
  {
433
575
  role: "alert",
@@ -440,7 +582,11 @@ function BacanoForm(props) {
440
582
  }
441
583
  );
442
584
  }
585
+ function BacanoForm(props) {
586
+ return /* @__PURE__ */ jsx3(BacanoFormInstance, { ...props }, props.formKey);
587
+ }
443
588
  export {
444
589
  BacanoForm,
445
- useBacanoForm
590
+ useBacanoForm,
591
+ useBacanoFormTracking
446
592
  };
@@ -6,5 +6,6 @@ export interface BacanoMarketingProviderProps {
6
6
  children: ReactNode;
7
7
  scriptLoadStrategy?: WebsiteMarketingScriptLoadStrategy;
8
8
  diagnostic?: (diagnostic: WebsiteMarketingDiagnostic) => void;
9
+ measurementAllowed?: boolean;
9
10
  }
10
- export declare function BacanoMarketingProvider({ publicConfig, children, scriptLoadStrategy, diagnostic, }: BacanoMarketingProviderProps): JSX.Element;
11
+ export declare function BacanoMarketingProvider({ publicConfig, children, scriptLoadStrategy, diagnostic, measurementAllowed, }: BacanoMarketingProviderProps): JSX.Element;