@brandlab-digital/site-next 2.0.0 → 3.0.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.
- package/dist/analytics.d.ts +111 -52
- package/dist/analytics.d.ts.map +1 -1
- package/dist/analytics.js +281 -153
- package/dist/analytics.js.map +1 -1
- package/dist/blog.d.ts +4 -2
- package/dist/blog.d.ts.map +1 -1
- package/dist/blog.js +7 -7
- package/dist/blog.js.map +1 -1
- package/dist/contact/client-entry.d.ts +2 -0
- package/dist/contact/client-entry.d.ts.map +1 -1
- package/dist/contact/client-entry.js +1 -0
- package/dist/contact/client-entry.js.map +1 -1
- package/dist/contact/client.d.ts +12 -22
- package/dist/contact/client.d.ts.map +1 -1
- package/dist/contact/client.js +28 -21
- package/dist/contact/client.js.map +1 -1
- package/dist/contact/form-client.d.ts +148 -0
- package/dist/contact/form-client.d.ts.map +1 -0
- package/dist/contact/form-client.js +234 -0
- package/dist/contact/form-client.js.map +1 -0
- package/dist/contact/index.d.ts +1 -1
- package/dist/contact/index.d.ts.map +1 -1
- package/dist/contact/index.js +1 -1
- package/dist/contact/index.js.map +1 -1
- package/dist/contact/route-handler.d.ts +32 -0
- package/dist/contact/route-handler.d.ts.map +1 -0
- package/dist/contact/route-handler.js +44 -0
- package/dist/contact/route-handler.js.map +1 -0
- package/dist/contact/server-entry.d.ts +1 -0
- package/dist/contact/server-entry.d.ts.map +1 -1
- package/dist/contact/server-entry.js +1 -0
- package/dist/contact/server-entry.js.map +1 -1
- package/dist/contact/server.d.ts +5 -0
- package/dist/contact/server.d.ts.map +1 -1
- package/dist/contact/server.js +13 -7
- package/dist/contact/server.js.map +1 -1
- package/dist/contact/shared.d.ts +4 -0
- package/dist/contact/shared.d.ts.map +1 -1
- package/dist/contact/shared.js.map +1 -1
- package/dist/contact/testing.d.ts +29 -0
- package/dist/contact/testing.d.ts.map +1 -1
- package/dist/contact/testing.js +27 -0
- package/dist/contact/testing.js.map +1 -1
- package/dist/google-reviews-client.d.ts +12 -1
- package/dist/google-reviews-client.d.ts.map +1 -1
- package/dist/google-reviews-client.js +38 -41
- package/dist/google-reviews-client.js.map +1 -1
- package/dist/google-reviews-ui.d.ts +4 -2
- package/dist/google-reviews-ui.d.ts.map +1 -1
- package/dist/google-reviews-ui.js +10 -9
- package/dist/google-reviews-ui.js.map +1 -1
- package/dist/google-tag-plan.d.ts +1 -4
- package/dist/google-tag-plan.d.ts.map +1 -1
- package/dist/google-tag-plan.js +1 -14
- package/dist/google-tag-plan.js.map +1 -1
- package/dist/google-tag.d.ts +5 -4
- package/dist/google-tag.d.ts.map +1 -1
- package/dist/google-tag.js +5 -4
- package/dist/google-tag.js.map +1 -1
- package/dist/headers.d.ts +21 -28
- package/dist/headers.d.ts.map +1 -1
- package/dist/headers.js +62 -51
- package/dist/headers.js.map +1 -1
- package/dist/instrumentation-client.d.ts +21 -1
- package/dist/instrumentation-client.d.ts.map +1 -1
- package/dist/instrumentation-client.js +62 -7
- package/dist/instrumentation-client.js.map +1 -1
- package/dist/lead-registry.d.ts +34 -0
- package/dist/lead-registry.d.ts.map +1 -0
- package/dist/lead-registry.js +30 -0
- package/dist/lead-registry.js.map +1 -0
- package/dist/lead-reporting.d.ts +37 -0
- package/dist/lead-reporting.d.ts.map +1 -0
- package/dist/lead-reporting.js +74 -0
- package/dist/lead-reporting.js.map +1 -0
- package/dist/metadata.d.ts +10 -11
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +17 -19
- package/dist/metadata.js.map +1 -1
- package/dist/next-config.d.ts +102 -0
- package/dist/next-config.d.ts.map +1 -0
- package/dist/next-config.js +140 -0
- package/dist/next-config.js.map +1 -0
- package/dist/robots.d.ts +14 -6
- package/dist/robots.d.ts.map +1 -1
- package/dist/robots.js +26 -17
- package/dist/robots.js.map +1 -1
- package/dist/sitemaps.d.ts +34 -0
- package/dist/sitemaps.d.ts.map +1 -1
- package/dist/sitemaps.js +66 -1
- package/dist/sitemaps.js.map +1 -1
- package/dist/testing/server-only.d.ts +8 -0
- package/dist/testing/server-only.d.ts.map +1 -0
- package/dist/testing/server-only.js +8 -0
- package/dist/testing/server-only.js.map +1 -0
- package/dist/ui-client.d.ts +1 -12
- package/dist/ui-client.d.ts.map +1 -1
- package/dist/ui-client.js +0 -17
- package/dist/ui-client.js.map +1 -1
- package/dist/ui.d.ts +22 -2
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +67 -6
- package/dist/ui.js.map +1 -1
- package/package.json +16 -3
|
@@ -16,13 +16,24 @@ export interface GooglePlaceReviewsClientProps extends Omit<GooglePlaceReviewsPr
|
|
|
16
16
|
/** Wrapper used only for lazy activation; projects own its visual treatment. */
|
|
17
17
|
wrapperProps?: Omit<HTMLAttributes<HTMLDivElement>, 'children'>;
|
|
18
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
|
+
};
|
|
19
28
|
export interface GooglePlaceReviewsProviderProps {
|
|
20
29
|
endpoint: string;
|
|
21
30
|
mode: GooglePlaceReviewsMode;
|
|
31
|
+
/** Refreshes only review data on navigation; preserves state in child components. */
|
|
32
|
+
pageKey?: string;
|
|
22
33
|
children: ReactNode;
|
|
23
34
|
}
|
|
24
35
|
/** Shares one in-memory request among matching placements for this page only. */
|
|
25
|
-
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;
|
|
26
37
|
/**
|
|
27
38
|
* Cost-aware display controller. It requests live Places data only when the
|
|
28
39
|
* approved placement approaches the viewport and always retains a stable link.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-reviews-client.d.ts","sourceRoot":"","sources":["../src/google-reviews-client.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
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,
|
|
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,10 +82,42 @@ 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
|
}
|
|
@@ -97,51 +129,16 @@ function ReviewFallback(props) {
|
|
|
97
129
|
* approved placement approaches the viewport and always retains a stable link.
|
|
98
130
|
*/
|
|
99
131
|
export function GooglePlaceReviewsClient({ mode, endpoint, fallbackGoogleMapsUri, fallbackLabel, fallbackClassName, fallbackContent, renderSnapshot, wrapperProps, selection = 'relevance', ...reviewProps }) {
|
|
100
|
-
const wrapperRef = useRef(null);
|
|
101
|
-
const [localSnapshot, setSnapshot] = useState(null);
|
|
102
|
-
const [activated, setActivated] = useState(false);
|
|
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
|
|
107
|
-
|
|
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
143
|
return (_jsx(ReviewFallback, { fallbackClassName: fallbackClassName, fallbackContent: fallbackContent, fallbackGoogleMapsUri: fallbackGoogleMapsUri, fallbackLabel: fallbackLabel }));
|
|
147
144
|
}
|
|
@@ -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 /** 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: 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' | '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 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 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"]}
|
|
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":"AAAA,OAAO,EAAiB,KAAK,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,OAAO,CAAA;AACrF,OAAO,EAOL,KAAK,iBAAiB,EACtB,KAAK,mCAAmC,EACxC,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAChC,MAAM,4CAA4C,CAAA;AAOnD,MAAM,WAAW,sBACf,SAAQ,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC7D,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,iBAAiB,CAAC,EAChC,aAAa,EACb,KAAiC,EACjC,GAAG,WAAW,EACf,EAAE,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAexB;AAED,MAAM,WAAW,uBAAwB,SAAQ,cAAc,CAAC,WAAW,CAAC;IAC1E,QAAQ,EAAE,0BAA0B,CAAA;IACpC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,8DAA8D;IAC9D,0BAA0B,CAAC,EAAE,MAAM,CAAA;IACnC,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,8FAA8F;IAC9F,SAAS,CAAC,EAAE,2BAA2B,CAAA;IACvC,qFAAqF;IACrF,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAClC,iFAAiF;IACjF,eAAe,CAAC,EAAE,MAAM,GAAG,wBAAwB,CAAA;CACpD;AAED,MAAM,WAAW,kCAAkC;IACjD,QAAQ,EAAE,mCAAmC,CAAA;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,eAAe,CAAC,EAAE,WAAW,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,CAAC,CAAA;IACzE,eAAe,CAAC,EAAE,WAAW,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,CAAC,CAAA;CAC1E;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,iBAAiB,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,iBAAiB,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,wCACf,SAAQ,kCAAkC;IAC1C,SAAS,CAAC,EAAE,2BAA2B,CAAA;IACvC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,0BAA0B,CAAC,EAAE,MAAM,CAAA;CACpC;AA+DD,qGAAqG;AACrG,wBAAgB,uBAAuB,CAAC,EACtC,MAAM,EACN,SAAS,EACT,eAAe,GAChB,EAAE,4BAA4B;;;gBAuC9B;AAED,iFAAiF;AACjF,wBAAgB,wBAAwB,CAAC,EACvC,MAAM,EACN,SAAS,GACV,EAAE,6BAA6B;;;uBA0C/B;AA4ED,8EAA8E;AAC9E,wBAAgB,6BAA6B,CAAC,EAC5C,QAAQ,EACR,SAAS,EACT,MAAc,EACd,eAAyB,EACzB,eAAwB,GACzB,EAAE,kCAAkC;;;gBA2BpC;AAED,wBAAgB,mCAAmC,CAAC,EAClD,QAAQ,EACR,SAAuB,EACvB,SAAS,EACT,eAAe,EACf,0BAA0B,EAC1B,MAAc,EACd,eAAyB,EACzB,eAAwB,GACzB,EAAE,wCAAwC;;;;gBAiC1C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,eAAe,EACf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,0BAA0B,EAC1B,uBAAuB,EACvB,mBAAuD,EACvD,SAAuB,EACvB,eAAyB,EACzB,eAAwB,EACxB,GAAG,YAAY,EAChB,EAAE,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBA6DzB"}
|
|
@@ -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":"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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 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"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
/** Supplied by `defineBrandlabAnalytics(...).googleTag`. */
|
|
2
2
|
export interface BrandlabGoogleTagConfig {
|
|
3
3
|
enabled: boolean;
|
|
4
4
|
measurementId?: string | null;
|
|
@@ -12,8 +12,5 @@ export interface BrandlabGoogleTagPlan {
|
|
|
12
12
|
destinations: readonly string[];
|
|
13
13
|
websiteCallDestination: string | null;
|
|
14
14
|
}
|
|
15
|
-
export declare function resolveBrandlabGoogleTagConfig(contract: BrandlabAnalyticsContract, environment: Readonly<Record<string, string | undefined>>, options: {
|
|
16
|
-
enabled: boolean;
|
|
17
|
-
}): BrandlabGoogleTagConfig;
|
|
18
15
|
export declare function createBrandlabGoogleTagPlan(config: BrandlabGoogleTagConfig, phoneNumber?: string | null): BrandlabGoogleTagPlan | null;
|
|
19
16
|
//# sourceMappingURL=google-tag-plan.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-tag-plan.d.ts","sourceRoot":"","sources":["../src/google-tag-plan.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"google-tag-plan.d.ts","sourceRoot":"","sources":["../src/google-tag-plan.ts"],"names":[],"mappings":"AAEA,4DAA4D;AAC5D,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,mCAAmC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACpD;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAA;CACtC;AAKD,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,uBAAuB,EAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,qBAAqB,GAAG,IAAI,CA2C9B"}
|
package/dist/google-tag-plan.js
CHANGED
|
@@ -1,19 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getGoogleAdsWebsiteCallSendTo } from '@brandlab-digital/site-core/analytics';
|
|
2
2
|
const GA4_MEASUREMENT_ID_PATTERN = /^G-[A-Z0-9]{4,20}$/i;
|
|
3
3
|
const GOOGLE_ADS_CONVERSION_ID_PATTERN = /^(?:AW-)?\d{6,20}$/;
|
|
4
|
-
export function resolveBrandlabGoogleTagConfig(contract, environment, options) {
|
|
5
|
-
defineAnalyticsContract(contract);
|
|
6
|
-
return {
|
|
7
|
-
enabled: options.enabled,
|
|
8
|
-
measurementId: environment[contract.measurementIdEnv],
|
|
9
|
-
googleAdsConversionId: contract.googleAds
|
|
10
|
-
? environment[contract.googleAds.conversionIdEnv]
|
|
11
|
-
: undefined,
|
|
12
|
-
googleAdsWebsiteCallConversionLabel: contract.googleAds?.websiteCalls
|
|
13
|
-
? environment[contract.googleAds.websiteCalls.conversionLabelEnv]
|
|
14
|
-
: undefined,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
4
|
export function createBrandlabGoogleTagPlan(config, phoneNumber) {
|
|
18
5
|
if (!config.enabled)
|
|
19
6
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-tag-plan.js","sourceRoot":"","sources":["../src/google-tag-plan.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"google-tag-plan.js","sourceRoot":"","sources":["../src/google-tag-plan.ts"],"names":[],"mappings":"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","sourcesContent":["import { getGoogleAdsWebsiteCallSendTo } from '@brandlab-digital/site-core/analytics'\n\n/** Supplied by `defineBrandlabAnalytics(...).googleTag`. */\nexport interface BrandlabGoogleTagConfig {\n enabled: boolean\n measurementId?: string | null\n googleAdsConversionId?: string | null\n googleAdsWebsiteCallConversionLabel?: string | null\n}\n\nexport interface BrandlabGoogleTagPlan {\n loaderId: string\n source: string\n inlineScript: string\n destinations: readonly string[]\n websiteCallDestination: string | null\n}\n\nconst GA4_MEASUREMENT_ID_PATTERN = /^G-[A-Z0-9]{4,20}$/i\nconst GOOGLE_ADS_CONVERSION_ID_PATTERN = /^(?:AW-)?\\d{6,20}$/\n\nexport function createBrandlabGoogleTagPlan(\n config: BrandlabGoogleTagConfig,\n phoneNumber?: string | null,\n): BrandlabGoogleTagPlan | null {\n if (!config.enabled) return null\n const measurementId = validMeasurementId(config.measurementId)\n const googleAdsConversionId = validGoogleAdsConversionId(config.googleAdsConversionId)\n const loaderId = measurementId ?? googleAdsConversionId\n if (!loaderId) return null\n\n const destinations = [...new Set([\n ...(measurementId ? [measurementId] : []),\n ...(googleAdsConversionId ? [googleAdsConversionId] : []),\n ])]\n const displayPhone = safeDisplayedBusinessPhone(phoneNumber)\n const websiteCallDestination = displayPhone\n ? getGoogleAdsWebsiteCallSendTo({\n conversionId: googleAdsConversionId,\n conversionLabel: config.googleAdsWebsiteCallConversionLabel,\n }) ?? null\n : null\n const configCommands = destinations.map(\n (destination) => `window.gtag('config', ${safeJson(destination)});`,\n )\n if (websiteCallDestination && displayPhone) {\n configCommands.push(\n `window.gtag('config', ${safeJson(websiteCallDestination)}, ${safeJson({\n phone_conversion_number: displayPhone,\n })});`,\n )\n }\n\n return {\n loaderId,\n source: `https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(loaderId)}`,\n inlineScript: [\n 'window.dataLayer = window.dataLayer || [];',\n 'window.gtag = window.gtag || function(){window.dataLayer.push(arguments);};',\n \"window.gtag('consent', 'default', {ad_user_data:'denied',ad_personalization:'denied'});\",\n \"window.gtag('set', 'user_data', {});\",\n \"window.gtag('js', new Date());\",\n ...configCommands,\n ].join('\\n'),\n destinations,\n websiteCallDestination,\n }\n}\n\nfunction validMeasurementId(value: string | null | undefined) {\n const normalized = value?.trim()\n return normalized && GA4_MEASUREMENT_ID_PATTERN.test(normalized)\n ? normalized.toUpperCase()\n : undefined\n}\n\nfunction validGoogleAdsConversionId(value: string | null | undefined) {\n const normalized = value?.trim()\n if (!normalized || !GOOGLE_ADS_CONVERSION_ID_PATTERN.test(normalized)) return undefined\n return normalized.startsWith('AW-') ? normalized : `AW-${normalized}`\n}\n\nfunction safeDisplayedBusinessPhone(value: string | null | undefined) {\n const normalized = value?.trim()\n const digits = normalized?.replace(/\\D/g, '') ?? ''\n return normalized &&\n normalized.length <= 32 &&\n digits.length >= 6 &&\n /^[0-9+().\\s-]+$/.test(normalized)\n ? normalized\n : undefined\n}\n\nfunction safeJson(value: unknown) {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e')\n .replace(/&/g, '\\\\u0026')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029')\n}\n"]}
|
package/dist/google-tag.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type BrandlabGoogleTagConfig } from './google-tag-plan.js';
|
|
2
|
-
export { createBrandlabGoogleTagPlan
|
|
2
|
+
export { createBrandlabGoogleTagPlan } from './google-tag-plan.js';
|
|
3
3
|
export type { BrandlabGoogleTagConfig, BrandlabGoogleTagPlan, } from './google-tag-plan.js';
|
|
4
4
|
export interface BrandlabGoogleTagProps extends BrandlabGoogleTagConfig {
|
|
5
5
|
/** Must match the verified public number exactly as it is rendered on the page. */
|
|
@@ -9,9 +9,10 @@ export interface BrandlabGoogleTagProps extends BrandlabGoogleTagConfig {
|
|
|
9
9
|
/**
|
|
10
10
|
* Shared Google tag and website-call forwarding-number snippet.
|
|
11
11
|
*
|
|
12
|
-
* Render this exactly once from the root layout
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* Render this exactly once from the root layout:
|
|
13
|
+
* `<BrandlabGoogleTag {...analytics.googleTag} phoneNumber={displayedPhone} />`.
|
|
14
|
+
* `analytics.googleTag.enabled` is true only on the production deployment;
|
|
15
|
+
* account-side conversion settings remain outside website runtime.
|
|
15
16
|
*/
|
|
16
17
|
export declare function BrandlabGoogleTag(props: BrandlabGoogleTagProps): import("react/jsx-runtime").JSX.Element | null;
|
|
17
18
|
//# sourceMappingURL=google-tag.d.ts.map
|
package/dist/google-tag.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-tag.d.ts","sourceRoot":"","sources":["../src/google-tag.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAA;AAE7B,OAAO,
|
|
1
|
+
{"version":3,"file":"google-tag.d.ts","sourceRoot":"","sources":["../src/google-tag.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAA;AAClE,YAAY,EACV,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,sBAAsB,CAAA;AAE7B,MAAM,WAAW,sBAAuB,SAAQ,uBAAuB;IACrE,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,kDAqB9D"}
|
package/dist/google-tag.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import Script from 'next/script';
|
|
3
3
|
import { createBrandlabGoogleTagPlan, } from './google-tag-plan.js';
|
|
4
|
-
export { createBrandlabGoogleTagPlan
|
|
4
|
+
export { createBrandlabGoogleTagPlan } from './google-tag-plan.js';
|
|
5
5
|
/**
|
|
6
6
|
* Shared Google tag and website-call forwarding-number snippet.
|
|
7
7
|
*
|
|
8
|
-
* Render this exactly once from the root layout
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Render this exactly once from the root layout:
|
|
9
|
+
* `<BrandlabGoogleTag {...analytics.googleTag} phoneNumber={displayedPhone} />`.
|
|
10
|
+
* `analytics.googleTag.enabled` is true only on the production deployment;
|
|
11
|
+
* account-side conversion settings remain outside website runtime.
|
|
11
12
|
*/
|
|
12
13
|
export function BrandlabGoogleTag(props) {
|
|
13
14
|
const plan = createBrandlabGoogleTagPlan(props, props.phoneNumber);
|
package/dist/google-tag.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-tag.js","sourceRoot":"","sources":["../src/google-tag.tsx"],"names":[],"mappings":";AAAA,OAAO,MAAM,MAAM,aAAa,CAAA;AAChC,OAAO,EACL,2BAA2B,GAE5B,MAAM,sBAAsB,CAAA;AAE7B,OAAO,
|
|
1
|
+
{"version":3,"file":"google-tag.js","sourceRoot":"","sources":["../src/google-tag.tsx"],"names":[],"mappings":";AAAA,OAAO,MAAM,MAAM,aAAa,CAAA;AAChC,OAAO,EACL,2BAA2B,GAE5B,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAA;AAYlE;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAA6B;IAC7D,MAAM,IAAI,GAAG,2BAA2B,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,CAAA;IAClE,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IACtB,OAAO,CACL,8BACE,KAAC,MAAM,IACL,EAAE,EAAC,4BAA4B,8BACN,QAAQ,EACjC,GAAG,EAAE,IAAI,CAAC,MAAM,EAChB,QAAQ,EAAC,kBAAkB,EAC3B,KAAK,EAAE,KAAK,CAAC,KAAK,GAClB,EACF,KAAC,MAAM,IACL,EAAE,EAAC,4BAA4B,8BACN,QAAQ,EACjC,QAAQ,EAAC,kBAAkB,EAC3B,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,uBAAuB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,GACtD,IACD,CACJ,CAAA;AACH,CAAC","sourcesContent":["import Script from 'next/script'\nimport {\n createBrandlabGoogleTagPlan,\n type BrandlabGoogleTagConfig,\n} from './google-tag-plan.js'\n\nexport { createBrandlabGoogleTagPlan } from './google-tag-plan.js'\nexport type {\n BrandlabGoogleTagConfig,\n BrandlabGoogleTagPlan,\n} from './google-tag-plan.js'\n\nexport interface BrandlabGoogleTagProps extends BrandlabGoogleTagConfig {\n /** Must match the verified public number exactly as it is rendered on the page. */\n phoneNumber?: string | null\n nonce?: string\n}\n\n/**\n * Shared Google tag and website-call forwarding-number snippet.\n *\n * Render this exactly once from the root layout:\n * `<BrandlabGoogleTag {...analytics.googleTag} phoneNumber={displayedPhone} />`.\n * `analytics.googleTag.enabled` is true only on the production deployment;\n * account-side conversion settings remain outside website runtime.\n */\nexport function BrandlabGoogleTag(props: BrandlabGoogleTagProps) {\n const plan = createBrandlabGoogleTagPlan(props, props.phoneNumber)\n if (!plan) return null\n return (\n <>\n <Script\n id=\"brandlab-google-tag-loader\"\n data-brandlab-google-tag=\"loader\"\n src={plan.source}\n strategy=\"afterInteractive\"\n nonce={props.nonce}\n />\n <Script\n id=\"brandlab-google-tag-config\"\n data-brandlab-google-tag=\"config\"\n strategy=\"afterInteractive\"\n nonce={props.nonce}\n dangerouslySetInnerHTML={{ __html: plan.inlineScript }}\n />\n </>\n )\n}\n"]}
|