@brandlab-digital/site-next 1.3.1 → 2.1.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.
@@ -75,11 +75,6 @@ export declare function trackPhoneLinkClick(input: {
75
75
  pagePath: string;
76
76
  placement: PhoneCallPlacement;
77
77
  }, config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'>): boolean;
78
- /** @deprecated Use trackPhoneLinkClick. This alias emits only phone_link_click. */
79
- export declare function trackPhoneCall(input: {
80
- pagePath: string;
81
- placement: PhoneCallPlacement;
82
- }, config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'>): boolean;
83
78
  export declare const LEAD_FORM_ERROR_STAGES: readonly ["validation", "submission", "delivery", "unknown"];
84
79
  export type LeadFormErrorStage = (typeof LEAD_FORM_ERROR_STAGES)[number];
85
80
  export declare const LEAD_CTA_PLACEMENTS: readonly ["header", "footer", "hero", "section", "navigation", "floating", "page"];
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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"}
package/dist/analytics.js CHANGED
@@ -175,10 +175,6 @@ export function trackPhoneLinkClick(input, config) {
175
175
  },
176
176
  });
177
177
  }
178
- /** @deprecated Use trackPhoneLinkClick. This alias emits only phone_link_click. */
179
- export function trackPhoneCall(input, config) {
180
- return trackPhoneLinkClick(input, config);
181
- }
182
178
  export const LEAD_FORM_ERROR_STAGES = [
183
179
  'validation',
184
180
  'submission',
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport {\n defineAnalyticsContract,\n normalizeEnhancedConversionEmail,\n normalizeEnhancedConversionPhone,\n sendBrandlabAnalyticsEvent,\n sendContactFormConversion,\n type BrandlabAnalyticsContract,\n type ContactFormConversionResult,\n type GtagTransport,\n} from '@brandlab-digital/site-core/analytics'\nimport type { ContactActionResult } from '@brandlab-digital/site-core/contact'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport type { BrandlabContactDefinition } from './contact/shared.js'\n\nexport interface BrandlabBrowserAnalyticsConfig {\n enabled: boolean\n webVitalsEnabled?: boolean\n leadDiagnosticsEnabled?: boolean\n enhancedConversionsEnabled?: boolean\n measurementId?: string | null\n googleAdsConversionId?: string | null\n googleAdsConversionLabel?: string | null\n gtag?: GtagTransport\n}\n\n/**\n * Public analytics values that a client bundle must bind through direct,\n * statically analyzable `process.env.NEXT_PUBLIC_*` property access.\n */\nexport interface BrandlabBrowserAnalyticsPublicValues {\n measurementId: string | null | undefined\n googleAdsConversionId: string | null | undefined\n googleAdsConversionLabel: string | null | undefined\n}\n\nexport interface SafeContactAnalyticsParams {\n page_template?: string\n service_slug?: string\n location_slug?: string\n}\n\nexport interface SafeContactAdsParams {\n currency?: string\n value?: number\n}\n\nexport const PHONE_CALL_PLACEMENTS = [\n 'header',\n 'footer',\n 'hero',\n 'cta',\n 'fab',\n 'contact',\n 'location',\n 'page',\n] as const\n\nexport type PhoneCallPlacement = (typeof PHONE_CALL_PLACEMENTS)[number]\n\nexport function resolveBrowserAnalyticsConfig(\n contract: BrandlabAnalyticsContract,\n publicValues: BrandlabBrowserAnalyticsPublicValues,\n options: { enabled: boolean; gtag?: GtagTransport },\n): BrandlabBrowserAnalyticsConfig {\n defineAnalyticsContract(contract)\n return {\n enabled: options.enabled,\n webVitalsEnabled: contract.webVitals,\n leadDiagnosticsEnabled: contract.leadDiagnostics?.enabled === true,\n enhancedConversionsEnabled:\n contract.googleAds?.enhancedConversions?.mode === 'consent-required',\n measurementId: publicValues.measurementId,\n googleAdsConversionId: contract.googleAds\n ? publicValues.googleAdsConversionId\n : undefined,\n googleAdsConversionLabel: contract.googleAds\n ? publicValues.googleAdsConversionLabel\n : undefined,\n gtag: options.gtag,\n }\n}\n\nexport type BrandlabWebVitalName = 'CLS' | 'FCP' | 'INP' | 'LCP' | 'TTFB'\nexport type BrandlabWebVitalRating = 'good' | 'needs-improvement' | 'poor'\n\nexport interface BrandlabWebVitalMetric {\n name: BrandlabWebVitalName\n value: number\n delta: number\n rating: BrandlabWebVitalRating\n navigationType?: string\n}\n\nconst WEB_VITAL_NAMES = new Set<BrandlabWebVitalName>(['CLS', 'FCP', 'INP', 'LCP', 'TTFB'])\nconst WEB_VITAL_RATINGS = new Set<BrandlabWebVitalRating>([\n 'good',\n 'needs-improvement',\n 'poor',\n])\nconst WEB_VITAL_NAVIGATION_TYPES = new Set([\n 'navigate',\n 'reload',\n 'back-forward',\n 'back-forward-cache',\n 'prerender',\n 'restore',\n])\n\n/** Privacy-safe callback for Next's useReportWebVitals hook. */\nexport function reportBrandlabWebVital(\n metric: BrandlabWebVitalMetric,\n config: Pick<\n BrandlabBrowserAnalyticsConfig,\n 'enabled' | 'webVitalsEnabled' | 'measurementId' | 'gtag'\n >,\n) {\n if (\n !WEB_VITAL_NAMES.has(metric.name) ||\n !WEB_VITAL_RATINGS.has(metric.rating) ||\n !Number.isFinite(metric.value) ||\n metric.value < 0 ||\n !Number.isFinite(metric.delta)\n ) {\n return false\n }\n const navigationType = WEB_VITAL_NAVIGATION_TYPES.has(metric.navigationType ?? '')\n ? metric.navigationType\n : undefined\n return sendBrandlabAnalyticsEvent({\n enabled: config.enabled && config.webVitalsEnabled !== false,\n measurementId: config.measurementId,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName: 'web_vital',\n params: {\n metric_name: metric.name,\n metric_value: metric.value,\n metric_delta: metric.delta,\n metric_rating: metric.rating,\n ...(navigationType ? { navigation_type: navigationType } : {}),\n },\n })\n}\n\nexport function createBrandlabWebVitalsReporter(\n config: Pick<\n BrandlabBrowserAnalyticsConfig,\n 'enabled' | 'webVitalsEnabled' | 'measurementId' | 'gtag'\n >,\n) {\n return (metric: BrandlabWebVitalMetric) => reportBrandlabWebVital(metric, config)\n}\n\nexport function getBrowserGtag(win: Window = window): GtagTransport | undefined {\n const candidate = (win as Window & { gtag?: GtagTransport }).gtag\n return typeof candidate === 'function' ? candidate : undefined\n}\n\nfunction safePagePath(value: string) {\n const path = value.trim().split(/[?#]/, 1)[0]\n if (!path || path.length > 500) return '/'\n try {\n return normalizeBrandlabRoutePath(path)\n } catch {\n return '/'\n }\n}\n\nfunction safeSlug(value: string | undefined) {\n const normalized = value?.trim().toLowerCase()\n return normalized && /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(normalized) && normalized.length <= 80\n ? normalized\n : undefined\n}\n\nfunction sanitizeContactParams(params: SafeContactAnalyticsParams | undefined) {\n return {\n ...(safeSlug(params?.page_template)\n ? { page_template: safeSlug(params?.page_template) }\n : {}),\n ...(safeSlug(params?.service_slug)\n ? { service_slug: safeSlug(params?.service_slug) }\n : {}),\n ...(safeSlug(params?.location_slug)\n ? { location_slug: safeSlug(params?.location_slug) }\n : {}),\n }\n}\n\nfunction sanitizeAdsParams(params: SafeContactAdsParams | undefined) {\n return {\n ...(params?.currency && /^[A-Z]{3}$/.test(params.currency)\n ? { currency: params.currency }\n : {}),\n ...(typeof params?.value === 'number' && Number.isFinite(params.value) && params.value >= 0\n ? { value: params.value }\n : {}),\n }\n}\n\nexport function isTrackableContactActionResult(\n result: ContactActionResult,\n): result is Extract<ContactActionResult, { ok: true; accepted: true }> {\n return result.ok && result.accepted && result.trackConversion\n}\n\nexport function trackDeliveredContact(\n result: ContactActionResult,\n config: BrandlabBrowserAnalyticsConfig,\n options: {\n pagePath: string\n params?: SafeContactAnalyticsParams\n adsParams?: SafeContactAdsParams\n },\n): ContactFormConversionResult {\n if (!isTrackableContactActionResult(result)) {\n return { ga4Sent: false, enhancedConversionSent: false, adsConversionSent: false }\n }\n return sendContactFormConversion({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n pagePath: safePagePath(options.pagePath),\n submissionId: result.confirmationId,\n params: sanitizeContactParams(options.params),\n adsParams: sanitizeAdsParams(options.adsParams),\n })\n}\n\nfunction explicitRoleValue(\n definition: BrandlabContactDefinition,\n formData: FormData,\n role: 'email' | 'phone',\n) {\n const field = definition.fields.find((candidate) => candidate.role === role)\n if (!field) return undefined\n const value = formData.get(field.name)\n return typeof value === 'string' ? value : undefined\n}\n\n/**\n * Sends Enhanced Conversions only after provider acceptance. Email and phone may\n * only be sourced from fields with explicit declarative roles; they never enter\n * the GA4 parameter object.\n */\nexport function trackDeliveredContactWithEnhancedConversions(\n result: ContactActionResult,\n config: BrandlabBrowserAnalyticsConfig,\n options: {\n pagePath: string\n definition: BrandlabContactDefinition\n formData: FormData\n /** Live Consent Mode decision for ad_user_data; absence is deny. */\n adUserDataConsent: boolean\n params?: SafeContactAnalyticsParams\n adsParams?: SafeContactAdsParams\n },\n): ContactFormConversionResult {\n if (!isTrackableContactActionResult(result)) {\n return { ga4Sent: false, enhancedConversionSent: false, adsConversionSent: false }\n }\n const email = normalizeEnhancedConversionEmail(\n explicitRoleValue(options.definition, options.formData, 'email'),\n )\n const phone = normalizeEnhancedConversionPhone(\n explicitRoleValue(options.definition, options.formData, 'phone'),\n )\n return sendContactFormConversion({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n pagePath: safePagePath(options.pagePath),\n submissionId: result.confirmationId,\n params: sanitizeContactParams(options.params),\n adsParams: sanitizeAdsParams(options.adsParams),\n enhancedConversionsEnabled: config.enhancedConversionsEnabled === true,\n adUserDataConsent: options.adUserDataConsent === true,\n ...((email || phone) ? { enhancedConversion: { email, phone } } : {}),\n })\n}\n\nexport function trackPhoneLinkClick(\n input: { pagePath: string; placement: PhoneCallPlacement },\n config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'>,\n) {\n if (!PHONE_CALL_PLACEMENTS.includes(input.placement)) return false\n return sendBrandlabAnalyticsEvent({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName: 'phone_link_click',\n params: {\n event_category: 'contact_interaction',\n page_path: safePagePath(input.pagePath),\n placement: input.placement,\n },\n })\n}\n\n/** @deprecated Use trackPhoneLinkClick. This alias emits only phone_link_click. */\nexport function trackPhoneCall(\n input: { pagePath: string; placement: PhoneCallPlacement },\n config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'>,\n) {\n return trackPhoneLinkClick(input, config)\n}\n\nexport const LEAD_FORM_ERROR_STAGES = [\n 'validation',\n 'submission',\n 'delivery',\n 'unknown',\n] as const\nexport type LeadFormErrorStage = (typeof LEAD_FORM_ERROR_STAGES)[number]\n\nexport const LEAD_CTA_PLACEMENTS = [\n 'header',\n 'footer',\n 'hero',\n 'section',\n 'navigation',\n 'floating',\n 'page',\n] as const\nexport type LeadCtaPlacement = (typeof LEAD_CTA_PLACEMENTS)[number]\n\ntype LeadDiagnosticConfig = Pick<\n BrandlabBrowserAnalyticsConfig,\n 'enabled' | 'leadDiagnosticsEnabled' | 'measurementId' | 'gtag'\n>\n\nexport function trackLeadFormStart(\n input: { pagePath: string; formId: string; pageTemplate?: string },\n config: LeadDiagnosticConfig,\n) {\n const formId = safeSlug(input.formId)\n if (!formId) return false\n return sendLeadDiagnosticEvent('lead_form_start', {\n form_id: formId,\n page_path: safePagePath(input.pagePath),\n ...(safeSlug(input.pageTemplate) ? { page_template: safeSlug(input.pageTemplate) } : {}),\n }, config)\n}\n\nexport function trackLeadFormError(\n input: {\n pagePath: string\n formId: string\n stage: LeadFormErrorStage\n errorCount: number\n },\n config: LeadDiagnosticConfig,\n) {\n const formId = safeSlug(input.formId)\n if (\n !formId ||\n !LEAD_FORM_ERROR_STAGES.includes(input.stage) ||\n !Number.isInteger(input.errorCount) ||\n input.errorCount < 1 ||\n input.errorCount > 50\n ) {\n return false\n }\n return sendLeadDiagnosticEvent('lead_form_error', {\n form_id: formId,\n page_path: safePagePath(input.pagePath),\n error_stage: input.stage,\n error_count: input.errorCount,\n }, config)\n}\n\nexport function trackLeadCtaClick(\n input: {\n pagePath: string\n ctaId: string\n placement: LeadCtaPlacement\n },\n config: LeadDiagnosticConfig,\n) {\n const ctaId = safeSlug(input.ctaId)\n if (!ctaId || !LEAD_CTA_PLACEMENTS.includes(input.placement)) return false\n return sendLeadDiagnosticEvent('lead_cta_click', {\n cta_id: ctaId,\n page_path: safePagePath(input.pagePath),\n placement: input.placement,\n }, config)\n}\n\nfunction sendLeadDiagnosticEvent(\n eventName: 'lead_form_start' | 'lead_form_error' | 'lead_cta_click',\n params: Record<string, unknown>,\n config: LeadDiagnosticConfig,\n) {\n return sendBrandlabAnalyticsEvent({\n enabled: config.enabled && config.leadDiagnosticsEnabled === true,\n measurementId: config.measurementId,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName,\n params,\n })\n}\n\nfunction safeAdditionalEventValue(\n value: unknown,\n policy: NonNullable<BrandlabAnalyticsContract['additionalEvents']>[number]['parameters'][number],\n) {\n if (policy.type === 'boolean') return typeof value === 'boolean' ? value : undefined\n if (policy.type === 'count') {\n const minimum = policy.minimum ?? 0\n const maximum = policy.maximum ?? 100_000\n return typeof value === 'number' && Number.isInteger(value) && value >= minimum && value <= maximum\n ? value\n : undefined\n }\n if (typeof value !== 'string') return undefined\n const normalized = value.trim()\n if (policy.type === 'enum') return policy.values.includes(normalized) ? normalized : undefined\n if (!/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/.test(normalized) || normalized.length > 80) {\n return undefined\n }\n const digits = normalized.replace(/\\D/g, '')\n return digits.length >= 4 || /^[a-f0-9]{24,}$/.test(normalized)\n ? undefined\n : normalized\n}\n\nexport function trackBrandlabBrowserEvent(\n eventName: string,\n params: Record<string, unknown>,\n config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'> & {\n contract: BrandlabAnalyticsContract\n },\n) {\n defineAnalyticsContract(config.contract)\n const event = config.contract.additionalEvents?.find(\n (candidate) => candidate.name === eventName,\n )\n if (!event) return false\n const safeParams = Object.fromEntries(\n Object.entries(params).flatMap(([key, value]) => {\n const policy = event.parameters.find((candidate) => candidate.key === key)\n if (!policy) return []\n const safeValue = safeAdditionalEventValue(value, policy)\n return safeValue === undefined ? [] : [[key, safeValue]]\n }),\n )\n return sendBrandlabAnalyticsEvent({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName,\n params: safeParams,\n })\n}\n"]}
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport {\n defineAnalyticsContract,\n normalizeEnhancedConversionEmail,\n normalizeEnhancedConversionPhone,\n sendBrandlabAnalyticsEvent,\n sendContactFormConversion,\n type BrandlabAnalyticsContract,\n type ContactFormConversionResult,\n type GtagTransport,\n} from '@brandlab-digital/site-core/analytics'\nimport type { ContactActionResult } from '@brandlab-digital/site-core/contact'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport type { BrandlabContactDefinition } from './contact/shared.js'\n\nexport interface BrandlabBrowserAnalyticsConfig {\n enabled: boolean\n webVitalsEnabled?: boolean\n leadDiagnosticsEnabled?: boolean\n enhancedConversionsEnabled?: boolean\n measurementId?: string | null\n googleAdsConversionId?: string | null\n googleAdsConversionLabel?: string | null\n gtag?: GtagTransport\n}\n\n/**\n * Public analytics values that a client bundle must bind through direct,\n * statically analyzable `process.env.NEXT_PUBLIC_*` property access.\n */\nexport interface BrandlabBrowserAnalyticsPublicValues {\n measurementId: string | null | undefined\n googleAdsConversionId: string | null | undefined\n googleAdsConversionLabel: string | null | undefined\n}\n\nexport interface SafeContactAnalyticsParams {\n page_template?: string\n service_slug?: string\n location_slug?: string\n}\n\nexport interface SafeContactAdsParams {\n currency?: string\n value?: number\n}\n\nexport const PHONE_CALL_PLACEMENTS = [\n 'header',\n 'footer',\n 'hero',\n 'cta',\n 'fab',\n 'contact',\n 'location',\n 'page',\n] as const\n\nexport type PhoneCallPlacement = (typeof PHONE_CALL_PLACEMENTS)[number]\n\nexport function resolveBrowserAnalyticsConfig(\n contract: BrandlabAnalyticsContract,\n publicValues: BrandlabBrowserAnalyticsPublicValues,\n options: { enabled: boolean; gtag?: GtagTransport },\n): BrandlabBrowserAnalyticsConfig {\n defineAnalyticsContract(contract)\n return {\n enabled: options.enabled,\n webVitalsEnabled: contract.webVitals,\n leadDiagnosticsEnabled: contract.leadDiagnostics?.enabled === true,\n enhancedConversionsEnabled:\n contract.googleAds?.enhancedConversions?.mode === 'consent-required',\n measurementId: publicValues.measurementId,\n googleAdsConversionId: contract.googleAds\n ? publicValues.googleAdsConversionId\n : undefined,\n googleAdsConversionLabel: contract.googleAds\n ? publicValues.googleAdsConversionLabel\n : undefined,\n gtag: options.gtag,\n }\n}\n\nexport type BrandlabWebVitalName = 'CLS' | 'FCP' | 'INP' | 'LCP' | 'TTFB'\nexport type BrandlabWebVitalRating = 'good' | 'needs-improvement' | 'poor'\n\nexport interface BrandlabWebVitalMetric {\n name: BrandlabWebVitalName\n value: number\n delta: number\n rating: BrandlabWebVitalRating\n navigationType?: string\n}\n\nconst WEB_VITAL_NAMES = new Set<BrandlabWebVitalName>(['CLS', 'FCP', 'INP', 'LCP', 'TTFB'])\nconst WEB_VITAL_RATINGS = new Set<BrandlabWebVitalRating>([\n 'good',\n 'needs-improvement',\n 'poor',\n])\nconst WEB_VITAL_NAVIGATION_TYPES = new Set([\n 'navigate',\n 'reload',\n 'back-forward',\n 'back-forward-cache',\n 'prerender',\n 'restore',\n])\n\n/** Privacy-safe callback for Next's useReportWebVitals hook. */\nexport function reportBrandlabWebVital(\n metric: BrandlabWebVitalMetric,\n config: Pick<\n BrandlabBrowserAnalyticsConfig,\n 'enabled' | 'webVitalsEnabled' | 'measurementId' | 'gtag'\n >,\n) {\n if (\n !WEB_VITAL_NAMES.has(metric.name) ||\n !WEB_VITAL_RATINGS.has(metric.rating) ||\n !Number.isFinite(metric.value) ||\n metric.value < 0 ||\n !Number.isFinite(metric.delta)\n ) {\n return false\n }\n const navigationType = WEB_VITAL_NAVIGATION_TYPES.has(metric.navigationType ?? '')\n ? metric.navigationType\n : undefined\n return sendBrandlabAnalyticsEvent({\n enabled: config.enabled && config.webVitalsEnabled !== false,\n measurementId: config.measurementId,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName: 'web_vital',\n params: {\n metric_name: metric.name,\n metric_value: metric.value,\n metric_delta: metric.delta,\n metric_rating: metric.rating,\n ...(navigationType ? { navigation_type: navigationType } : {}),\n },\n })\n}\n\nexport function createBrandlabWebVitalsReporter(\n config: Pick<\n BrandlabBrowserAnalyticsConfig,\n 'enabled' | 'webVitalsEnabled' | 'measurementId' | 'gtag'\n >,\n) {\n return (metric: BrandlabWebVitalMetric) => reportBrandlabWebVital(metric, config)\n}\n\nexport function getBrowserGtag(win: Window = window): GtagTransport | undefined {\n const candidate = (win as Window & { gtag?: GtagTransport }).gtag\n return typeof candidate === 'function' ? candidate : undefined\n}\n\nfunction safePagePath(value: string) {\n const path = value.trim().split(/[?#]/, 1)[0]\n if (!path || path.length > 500) return '/'\n try {\n return normalizeBrandlabRoutePath(path)\n } catch {\n return '/'\n }\n}\n\nfunction safeSlug(value: string | undefined) {\n const normalized = value?.trim().toLowerCase()\n return normalized && /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(normalized) && normalized.length <= 80\n ? normalized\n : undefined\n}\n\nfunction sanitizeContactParams(params: SafeContactAnalyticsParams | undefined) {\n return {\n ...(safeSlug(params?.page_template)\n ? { page_template: safeSlug(params?.page_template) }\n : {}),\n ...(safeSlug(params?.service_slug)\n ? { service_slug: safeSlug(params?.service_slug) }\n : {}),\n ...(safeSlug(params?.location_slug)\n ? { location_slug: safeSlug(params?.location_slug) }\n : {}),\n }\n}\n\nfunction sanitizeAdsParams(params: SafeContactAdsParams | undefined) {\n return {\n ...(params?.currency && /^[A-Z]{3}$/.test(params.currency)\n ? { currency: params.currency }\n : {}),\n ...(typeof params?.value === 'number' && Number.isFinite(params.value) && params.value >= 0\n ? { value: params.value }\n : {}),\n }\n}\n\nexport function isTrackableContactActionResult(\n result: ContactActionResult,\n): result is Extract<ContactActionResult, { ok: true; accepted: true }> {\n return result.ok && result.accepted && result.trackConversion\n}\n\nexport function trackDeliveredContact(\n result: ContactActionResult,\n config: BrandlabBrowserAnalyticsConfig,\n options: {\n pagePath: string\n params?: SafeContactAnalyticsParams\n adsParams?: SafeContactAdsParams\n },\n): ContactFormConversionResult {\n if (!isTrackableContactActionResult(result)) {\n return { ga4Sent: false, enhancedConversionSent: false, adsConversionSent: false }\n }\n return sendContactFormConversion({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n pagePath: safePagePath(options.pagePath),\n submissionId: result.confirmationId,\n params: sanitizeContactParams(options.params),\n adsParams: sanitizeAdsParams(options.adsParams),\n })\n}\n\nfunction explicitRoleValue(\n definition: BrandlabContactDefinition,\n formData: FormData,\n role: 'email' | 'phone',\n) {\n const field = definition.fields.find((candidate) => candidate.role === role)\n if (!field) return undefined\n const value = formData.get(field.name)\n return typeof value === 'string' ? value : undefined\n}\n\n/**\n * Sends Enhanced Conversions only after provider acceptance. Email and phone may\n * only be sourced from fields with explicit declarative roles; they never enter\n * the GA4 parameter object.\n */\nexport function trackDeliveredContactWithEnhancedConversions(\n result: ContactActionResult,\n config: BrandlabBrowserAnalyticsConfig,\n options: {\n pagePath: string\n definition: BrandlabContactDefinition\n formData: FormData\n /** Live Consent Mode decision for ad_user_data; absence is deny. */\n adUserDataConsent: boolean\n params?: SafeContactAnalyticsParams\n adsParams?: SafeContactAdsParams\n },\n): ContactFormConversionResult {\n if (!isTrackableContactActionResult(result)) {\n return { ga4Sent: false, enhancedConversionSent: false, adsConversionSent: false }\n }\n const email = normalizeEnhancedConversionEmail(\n explicitRoleValue(options.definition, options.formData, 'email'),\n )\n const phone = normalizeEnhancedConversionPhone(\n explicitRoleValue(options.definition, options.formData, 'phone'),\n )\n return sendContactFormConversion({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n pagePath: safePagePath(options.pagePath),\n submissionId: result.confirmationId,\n params: sanitizeContactParams(options.params),\n adsParams: sanitizeAdsParams(options.adsParams),\n enhancedConversionsEnabled: config.enhancedConversionsEnabled === true,\n adUserDataConsent: options.adUserDataConsent === true,\n ...((email || phone) ? { enhancedConversion: { email, phone } } : {}),\n })\n}\n\nexport function trackPhoneLinkClick(\n input: { pagePath: string; placement: PhoneCallPlacement },\n config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'>,\n) {\n if (!PHONE_CALL_PLACEMENTS.includes(input.placement)) return false\n return sendBrandlabAnalyticsEvent({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName: 'phone_link_click',\n params: {\n event_category: 'contact_interaction',\n page_path: safePagePath(input.pagePath),\n placement: input.placement,\n },\n })\n}\n\nexport const LEAD_FORM_ERROR_STAGES = [\n 'validation',\n 'submission',\n 'delivery',\n 'unknown',\n] as const\nexport type LeadFormErrorStage = (typeof LEAD_FORM_ERROR_STAGES)[number]\n\nexport const LEAD_CTA_PLACEMENTS = [\n 'header',\n 'footer',\n 'hero',\n 'section',\n 'navigation',\n 'floating',\n 'page',\n] as const\nexport type LeadCtaPlacement = (typeof LEAD_CTA_PLACEMENTS)[number]\n\ntype LeadDiagnosticConfig = Pick<\n BrandlabBrowserAnalyticsConfig,\n 'enabled' | 'leadDiagnosticsEnabled' | 'measurementId' | 'gtag'\n>\n\nexport function trackLeadFormStart(\n input: { pagePath: string; formId: string; pageTemplate?: string },\n config: LeadDiagnosticConfig,\n) {\n const formId = safeSlug(input.formId)\n if (!formId) return false\n return sendLeadDiagnosticEvent('lead_form_start', {\n form_id: formId,\n page_path: safePagePath(input.pagePath),\n ...(safeSlug(input.pageTemplate) ? { page_template: safeSlug(input.pageTemplate) } : {}),\n }, config)\n}\n\nexport function trackLeadFormError(\n input: {\n pagePath: string\n formId: string\n stage: LeadFormErrorStage\n errorCount: number\n },\n config: LeadDiagnosticConfig,\n) {\n const formId = safeSlug(input.formId)\n if (\n !formId ||\n !LEAD_FORM_ERROR_STAGES.includes(input.stage) ||\n !Number.isInteger(input.errorCount) ||\n input.errorCount < 1 ||\n input.errorCount > 50\n ) {\n return false\n }\n return sendLeadDiagnosticEvent('lead_form_error', {\n form_id: formId,\n page_path: safePagePath(input.pagePath),\n error_stage: input.stage,\n error_count: input.errorCount,\n }, config)\n}\n\nexport function trackLeadCtaClick(\n input: {\n pagePath: string\n ctaId: string\n placement: LeadCtaPlacement\n },\n config: LeadDiagnosticConfig,\n) {\n const ctaId = safeSlug(input.ctaId)\n if (!ctaId || !LEAD_CTA_PLACEMENTS.includes(input.placement)) return false\n return sendLeadDiagnosticEvent('lead_cta_click', {\n cta_id: ctaId,\n page_path: safePagePath(input.pagePath),\n placement: input.placement,\n }, config)\n}\n\nfunction sendLeadDiagnosticEvent(\n eventName: 'lead_form_start' | 'lead_form_error' | 'lead_cta_click',\n params: Record<string, unknown>,\n config: LeadDiagnosticConfig,\n) {\n return sendBrandlabAnalyticsEvent({\n enabled: config.enabled && config.leadDiagnosticsEnabled === true,\n measurementId: config.measurementId,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName,\n params,\n })\n}\n\nfunction safeAdditionalEventValue(\n value: unknown,\n policy: NonNullable<BrandlabAnalyticsContract['additionalEvents']>[number]['parameters'][number],\n) {\n if (policy.type === 'boolean') return typeof value === 'boolean' ? value : undefined\n if (policy.type === 'count') {\n const minimum = policy.minimum ?? 0\n const maximum = policy.maximum ?? 100_000\n return typeof value === 'number' && Number.isInteger(value) && value >= minimum && value <= maximum\n ? value\n : undefined\n }\n if (typeof value !== 'string') return undefined\n const normalized = value.trim()\n if (policy.type === 'enum') return policy.values.includes(normalized) ? normalized : undefined\n if (!/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/.test(normalized) || normalized.length > 80) {\n return undefined\n }\n const digits = normalized.replace(/\\D/g, '')\n return digits.length >= 4 || /^[a-f0-9]{24,}$/.test(normalized)\n ? undefined\n : normalized\n}\n\nexport function trackBrandlabBrowserEvent(\n eventName: string,\n params: Record<string, unknown>,\n config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'> & {\n contract: BrandlabAnalyticsContract\n },\n) {\n defineAnalyticsContract(config.contract)\n const event = config.contract.additionalEvents?.find(\n (candidate) => candidate.name === eventName,\n )\n if (!event) return false\n const safeParams = Object.fromEntries(\n Object.entries(params).flatMap(([key, value]) => {\n const policy = event.parameters.find((candidate) => candidate.key === key)\n if (!policy) return []\n const safeValue = safeAdditionalEventValue(value, policy)\n return safeValue === undefined ? [] : [[key, safeValue]]\n }),\n )\n return sendBrandlabAnalyticsEvent({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName,\n params: safeParams,\n })\n}\n"]}
@@ -9,21 +9,34 @@ export interface GooglePlaceReviewsClientProps extends Omit<GooglePlaceReviewsPr
9
9
  fallbackGoogleMapsUri: string;
10
10
  fallbackLabel?: string;
11
11
  fallbackClassName?: string;
12
+ /** Existing project-owned proof shown while live data is unavailable. The Google link is retained separately. */
13
+ fallbackContent?: ReactNode;
12
14
  /** Lets the project own all visual presentation while retaining shared data safety. */
13
15
  renderSnapshot?: (snapshot: GooglePlaceReviewsAvailableSnapshot) => ReactNode;
14
16
  /** Wrapper used only for lazy activation; projects own its visual treatment. */
15
17
  wrapperProps?: Omit<HTMLAttributes<HTMLDivElement>, 'children'>;
16
18
  }
19
+ /**
20
+ * Inline project-owned presentation sharing its enclosing page provider.
21
+ * Attach ref to the real placement for lazy activation. The caller owns fallback
22
+ * content and must display GooglePlaceReviewsAttribution beside live data.
23
+ */
24
+ export declare function useGooglePlaceReviewsSnapshot<Element extends HTMLElement = HTMLSpanElement>(): {
25
+ ref: import("react").Dispatch<import("react").SetStateAction<Element | null>>;
26
+ snapshot: GooglePlaceReviewsAvailableSnapshot | null;
27
+ };
17
28
  export interface GooglePlaceReviewsProviderProps {
18
29
  endpoint: string;
19
30
  mode: GooglePlaceReviewsMode;
31
+ /** Refreshes only review data on navigation; preserves state in child components. */
32
+ pageKey?: string;
20
33
  children: ReactNode;
21
34
  }
22
35
  /** Shares one in-memory request among matching placements for this page only. */
23
- export declare function GooglePlaceReviewsProvider({ endpoint, mode, children }: GooglePlaceReviewsProviderProps): import("react/jsx-runtime").JSX.Element;
36
+ export declare function GooglePlaceReviewsProvider({ endpoint, mode, pageKey, children }: GooglePlaceReviewsProviderProps): import("react/jsx-runtime").JSX.Element;
24
37
  /**
25
38
  * Cost-aware display controller. It requests live Places data only when the
26
39
  * approved placement approaches the viewport and always retains a stable link.
27
40
  */
28
- export declare function GooglePlaceReviewsClient({ mode, endpoint, fallbackGoogleMapsUri, fallbackLabel, fallbackClassName, renderSnapshot, wrapperProps, selection, ...reviewProps }: GooglePlaceReviewsClientProps): import("react/jsx-runtime").JSX.Element;
41
+ export declare function GooglePlaceReviewsClient({ mode, endpoint, fallbackGoogleMapsUri, fallbackLabel, fallbackClassName, fallbackContent, renderSnapshot, wrapperProps, selection, ...reviewProps }: GooglePlaceReviewsClientProps): import("react/jsx-runtime").JSX.Element;
29
42
  //# sourceMappingURL=google-reviews-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"google-reviews-client.d.ts","sourceRoot":"","sources":["../src/google-reviews-client.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAyF,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAClJ,OAAO,EAIL,KAAK,mCAAmC,EACxC,KAAK,sBAAsB,EAE5B,MAAM,4CAA4C,CAAA;AACnD,OAAO,EAIL,KAAK,uBAAuB,EAC7B,MAAM,wBAAwB,CAAA;AAI/B,MAAM,MAAM,gCAAgC,GAAG,WAAW,GAAG,sBAAsB,CAAA;AAEnF,MAAM,WAAW,6BACf,SAAQ,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC;IACjD,IAAI,EAAE,gCAAgC,CAAA;IACtC,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,uFAAuF;IACvF,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,mCAAmC,KAAK,SAAS,CAAA;IAC7E,gFAAgF;IAChF,YAAY,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,CAAA;CAChE;AA2ED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,sBAAsB,CAAA;IAC5B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,iFAAiF;AACjF,wBAAgB,0BAA0B,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,+BAA+B,2CAKvG;AAeD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,IAAI,EACJ,QAAQ,EACR,qBAAqB,EACrB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,SAAuB,EACvB,GAAG,WAAW,EACf,EAAE,6BAA6B,2CA2F/B"}
1
+ {"version":3,"file":"google-reviews-client.d.ts","sourceRoot":"","sources":["../src/google-reviews-client.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAiF,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAC1I,OAAO,EAIL,KAAK,mCAAmC,EACxC,KAAK,sBAAsB,EAC5B,MAAM,4CAA4C,CAAA;AACnD,OAAO,EAIL,KAAK,uBAAuB,EAC7B,MAAM,wBAAwB,CAAA;AAI/B,MAAM,MAAM,gCAAgC,GAAG,WAAW,GAAG,sBAAsB,CAAA;AAEnF,MAAM,WAAW,6BACf,SAAQ,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC;IACjD,IAAI,EAAE,gCAAgC,CAAA;IACtC,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,iHAAiH;IACjH,eAAe,CAAC,EAAE,SAAS,CAAA;IAC3B,uFAAuF;IACvF,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,mCAAmC,KAAK,SAAS,CAAA;IAC7E,gFAAgF;IAChF,YAAY,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,CAAA;CAChE;AAoGD;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,SAAS,WAAW,GAAG,eAAe;;;EAI1F;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,sBAAsB,CAAA;IAC5B,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,iFAAiF;AACjF,wBAAgB,0BAA0B,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,+BAA+B,2CAKhH;AAkBD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,IAAI,EACJ,QAAQ,EACR,qBAAqB,EACrB,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,YAAY,EACZ,SAAuB,EACvB,GAAG,WAAW,EACf,EAAE,6BAA6B,2CA6D/B"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { createContext, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
3
+ import { createContext, useContext, useEffect, useMemo, useState, useSyncExternalStore } from 'react';
4
4
  import { normalizeGooglePlaceReviewsSelection, parseGooglePlaceReviewsSnapshot, selectGooglePlaceReviewsSnapshot, } from '@brandlab-digital/site-core/google-reviews';
5
5
  import { GooglePlaceReviews, GooglePlaceReviewsPolicyAttribution, GoogleReviewsLink, } from './google-reviews-ui.js';
6
6
  const MAXIMUM_ROUTE_RESPONSE_BYTES = 64 * 1_024;
@@ -82,73 +82,70 @@ function createPageReviewStore(endpoint, mode) {
82
82
  const PageReviewsContext = createContext(null);
83
83
  const emptySnapshot = () => null;
84
84
  const emptySubscribe = () => () => { };
85
+ function useReviewSnapshot(store) {
86
+ const [element, ref] = useState(null);
87
+ const snapshot = useSyncExternalStore(store?.subscribe ?? emptySubscribe, store?.getSnapshot ?? emptySnapshot, emptySnapshot);
88
+ useEffect(() => {
89
+ if (!element || !store?.endpoint)
90
+ return;
91
+ if (typeof IntersectionObserver !== 'function') {
92
+ store.activate();
93
+ return;
94
+ }
95
+ const observer = new IntersectionObserver((entries) => {
96
+ if (!entries.some((entry) => entry.isIntersecting))
97
+ return;
98
+ store.activate();
99
+ observer.disconnect();
100
+ }, { rootMargin: '320px 0px' });
101
+ observer.observe(element);
102
+ return () => observer.disconnect();
103
+ }, [element, store]);
104
+ return { ref, snapshot };
105
+ }
106
+ /**
107
+ * Inline project-owned presentation sharing its enclosing page provider.
108
+ * Attach ref to the real placement for lazy activation. The caller owns fallback
109
+ * content and must display GooglePlaceReviewsAttribution beside live data.
110
+ */
111
+ export function useGooglePlaceReviewsSnapshot() {
112
+ const store = useContext(PageReviewsContext);
113
+ if (!store)
114
+ throw new Error('useGooglePlaceReviewsSnapshot requires GooglePlaceReviewsProvider.');
115
+ return useReviewSnapshot(store);
116
+ }
85
117
  /** Shares one in-memory request among matching placements for this page only. */
86
- export function GooglePlaceReviewsProvider({ endpoint, mode, children }) {
118
+ export function GooglePlaceReviewsProvider({ endpoint, mode, pageKey, children }) {
87
119
  const safeEndpoint = normalizeSameOriginEndpoint(endpoint);
88
- const store = useMemo(() => createPageReviewStore(safeEndpoint, mode), [safeEndpoint, mode]);
120
+ const store = useMemo(() => createPageReviewStore(safeEndpoint, mode), [safeEndpoint, mode, pageKey]);
89
121
  useEffect(() => store.mount(), [store]);
90
122
  return _jsx(PageReviewsContext.Provider, { value: store, children: children });
91
123
  }
92
124
  function ReviewFallback(props) {
93
- return (_jsx(GoogleReviewsLink, { className: props.fallbackClassName, googleMapsUri: props.fallbackGoogleMapsUri, label: props.fallbackLabel }));
125
+ return (_jsxs(_Fragment, { children: [props.fallbackContent, _jsx(GoogleReviewsLink, { className: props.fallbackClassName, googleMapsUri: props.fallbackGoogleMapsUri, label: props.fallbackLabel })] }));
94
126
  }
95
127
  /**
96
128
  * Cost-aware display controller. It requests live Places data only when the
97
129
  * approved placement approaches the viewport and always retains a stable link.
98
130
  */
99
- export function GooglePlaceReviewsClient({ mode, endpoint, fallbackGoogleMapsUri, fallbackLabel, fallbackClassName, renderSnapshot, wrapperProps, selection = 'relevance', ...reviewProps }) {
100
- const wrapperRef = useRef(null);
101
- const [localSnapshot, setSnapshot] = useState(null);
102
- const [activated, setActivated] = useState(false);
131
+ export function GooglePlaceReviewsClient({ mode, endpoint, fallbackGoogleMapsUri, fallbackLabel, fallbackClassName, fallbackContent, renderSnapshot, wrapperProps, selection = 'relevance', ...reviewProps }) {
103
132
  const safeEndpoint = normalizeSameOriginEndpoint(endpoint);
104
133
  const provider = useContext(PageReviewsContext);
105
134
  const shared = provider?.endpoint === safeEndpoint && provider?.mode === mode ? provider : null;
106
- const sharedSnapshot = useSyncExternalStore(shared?.subscribe ?? emptySubscribe, shared?.getSnapshot ?? emptySnapshot, emptySnapshot);
107
- const snapshot = shared ? sharedSnapshot : localSnapshot;
135
+ const localStore = useMemo(() => !shared && mode !== 'link-only' ? createPageReviewStore(safeEndpoint, mode) : null, [shared, safeEndpoint, mode]);
136
+ useEffect(() => localStore?.mount(), [localStore]);
137
+ const { ref: wrapperRef, snapshot } = useReviewSnapshot(shared ?? localStore);
108
138
  const normalizedSelection = normalizeGooglePlaceReviewsSelection(selection);
109
139
  if (normalizedSelection === 'five-star-featured' && mode !== 'full') {
110
140
  throw new Error('Five-star featured reviews require full mode.');
111
141
  }
112
- useEffect(() => {
113
- if (mode === 'link-only' || !safeEndpoint)
114
- return;
115
- const element = wrapperRef.current;
116
- if (!element)
117
- return;
118
- if (typeof IntersectionObserver !== 'function') {
119
- setActivated(true);
120
- return;
121
- }
122
- const observer = new IntersectionObserver((entries) => {
123
- if (!entries.some((entry) => entry.isIntersecting))
124
- return;
125
- setActivated(true);
126
- observer.disconnect();
127
- }, { rootMargin: '320px 0px' });
128
- observer.observe(element);
129
- return () => observer.disconnect();
130
- }, [mode, safeEndpoint]);
131
- useEffect(() => {
132
- if (!activated || mode === 'link-only' || !safeEndpoint)
133
- return;
134
- if (shared) {
135
- shared.activate();
136
- return;
137
- }
138
- const controller = new AbortController();
139
- void requestSnapshot(safeEndpoint, mode, controller.signal).then((parsed) => {
140
- if (!controller.signal.aborted && parsed)
141
- setSnapshot(parsed);
142
- });
143
- return () => controller.abort();
144
- }, [activated, mode, safeEndpoint, shared]);
145
142
  if (mode === 'link-only') {
146
- return (_jsx(ReviewFallback, { fallbackClassName: fallbackClassName, fallbackGoogleMapsUri: fallbackGoogleMapsUri, fallbackLabel: fallbackLabel }));
143
+ return (_jsx(ReviewFallback, { fallbackClassName: fallbackClassName, fallbackContent: fallbackContent, fallbackGoogleMapsUri: fallbackGoogleMapsUri, fallbackLabel: fallbackLabel }));
147
144
  }
148
145
  return (_jsx("div", { ...wrapperProps, ref: wrapperRef, children: snapshot?.status === 'available'
149
146
  ? renderSnapshot
150
147
  ? (_jsxs(_Fragment, { children: [renderSnapshot(selectGooglePlaceReviewsSnapshot(snapshot, normalizedSelection)), _jsx(GooglePlaceReviewsPolicyAttribution, { attributionMode: reviewProps.attributionMode, attributionTone: reviewProps.attributionTone, className: reviewProps.attributionClassName, policyAttributionClassName: reviewProps.policyAttributionClassName, policyClassName: reviewProps.policyClassName, selection: normalizedSelection, snapshot: selectGooglePlaceReviewsSnapshot(snapshot, normalizedSelection) })] }))
151
148
  : (_jsx(GooglePlaceReviews, { ...reviewProps, selection: normalizedSelection, snapshot: snapshot }))
152
- : (_jsx(ReviewFallback, { fallbackClassName: fallbackClassName, fallbackGoogleMapsUri: fallbackGoogleMapsUri, fallbackLabel: fallbackLabel })) }));
149
+ : (_jsx(ReviewFallback, { fallbackClassName: fallbackClassName, fallbackContent: fallbackContent, fallbackGoogleMapsUri: fallbackGoogleMapsUri, fallbackLabel: fallbackLabel })) }));
153
150
  }
154
151
  //# sourceMappingURL=google-reviews-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"google-reviews-client.js","sourceRoot":"","sources":["../src/google-reviews-client.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport { createContext, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore, type HTMLAttributes, type ReactNode } from 'react'\nimport {\n normalizeGooglePlaceReviewsSelection,\n parseGooglePlaceReviewsSnapshot,\n selectGooglePlaceReviewsSnapshot,\n type GooglePlaceReviewsAvailableSnapshot,\n type GooglePlaceReviewsMode,\n type GooglePlaceReviewsSnapshot,\n} from '@brandlab-digital/site-core/google-reviews'\nimport {\n GooglePlaceReviews,\n GooglePlaceReviewsPolicyAttribution,\n GoogleReviewsLink,\n type GooglePlaceReviewsProps,\n} from './google-reviews-ui.js'\n\nconst MAXIMUM_ROUTE_RESPONSE_BYTES = 64 * 1_024\n\nexport type BrandlabGoogleReviewsDisplayMode = 'link-only' | GooglePlaceReviewsMode\n\nexport interface GooglePlaceReviewsClientProps\n extends Omit<GooglePlaceReviewsProps, 'snapshot'> {\n mode: BrandlabGoogleReviewsDisplayMode\n /** Same-origin Brandlab route. Ignored in link-only mode. */\n endpoint?: string\n fallbackGoogleMapsUri: string\n fallbackLabel?: string\n fallbackClassName?: string\n /** Lets the project own all visual presentation while retaining shared data safety. */\n renderSnapshot?: (snapshot: GooglePlaceReviewsAvailableSnapshot) => ReactNode\n /** Wrapper used only for lazy activation; projects own its visual treatment. */\n wrapperProps?: Omit<HTMLAttributes<HTMLDivElement>, 'children'>\n}\n\nfunction normalizeSameOriginEndpoint(value: string | undefined) {\n if (!value || !value.startsWith('/') || value.startsWith('//')) return undefined\n try {\n const parsed = new URL(value, 'https://brandlab.invalid')\n if (parsed.origin !== 'https://brandlab.invalid' || parsed.hash) return undefined\n return `${parsed.pathname}${parsed.search}`\n } catch {\n return undefined\n }\n}\n\nasync function requestSnapshot(endpoint: string, mode: GooglePlaceReviewsMode, signal: AbortSignal) {\n try {\n const response = await fetch(endpoint, {\n cache: 'no-store',\n credentials: 'same-origin',\n headers: { accept: 'application/json' },\n signal,\n })\n if (!response.ok) return null\n const raw = await response.text()\n if (new TextEncoder().encode(raw).byteLength > MAXIMUM_ROUTE_RESPONSE_BYTES) return null\n const parsed = parseGooglePlaceReviewsSnapshot(JSON.parse(raw), mode)\n return parsed?.status === 'available' ? parsed : null\n } catch {\n return null\n }\n}\n\nfunction createPageReviewStore(endpoint: string | undefined, mode: GooglePlaceReviewsMode) {\n let snapshot: GooglePlaceReviewsSnapshot | null = null\n let attempted = false\n let disposed = false\n let lifecycle = 0\n let controller: AbortController | undefined\n const listeners = new Set<() => void>()\n return {\n endpoint,\n mode,\n getSnapshot: () => snapshot,\n subscribe(listener: () => void) {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n },\n activate() {\n if (attempted || disposed || !endpoint) return\n attempted = true\n controller = new AbortController()\n void requestSnapshot(endpoint, mode, controller.signal).then((result) => {\n if (disposed || !result) return\n snapshot = result\n listeners.forEach((listener) => listener())\n })\n },\n mount() {\n const current = ++lifecycle\n return () => {\n // React's development effect replay must not cancel the page's only request.\n queueMicrotask(() => {\n if (lifecycle !== current) return\n disposed = true\n controller?.abort()\n listeners.clear()\n })\n }\n },\n }\n}\n\nconst PageReviewsContext = createContext<ReturnType<typeof createPageReviewStore> | null>(null)\nconst emptySnapshot = () => null\nconst emptySubscribe = () => () => {}\n\nexport interface GooglePlaceReviewsProviderProps {\n endpoint: string\n mode: GooglePlaceReviewsMode\n children: ReactNode\n}\n\n/** Shares one in-memory request among matching placements for this page only. */\nexport function GooglePlaceReviewsProvider({ endpoint, mode, children }: GooglePlaceReviewsProviderProps) {\n const safeEndpoint = normalizeSameOriginEndpoint(endpoint)\n const store = useMemo(() => createPageReviewStore(safeEndpoint, mode), [safeEndpoint, mode])\n useEffect(() => store.mount(), [store])\n return <PageReviewsContext.Provider value={store}>{children}</PageReviewsContext.Provider>\n}\n\nfunction ReviewFallback(props: Pick<\n GooglePlaceReviewsClientProps,\n 'fallbackGoogleMapsUri' | 'fallbackLabel' | 'fallbackClassName'\n>) {\n return (\n <GoogleReviewsLink\n className={props.fallbackClassName}\n googleMapsUri={props.fallbackGoogleMapsUri}\n label={props.fallbackLabel}\n />\n )\n}\n\n/**\n * Cost-aware display controller. It requests live Places data only when the\n * approved placement approaches the viewport and always retains a stable link.\n */\nexport function GooglePlaceReviewsClient({\n mode,\n endpoint,\n fallbackGoogleMapsUri,\n fallbackLabel,\n fallbackClassName,\n renderSnapshot,\n wrapperProps,\n selection = 'relevance',\n ...reviewProps\n}: GooglePlaceReviewsClientProps) {\n const wrapperRef = useRef<HTMLDivElement>(null)\n const [localSnapshot, setSnapshot] = useState<GooglePlaceReviewsSnapshot | null>(null)\n const [activated, setActivated] = useState(false)\n const safeEndpoint = normalizeSameOriginEndpoint(endpoint)\n const provider = useContext(PageReviewsContext)\n const shared = provider?.endpoint === safeEndpoint && provider?.mode === mode ? provider : null\n const sharedSnapshot = useSyncExternalStore(shared?.subscribe ?? emptySubscribe, shared?.getSnapshot ?? emptySnapshot, emptySnapshot)\n const snapshot = shared ? sharedSnapshot : localSnapshot\n const normalizedSelection = normalizeGooglePlaceReviewsSelection(selection)\n if (normalizedSelection === 'five-star-featured' && mode !== 'full') {\n throw new Error('Five-star featured reviews require full mode.')\n }\n\n useEffect(() => {\n if (mode === 'link-only' || !safeEndpoint) return\n const element = wrapperRef.current\n if (!element) return\n if (typeof IntersectionObserver !== 'function') {\n setActivated(true)\n return\n }\n const observer = new IntersectionObserver(\n (entries) => {\n if (!entries.some((entry) => entry.isIntersecting)) return\n setActivated(true)\n observer.disconnect()\n },\n { rootMargin: '320px 0px' },\n )\n observer.observe(element)\n return () => observer.disconnect()\n }, [mode, safeEndpoint])\n\n useEffect(() => {\n if (!activated || mode === 'link-only' || !safeEndpoint) return\n if (shared) {\n shared.activate()\n return\n }\n const controller = new AbortController()\n void requestSnapshot(safeEndpoint, mode, controller.signal).then((parsed) => {\n if (!controller.signal.aborted && parsed) setSnapshot(parsed)\n })\n return () => controller.abort()\n }, [activated, mode, safeEndpoint, shared])\n\n if (mode === 'link-only') {\n return (\n <ReviewFallback\n fallbackClassName={fallbackClassName}\n fallbackGoogleMapsUri={fallbackGoogleMapsUri}\n fallbackLabel={fallbackLabel}\n />\n )\n }\n\n return (\n <div {...wrapperProps} ref={wrapperRef}>\n {snapshot?.status === 'available'\n ? renderSnapshot\n ? (\n <>\n {renderSnapshot(selectGooglePlaceReviewsSnapshot(snapshot, normalizedSelection))}\n <GooglePlaceReviewsPolicyAttribution\n attributionMode={reviewProps.attributionMode}\n attributionTone={reviewProps.attributionTone}\n className={reviewProps.attributionClassName}\n policyAttributionClassName={reviewProps.policyAttributionClassName}\n policyClassName={reviewProps.policyClassName}\n selection={normalizedSelection}\n snapshot={selectGooglePlaceReviewsSnapshot(snapshot, normalizedSelection)}\n />\n </>\n )\n : (\n <GooglePlaceReviews\n {...reviewProps}\n selection={normalizedSelection}\n snapshot={snapshot}\n />\n )\n : (\n <ReviewFallback\n fallbackClassName={fallbackClassName}\n fallbackGoogleMapsUri={fallbackGoogleMapsUri}\n fallbackLabel={fallbackLabel}\n />\n )}\n </div>\n )\n}\n"]}
1
+ {"version":3,"file":"google-reviews-client.js","sourceRoot":"","sources":["../src/google-reviews-client.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport { createContext, useContext, useEffect, useMemo, useState, useSyncExternalStore, type HTMLAttributes, type ReactNode } from 'react'\nimport {\n normalizeGooglePlaceReviewsSelection,\n parseGooglePlaceReviewsSnapshot,\n selectGooglePlaceReviewsSnapshot,\n type GooglePlaceReviewsAvailableSnapshot,\n type GooglePlaceReviewsMode,\n} from '@brandlab-digital/site-core/google-reviews'\nimport {\n GooglePlaceReviews,\n GooglePlaceReviewsPolicyAttribution,\n GoogleReviewsLink,\n type GooglePlaceReviewsProps,\n} from './google-reviews-ui.js'\n\nconst MAXIMUM_ROUTE_RESPONSE_BYTES = 64 * 1_024\n\nexport type BrandlabGoogleReviewsDisplayMode = 'link-only' | GooglePlaceReviewsMode\n\nexport interface GooglePlaceReviewsClientProps\n extends Omit<GooglePlaceReviewsProps, 'snapshot'> {\n mode: BrandlabGoogleReviewsDisplayMode\n /** Same-origin Brandlab route. Ignored in link-only mode. */\n endpoint?: string\n fallbackGoogleMapsUri: string\n fallbackLabel?: string\n fallbackClassName?: string\n /** Existing project-owned proof shown while live data is unavailable. The Google link is retained separately. */\n fallbackContent?: ReactNode\n /** Lets the project own all visual presentation while retaining shared data safety. */\n renderSnapshot?: (snapshot: GooglePlaceReviewsAvailableSnapshot) => ReactNode\n /** Wrapper used only for lazy activation; projects own its visual treatment. */\n wrapperProps?: Omit<HTMLAttributes<HTMLDivElement>, 'children'>\n}\n\nfunction normalizeSameOriginEndpoint(value: string | undefined) {\n if (!value || !value.startsWith('/') || value.startsWith('//')) return undefined\n try {\n const parsed = new URL(value, 'https://brandlab.invalid')\n if (parsed.origin !== 'https://brandlab.invalid' || parsed.hash) return undefined\n return `${parsed.pathname}${parsed.search}`\n } catch {\n return undefined\n }\n}\n\nasync function requestSnapshot(endpoint: string, mode: GooglePlaceReviewsMode, signal: AbortSignal) {\n try {\n const response = await fetch(endpoint, {\n cache: 'no-store',\n credentials: 'same-origin',\n headers: { accept: 'application/json' },\n signal,\n })\n if (!response.ok) return null\n const raw = await response.text()\n if (new TextEncoder().encode(raw).byteLength > MAXIMUM_ROUTE_RESPONSE_BYTES) return null\n const parsed = parseGooglePlaceReviewsSnapshot(JSON.parse(raw), mode)\n return parsed?.status === 'available' ? parsed : null\n } catch {\n return null\n }\n}\n\nfunction createPageReviewStore(endpoint: string | undefined, mode: GooglePlaceReviewsMode) {\n let snapshot: GooglePlaceReviewsAvailableSnapshot | null = null\n let attempted = false\n let disposed = false\n let lifecycle = 0\n let controller: AbortController | undefined\n const listeners = new Set<() => void>()\n return {\n endpoint,\n mode,\n getSnapshot: () => snapshot,\n subscribe(listener: () => void) {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n },\n activate() {\n if (attempted || disposed || !endpoint) return\n attempted = true\n controller = new AbortController()\n void requestSnapshot(endpoint, mode, controller.signal).then((result) => {\n if (disposed || !result) return\n snapshot = result\n listeners.forEach((listener) => listener())\n })\n },\n mount() {\n const current = ++lifecycle\n return () => {\n // React's development effect replay must not cancel the page's only request.\n queueMicrotask(() => {\n if (lifecycle !== current) return\n disposed = true\n controller?.abort()\n listeners.clear()\n })\n }\n },\n }\n}\n\nconst PageReviewsContext = createContext<ReturnType<typeof createPageReviewStore> | null>(null)\nconst emptySnapshot = () => null\nconst emptySubscribe = () => () => {}\n\nfunction useReviewSnapshot<Element extends HTMLElement>(store: ReturnType<typeof createPageReviewStore> | null) {\n const [element, ref] = useState<Element | null>(null)\n const snapshot = useSyncExternalStore(store?.subscribe ?? emptySubscribe, store?.getSnapshot ?? emptySnapshot, emptySnapshot)\n\n useEffect(() => {\n if (!element || !store?.endpoint) return\n if (typeof IntersectionObserver !== 'function') {\n store.activate()\n return\n }\n const observer = new IntersectionObserver(\n (entries) => {\n if (!entries.some((entry) => entry.isIntersecting)) return\n store.activate()\n observer.disconnect()\n },\n { rootMargin: '320px 0px' },\n )\n observer.observe(element)\n return () => observer.disconnect()\n }, [element, store])\n\n return { ref, snapshot }\n}\n\n/**\n * Inline project-owned presentation sharing its enclosing page provider.\n * Attach ref to the real placement for lazy activation. The caller owns fallback\n * content and must display GooglePlaceReviewsAttribution beside live data.\n */\nexport function useGooglePlaceReviewsSnapshot<Element extends HTMLElement = HTMLSpanElement>() {\n const store = useContext(PageReviewsContext)\n if (!store) throw new Error('useGooglePlaceReviewsSnapshot requires GooglePlaceReviewsProvider.')\n return useReviewSnapshot<Element>(store)\n}\n\nexport interface GooglePlaceReviewsProviderProps {\n endpoint: string\n mode: GooglePlaceReviewsMode\n /** Refreshes only review data on navigation; preserves state in child components. */\n pageKey?: string\n children: ReactNode\n}\n\n/** Shares one in-memory request among matching placements for this page only. */\nexport function GooglePlaceReviewsProvider({ endpoint, mode, pageKey, children }: GooglePlaceReviewsProviderProps) {\n const safeEndpoint = normalizeSameOriginEndpoint(endpoint)\n const store = useMemo(() => createPageReviewStore(safeEndpoint, mode), [safeEndpoint, mode, pageKey])\n useEffect(() => store.mount(), [store])\n return <PageReviewsContext.Provider value={store}>{children}</PageReviewsContext.Provider>\n}\n\nfunction ReviewFallback(props: Pick<\n GooglePlaceReviewsClientProps,\n 'fallbackGoogleMapsUri' | 'fallbackLabel' | 'fallbackClassName' | 'fallbackContent'\n>) {\n return (\n <>\n {props.fallbackContent}\n <GoogleReviewsLink\n className={props.fallbackClassName}\n googleMapsUri={props.fallbackGoogleMapsUri}\n label={props.fallbackLabel}\n />\n </>\n )\n}\n\n/**\n * Cost-aware display controller. It requests live Places data only when the\n * approved placement approaches the viewport and always retains a stable link.\n */\nexport function GooglePlaceReviewsClient({\n mode,\n endpoint,\n fallbackGoogleMapsUri,\n fallbackLabel,\n fallbackClassName,\n fallbackContent,\n renderSnapshot,\n wrapperProps,\n selection = 'relevance',\n ...reviewProps\n}: GooglePlaceReviewsClientProps) {\n const safeEndpoint = normalizeSameOriginEndpoint(endpoint)\n const provider = useContext(PageReviewsContext)\n const shared = provider?.endpoint === safeEndpoint && provider?.mode === mode ? provider : null\n const localStore = useMemo(\n () => !shared && mode !== 'link-only' ? createPageReviewStore(safeEndpoint, mode) : null,\n [shared, safeEndpoint, mode],\n )\n useEffect(() => localStore?.mount(), [localStore])\n const { ref: wrapperRef, snapshot } = useReviewSnapshot<HTMLDivElement>(shared ?? localStore)\n const normalizedSelection = normalizeGooglePlaceReviewsSelection(selection)\n if (normalizedSelection === 'five-star-featured' && mode !== 'full') {\n throw new Error('Five-star featured reviews require full mode.')\n }\n\n if (mode === 'link-only') {\n return (\n <ReviewFallback\n fallbackClassName={fallbackClassName}\n fallbackContent={fallbackContent}\n fallbackGoogleMapsUri={fallbackGoogleMapsUri}\n fallbackLabel={fallbackLabel}\n />\n )\n }\n\n return (\n <div {...wrapperProps} ref={wrapperRef}>\n {snapshot?.status === 'available'\n ? renderSnapshot\n ? (\n <>\n {renderSnapshot(selectGooglePlaceReviewsSnapshot(snapshot, normalizedSelection))}\n <GooglePlaceReviewsPolicyAttribution\n attributionMode={reviewProps.attributionMode}\n attributionTone={reviewProps.attributionTone}\n className={reviewProps.attributionClassName}\n policyAttributionClassName={reviewProps.policyAttributionClassName}\n policyClassName={reviewProps.policyClassName}\n selection={normalizedSelection}\n snapshot={selectGooglePlaceReviewsSnapshot(snapshot, normalizedSelection)}\n />\n </>\n )\n : (\n <GooglePlaceReviews\n {...reviewProps}\n selection={normalizedSelection}\n snapshot={snapshot}\n />\n )\n : (\n <ReviewFallback\n fallbackClassName={fallbackClassName}\n fallbackContent={fallbackContent}\n fallbackGoogleMapsUri={fallbackGoogleMapsUri}\n fallbackLabel={fallbackLabel}\n />\n )}\n </div>\n )\n}\n"]}
@@ -319,6 +319,8 @@ export interface GooglePlaceReviewsProps extends HTMLAttributes<HTMLElement> {
319
319
  export interface GooglePlaceReviewsAttributionProps {
320
320
  snapshot: GooglePlaceReviewsAvailableSnapshot;
321
321
  className?: string;
322
+ /** Uses phrasing elements for placement beside inline data. Keep outside links. */
323
+ inline?: boolean;
322
324
  attributionTone?: NonNullable<GooglePlaceReviewsProps['attributionTone']>;
323
325
  attributionMode?: NonNullable<GooglePlaceReviewsProps['attributionMode']>;
324
326
  }
@@ -347,11 +349,11 @@ export declare function GooglePlaceReviewActions({ review, className, }: GoogleP
347
349
  'data-brandlab-google-review-actions': string;
348
350
  }, HTMLElement> | null;
349
351
  /** Required provider attribution with no project styling or layout policy. */
350
- export declare function GooglePlaceReviewsAttribution({ snapshot, className, attributionTone, attributionMode, }: GooglePlaceReviewsAttributionProps): import("react").DetailedReactHTMLElement<{
352
+ export declare function GooglePlaceReviewsAttribution({ snapshot, className, inline, attributionTone, attributionMode, }: GooglePlaceReviewsAttributionProps): import("react").DetailedReactHTMLElement<{
351
353
  className: string | undefined;
352
354
  'data-brandlab-google-reviews-attribution': string;
353
355
  }, HTMLElement>;
354
- export declare function GooglePlaceReviewsPolicyAttribution({ snapshot, selection, className, policyClassName, policyAttributionClassName, attributionTone, attributionMode, }: GooglePlaceReviewsPolicyAttributionProps): import("react").DetailedReactHTMLElement<{
356
+ export declare function GooglePlaceReviewsPolicyAttribution({ snapshot, selection, className, policyClassName, policyAttributionClassName, inline, attributionTone, attributionMode, }: GooglePlaceReviewsPolicyAttributionProps): import("react").DetailedReactHTMLElement<{
355
357
  className: string | undefined;
356
358
  'data-brandlab-google-review-selection': GooglePlaceReviewsSelection;
357
359
  'data-brandlab-google-reviews-policy-attribution': string;
@@ -1 +1 @@
1
- {"version":3,"file":"google-reviews-ui.d.ts","sourceRoot":"","sources":["../src/google-reviews-ui.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"google-reviews-ui.d.ts","sourceRoot":"","sources":["../src/google-reviews-ui.ts"],"names":[],"mappings":"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"}
@@ -156,35 +156,36 @@ function renderReview(review, index, props) {
156
156
  })), createElement('blockquote', { className: props.textClassName }, createElement('p', null, review.text)));
157
157
  }
158
158
  /** Required provider attribution with no project styling or layout policy. */
159
- export function GooglePlaceReviewsAttribution({ snapshot, className, attributionTone = 'light', attributionMode = 'logo', }) {
159
+ export function GooglePlaceReviewsAttribution({ snapshot, className, inline = false, attributionTone = 'light', attributionMode = 'logo', }) {
160
160
  const attributionUrl = normalizeGooglePlacePublicUrl(snapshot.googleMapsUri);
161
- return createElement('div', {
161
+ return createElement(inline ? 'span' : 'div', {
162
162
  className,
163
163
  'data-brandlab-google-reviews-attribution': 'required',
164
164
  }, ...snapshot.thirdPartyAttributions.map((item) => {
165
165
  const providerUri = normalizeGooglePlacePublicUrl(item.providerUri);
166
- return createElement('p', { key: `${item.provider}:${providerUri ?? ''}` }, 'Data provider: ', providerUri
166
+ return createElement(inline ? 'span' : 'p', { key: `${item.provider}:${providerUri ?? ''}` }, 'Data provider: ', providerUri
167
167
  ? createElement('a', externalLinkProps(providerUri), item.provider)
168
- : item.provider);
169
- }), createElement('p', null, 'Reviews provided by ', renderGoogleMapsAttribution(attributionUrl, attributionMode, attributionTone)));
168
+ : item.provider, inline ? ' ' : null);
169
+ }), createElement(inline ? 'span' : 'p', null, 'Reviews provided by ', renderGoogleMapsAttribution(attributionUrl, attributionMode, attributionTone)));
170
170
  }
171
- export function GooglePlaceReviewsPolicyAttribution({ snapshot, selection = 'relevance', className, policyClassName, policyAttributionClassName, attributionTone = 'light', attributionMode = 'logo', }) {
171
+ export function GooglePlaceReviewsPolicyAttribution({ snapshot, selection = 'relevance', className, policyClassName, policyAttributionClassName, inline = false, attributionTone = 'light', attributionMode = 'logo', }) {
172
172
  const normalizedSelection = normalizeGooglePlaceReviewsSelection(selection);
173
173
  const policy = snapshot.mode === 'full' && snapshot.reviews.length > 0
174
174
  ? normalizedSelection === 'five-star-featured'
175
175
  ? "Showing 5-star reviews selected from Google's relevance-ranked results."
176
176
  : 'Google Maps reviews are ordered by relevance.'
177
177
  : null;
178
- return createElement('div', {
178
+ return createElement(inline ? 'span' : 'div', {
179
179
  className: policyAttributionClassName,
180
180
  'data-brandlab-google-review-selection': normalizedSelection,
181
181
  'data-brandlab-google-reviews-policy-attribution': 'compact',
182
182
  }, policy
183
- ? createElement('p', {
183
+ ? createElement(inline ? 'span' : 'p', {
184
184
  className: policyClassName,
185
185
  'data-brandlab-google-review-ordering': normalizedSelection,
186
- }, policy)
186
+ }, inline ? `${policy} ` : policy)
187
187
  : null, createElement(GooglePlaceReviewsAttribution, {
188
+ inline,
188
189
  attributionMode,
189
190
  attributionTone,
190
191
  className,
@@ -1 +1 @@
1
- {"version":3,"file":"google-reviews-ui.js","sourceRoot":"","sources":["../src/google-reviews-ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkD,MAAM,OAAO,CAAA;AACrF,OAAO,EACL,6BAA6B,EAC7B,4BAA4B,EAC5B,gCAAgC,EAChC,6BAA6B,EAC7B,oCAAoC,EACpC,gCAAgC,GAKjC,MAAM,4CAA4C,CAAA;AACnD,OAAO,EACL,qCAAqC,EACrC,mCAAmC,EACnC,kCAAkC,GACnC,MAAM,qCAAqC,CAAA;AAQ5C,MAAM,UAAU,iBAAiB,CAAC,EAChC,aAAa,EACb,KAAK,GAAG,yBAAyB,EACjC,GAAG,WAAW,EACS;IACvB,MAAM,IAAI,GAAG,6BAA6B,CAAC,aAAa,CAAC,CAAA;IACzD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IACtB,OAAO,aAAa,CAClB,GAAG,EACH;QACE,GAAG,WAAW;QACd,IAAI;QACJ,8BAA8B,EAAE,WAAW;QAC3C,cAAc,EAAE,aAAa;QAC7B,GAAG,EAAE,qBAAqB;QAC1B,MAAM,EAAE,QAAQ;KACjB,EACD,KAAK,CACN,CAAA;AACH,CAAC;AAiDD,SAAS,kBAAkB,CAAC,KAAc,EAAE,KAAa;IACvD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,2CAA2C,CAAC,CAAA;IACtE,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAc,EAAE,KAAa,EAAE,QAAQ,GAAG,KAAK;IACtE,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,QAAQ;QAAE,OAAM;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,6BAA6B,CAAC,KAAK,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,uCAAuC,CAAC,CAAA;IAClE,CAAC;AACH,CAAC;AAED,SAAS,4CAA4C,CACnD,QAA6C;IAE7C,kBAAkB,CAAC,QAAQ,CAAC,YAAY,EAAE,uBAAuB,CAAC,CAAA;IAClE,eAAe,CAAC,QAAQ,CAAC,aAAa,EAAE,wBAAwB,EAAE,IAAI,CAAC,CAAA;IACvE,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAC3D,CAAC;IACD,IACE,QAAQ,CAAC,WAAW,EAAE,KAAK,KAAK,6BAA6B;QAC7D,QAAQ,CAAC,WAAW,EAAE,IAAI,KAAK,4BAA4B,EAC3D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAA;IAC3F,CAAC;IACD,IACE,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;QAChC,QAAQ,CAAC,OAAO,CAAC,MAAM,GAAG,gCAAgC;QAC1D,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,EAC5D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAA;IAC3F,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAA;IAC1F,CAAC;IAED,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QACzC,kBAAkB,CAAC,MAAM,CAAC,UAAU,EAAE,oBAAoB,KAAK,cAAc,CAAC,CAAA;QAC9E,kBAAkB,CAAC,MAAM,CAAC,IAAI,EAAE,oBAAoB,KAAK,QAAQ,CAAC,CAAA;QAClE,eAAe,CAAC,MAAM,CAAC,aAAa,EAAE,oBAAoB,KAAK,iBAAiB,EAAE,IAAI,CAAC,CAAA;QACvF,eAAe,CAAC,MAAM,CAAC,SAAS,EAAE,oBAAoB,KAAK,aAAa,CAAC,CAAA;QACzE,eAAe,CAAC,MAAM,CAAC,cAAc,EAAE,oBAAoB,KAAK,kBAAkB,CAAC,CAAA;QACnF,eAAe,CAAC,MAAM,CAAC,cAAc,EAAE,oBAAoB,KAAK,kBAAkB,CAAC,CAAA;IACrF,CAAC,CAAC,CAAA;IACF,QAAQ,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACtD,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,mCAAmC,KAAK,YAAY,CAAC,CAAA;QACvF,eAAe,CAAC,IAAI,CAAC,WAAW,EAAE,mCAAmC,KAAK,eAAe,CAAC,CAAA;IAC5F,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY;IACrC,OAAO;QACL,IAAI;QACJ,cAAc,EAAE,aAAsB;QACtC,GAAG,EAAE,qBAAqB;QAC1B,MAAM,EAAE,QAAiB;KAC1B,CAAA;AACH,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,uBAAuB,CAAC,EACtC,MAAM,EACN,SAAS,EACT,eAAe,GACc;IAC7B,MAAM,SAAS,GAAG,6BAA6B,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACjE,MAAM,cAAc,GAAG,6BAA6B,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;IAC3E,MAAM,QAAQ,GAAG;QACf,cAAc;YACZ,CAAC,CAAC,aAAa,CAAC,KAAK,EAAE;gBACnB,GAAG,EAAE,EAAE;gBACP,SAAS,EAAE,eAAe;gBAC1B,QAAQ,EAAE,OAAO;gBACjB,oCAAoC,EAAE,QAAQ;gBAC9C,MAAM,EAAE,EAAE;gBACV,GAAG,EAAE,QAAQ;gBACb,OAAO,EAAE,MAAM;gBACf,cAAc,EAAE,aAAa;gBAC7B,GAAG,EAAE,cAAc;gBACnB,KAAK,EAAE,EAAE;aACV,CAAC;YACJ,CAAC,CAAC,IAAI;QACR,aAAa,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,UAAU,CAAC;KAC1D,CAAA;IAED,OAAO,SAAS;QACd,CAAC,CAAC,aAAa,CACX,GAAG,EACH;YACE,GAAG,iBAAiB,CAAC,SAAS,CAAC;YAC/B,SAAS;YACT,oCAAoC,EAAE,cAAc;SACrD,EACD,GAAG,QAAQ,CACZ;QACH,CAAC,CAAC,aAAa,CACX,MAAM,EACN;YACE,SAAS;YACT,oCAAoC,EAAE,MAAM;SAC7C,EACD,GAAG,QAAQ,CACZ,CAAA;AACP,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,wBAAwB,CAAC,EACvC,MAAM,EACN,SAAS,GACqB;IAC9B,MAAM,SAAS,GAAG,6BAA6B,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;IACrE,MAAM,cAAc,GAAG,6BAA6B,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;IAC3E,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAA;IAE3B,OAAO,aAAa,CAClB,SAAS,EACT;QACE,SAAS;QACT,qCAAqC,EAAE,SAAS;KACjD,EACD,aAAa,CACX,SAAS,EACT;QACE,YAAY,EAAE,sBAAsB,MAAM,CAAC,UAAU,EAAE;QACvD,qCAAqC,EAAE,SAAS;KACjD,EACD,aAAa,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,KAAK,CAAC,CACtD,EACD,aAAa,CACX,KAAK,EACL,EAAE,qCAAqC,EAAE,MAAM,EAAE,EACjD,aAAa,CACX,GAAG,EACH;QACE,GAAG,iBAAiB,CAAC,SAAS,CAAC;QAC/B,oCAAoC,EAAE,QAAQ;KAC/C,EACD,iCAAiC,CAClC,EACD,cAAc;QACZ,CAAC,CAAC,aAAa,CACX,GAAG,EACH;YACE,GAAG,iBAAiB,CAAC,cAAc,CAAC;YACpC,oCAAoC,EAAE,QAAQ;SAC/C,EACD,8BAA8B,CAC/B;QACH,CAAC,CAAC,IAAI,CACT,CACF,CAAA;AACH,CAAC;AAED,SAAS,2BAA2B,CAClC,cAAkC,EAClC,IAA6D,EAC7D,IAA6D;IAE7D,MAAM,OAAO,GAAG,IAAI,KAAK,MAAM;QAC7B,CAAC,CAAC,aAAa,CAAC,KAAK,EAAE;YACnB,GAAG,EAAE,6BAA6B;YAClC,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,KAAK;YAChB,MAAM,EAAE,mCAAmC;YAC3C,GAAG,EAAE,qCAAqC,CAAC,IAAI,CAAC;YAChD,KAAK,EAAE,kCAAkC;SAC1C,CAAC;QACJ,CAAC,CAAC,aAAa,CACX,MAAM,EACN;YACE,uCAAuC,EAAE,wBAAwB;YACjE,SAAS,EAAE,IAAa;SACzB,EACD,4BAA4B,CAC7B,CAAA;IAEL,IAAI,CAAC,cAAc;QAAE,OAAO,OAAO,CAAA;IACnC,OAAO,aAAa,CAClB,GAAG,EACH;QACE,GAAG,iBAAiB,CAAC,cAAc,CAAC;QACpC,YAAY,EAAE,6BAA6B;QAC3C,uCAAuC,EAAE,IAAI;KAC9C,EACD,OAAO,CACR,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CACnB,MAAyB,EACzB,KAAa,EACb,KAA8B;IAE9B,OAAO,aAAa,CAClB,SAAS,EACT,EAAE,SAAS,EAAE,KAAK,CAAC,eAAe,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,WAAW,IAAI,KAAK,EAAE,EAAE,EAChG,aAAa,CACX,QAAQ,EACR,IAAI,EACJ,aAAa,CAAC,uBAAuB,EAAE;QACrC,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,SAAS,EAAE,KAAK,CAAC,eAAe;QAChC,MAAM;KACP,CAAC,EACF,MAAM,CAAC,MAAM;QACX,CAAC,CAAC,aAAa,CACX,MAAM,EACN,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC,MAAM,iBAAiB,EAAE,EACnD,GAAG,MAAM,CAAC,MAAM,IAAI,CACrB;QACH,CAAC,CAAC,IAAI,EACR,MAAM,CAAC,8BAA8B;QACnC,CAAC,CAAC,aAAa,CACX,MAAM,EACN,EAAE,QAAQ,EAAE,MAAM,CAAC,WAAW,EAAE,EAChC,MAAM,CAAC,8BAA8B,CACtC;QACH,CAAC,CAAC,IAAI,EACR,aAAa,CAAC,wBAAwB,EAAE;QACtC,SAAS,EAAE,KAAK,CAAC,gBAAgB;QACjC,MAAM;KACP,CAAC,CACH,EACD,aAAa,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,aAAa,EAAE,EAAE,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CACvG,CAAA;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,6BAA6B,CAAC,EAC5C,QAAQ,EACR,SAAS,EACT,eAAe,GAAG,OAAO,EACzB,eAAe,GAAG,MAAM,GACW;IACnC,MAAM,cAAc,GAAG,6BAA6B,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAA;IAC5E,OAAO,aAAa,CAClB,KAAK,EACL;QACE,SAAS;QACT,0CAA0C,EAAE,UAAU;KACvD,EACD,GAAG,QAAQ,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC9C,MAAM,WAAW,GAAG,6BAA6B,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACnE,OAAO,aAAa,CAClB,GAAG,EACH,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,IAAI,WAAW,IAAI,EAAE,EAAE,EAAE,EAChD,iBAAiB,EACjB,WAAW;YACT,CAAC,CAAC,aAAa,CAAC,GAAG,EAAE,iBAAiB,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC;YACnE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAClB,CAAA;IACH,CAAC,CAAC,EACF,aAAa,CACX,GAAG,EACH,IAAI,EACJ,sBAAsB,EACtB,2BAA2B,CAAC,cAAc,EAAE,eAAe,EAAE,eAAe,CAAC,CAC9E,CACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,mCAAmC,CAAC,EAClD,QAAQ,EACR,SAAS,GAAG,WAAW,EACvB,SAAS,EACT,eAAe,EACf,0BAA0B,EAC1B,eAAe,GAAG,OAAO,EACzB,eAAe,GAAG,MAAM,GACiB;IACzC,MAAM,mBAAmB,GAAG,oCAAoC,CAAC,SAAS,CAAC,CAAA;IAC3E,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,KAAK,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QACpE,CAAC,CAAC,mBAAmB,KAAK,oBAAoB;YAC5C,CAAC,CAAC,yEAAyE;YAC3E,CAAC,CAAC,+CAA+C;QACnD,CAAC,CAAC,IAAI,CAAA;IAER,OAAO,aAAa,CAClB,KAAK,EACL;QACE,SAAS,EAAE,0BAA0B;QACrC,uCAAuC,EAAE,mBAAmB;QAC5D,iDAAiD,EAAE,SAAS;KAC7D,EACD,MAAM;QACJ,CAAC,CAAC,aAAa,CACX,GAAG,EACH;YACE,SAAS,EAAE,eAAe;YAC1B,sCAAsC,EAAE,mBAAmB;SAC5D,EACD,MAAM,CACP;QACH,CAAC,CAAC,IAAI,EACR,aAAa,CAAC,6BAA6B,EAAE;QAC3C,eAAe;QACf,eAAe;QACf,SAAS;QACT,QAAQ;KACT,CAAC,CACH,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,QAAQ,EACR,eAAe,EACf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,0BAA0B,EAC1B,uBAAuB,EACvB,mBAAmB,GAAG,iCAAiC,EACvD,SAAS,GAAG,WAAW,EACvB,eAAe,GAAG,OAAO,EACzB,eAAe,GAAG,MAAM,EACxB,GAAG,YAAY,EACS;IACxB,IAAI,QAAQ,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,IAAI,CAAA;IAChD,4CAA4C,CAAC,QAAQ,CAAC,CAAA;IACtD,MAAM,mBAAmB,GAAG,oCAAoC,CAAC,SAAS,CAAC,CAAA;IAC3E,IAAI,mBAAmB,KAAK,oBAAoB,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC7E,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,MAAM,iBAAiB,GAAG,gCAAgC,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;IACzF,MAAM,KAAK,GAAG;QACZ,GAAG,YAAY;QACf,QAAQ,EAAE,iBAAiB;QAC3B,eAAe;QACf,eAAe;QACf,eAAe;QACf,gBAAgB;QAChB,aAAa;QACb,oBAAoB;QACpB,eAAe;QACf,eAAe;KAChB,CAAA;IACD,OAAO,aAAa,CAClB,SAAS,EACT;QACE,GAAG,YAAY;QACf,YAAY,EAAE,YAAY,CAAC,YAAY,CAAC,IAAI,GAAG,QAAQ,CAAC,YAAY,yBAAyB;QAC7F,8BAA8B,EAAE,wBAAwB,QAAQ,CAAC,IAAI,EAAE;QACvE,uCAAuC,EAAE,eAAe;QACxD,mCAAmC,EAAE,iBAAiB,CAAC,OAAO,CAAC,MAAM;QACrE,uCAAuC,EAAE,mBAAmB;KAC7D,EACD,QAAQ,CAAC,MAAM;QACb,CAAC,CAAC,aAAa,CACX,GAAG,EACH;YACE,YAAY,EAAE,kBAAkB,QAAQ,CAAC,MAAM,YAC7C,QAAQ,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC,eAAe,UACjF,EAAE;SACH,EACD,GAAG,QAAQ,CAAC,MAAM,KAChB,QAAQ,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC,eAAe,UACjF,EAAE,CACH;QACH,CAAC,CAAC,IAAI,EACR,GAAG,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,EACvF,mBAAmB,KAAK,oBAAoB,IAAI,iBAAiB,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QACpF,CAAC,CAAC,aAAa,CAAC,iBAAiB,EAAE;YAC/B,SAAS,EAAE,uBAAuB;YAClC,aAAa,EAAE,iBAAiB,CAAC,aAAa;YAC9C,KAAK,EAAE,mBAAmB;SAC3B,CAAC;QACJ,CAAC,CAAC,IAAI,EACR,aAAa,CAAC,mCAAmC,EAAE;QACjD,eAAe;QACf,eAAe;QACf,SAAS,EAAE,oBAAoB;QAC/B,0BAA0B;QAC1B,eAAe;QACf,SAAS,EAAE,mBAAmB;QAC9B,QAAQ,EAAE,iBAAiB;KAC5B,CAAC,CACH,CAAA;AACH,CAAC","sourcesContent":["import { createElement, type AnchorHTMLAttributes, type HTMLAttributes } from 'react'\nimport {\n GOOGLE_MAPS_ATTRIBUTION_LABEL,\n GOOGLE_MAPS_ATTRIBUTION_TEXT,\n GOOGLE_PLACE_REVIEWS_MAX_REVIEWS,\n normalizeGooglePlacePublicUrl,\n normalizeGooglePlaceReviewsSelection,\n selectGooglePlaceReviewsSnapshot,\n type GooglePlaceReview,\n type GooglePlaceReviewsAvailableSnapshot,\n type GooglePlaceReviewsSelection,\n type GooglePlaceReviewsSnapshot,\n} from '@brandlab-digital/site-core/google-reviews'\nimport {\n GOOGLE_MAPS_ATTRIBUTION_LOGO_DATA_URL,\n GOOGLE_MAPS_ATTRIBUTION_LOGO_HEIGHT,\n GOOGLE_MAPS_ATTRIBUTION_LOGO_WIDTH,\n} from './google-maps-attribution-assets.js'\n\nexport interface GoogleReviewsLinkProps\n extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {\n googleMapsUri: string\n label?: string\n}\n\nexport function GoogleReviewsLink({\n googleMapsUri,\n label = 'Read our Google reviews',\n ...anchorProps\n}: GoogleReviewsLinkProps) {\n const href = normalizeGooglePlacePublicUrl(googleMapsUri)\n if (!href) return null\n return createElement(\n 'a',\n {\n ...anchorProps,\n href,\n 'data-brandlab-google-reviews': 'link-only',\n referrerPolicy: 'no-referrer',\n rel: 'noopener noreferrer',\n target: '_blank',\n },\n label,\n )\n}\n\nexport interface GooglePlaceReviewsProps extends HTMLAttributes<HTMLElement> {\n snapshot: GooglePlaceReviewsSnapshot\n reviewClassName?: string\n authorClassName?: string\n avatarClassName?: string\n actionsClassName?: string\n textClassName?: string\n attributionClassName?: string\n /** Styles the required review-ordering notice in full mode. */\n policyClassName?: string\n /** Styles the compact policy and provider-attribution row. */\n policyAttributionClassName?: string\n allReviewsLinkClassName?: string\n allReviewsLinkLabel?: string\n /** Keeps source order or presents up to three five-star reviews from the relevance window. */\n selection?: GooglePlaceReviewsSelection\n /** Selects the approved Google Maps attribution asset for the project background. */\n attributionTone?: 'light' | 'dark'\n /** Text is reserved for interfaces that cannot accommodate the official logo. */\n attributionMode?: 'logo' | 'text-constrained-space'\n}\n\nexport interface GooglePlaceReviewsAttributionProps {\n snapshot: GooglePlaceReviewsAvailableSnapshot\n className?: string\n attributionTone?: NonNullable<GooglePlaceReviewsProps['attributionTone']>\n attributionMode?: NonNullable<GooglePlaceReviewsProps['attributionMode']>\n}\n\nexport interface GooglePlaceReviewAuthorProps {\n review: GooglePlaceReview\n className?: string\n avatarClassName?: string\n}\n\nexport interface GooglePlaceReviewActionsProps {\n review: GooglePlaceReview\n className?: string\n}\n\nexport interface GooglePlaceReviewsPolicyAttributionProps\n extends GooglePlaceReviewsAttributionProps {\n selection?: GooglePlaceReviewsSelection\n policyClassName?: string\n policyAttributionClassName?: string\n}\n\nfunction assertNonEmptyText(value: unknown, field: string) {\n if (typeof value !== 'string' || !value.trim()) {\n throw new Error(`${field} is required for Google Places rendering.`)\n }\n}\n\nfunction assertPublicUrl(value: unknown, field: string, required = false) {\n if (value === undefined && !required) return\n if (typeof value !== 'string' || !normalizeGooglePlacePublicUrl(value)) {\n throw new Error(`${field} must be a credential-free HTTPS URL.`)\n }\n}\n\nfunction assertGooglePlaceReviewsSnapshotIsRenderable(\n snapshot: GooglePlaceReviewsAvailableSnapshot,\n) {\n assertNonEmptyText(snapshot.businessName, 'snapshot.businessName')\n assertPublicUrl(snapshot.googleMapsUri, 'snapshot.googleMapsUri', true)\n if (!['summary', 'full'].includes(snapshot.mode)) {\n throw new Error('snapshot.mode must be summary or full.')\n }\n if (\n snapshot.attribution?.label !== GOOGLE_MAPS_ATTRIBUTION_LABEL ||\n snapshot.attribution?.text !== GOOGLE_MAPS_ATTRIBUTION_TEXT\n ) {\n throw new Error('Google Maps attribution must use the unmodified shared label and text.')\n }\n if (\n !Array.isArray(snapshot.reviews) ||\n snapshot.reviews.length > GOOGLE_PLACE_REVIEWS_MAX_REVIEWS ||\n (snapshot.mode === 'summary' && snapshot.reviews.length > 0)\n ) {\n throw new Error('Google Places review content does not match the declared display mode.')\n }\n if (!Array.isArray(snapshot.thirdPartyAttributions)) {\n throw new Error('snapshot.thirdPartyAttributions is required for provider attribution.')\n }\n\n snapshot.reviews.forEach((review, index) => {\n assertNonEmptyText(review.authorName, `snapshot.reviews[${index}].authorName`)\n assertNonEmptyText(review.text, `snapshot.reviews[${index}].text`)\n assertPublicUrl(review.googleMapsUri, `snapshot.reviews[${index}].googleMapsUri`, true)\n assertPublicUrl(review.authorUri, `snapshot.reviews[${index}].authorUri`)\n assertPublicUrl(review.authorPhotoUri, `snapshot.reviews[${index}].authorPhotoUri`)\n assertPublicUrl(review.flagContentUri, `snapshot.reviews[${index}].flagContentUri`)\n })\n snapshot.thirdPartyAttributions.forEach((item, index) => {\n assertNonEmptyText(item.provider, `snapshot.thirdPartyAttributions[${index}].provider`)\n assertPublicUrl(item.providerUri, `snapshot.thirdPartyAttributions[${index}].providerUri`)\n })\n}\n\nfunction externalLinkProps(href: string) {\n return {\n href,\n referrerPolicy: 'no-referrer' as const,\n rel: 'noopener noreferrer',\n target: '_blank' as const,\n }\n}\n\n/** Reviewer identity. The avatar identifies and links to the author; it is not an actions button. */\nexport function GooglePlaceReviewAuthor({\n review,\n className,\n avatarClassName,\n}: GooglePlaceReviewAuthorProps) {\n const authorUri = normalizeGooglePlacePublicUrl(review.authorUri)\n const authorPhotoUri = normalizeGooglePlacePublicUrl(review.authorPhotoUri)\n const children = [\n authorPhotoUri\n ? createElement('img', {\n alt: '',\n className: avatarClassName,\n decoding: 'async',\n 'data-brandlab-google-review-avatar': 'author',\n height: 40,\n key: 'avatar',\n loading: 'lazy',\n referrerPolicy: 'no-referrer',\n src: authorPhotoUri,\n width: 40,\n })\n : null,\n createElement('span', { key: 'name' }, review.authorName),\n ]\n\n return authorUri\n ? createElement(\n 'a',\n {\n ...externalLinkProps(authorUri),\n className,\n 'data-brandlab-google-review-author': 'profile-link',\n },\n ...children,\n )\n : createElement(\n 'span',\n {\n className,\n 'data-brandlab-google-review-author': 'text',\n },\n ...children,\n )\n}\n\n/** Compact per-review source and reporting actions with no client JavaScript. */\nexport function GooglePlaceReviewActions({\n review,\n className,\n}: GooglePlaceReviewActionsProps) {\n const sourceUrl = normalizeGooglePlacePublicUrl(review.googleMapsUri)\n const flagContentUri = normalizeGooglePlacePublicUrl(review.flagContentUri)\n if (!sourceUrl) return null\n\n return createElement(\n 'details',\n {\n className,\n 'data-brandlab-google-review-actions': 'details',\n },\n createElement(\n 'summary',\n {\n 'aria-label': `Review options for ${review.authorName}`,\n 'data-brandlab-google-review-actions': 'trigger',\n },\n createElement('span', { 'aria-hidden': true }, '•••'),\n ),\n createElement(\n 'div',\n { 'data-brandlab-google-review-actions': 'menu' },\n createElement(\n 'a',\n {\n ...externalLinkProps(sourceUrl),\n 'data-brandlab-google-review-action': 'source',\n },\n 'Read this review on Google Maps',\n ),\n flagContentUri\n ? createElement(\n 'a',\n {\n ...externalLinkProps(flagContentUri),\n 'data-brandlab-google-review-action': 'report',\n },\n 'Report this review to Google',\n )\n : null,\n ),\n )\n}\n\nfunction renderGoogleMapsAttribution(\n attributionUrl: string | undefined,\n mode: NonNullable<GooglePlaceReviewsProps['attributionMode']>,\n tone: NonNullable<GooglePlaceReviewsProps['attributionTone']>,\n) {\n const content = mode === 'logo'\n ? createElement('img', {\n alt: GOOGLE_MAPS_ATTRIBUTION_LABEL,\n decoding: 'async',\n draggable: false,\n height: GOOGLE_MAPS_ATTRIBUTION_LOGO_HEIGHT,\n src: GOOGLE_MAPS_ATTRIBUTION_LOGO_DATA_URL[tone],\n width: GOOGLE_MAPS_ATTRIBUTION_LOGO_WIDTH,\n })\n : createElement(\n 'span',\n {\n 'data-brandlab-google-maps-attribution': 'text-constrained-space',\n translate: 'no' as const,\n },\n GOOGLE_MAPS_ATTRIBUTION_TEXT,\n )\n\n if (!attributionUrl) return content\n return createElement(\n 'a',\n {\n ...externalLinkProps(attributionUrl),\n 'aria-label': GOOGLE_MAPS_ATTRIBUTION_LABEL,\n 'data-brandlab-google-maps-attribution': mode,\n },\n content,\n )\n}\n\nfunction renderReview(\n review: GooglePlaceReview,\n index: number,\n props: GooglePlaceReviewsProps,\n) {\n return createElement(\n 'article',\n { className: props.reviewClassName, key: `${review.authorName}:${review.publishTime ?? index}` },\n createElement(\n 'header',\n null,\n createElement(GooglePlaceReviewAuthor, {\n avatarClassName: props.avatarClassName,\n className: props.authorClassName,\n review,\n }),\n review.rating\n ? createElement(\n 'span',\n { 'aria-label': `${review.rating} out of 5 stars` },\n `${review.rating}/5`,\n )\n : null,\n review.relativePublishTimeDescription\n ? createElement(\n 'time',\n { dateTime: review.publishTime },\n review.relativePublishTimeDescription,\n )\n : null,\n createElement(GooglePlaceReviewActions, {\n className: props.actionsClassName,\n review,\n }),\n ),\n createElement('blockquote', { className: props.textClassName }, createElement('p', null, review.text)),\n )\n}\n\n/** Required provider attribution with no project styling or layout policy. */\nexport function GooglePlaceReviewsAttribution({\n snapshot,\n className,\n attributionTone = 'light',\n attributionMode = 'logo',\n}: GooglePlaceReviewsAttributionProps) {\n const attributionUrl = normalizeGooglePlacePublicUrl(snapshot.googleMapsUri)\n return createElement(\n 'div',\n {\n className,\n 'data-brandlab-google-reviews-attribution': 'required',\n },\n ...snapshot.thirdPartyAttributions.map((item) => {\n const providerUri = normalizeGooglePlacePublicUrl(item.providerUri)\n return createElement(\n 'p',\n { key: `${item.provider}:${providerUri ?? ''}` },\n 'Data provider: ',\n providerUri\n ? createElement('a', externalLinkProps(providerUri), item.provider)\n : item.provider,\n )\n }),\n createElement(\n 'p',\n null,\n 'Reviews provided by ',\n renderGoogleMapsAttribution(attributionUrl, attributionMode, attributionTone),\n ),\n )\n}\n\nexport function GooglePlaceReviewsPolicyAttribution({\n snapshot,\n selection = 'relevance',\n className,\n policyClassName,\n policyAttributionClassName,\n attributionTone = 'light',\n attributionMode = 'logo',\n}: GooglePlaceReviewsPolicyAttributionProps) {\n const normalizedSelection = normalizeGooglePlaceReviewsSelection(selection)\n const policy = snapshot.mode === 'full' && snapshot.reviews.length > 0\n ? normalizedSelection === 'five-star-featured'\n ? \"Showing 5-star reviews selected from Google's relevance-ranked results.\"\n : 'Google Maps reviews are ordered by relevance.'\n : null\n\n return createElement(\n 'div',\n {\n className: policyAttributionClassName,\n 'data-brandlab-google-review-selection': normalizedSelection,\n 'data-brandlab-google-reviews-policy-attribution': 'compact',\n },\n policy\n ? createElement(\n 'p',\n {\n className: policyClassName,\n 'data-brandlab-google-review-ordering': normalizedSelection,\n },\n policy,\n )\n : null,\n createElement(GooglePlaceReviewsAttribution, {\n attributionMode,\n attributionTone,\n className,\n snapshot,\n }),\n )\n}\n\n/**\n * Minimal, unstyled Places output. Projects may use this semantic renderer or\n * render a validated snapshot themselves through GooglePlaceReviewsClient.\n */\nexport function GooglePlaceReviews({\n snapshot,\n reviewClassName,\n authorClassName,\n avatarClassName,\n actionsClassName,\n textClassName,\n attributionClassName,\n policyClassName,\n policyAttributionClassName,\n allReviewsLinkClassName,\n allReviewsLinkLabel = 'Read all reviews on Google Maps',\n selection = 'relevance',\n attributionTone = 'light',\n attributionMode = 'logo',\n ...sectionProps\n}: GooglePlaceReviewsProps) {\n if (snapshot.status !== 'available') return null\n assertGooglePlaceReviewsSnapshotIsRenderable(snapshot)\n const normalizedSelection = normalizeGooglePlaceReviewsSelection(selection)\n if (normalizedSelection === 'five-star-featured' && snapshot.mode !== 'full') {\n throw new Error('Five-star featured reviews require full mode.')\n }\n const displayedSnapshot = selectGooglePlaceReviewsSnapshot(snapshot, normalizedSelection)\n const props = {\n ...sectionProps,\n snapshot: displayedSnapshot,\n reviewClassName,\n authorClassName,\n avatarClassName,\n actionsClassName,\n textClassName,\n attributionClassName,\n attributionTone,\n attributionMode,\n }\n return createElement(\n 'section',\n {\n ...sectionProps,\n 'aria-label': sectionProps['aria-label'] ?? `${snapshot.businessName} reviews on Google Maps`,\n 'data-brandlab-google-reviews': `attribution-complete-${snapshot.mode}`,\n 'data-brandlab-google-attribution-mode': attributionMode,\n 'data-brandlab-google-review-count': displayedSnapshot.reviews.length,\n 'data-brandlab-google-review-selection': normalizedSelection,\n },\n snapshot.rating\n ? createElement(\n 'p',\n {\n 'aria-label': `Average rating ${snapshot.rating} out of 5${\n snapshot.userRatingCount === undefined ? '' : ` from ${snapshot.userRatingCount} reviews`\n }`,\n },\n `${snapshot.rating}/5${\n snapshot.userRatingCount === undefined ? '' : ` from ${snapshot.userRatingCount} reviews`\n }`,\n )\n : null,\n ...displayedSnapshot.reviews.map((review, index) => renderReview(review, index, props)),\n normalizedSelection === 'five-star-featured' && displayedSnapshot.reviews.length === 0\n ? createElement(GoogleReviewsLink, {\n className: allReviewsLinkClassName,\n googleMapsUri: displayedSnapshot.googleMapsUri,\n label: allReviewsLinkLabel,\n })\n : null,\n createElement(GooglePlaceReviewsPolicyAttribution, {\n attributionMode,\n attributionTone,\n className: attributionClassName,\n policyAttributionClassName,\n policyClassName,\n selection: normalizedSelection,\n snapshot: displayedSnapshot,\n }),\n )\n}\n"]}
1
+ {"version":3,"file":"google-reviews-ui.js","sourceRoot":"","sources":["../src/google-reviews-ui.ts"],"names":[],"mappings":"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","sourcesContent":["import { createElement, type AnchorHTMLAttributes, type HTMLAttributes } from 'react'\nimport {\n GOOGLE_MAPS_ATTRIBUTION_LABEL,\n GOOGLE_MAPS_ATTRIBUTION_TEXT,\n GOOGLE_PLACE_REVIEWS_MAX_REVIEWS,\n normalizeGooglePlacePublicUrl,\n normalizeGooglePlaceReviewsSelection,\n selectGooglePlaceReviewsSnapshot,\n type GooglePlaceReview,\n type GooglePlaceReviewsAvailableSnapshot,\n type GooglePlaceReviewsSelection,\n type GooglePlaceReviewsSnapshot,\n} from '@brandlab-digital/site-core/google-reviews'\nimport {\n GOOGLE_MAPS_ATTRIBUTION_LOGO_DATA_URL,\n GOOGLE_MAPS_ATTRIBUTION_LOGO_HEIGHT,\n GOOGLE_MAPS_ATTRIBUTION_LOGO_WIDTH,\n} from './google-maps-attribution-assets.js'\n\nexport interface GoogleReviewsLinkProps\n extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {\n googleMapsUri: string\n label?: string\n}\n\nexport function GoogleReviewsLink({\n googleMapsUri,\n label = 'Read our Google reviews',\n ...anchorProps\n}: GoogleReviewsLinkProps) {\n const href = normalizeGooglePlacePublicUrl(googleMapsUri)\n if (!href) return null\n return createElement(\n 'a',\n {\n ...anchorProps,\n href,\n 'data-brandlab-google-reviews': 'link-only',\n referrerPolicy: 'no-referrer',\n rel: 'noopener noreferrer',\n target: '_blank',\n },\n label,\n )\n}\n\nexport interface GooglePlaceReviewsProps extends HTMLAttributes<HTMLElement> {\n snapshot: GooglePlaceReviewsSnapshot\n reviewClassName?: string\n authorClassName?: string\n avatarClassName?: string\n actionsClassName?: string\n textClassName?: string\n attributionClassName?: string\n /** Styles the required review-ordering notice in full mode. */\n policyClassName?: string\n /** Styles the compact policy and provider-attribution row. */\n policyAttributionClassName?: string\n allReviewsLinkClassName?: string\n allReviewsLinkLabel?: string\n /** Keeps source order or presents up to three five-star reviews from the relevance window. */\n selection?: GooglePlaceReviewsSelection\n /** Selects the approved Google Maps attribution asset for the project background. */\n attributionTone?: 'light' | 'dark'\n /** Text is reserved for interfaces that cannot accommodate the official logo. */\n attributionMode?: 'logo' | 'text-constrained-space'\n}\n\nexport interface GooglePlaceReviewsAttributionProps {\n snapshot: GooglePlaceReviewsAvailableSnapshot\n className?: string\n /** Uses phrasing elements for placement beside inline data. Keep outside links. */\n inline?: boolean\n attributionTone?: NonNullable<GooglePlaceReviewsProps['attributionTone']>\n attributionMode?: NonNullable<GooglePlaceReviewsProps['attributionMode']>\n}\n\nexport interface GooglePlaceReviewAuthorProps {\n review: GooglePlaceReview\n className?: string\n avatarClassName?: string\n}\n\nexport interface GooglePlaceReviewActionsProps {\n review: GooglePlaceReview\n className?: string\n}\n\nexport interface GooglePlaceReviewsPolicyAttributionProps\n extends GooglePlaceReviewsAttributionProps {\n selection?: GooglePlaceReviewsSelection\n policyClassName?: string\n policyAttributionClassName?: string\n}\n\nfunction assertNonEmptyText(value: unknown, field: string) {\n if (typeof value !== 'string' || !value.trim()) {\n throw new Error(`${field} is required for Google Places rendering.`)\n }\n}\n\nfunction assertPublicUrl(value: unknown, field: string, required = false) {\n if (value === undefined && !required) return\n if (typeof value !== 'string' || !normalizeGooglePlacePublicUrl(value)) {\n throw new Error(`${field} must be a credential-free HTTPS URL.`)\n }\n}\n\nfunction assertGooglePlaceReviewsSnapshotIsRenderable(\n snapshot: GooglePlaceReviewsAvailableSnapshot,\n) {\n assertNonEmptyText(snapshot.businessName, 'snapshot.businessName')\n assertPublicUrl(snapshot.googleMapsUri, 'snapshot.googleMapsUri', true)\n if (!['summary', 'full'].includes(snapshot.mode)) {\n throw new Error('snapshot.mode must be summary or full.')\n }\n if (\n snapshot.attribution?.label !== GOOGLE_MAPS_ATTRIBUTION_LABEL ||\n snapshot.attribution?.text !== GOOGLE_MAPS_ATTRIBUTION_TEXT\n ) {\n throw new Error('Google Maps attribution must use the unmodified shared label and text.')\n }\n if (\n !Array.isArray(snapshot.reviews) ||\n snapshot.reviews.length > GOOGLE_PLACE_REVIEWS_MAX_REVIEWS ||\n (snapshot.mode === 'summary' && snapshot.reviews.length > 0)\n ) {\n throw new Error('Google Places review content does not match the declared display mode.')\n }\n if (!Array.isArray(snapshot.thirdPartyAttributions)) {\n throw new Error('snapshot.thirdPartyAttributions is required for provider attribution.')\n }\n\n snapshot.reviews.forEach((review, index) => {\n assertNonEmptyText(review.authorName, `snapshot.reviews[${index}].authorName`)\n assertNonEmptyText(review.text, `snapshot.reviews[${index}].text`)\n assertPublicUrl(review.googleMapsUri, `snapshot.reviews[${index}].googleMapsUri`, true)\n assertPublicUrl(review.authorUri, `snapshot.reviews[${index}].authorUri`)\n assertPublicUrl(review.authorPhotoUri, `snapshot.reviews[${index}].authorPhotoUri`)\n assertPublicUrl(review.flagContentUri, `snapshot.reviews[${index}].flagContentUri`)\n })\n snapshot.thirdPartyAttributions.forEach((item, index) => {\n assertNonEmptyText(item.provider, `snapshot.thirdPartyAttributions[${index}].provider`)\n assertPublicUrl(item.providerUri, `snapshot.thirdPartyAttributions[${index}].providerUri`)\n })\n}\n\nfunction externalLinkProps(href: string) {\n return {\n href,\n referrerPolicy: 'no-referrer' as const,\n rel: 'noopener noreferrer',\n target: '_blank' as const,\n }\n}\n\n/** Reviewer identity. The avatar identifies and links to the author; it is not an actions button. */\nexport function GooglePlaceReviewAuthor({\n review,\n className,\n avatarClassName,\n}: GooglePlaceReviewAuthorProps) {\n const authorUri = normalizeGooglePlacePublicUrl(review.authorUri)\n const authorPhotoUri = normalizeGooglePlacePublicUrl(review.authorPhotoUri)\n const children = [\n authorPhotoUri\n ? createElement('img', {\n alt: '',\n className: avatarClassName,\n decoding: 'async',\n 'data-brandlab-google-review-avatar': 'author',\n height: 40,\n key: 'avatar',\n loading: 'lazy',\n referrerPolicy: 'no-referrer',\n src: authorPhotoUri,\n width: 40,\n })\n : null,\n createElement('span', { key: 'name' }, review.authorName),\n ]\n\n return authorUri\n ? createElement(\n 'a',\n {\n ...externalLinkProps(authorUri),\n className,\n 'data-brandlab-google-review-author': 'profile-link',\n },\n ...children,\n )\n : createElement(\n 'span',\n {\n className,\n 'data-brandlab-google-review-author': 'text',\n },\n ...children,\n )\n}\n\n/** Compact per-review source and reporting actions with no client JavaScript. */\nexport function GooglePlaceReviewActions({\n review,\n className,\n}: GooglePlaceReviewActionsProps) {\n const sourceUrl = normalizeGooglePlacePublicUrl(review.googleMapsUri)\n const flagContentUri = normalizeGooglePlacePublicUrl(review.flagContentUri)\n if (!sourceUrl) return null\n\n return createElement(\n 'details',\n {\n className,\n 'data-brandlab-google-review-actions': 'details',\n },\n createElement(\n 'summary',\n {\n 'aria-label': `Review options for ${review.authorName}`,\n 'data-brandlab-google-review-actions': 'trigger',\n },\n createElement('span', { 'aria-hidden': true }, '•••'),\n ),\n createElement(\n 'div',\n { 'data-brandlab-google-review-actions': 'menu' },\n createElement(\n 'a',\n {\n ...externalLinkProps(sourceUrl),\n 'data-brandlab-google-review-action': 'source',\n },\n 'Read this review on Google Maps',\n ),\n flagContentUri\n ? createElement(\n 'a',\n {\n ...externalLinkProps(flagContentUri),\n 'data-brandlab-google-review-action': 'report',\n },\n 'Report this review to Google',\n )\n : null,\n ),\n )\n}\n\nfunction renderGoogleMapsAttribution(\n attributionUrl: string | undefined,\n mode: NonNullable<GooglePlaceReviewsProps['attributionMode']>,\n tone: NonNullable<GooglePlaceReviewsProps['attributionTone']>,\n) {\n const content = mode === 'logo'\n ? createElement('img', {\n alt: GOOGLE_MAPS_ATTRIBUTION_LABEL,\n decoding: 'async',\n draggable: false,\n height: GOOGLE_MAPS_ATTRIBUTION_LOGO_HEIGHT,\n src: GOOGLE_MAPS_ATTRIBUTION_LOGO_DATA_URL[tone],\n width: GOOGLE_MAPS_ATTRIBUTION_LOGO_WIDTH,\n })\n : createElement(\n 'span',\n {\n 'data-brandlab-google-maps-attribution': 'text-constrained-space',\n translate: 'no' as const,\n },\n GOOGLE_MAPS_ATTRIBUTION_TEXT,\n )\n\n if (!attributionUrl) return content\n return createElement(\n 'a',\n {\n ...externalLinkProps(attributionUrl),\n 'aria-label': GOOGLE_MAPS_ATTRIBUTION_LABEL,\n 'data-brandlab-google-maps-attribution': mode,\n },\n content,\n )\n}\n\nfunction renderReview(\n review: GooglePlaceReview,\n index: number,\n props: GooglePlaceReviewsProps,\n) {\n return createElement(\n 'article',\n { className: props.reviewClassName, key: `${review.authorName}:${review.publishTime ?? index}` },\n createElement(\n 'header',\n null,\n createElement(GooglePlaceReviewAuthor, {\n avatarClassName: props.avatarClassName,\n className: props.authorClassName,\n review,\n }),\n review.rating\n ? createElement(\n 'span',\n { 'aria-label': `${review.rating} out of 5 stars` },\n `${review.rating}/5`,\n )\n : null,\n review.relativePublishTimeDescription\n ? createElement(\n 'time',\n { dateTime: review.publishTime },\n review.relativePublishTimeDescription,\n )\n : null,\n createElement(GooglePlaceReviewActions, {\n className: props.actionsClassName,\n review,\n }),\n ),\n createElement('blockquote', { className: props.textClassName }, createElement('p', null, review.text)),\n )\n}\n\n/** Required provider attribution with no project styling or layout policy. */\nexport function GooglePlaceReviewsAttribution({\n snapshot,\n className,\n inline = false,\n attributionTone = 'light',\n attributionMode = 'logo',\n}: GooglePlaceReviewsAttributionProps) {\n const attributionUrl = normalizeGooglePlacePublicUrl(snapshot.googleMapsUri)\n return createElement(\n inline ? 'span' : 'div',\n {\n className,\n 'data-brandlab-google-reviews-attribution': 'required',\n },\n ...snapshot.thirdPartyAttributions.map((item) => {\n const providerUri = normalizeGooglePlacePublicUrl(item.providerUri)\n return createElement(\n inline ? 'span' : 'p',\n { key: `${item.provider}:${providerUri ?? ''}` },\n 'Data provider: ',\n providerUri\n ? createElement('a', externalLinkProps(providerUri), item.provider)\n : item.provider,\n inline ? ' ' : null,\n )\n }),\n createElement(\n inline ? 'span' : 'p',\n null,\n 'Reviews provided by ',\n renderGoogleMapsAttribution(attributionUrl, attributionMode, attributionTone),\n ),\n )\n}\n\nexport function GooglePlaceReviewsPolicyAttribution({\n snapshot,\n selection = 'relevance',\n className,\n policyClassName,\n policyAttributionClassName,\n inline = false,\n attributionTone = 'light',\n attributionMode = 'logo',\n}: GooglePlaceReviewsPolicyAttributionProps) {\n const normalizedSelection = normalizeGooglePlaceReviewsSelection(selection)\n const policy = snapshot.mode === 'full' && snapshot.reviews.length > 0\n ? normalizedSelection === 'five-star-featured'\n ? \"Showing 5-star reviews selected from Google's relevance-ranked results.\"\n : 'Google Maps reviews are ordered by relevance.'\n : null\n\n return createElement(\n inline ? 'span' : 'div',\n {\n className: policyAttributionClassName,\n 'data-brandlab-google-review-selection': normalizedSelection,\n 'data-brandlab-google-reviews-policy-attribution': 'compact',\n },\n policy\n ? createElement(\n inline ? 'span' : 'p',\n {\n className: policyClassName,\n 'data-brandlab-google-review-ordering': normalizedSelection,\n },\n inline ? `${policy} ` : policy,\n )\n : null,\n createElement(GooglePlaceReviewsAttribution, {\n inline,\n attributionMode,\n attributionTone,\n className,\n snapshot,\n }),\n )\n}\n\n/**\n * Minimal, unstyled Places output. Projects may use this semantic renderer or\n * render a validated snapshot themselves through GooglePlaceReviewsClient.\n */\nexport function GooglePlaceReviews({\n snapshot,\n reviewClassName,\n authorClassName,\n avatarClassName,\n actionsClassName,\n textClassName,\n attributionClassName,\n policyClassName,\n policyAttributionClassName,\n allReviewsLinkClassName,\n allReviewsLinkLabel = 'Read all reviews on Google Maps',\n selection = 'relevance',\n attributionTone = 'light',\n attributionMode = 'logo',\n ...sectionProps\n}: GooglePlaceReviewsProps) {\n if (snapshot.status !== 'available') return null\n assertGooglePlaceReviewsSnapshotIsRenderable(snapshot)\n const normalizedSelection = normalizeGooglePlaceReviewsSelection(selection)\n if (normalizedSelection === 'five-star-featured' && snapshot.mode !== 'full') {\n throw new Error('Five-star featured reviews require full mode.')\n }\n const displayedSnapshot = selectGooglePlaceReviewsSnapshot(snapshot, normalizedSelection)\n const props = {\n ...sectionProps,\n snapshot: displayedSnapshot,\n reviewClassName,\n authorClassName,\n avatarClassName,\n actionsClassName,\n textClassName,\n attributionClassName,\n attributionTone,\n attributionMode,\n }\n return createElement(\n 'section',\n {\n ...sectionProps,\n 'aria-label': sectionProps['aria-label'] ?? `${snapshot.businessName} reviews on Google Maps`,\n 'data-brandlab-google-reviews': `attribution-complete-${snapshot.mode}`,\n 'data-brandlab-google-attribution-mode': attributionMode,\n 'data-brandlab-google-review-count': displayedSnapshot.reviews.length,\n 'data-brandlab-google-review-selection': normalizedSelection,\n },\n snapshot.rating\n ? createElement(\n 'p',\n {\n 'aria-label': `Average rating ${snapshot.rating} out of 5${\n snapshot.userRatingCount === undefined ? '' : ` from ${snapshot.userRatingCount} reviews`\n }`,\n },\n `${snapshot.rating}/5${\n snapshot.userRatingCount === undefined ? '' : ` from ${snapshot.userRatingCount} reviews`\n }`,\n )\n : null,\n ...displayedSnapshot.reviews.map((review, index) => renderReview(review, index, props)),\n normalizedSelection === 'five-star-featured' && displayedSnapshot.reviews.length === 0\n ? createElement(GoogleReviewsLink, {\n className: allReviewsLinkClassName,\n googleMapsUri: displayedSnapshot.googleMapsUri,\n label: allReviewsLinkLabel,\n })\n : null,\n createElement(GooglePlaceReviewsPolicyAttribution, {\n attributionMode,\n attributionTone,\n className: attributionClassName,\n policyAttributionClassName,\n policyClassName,\n selection: normalizedSelection,\n snapshot: displayedSnapshot,\n }),\n )\n}\n"]}
@@ -19,13 +19,7 @@ export declare function getInitialLandingPath(win?: Window): string | undefined;
19
19
  export declare function getInitialContactAttribution(win?: Window): ContactAttributionSummary;
20
20
  export declare function getPhoneCallLocation(link: HTMLAnchorElement): PhoneCallLocation;
21
21
  export declare function installPhoneClickListener(options: {
22
- trackPhoneLinkClick?: (context: {
23
- pagePath: string;
24
- location: PhoneCallLocation;
25
- initialLandingPath?: string;
26
- }) => void;
27
- /** @deprecated Use trackPhoneLinkClick. */
28
- trackPhoneCall?: (context: {
22
+ trackPhoneLinkClick: (context: {
29
23
  pagePath: string;
30
24
  location: PhoneCallLocation;
31
25
  initialLandingPath?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation-client.d.ts","sourceRoot":"","sources":["../src/instrumentation-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,qCAAqC,CAAA;AAM5C,MAAM,MAAM,iBAAiB,GACzB,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,KAAK,GACL,KAAK,GACL,SAAS,GACT,UAAU,GACV,MAAM,CAAA;AAEV,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,EAAE,EAAE,MAAM,CAAA;CACX;AAED,eAAO,MAAM,8BAA8B,6BAA6B,CAAA;AACxE,eAAO,MAAM,mCAAmC,OAAO,CAAA;AAEvD,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,UAe9E;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAEtE;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IACjD,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,kBAAkB,CAAA;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,WAOA;AAED,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAe,QAgCzD;AAED,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAe,sBAOzD;AAED,wBAAgB,4BAA4B,CAAC,GAAG,GAAE,MAAe,GAAG,yBAAyB,CAkB5F;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,CAU/E;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IACjD,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE;QAC9B,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,EAAE,iBAAiB,CAAA;QAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAC5B,KAAK,IAAI,CAAA;IACV,2CAA2C;IAC3C,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE;QACzB,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,EAAE,iBAAiB,CAAA;QAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAC5B,KAAK,IAAI,CAAA;IACV,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,cA4CA"}
1
+ {"version":3,"file":"instrumentation-client.d.ts","sourceRoot":"","sources":["../src/instrumentation-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,qCAAqC,CAAA;AAM5C,MAAM,MAAM,iBAAiB,GACzB,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,KAAK,GACL,KAAK,GACL,SAAS,GACT,UAAU,GACV,MAAM,CAAA;AAEV,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,EAAE,EAAE,MAAM,CAAA;CACX;AAED,eAAO,MAAM,8BAA8B,6BAA6B,CAAA;AACxE,eAAO,MAAM,mCAAmC,OAAO,CAAA;AAEvD,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,UAe9E;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAEtE;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IACjD,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,kBAAkB,CAAA;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,WAOA;AAED,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAe,QAgCzD;AAED,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAe,sBAOzD;AAED,wBAAgB,4BAA4B,CAAC,GAAG,GAAE,MAAe,GAAG,yBAAyB,CAkB5F;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,CAU/E;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IACjD,mBAAmB,EAAE,CAAC,OAAO,EAAE;QAC7B,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,EAAE,iBAAiB,CAAA;QAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAC5B,KAAK,IAAI,CAAA;IACV,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,cA4CA"}
@@ -101,7 +101,7 @@ export function getPhoneCallLocation(link) {
101
101
  }
102
102
  export function installPhoneClickListener(options) {
103
103
  const win = options.win ?? window;
104
- const trackPhoneLinkClick = options.trackPhoneLinkClick ?? options.trackPhoneCall;
104
+ const trackPhoneLinkClick = options.trackPhoneLinkClick;
105
105
  if (!trackPhoneLinkClick) {
106
106
  throw new Error('installPhoneClickListener requires trackPhoneLinkClick.');
107
107
  }
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation-client.js","sourceRoot":"","sources":["../src/instrumentation-client.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isContactVisitSource,\n type ContactAttributionSummary,\n} from '@brandlab-digital/site-core/contact'\nimport {\n classifyContactAttribution,\n normalizeContactAttributionSummary,\n} from './contact/attribution.js'\n\nexport type PhoneCallLocation =\n | 'header'\n | 'footer'\n | 'hero'\n | 'cta'\n | 'fab'\n | 'contact'\n | 'location'\n | 'page'\n\nexport interface LastPhoneCallEvent {\n key: string\n at: number\n}\n\nexport const INITIAL_LANDING_STORAGE_PREFIX = 'brandlab.initialLanding.'\nexport const DEFAULT_PHONE_CALL_DEDUPE_WINDOW_MS = 1200\n\nexport function normalizeInitialLandingPath(pathname: string | null | undefined) {\n const trimmed = pathname?.trim() || '/'\n if (\n !trimmed.startsWith('/') ||\n trimmed.startsWith('//') ||\n trimmed.includes('\\\\') ||\n /%(?:2f|5c)/i.test(trimmed) ||\n /[\\u0000-\\u001f\\u007f]/.test(trimmed) ||\n trimmed.includes('?') ||\n trimmed.includes('#')\n ) {\n return '/'\n }\n const normalized = trimmed.replace(/\\/{2,}/g, '/')\n return normalized === '/' ? '/' : normalized.replace(/\\/+$/, '')\n}\n\nexport function createPhoneCallDedupeKey(pagePath: string, href: string) {\n return `${pagePath}|${href}`\n}\n\nexport function shouldTrackPhoneCallClick(options: {\n key: string\n now: number\n lastEvent?: LastPhoneCallEvent\n dedupeWindowMs?: number\n}) {\n const windowMs = options.dedupeWindowMs ?? DEFAULT_PHONE_CALL_DEDUPE_WINDOW_MS\n return !(\n options.lastEvent &&\n options.lastEvent.key === options.key &&\n options.now - options.lastEvent.at < windowMs\n )\n}\n\nexport function persistInitialLanding(win: Window = window) {\n try {\n const pathKey = `${INITIAL_LANDING_STORAGE_PREFIX}path`\n const sourceKey = `${INITIAL_LANDING_STORAGE_PREFIX}source`\n const detailKey = `${INITIAL_LANDING_STORAGE_PREFIX}sourceDetail`\n const existingPath = win.sessionStorage.getItem(pathKey)\n const safePath = normalizeInitialLandingPath(existingPath ?? win.location.pathname)\n if (existingPath !== safePath) {\n win.sessionStorage.setItem(pathKey, safePath)\n }\n const existingSource = win.sessionStorage.getItem(sourceKey)\n if (!isContactVisitSource(existingSource)) {\n const attribution = classifyContactAttribution({\n initialLandingPath: safePath,\n search: win.location.search,\n referrer: win.document.referrer,\n siteOrigin: win.location.origin,\n })\n win.sessionStorage.setItem(sourceKey, attribution.visitSource)\n if (attribution.visitSourceDetail) {\n win.sessionStorage.setItem(detailKey, attribution.visitSourceDetail)\n } else {\n win.sessionStorage.removeItem(detailKey)\n }\n }\n // Remove values written by the pre-RC privacy contract. Query strings and\n // referrers are not needed for canonical lead measurement.\n win.sessionStorage.removeItem(`${INITIAL_LANDING_STORAGE_PREFIX}url`)\n win.sessionStorage.removeItem(`${INITIAL_LANDING_STORAGE_PREFIX}referrer`)\n } catch {\n // Storage failures must not affect navigation or lead tracking.\n }\n}\n\nexport function getInitialLandingPath(win: Window = window) {\n try {\n const value = win.sessionStorage.getItem(`${INITIAL_LANDING_STORAGE_PREFIX}path`)\n return value ? normalizeInitialLandingPath(value) : undefined\n } catch {\n return undefined\n }\n}\n\nexport function getInitialContactAttribution(win: Window = window): ContactAttributionSummary {\n const fallbackPath = normalizeInitialLandingPath(win.location.pathname)\n try {\n const initialLandingPath = normalizeInitialLandingPath(\n win.sessionStorage.getItem(`${INITIAL_LANDING_STORAGE_PREFIX}path`) ?? fallbackPath,\n )\n const visitSource = win.sessionStorage.getItem(`${INITIAL_LANDING_STORAGE_PREFIX}source`)\n const visitSourceDetail = win.sessionStorage.getItem(\n `${INITIAL_LANDING_STORAGE_PREFIX}sourceDetail`,\n )\n return normalizeContactAttributionSummary({\n initialLandingPath,\n visitSource: isContactVisitSource(visitSource) ? visitSource : 'direct-or-unknown',\n ...(visitSourceDetail ? { visitSourceDetail } : {}),\n })\n } catch {\n return { initialLandingPath: fallbackPath, visitSource: 'direct-or-unknown' }\n }\n}\n\nexport function getPhoneCallLocation(link: HTMLAnchorElement): PhoneCallLocation {\n const explicitLocation = link.dataset.phoneLocation as PhoneCallLocation | undefined\n\n if (explicitLocation) return explicitLocation\n if (link.closest('header')) return 'header'\n if (link.closest('footer')) return 'footer'\n if (link.closest('[data-phone-location=\"hero\"]')) return 'hero'\n if (link.closest('[data-phone-location=\"cta\"]')) return 'cta'\n\n return 'page'\n}\n\nexport function installPhoneClickListener(options: {\n trackPhoneLinkClick?: (context: {\n pagePath: string\n location: PhoneCallLocation\n initialLandingPath?: string\n }) => void\n /** @deprecated Use trackPhoneLinkClick. */\n trackPhoneCall?: (context: {\n pagePath: string\n location: PhoneCallLocation\n initialLandingPath?: string\n }) => void\n win?: Window\n dedupeWindowMs?: number\n}) {\n const win = options.win ?? window\n const trackPhoneLinkClick = options.trackPhoneLinkClick ?? options.trackPhoneCall\n if (!trackPhoneLinkClick) {\n throw new Error('installPhoneClickListener requires trackPhoneLinkClick.')\n }\n let lastEvent: LastPhoneCallEvent | undefined\n\n const handlePhoneClick = (event: MouseEvent) => {\n const target = event.target\n if (!(target instanceof Element)) return\n\n const link = target.closest<HTMLAnchorElement>('a[href^=\"tel:\"]')\n if (!link) return\n\n const pagePath = win.location.pathname || '/'\n const href = link.getAttribute('href') || link.href\n const key = createPhoneCallDedupeKey(pagePath, href)\n const now = Date.now()\n\n if (\n !shouldTrackPhoneCallClick({\n key,\n now,\n lastEvent,\n dedupeWindowMs: options.dedupeWindowMs,\n })\n ) {\n return\n }\n\n lastEvent = { key, at: now }\n trackPhoneLinkClick({\n pagePath,\n location: getPhoneCallLocation(link),\n initialLandingPath: getInitialLandingPath(win),\n })\n }\n\n win.document.addEventListener('click', handlePhoneClick, true)\n\n return () => {\n win.document.removeEventListener('click', handlePhoneClick, true)\n }\n}\n"]}
1
+ {"version":3,"file":"instrumentation-client.js","sourceRoot":"","sources":["../src/instrumentation-client.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isContactVisitSource,\n type ContactAttributionSummary,\n} from '@brandlab-digital/site-core/contact'\nimport {\n classifyContactAttribution,\n normalizeContactAttributionSummary,\n} from './contact/attribution.js'\n\nexport type PhoneCallLocation =\n | 'header'\n | 'footer'\n | 'hero'\n | 'cta'\n | 'fab'\n | 'contact'\n | 'location'\n | 'page'\n\nexport interface LastPhoneCallEvent {\n key: string\n at: number\n}\n\nexport const INITIAL_LANDING_STORAGE_PREFIX = 'brandlab.initialLanding.'\nexport const DEFAULT_PHONE_CALL_DEDUPE_WINDOW_MS = 1200\n\nexport function normalizeInitialLandingPath(pathname: string | null | undefined) {\n const trimmed = pathname?.trim() || '/'\n if (\n !trimmed.startsWith('/') ||\n trimmed.startsWith('//') ||\n trimmed.includes('\\\\') ||\n /%(?:2f|5c)/i.test(trimmed) ||\n /[\\u0000-\\u001f\\u007f]/.test(trimmed) ||\n trimmed.includes('?') ||\n trimmed.includes('#')\n ) {\n return '/'\n }\n const normalized = trimmed.replace(/\\/{2,}/g, '/')\n return normalized === '/' ? '/' : normalized.replace(/\\/+$/, '')\n}\n\nexport function createPhoneCallDedupeKey(pagePath: string, href: string) {\n return `${pagePath}|${href}`\n}\n\nexport function shouldTrackPhoneCallClick(options: {\n key: string\n now: number\n lastEvent?: LastPhoneCallEvent\n dedupeWindowMs?: number\n}) {\n const windowMs = options.dedupeWindowMs ?? DEFAULT_PHONE_CALL_DEDUPE_WINDOW_MS\n return !(\n options.lastEvent &&\n options.lastEvent.key === options.key &&\n options.now - options.lastEvent.at < windowMs\n )\n}\n\nexport function persistInitialLanding(win: Window = window) {\n try {\n const pathKey = `${INITIAL_LANDING_STORAGE_PREFIX}path`\n const sourceKey = `${INITIAL_LANDING_STORAGE_PREFIX}source`\n const detailKey = `${INITIAL_LANDING_STORAGE_PREFIX}sourceDetail`\n const existingPath = win.sessionStorage.getItem(pathKey)\n const safePath = normalizeInitialLandingPath(existingPath ?? win.location.pathname)\n if (existingPath !== safePath) {\n win.sessionStorage.setItem(pathKey, safePath)\n }\n const existingSource = win.sessionStorage.getItem(sourceKey)\n if (!isContactVisitSource(existingSource)) {\n const attribution = classifyContactAttribution({\n initialLandingPath: safePath,\n search: win.location.search,\n referrer: win.document.referrer,\n siteOrigin: win.location.origin,\n })\n win.sessionStorage.setItem(sourceKey, attribution.visitSource)\n if (attribution.visitSourceDetail) {\n win.sessionStorage.setItem(detailKey, attribution.visitSourceDetail)\n } else {\n win.sessionStorage.removeItem(detailKey)\n }\n }\n // Remove values written by the pre-RC privacy contract. Query strings and\n // referrers are not needed for canonical lead measurement.\n win.sessionStorage.removeItem(`${INITIAL_LANDING_STORAGE_PREFIX}url`)\n win.sessionStorage.removeItem(`${INITIAL_LANDING_STORAGE_PREFIX}referrer`)\n } catch {\n // Storage failures must not affect navigation or lead tracking.\n }\n}\n\nexport function getInitialLandingPath(win: Window = window) {\n try {\n const value = win.sessionStorage.getItem(`${INITIAL_LANDING_STORAGE_PREFIX}path`)\n return value ? normalizeInitialLandingPath(value) : undefined\n } catch {\n return undefined\n }\n}\n\nexport function getInitialContactAttribution(win: Window = window): ContactAttributionSummary {\n const fallbackPath = normalizeInitialLandingPath(win.location.pathname)\n try {\n const initialLandingPath = normalizeInitialLandingPath(\n win.sessionStorage.getItem(`${INITIAL_LANDING_STORAGE_PREFIX}path`) ?? fallbackPath,\n )\n const visitSource = win.sessionStorage.getItem(`${INITIAL_LANDING_STORAGE_PREFIX}source`)\n const visitSourceDetail = win.sessionStorage.getItem(\n `${INITIAL_LANDING_STORAGE_PREFIX}sourceDetail`,\n )\n return normalizeContactAttributionSummary({\n initialLandingPath,\n visitSource: isContactVisitSource(visitSource) ? visitSource : 'direct-or-unknown',\n ...(visitSourceDetail ? { visitSourceDetail } : {}),\n })\n } catch {\n return { initialLandingPath: fallbackPath, visitSource: 'direct-or-unknown' }\n }\n}\n\nexport function getPhoneCallLocation(link: HTMLAnchorElement): PhoneCallLocation {\n const explicitLocation = link.dataset.phoneLocation as PhoneCallLocation | undefined\n\n if (explicitLocation) return explicitLocation\n if (link.closest('header')) return 'header'\n if (link.closest('footer')) return 'footer'\n if (link.closest('[data-phone-location=\"hero\"]')) return 'hero'\n if (link.closest('[data-phone-location=\"cta\"]')) return 'cta'\n\n return 'page'\n}\n\nexport function installPhoneClickListener(options: {\n trackPhoneLinkClick: (context: {\n pagePath: string\n location: PhoneCallLocation\n initialLandingPath?: string\n }) => void\n win?: Window\n dedupeWindowMs?: number\n}) {\n const win = options.win ?? window\n const trackPhoneLinkClick = options.trackPhoneLinkClick\n if (!trackPhoneLinkClick) {\n throw new Error('installPhoneClickListener requires trackPhoneLinkClick.')\n }\n let lastEvent: LastPhoneCallEvent | undefined\n\n const handlePhoneClick = (event: MouseEvent) => {\n const target = event.target\n if (!(target instanceof Element)) return\n\n const link = target.closest<HTMLAnchorElement>('a[href^=\"tel:\"]')\n if (!link) return\n\n const pagePath = win.location.pathname || '/'\n const href = link.getAttribute('href') || link.href\n const key = createPhoneCallDedupeKey(pagePath, href)\n const now = Date.now()\n\n if (\n !shouldTrackPhoneCallClick({\n key,\n now,\n lastEvent,\n dedupeWindowMs: options.dedupeWindowMs,\n })\n ) {\n return\n }\n\n lastEvent = { key, at: now }\n trackPhoneLinkClick({\n pagePath,\n location: getPhoneCallLocation(link),\n initialLandingPath: getInitialLandingPath(win),\n })\n }\n\n win.document.addEventListener('click', handlePhoneClick, true)\n\n return () => {\n win.document.removeEventListener('click', handlePhoneClick, true)\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brandlab-digital/site-next",
3
- "version": "1.3.1",
3
+ "version": "2.1.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/RomieDandan/brandlab.git",
@@ -20,7 +20,7 @@
20
20
  "typecheck": "tsc --noEmit -p tsconfig.json"
21
21
  },
22
22
  "dependencies": {
23
- "@brandlab-digital/site-core": "1.3.1",
23
+ "@brandlab-digital/site-core": "2.1.0",
24
24
  "browser-image-compression": "2.0.2",
25
25
  "pdf-lib": "1.17.1",
26
26
  "server-only": "0.0.1",