@c15t/react 3.1.0-canary.0 → 3.2.0-canary.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/AGENTS.md +11 -4
- package/README.md +4 -4
- package/dist/component-hooks/use-consent-gate.js +2 -0
- package/dist/component-hooks/use-consent-labels.js +2 -0
- package/dist/component-hooks/use-consent-text-direction.js +2 -0
- package/dist/component-hooks/use-vendors-listed-under.js +2 -0
- package/dist/components/consent-gate/atoms.js +1 -1
- package/dist/components/consent-gate/consent-gate.js +1 -1
- package/dist/components/iab-prompt/atoms/root.js +1 -1
- package/dist/components/panel-trigger/atoms/toolbar.js +1 -1
- package/dist/components/preferences/atoms/button.js +1 -1
- package/dist/components/preferences/atoms/vendor-list.js +1 -1
- package/dist/components/prompt/atoms/root.js +1 -1
- package/dist/components/prompt/components.js +1 -1
- package/dist/components/prompt/policy-actions.js +1 -1
- package/dist/components/prompt/prompt.js +1 -1
- package/dist/components/prompt/surface-context.js +1 -1
- package/dist/components/prompt/use-banner-copy.js +1 -1
- package/dist/components/shared/streamed-surface.js +1 -1
- package/dist/event-dispatcher.js +2 -0
- package/dist/headless.js +1 -1
- package/dist/index-parts/event-dispatcher.js +1 -0
- package/dist/index-parts/offline.js +1 -1
- package/dist/index.js +1 -1
- package/dist/modes.js +1 -1
- package/dist/provider.js +1 -1
- package/dist/transports/offline.js +1 -1
- package/dist/version.js +1 -1
- package/dist-types/component-hooks/use-consent-gate.d.ts +102 -0
- package/dist-types/component-hooks/use-consent-labels.d.ts +32 -0
- package/dist-types/component-hooks/use-consent-text-direction.d.ts +22 -0
- package/dist-types/component-hooks/use-vendors-listed-under.d.ts +30 -0
- package/dist-types/components/prompt/atoms/root.d.ts +3 -3
- package/dist-types/components/prompt/prompt.d.ts +4 -3
- package/dist-types/components/prompt/surface-context.d.ts +1 -14
- package/dist-types/components/prompt/use-banner-copy.d.ts +8 -3
- package/dist-types/components/shared/streamed-surface.d.ts +47 -10
- package/dist-types/context.d.ts +3 -1
- package/dist-types/event-dispatcher.d.ts +24 -0
- package/dist-types/headless.d.ts +10 -1
- package/dist-types/hooks/use-iab-policy-guard.d.ts +17 -1
- package/dist-types/hooks/use-scroll-lock.d.ts +16 -2
- package/dist-types/index-parts/event-dispatcher.d.ts +7 -0
- package/dist-types/index-parts/offline.d.ts +1 -1
- package/dist-types/index.d.ts +2 -0
- package/dist-types/modes.d.ts +1 -1
- package/dist-types/module-hooks/script-loader.d.ts +9 -0
- package/dist-types/provider.d.ts +3 -3
- package/dist-types/transports/offline.d.ts +2 -2
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +11 -4
- package/docs/concepts/choose-your-setup.md +9 -9
- package/docs/concepts/consent-state.md +93 -9
- package/docs/concepts/data-fetching.md +30 -23
- package/docs/concepts/modes.md +85 -35
- package/docs/customization/recipes.md +4 -4
- package/docs/customization/stylesheets.md +3 -3
- package/docs/customization/tailwind.md +17 -34
- package/docs/customization/translations.md +18 -12
- package/docs/frameworks/react/clear-on-revocation.md +3 -2
- package/docs/frameworks/react/components/consent-banner.md +3 -3
- package/docs/frameworks/react/components/consent-provider.md +29 -29
- package/docs/frameworks/react/gpp.md +1 -1
- package/docs/frameworks/react/headless.md +146 -19
- package/docs/frameworks/react/iab.md +8 -1
- package/docs/frameworks/react/quickstart.md +1 -1
- package/docs/frameworks/react/rendering.md +1 -1
- package/docs/frameworks/react/scripts.md +44 -0
- package/docs/frameworks/react/translations.md +9 -9
- package/docs/frameworks/react/troubleshooting.md +1 -1
- package/docs/frameworks/react/upgrade-v3.md +39 -32
- package/docs/frameworks/react/vendor-consent.md +5 -0
- package/docs/guides/banner-experiments.md +3 -3
- package/docs/guides/troubleshooting.md +3 -2
- package/docs/integrations/adobe-analytics.md +2 -2
- package/docs/integrations/ahrefs-analytics.md +2 -2
- package/docs/integrations/amplitude.md +2 -2
- package/docs/integrations/clay.md +305 -0
- package/docs/integrations/clearbit.md +2 -2
- package/docs/integrations/cloudflare-web-analytics.md +2 -2
- package/docs/integrations/cloudflare-zaraz.md +2 -2
- package/docs/integrations/crisp.md +2 -2
- package/docs/integrations/databuddy.md +2 -2
- package/docs/integrations/fathom-analytics.md +2 -2
- package/docs/integrations/front-chat.md +2 -2
- package/docs/integrations/google-maps.md +2 -2
- package/docs/integrations/google-tag-manager.md +59 -2
- package/docs/integrations/google-tag.md +2 -2
- package/docs/integrations/heap.md +2 -2
- package/docs/integrations/hightouch.md +2 -2
- package/docs/integrations/hotjar.md +40 -26
- package/docs/integrations/intercom.md +2 -2
- package/docs/integrations/klaviyo.md +2 -2
- package/docs/integrations/linkedin-insights.md +2 -2
- package/docs/integrations/logrocket.md +2 -2
- package/docs/integrations/matomo-analytics.md +2 -2
- package/docs/integrations/meta-pixel.md +2 -2
- package/docs/integrations/microsoft-clarity.md +2 -2
- package/docs/integrations/microsoft-uet.md +2 -2
- package/docs/integrations/mixpanel-analytics.md +2 -2
- package/docs/integrations/one-dollar-stats.md +2 -2
- package/docs/integrations/openai-pixel.md +2 -2
- package/docs/integrations/other-ads-and-pixels.md +94 -0
- package/docs/integrations/other-analytics.md +108 -0
- package/docs/integrations/other-chat-and-support.md +112 -0
- package/docs/integrations/other-email-and-sms.md +156 -0
- package/docs/integrations/other-experience.md +222 -0
- package/docs/integrations/overview.md +102 -45
- package/docs/integrations/pinterest-tag.md +2 -2
- package/docs/integrations/pirsch.md +2 -2
- package/docs/integrations/plausible-analytics.md +2 -2
- package/docs/integrations/posthog.md +10 -2
- package/docs/integrations/promptwatch.md +2 -2
- package/docs/integrations/reddit-pixel.md +2 -2
- package/docs/integrations/rudderstack.md +2 -2
- package/docs/integrations/rybbit-analytics.md +2 -2
- package/docs/integrations/segment.md +2 -2
- package/docs/integrations/sentry.md +2 -2
- package/docs/integrations/shopify.md +323 -0
- package/docs/integrations/snapchat-pixel.md +2 -2
- package/docs/integrations/tiktok-pixel.md +2 -2
- package/docs/integrations/umami-analytics.md +2 -2
- package/docs/integrations/vercel-analytics.md +2 -2
- package/docs/integrations/vercel-speed-insights.md +7 -2
- package/docs/integrations/x-pixel.md +2 -2
- package/docs/integrations/youtube.md +2 -2
- package/package.json +12 -29
- package/dist/components/prompt/resolve-banner-primary-actions.js +0 -1
- package/dist-types/components/prompt/resolve-banner-primary-actions.d.ts +0 -14
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The text direction of the language c15t shows consent copy in, for a
|
|
3
|
+
* custom banner or preference center.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* c15t can pick the copy's language from the visitor's browser, so an
|
|
7
|
+
* Arabic or Hebrew visitor can read right-to-left copy on a left-to-right
|
|
8
|
+
* page. The stock banner and dialog set `dir` on their root from this
|
|
9
|
+
* language. Set it on yours the same way.
|
|
10
|
+
*
|
|
11
|
+
* @returns `'rtl'` for a right-to-left language, otherwise `'ltr'`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* function Banner({ children }: { children: React.ReactNode }) {
|
|
16
|
+
* const dir = useConsentTextDirection();
|
|
17
|
+
* return <section dir={dir}>{children}</section>;
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
export declare const useConsentTextDirection: () => "ltr" | "rtl";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AllConsentNames, ResolvedVendor } from '@c15t/core';
|
|
2
|
+
/**
|
|
3
|
+
* The vendors the stock preference center lists under one category, for a
|
|
4
|
+
* custom preference center that shows the same rows.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* A vendor known only from a script's `vendor` slug gets no row until the
|
|
8
|
+
* site declares a vendor in `vendors` or on the backend, unless the visitor
|
|
9
|
+
* turned it off. Then it stays listed so the visitor can turn it on again.
|
|
10
|
+
* Under an `iab` policy the list is empty.
|
|
11
|
+
*
|
|
12
|
+
* @param category - The category row being rendered.
|
|
13
|
+
* @returns The vendors to list, in declared order.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* function CategoryVendors({ category }: { category: AllConsentNames }) {
|
|
18
|
+
* const vendors = useVendorsListedUnder(category);
|
|
19
|
+
* return (
|
|
20
|
+
* <ul>
|
|
21
|
+
* {vendors.map((vendor) => (
|
|
22
|
+
* <li key={vendor.id}>{vendor.name ?? vendor.id}</li>
|
|
23
|
+
* ))}
|
|
24
|
+
* </ul>
|
|
25
|
+
* );
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export declare const useVendorsListedUnder: (category: AllConsentNames) => ResolvedVendor[];
|
|
@@ -62,8 +62,8 @@ interface ConsentBannerRootProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
62
62
|
/**
|
|
63
63
|
* Placement of the prompt. Overrides `presentation.prompt.position`.
|
|
64
64
|
* @remarks Must be valid for the resolved variant; otherwise the variant
|
|
65
|
-
* default is used and a development diagnostic is logged.
|
|
66
|
-
*
|
|
65
|
+
* default is used and a development diagnostic is logged. Right-to-left
|
|
66
|
+
* text does not move the prompt.
|
|
67
67
|
*/
|
|
68
68
|
position?: PromptPosition;
|
|
69
69
|
/**
|
|
@@ -75,7 +75,7 @@ interface ConsentBannerRootProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
77
|
* The banner, rendered where the server can stream it: see
|
|
78
|
-
* `
|
|
78
|
+
* `StreamedConsentSurface`.
|
|
79
79
|
*/
|
|
80
80
|
declare const ConsentBannerRoot: FC<ConsentBannerRootProps>;
|
|
81
81
|
declare const Root: FC<ConsentBannerRootProps>;
|
|
@@ -151,8 +151,8 @@ export interface ConsentBannerProps {
|
|
|
151
151
|
/**
|
|
152
152
|
* Placement of the prompt. Overrides `presentation.prompt.position`.
|
|
153
153
|
* @remarks Must be valid for the resolved variant; otherwise the variant
|
|
154
|
-
* default is used and a development diagnostic is logged.
|
|
155
|
-
*
|
|
154
|
+
* default is used and a development diagnostic is logged. Right-to-left
|
|
155
|
+
* text does not move the prompt.
|
|
156
156
|
*/
|
|
157
157
|
position?: PromptPosition;
|
|
158
158
|
/**
|
|
@@ -164,7 +164,8 @@ export interface ConsentBannerProps {
|
|
|
164
164
|
}
|
|
165
165
|
/**
|
|
166
166
|
* The stock banner. It reads the policy to choose its buttons, so all of
|
|
167
|
-
* it renders where the server can stream it: see
|
|
167
|
+
* it renders where the server can stream it: see
|
|
168
|
+
* `StreamedConsentSurface`.
|
|
168
169
|
*/
|
|
169
170
|
export declare const ConsentBanner: FC<ConsentBannerProps>;
|
|
170
171
|
/**
|
|
@@ -9,7 +9,7 @@ import type { PromptPosition, PromptVariant } from '@c15t/core';
|
|
|
9
9
|
export interface ConsentBannerSurface {
|
|
10
10
|
/** Shape of the first-layer prompt. */
|
|
11
11
|
variant: PromptVariant;
|
|
12
|
-
/** Placement
|
|
12
|
+
/** Placement. It stays the same for right-to-left text. */
|
|
13
13
|
position: PromptPosition;
|
|
14
14
|
/** Whether the host chose the position or the resolver defaulted it. */
|
|
15
15
|
positionSource: 'host' | 'default';
|
|
@@ -30,16 +30,3 @@ export declare const ConsentBannerSurfaceContext: import("react").Context<Consen
|
|
|
30
30
|
* @public
|
|
31
31
|
*/
|
|
32
32
|
export declare const useConsentBannerSurface: () => ConsentBannerSurface;
|
|
33
|
-
/**
|
|
34
|
-
* Mirror a defaulted corner for right-to-left text so the banner keeps
|
|
35
|
-
* hugging the reading start. Host-chosen positions and edge or center
|
|
36
|
-
* placements are returned unchanged.
|
|
37
|
-
*
|
|
38
|
-
* @param position - The resolved position.
|
|
39
|
-
* @param positionSource - Whether the host chose it.
|
|
40
|
-
* @param variant - The resolved variant; only corners of floating and widget mirror.
|
|
41
|
-
* @param textDirection - Document text direction.
|
|
42
|
-
* @returns The position to render.
|
|
43
|
-
* @internal
|
|
44
|
-
*/
|
|
45
|
-
export declare const mirrorDefaultPosition: (position: PromptPosition, positionSource: 'host' | 'default', variant: PromptVariant, textDirection: 'ltr' | 'rtl') => PromptPosition;
|
|
@@ -4,13 +4,18 @@
|
|
|
4
4
|
* @remarks
|
|
5
5
|
* A notice prompt reads the `noticeTitle` and `noticeDescription` copy so
|
|
6
6
|
* it informs rather than asks. Languages that have not translated the notice
|
|
7
|
-
* copy fall back to
|
|
7
|
+
* copy fall back to their own choice copy, then to English.
|
|
8
8
|
*
|
|
9
9
|
* @returns The copy the banner should render when no props override it.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* const { title, description } = useBannerCopy();
|
|
14
|
+
* ```
|
|
10
15
|
* @public
|
|
11
16
|
*/
|
|
12
17
|
export declare const useBannerCopy: () => {
|
|
13
|
-
title: string
|
|
14
|
-
description: string
|
|
18
|
+
title: string;
|
|
19
|
+
description: string;
|
|
15
20
|
prompt: 'choice' | 'notice' | 'none';
|
|
16
21
|
};
|
|
@@ -8,16 +8,53 @@ import type { ReactNode } from 'react';
|
|
|
8
8
|
* @internal
|
|
9
9
|
*/
|
|
10
10
|
export declare const readRecorded: <Value>(thenable: PromiseLike<Value>) => Value;
|
|
11
|
+
/** Props for {@link StreamedConsentSurface}. */
|
|
12
|
+
export interface StreamedConsentSurfaceProps {
|
|
13
|
+
/** The surface. Its consent hooks must run inside this component. */
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
}
|
|
11
16
|
/**
|
|
12
|
-
* Renders a consent surface the server can stream
|
|
13
|
-
*
|
|
14
|
-
* boundary: the rest of the page streams at once, and the surface follows
|
|
15
|
-
* in a later chunk of the same response, rendered from the resolved
|
|
16
|
-
* config. It shows only when that config carries a policy that shows it.
|
|
17
|
-
* Hydration reads the same config, so the surface hydrates in place.
|
|
17
|
+
* Renders a consent surface the server can stream, such as a banner built
|
|
18
|
+
* with the headless hooks. The stock `ConsentBanner` uses it too.
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
+
* While the provider's `prefetch` is a promise, as with Next.js
|
|
21
|
+
* `<ConsentRoot state={resolveConsent()}>`, the surface waits for it in its
|
|
22
|
+
* own Suspense boundary: the rest of the page streams at once, and the
|
|
23
|
+
* surface follows in a later chunk of the same response, rendered from the
|
|
24
|
+
* resolved config. It shows only when that config carries a policy that
|
|
25
|
+
* shows it. Hydration reads the same config, so the surface hydrates in
|
|
26
|
+
* place. Without a pending `prefetch`, it renders its children as they are.
|
|
27
|
+
*
|
|
28
|
+
* Call the hooks in a component inside it. Hooks called above it read the
|
|
29
|
+
* snapshot from before consent resolved, which has no banner.
|
|
30
|
+
*
|
|
31
|
+
* @param props - The surface to stream.
|
|
32
|
+
* @returns The children, in a Suspense boundary while consent streams.
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* 'use client';
|
|
36
|
+
* import {
|
|
37
|
+
* StreamedConsentSurface,
|
|
38
|
+
* useHeadlessConsentUI,
|
|
39
|
+
* } from 'c15t/next/headless';
|
|
40
|
+
*
|
|
41
|
+
* function BannerContent() {
|
|
42
|
+
* const { banner, performAction } = useHeadlessConsentUI();
|
|
43
|
+
* if (!banner.isVisible) return null;
|
|
44
|
+
* return (
|
|
45
|
+
* <section aria-label="Cookie consent">
|
|
46
|
+
* <button onClick={() => performAction('accept')}>Accept</button>
|
|
47
|
+
* </section>
|
|
48
|
+
* );
|
|
49
|
+
* }
|
|
50
|
+
*
|
|
51
|
+
* export function ConsentBanner() {
|
|
52
|
+
* return (
|
|
53
|
+
* <StreamedConsentSurface>
|
|
54
|
+
* <BannerContent />
|
|
55
|
+
* </StreamedConsentSurface>
|
|
56
|
+
* );
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
20
59
|
*/
|
|
21
|
-
export declare const
|
|
22
|
-
children: ReactNode;
|
|
23
|
-
}) => string | number | bigint | boolean | React.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | React.ReactPortal | null | undefined> | null | undefined;
|
|
60
|
+
export declare const StreamedConsentSurface: ({ children, }: StreamedConsentSurfaceProps) => string | number | bigint | boolean | React.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | React.ReactPortal | null | undefined> | null | undefined;
|
package/dist-types/context.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AllConsentNames, ConsentKernel, ConsentPresentation, ConsentSnapshot } from '@c15t/core';
|
|
2
|
-
import type { StreamedPrefetch } from '@c15t/core/runtime';
|
|
2
|
+
import type { ConsentRuntime, StreamedPrefetch } from '@c15t/core/runtime';
|
|
3
3
|
/**
|
|
4
4
|
* React context carrying the kernel instance.
|
|
5
5
|
*
|
|
@@ -16,6 +16,8 @@ export interface ProviderServices {
|
|
|
16
16
|
getConsentCategories: () => readonly AllConsentNames[];
|
|
17
17
|
/** Whether the runtime has started: records hydrated, prefetch adopted. */
|
|
18
18
|
isStarted: () => boolean;
|
|
19
|
+
/** The runtime the provider renders, owned or borrowed. */
|
|
20
|
+
runtime: ConsentRuntime;
|
|
19
21
|
/**
|
|
20
22
|
* Store a language override and load its copy: init runs again on the
|
|
21
23
|
* provider's own kernel while it is enabled, and a borrowed runtime
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { EventDispatcher, RuntimeEventDispatcherOptions } from '@c15t/core/events';
|
|
2
|
+
/**
|
|
3
|
+
* Get the provider's event dispatcher.
|
|
4
|
+
*
|
|
5
|
+
* It delivers to the scripts the provider registered, plus any you pass, and
|
|
6
|
+
* checks consent when it sends, so a revoked category stops the next event.
|
|
7
|
+
* The returned object stays the same for the provider's lifetime, and
|
|
8
|
+
* pageview de-duplication survives navigation, consent changes and the
|
|
9
|
+
* `enabled` toggle.
|
|
10
|
+
*
|
|
11
|
+
* @param options - Extra `scripts`, SPA `pageviews` integrations and
|
|
12
|
+
* injectable `globals`. The latest committed options apply on each call.
|
|
13
|
+
* @returns A dispatcher with `track` and `pageview`.
|
|
14
|
+
* @throws {Error} When called outside `ConsentProvider`.
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* const events = useEventDispatcher({ pageviews: ['posthog'] });
|
|
18
|
+
* const pathname = usePathname();
|
|
19
|
+
* useEffect(() => events.pageview(pathname), [events, pathname]);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare const useEventDispatcher: (options?: RuntimeEventDispatcherOptions) => EventDispatcher;
|
|
23
|
+
export type { EventDispatcher, EventProperties } from '@c15t/core/events';
|
|
24
|
+
export type { RuntimeEventDispatcherOptions as UseEventDispatcherOptions };
|
package/dist-types/headless.d.ts
CHANGED
|
@@ -4,10 +4,19 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Pair with `ConsentProvider` from `@c15t/react` (or `@c15t/react/provider`).
|
|
6
6
|
*/
|
|
7
|
-
export { defaultTranslationConfig, detectBrowserLanguage, mergeTranslationConfigs, prepareTranslationConfig, } from '@c15t/core';
|
|
7
|
+
export { defaultTranslationConfig, detectBrowserLanguage, mergeTranslationConfigs, prepareTranslationConfig, resolveActionLabels, resolvePreferenceControlLabels, resolvePromptCopy, } from '@c15t/core';
|
|
8
|
+
export type { PreferenceControl, PresentationAction, PromptCopy, ResolvedVendor, } from '@c15t/core';
|
|
9
|
+
export { type ConsentLabels, useConsentLabels, } from './component-hooks/use-consent-labels.js';
|
|
10
|
+
export { useConsentTextDirection } from './component-hooks/use-consent-text-direction.js';
|
|
11
|
+
export { type ConsentGateState, type UseConsentGateResult, useConsentGate, } from './component-hooks/use-consent-gate.js';
|
|
8
12
|
export { type ConsentDialogTriggerVisibility, type UseConsentDialogTriggerOptions, type UseConsentDialogTriggerResult, useConsentDialogTrigger, } from './component-hooks/use-panel-trigger.js';
|
|
9
13
|
export { type HeadlessConsentBannerAction, type HeadlessConsentBannerState, type HeadlessConsentDialogAction, type HeadlessConsentDialogState, type HeadlessConsentSurface, type HeadlessConsentSurfaceAction, type HeadlessConsentSurfaceState, type HeadlessConsentWriteAction, useHeadlessConsentUI, } from './component-hooks/use-headless-consent-ui.js';
|
|
10
14
|
export { useTranslations } from './component-hooks/use-translations.js';
|
|
15
|
+
export { useVendorsListedUnder } from './component-hooks/use-vendors-listed-under.js';
|
|
16
|
+
export { useBannerCopy } from './components/prompt/use-banner-copy.js';
|
|
17
|
+
export { StreamedConsentSurface, type StreamedConsentSurfaceProps, } from './components/shared/streamed-surface.js';
|
|
11
18
|
export { useColorScheme } from './hooks/use-color-scheme.js';
|
|
12
19
|
export { useFocusTrap } from './hooks/use-focus-trap.js';
|
|
20
|
+
export { useIABPolicyGuard } from './hooks/use-iab-policy-guard.js';
|
|
21
|
+
export { useScrollLock } from './hooks/use-scroll-lock.js';
|
|
13
22
|
export type { ReactUIOptions } from './types/manager.js';
|
|
@@ -28,8 +28,24 @@ export declare const missingIABProviderError: () => IABUnavailableError;
|
|
|
28
28
|
* around them, so a missing IAB context alone does not prove the app has
|
|
29
29
|
* none. The check also passes once `@c15t/react/iab` has loaded.
|
|
30
30
|
*
|
|
31
|
+
* A custom banner or preference center that only handles opt-in and
|
|
32
|
+
* opt-out should call this too, and render nothing when `useModel()` is
|
|
33
|
+
* `'iab'`, as the standard surfaces do.
|
|
34
|
+
*
|
|
31
35
|
* @throws {IABUnavailableError} When the policy needs IAB and neither an
|
|
32
36
|
* IAB context nor `@c15t/react/iab` is present.
|
|
33
|
-
*
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* function Banner() {
|
|
41
|
+
* useIABPolicyGuard();
|
|
42
|
+
* const model = useModel();
|
|
43
|
+
* const { banner } = useHeadlessConsentUI();
|
|
44
|
+
* const copy = useBannerCopy();
|
|
45
|
+
* if (model === 'iab' || !banner.isVisible) return null;
|
|
46
|
+
* return <section>{copy.title}</section>;
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
* @public
|
|
34
50
|
*/
|
|
35
51
|
export declare const useIABPolicyGuard: () => void;
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Locks page scroll while `shouldLock` is true, as the stock banner does
|
|
3
|
+
* when its policy is blocking.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Locks are counted, so a banner and a dialog can both hold one and the page
|
|
7
|
+
* scrolls again only when both release. Unmounting releases the lock.
|
|
8
|
+
*
|
|
9
|
+
* @param shouldLock - Whether the page should stop scrolling
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* const { banner } = useHeadlessConsentUI();
|
|
14
|
+
* useScrollLock(banner.isVisible && banner.blocking);
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
4
18
|
*/
|
|
5
19
|
export declare const useScrollLock: (shouldLock: boolean) => void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One group of `@c15t/react`'s public exports. The package index re-exports
|
|
3
|
+
* each group with `export *`, so a bundler that splits code by reachability
|
|
4
|
+
* (esbuild) does not treat every module the index names as part of an app
|
|
5
|
+
* that imports one hook: only the groups it uses are live.
|
|
6
|
+
*/
|
|
7
|
+
export { useEventDispatcher } from '../event-dispatcher.js';
|
package/dist-types/index.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export type { ConsentDialogTriggerProps, ConsentDialogTriggerToolbarAction, Cons
|
|
|
40
40
|
export type { ConsentWidgetCompoundComponent, ConsentWidgetProps, } from './components/preferences/index.js';
|
|
41
41
|
export type { ConsentGateProps, FrameProps } from './components/consent-gate/index.js';
|
|
42
42
|
export type { ConsentDraftHandle, ConsentDraftProviderProps, VendorDraftHandle, } from './draft.js';
|
|
43
|
+
export type { EventDispatcher, EventProperties, UseEventDispatcherOptions, } from './event-dispatcher.js';
|
|
43
44
|
export type { UseIframeBlockerOptions, UseNetworkBlockerOptions, UsePersistenceOptions, UseScriptLoaderOptions, } from './module-hooks.js';
|
|
44
45
|
export type { ConsentProviderOptions, ConsentProviderCallbacks, ConsentProviderPrefetch, ConsentProviderProps, ExternalRuntimeProviderOptions, ExternalRuntimeProviderProps, OwnedRuntimeProviderProps, } from './provider.js';
|
|
45
46
|
export type { ConsentThemeProps } from './consent-theme.js';
|
|
@@ -58,6 +59,7 @@ export * from './index-parts/consent-dialog-trigger.js';
|
|
|
58
59
|
export * from './index-parts/consent-gate.js';
|
|
59
60
|
export * from './index-parts/frame.js';
|
|
60
61
|
export * from './index-parts/draft.js';
|
|
62
|
+
export * from './index-parts/event-dispatcher.js';
|
|
61
63
|
export * from './index-parts/translations.js';
|
|
62
64
|
export * from './index-parts/module-hooks.js';
|
|
63
65
|
export * from './index-parts/provider.js';
|
package/dist-types/modes.d.ts
CHANGED
|
@@ -22,5 +22,5 @@ export { hosted } from './transports/hosted.js';
|
|
|
22
22
|
export type { HostedOptions } from './transports/hosted.js';
|
|
23
23
|
export { manifest } from './transports/manifest.js';
|
|
24
24
|
export type { BrowserManifestModeFactory, ManifestModeOptions, } from './transports/manifest.js';
|
|
25
|
-
export { offline } from './transports/offline.js';
|
|
25
|
+
export { local, offline } from './transports/offline.js';
|
|
26
26
|
export type { OfflineModeOptions } from './transports/offline.js';
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { Script, ScriptLoaderDebugEvent, ScriptLoaderHandle } from '@c15t/core/modules/script-loader';
|
|
2
2
|
export interface UseScriptLoaderOptions {
|
|
3
3
|
onDebug?: (event: ScriptLoaderDebugEvent) => void;
|
|
4
|
+
/**
|
|
5
|
+
* Set `false` to start every `scripts` entry after hydration. By default
|
|
6
|
+
* `ConsentRoot` in `c15t/next` and `c15t/tanstack-start` starts the
|
|
7
|
+
* entries the visitor's consent already allows from the server HTML,
|
|
8
|
+
* before the page hydrates.
|
|
9
|
+
*
|
|
10
|
+
* @default true
|
|
11
|
+
*/
|
|
12
|
+
serverStart?: boolean;
|
|
4
13
|
}
|
|
5
14
|
export declare const useScriptLoader: (scripts: Script[], options?: UseScriptLoaderOptions) => ScriptLoaderHandle;
|
|
6
15
|
export type { Script, ScriptLoaderDebugEvent, ScriptLoaderHandle };
|
package/dist-types/provider.d.ts
CHANGED
|
@@ -66,20 +66,20 @@ export interface ConsentProviderOptions extends ConsentControlOptions, Pick<Reac
|
|
|
66
66
|
/**
|
|
67
67
|
* Transport factory the provider builds its kernel with. Required.
|
|
68
68
|
*
|
|
69
|
-
* Pass `hosted()` to talk to a c15t backend, `
|
|
69
|
+
* Pass `hosted()` to talk to a c15t backend, `local()` to resolve
|
|
70
70
|
* policies locally with no network, or `custom()` to supply your own
|
|
71
71
|
* kernel transport. This is an initial-only
|
|
72
72
|
* option: remount the provider to change it.
|
|
73
73
|
*
|
|
74
74
|
* @example
|
|
75
75
|
* ```tsx
|
|
76
|
-
* import { ConsentProvider, hosted,
|
|
76
|
+
* import { ConsentProvider, hosted, local } from '@c15t/react';
|
|
77
77
|
*
|
|
78
78
|
* <ConsentProvider options={{ mode: hosted({ backendURL: '/api/c15t' }) }}>
|
|
79
79
|
* {children}
|
|
80
80
|
* </ConsentProvider>
|
|
81
81
|
*
|
|
82
|
-
* <ConsentProvider options={{ mode:
|
|
82
|
+
* <ConsentProvider options={{ mode: local() }}>{children}</ConsentProvider>
|
|
83
83
|
* ```
|
|
84
84
|
*/
|
|
85
85
|
mode: ProviderTransportFactory;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Local mode for the React provider: core's `local()`, which resolves
|
|
3
3
|
* policy rules locally and switches copy when `overrides.language` or
|
|
4
4
|
* `useSetLanguage()` names a language the bundle or `i18n.messages` has.
|
|
5
5
|
* The language a server prefetch detected from `Accept-Language` keeps the
|
|
6
6
|
* startup copy.
|
|
7
7
|
*/
|
|
8
|
-
export { offline } from '@c15t/core';
|
|
8
|
+
export { local, offline } from '@c15t/core';
|
|
9
9
|
export type { OfflineModeOptions } from '@c15t/core';
|
package/dist-types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "3.
|
|
1
|
+
export declare const version = "3.2.0-canary.0";
|
package/docs/README.md
CHANGED
|
@@ -39,7 +39,7 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
39
39
|
- [Customize](./frameworks/react/customize.md): Change the colors, fonts, layout, button styles and copy of the c15t banner and dialog in a React app with theme tokens, provider options and slots, and load the stylesheet yourself when you need to.
|
|
40
40
|
- [Embeds](./frameworks/react/embeds.md): Keep YouTube videos, maps and other iframes out of a React page until their consent category is allowed, with ConsentGate or the iframe blocker in ConsentProvider.
|
|
41
41
|
- [IAB GPP](./frameworks/react/gpp.md): Add the IAB Global Privacy Platform API (__gpp) to a React app with ConsentGPP from @c15t/react/gpp, so ad tech can read US state opt-outs and the TCF EU consent string.
|
|
42
|
-
- [Headless](./frameworks/react/headless.md): Build a custom consent banner in React with the c15t/react/headless hooks inside your ConsentProvider.
|
|
42
|
+
- [Headless](./frameworks/react/headless.md): Build a custom consent banner or embed gate in React with the c15t/react/headless hooks inside your ConsentProvider.
|
|
43
43
|
- [Hooks](./frameworks/react/hooks.md): Gate features and save consent choices in React components with the focused hooks exported from c15t/react.
|
|
44
44
|
- [IAB TCF](./frameworks/react/iab.md): Mount the IAB TCF banner and dialog inside a React ConsentProvider and configure the CMP ID, policy and vendor data.
|
|
45
45
|
- [Network blocker](./frameworks/react/network-blocker.md): Hold fetch and XMLHttpRequest calls in a React app until their consent category is allowed, with networkBlocker rules in the ConsentProvider options.
|
|
@@ -56,9 +56,9 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
56
56
|
- [Choose your setup](./concepts/choose-your-setup.md): Pick the c15t setup for your framework, rendering mode and hosting, and decide who runs the consent backend.
|
|
57
57
|
- [Consent categories](./concepts/consent-categories.md): Assign scripts, embeds and features to c15t consent categories, and understand which categories the preference dialog shows.
|
|
58
58
|
- [Consent state reference](./concepts/consent-state.md): How c15t saves choices, gates IAB vendors, hydrates server records and keeps browser tabs and storage in step.
|
|
59
|
-
- [Data fetching](./concepts/data-fetching.md): Choose the recommended build-time policy snapshot or runtime manifest fetching, backend /init, browser resolution or
|
|
59
|
+
- [Data fetching](./concepts/data-fetching.md): Choose the recommended build-time policy snapshot or runtime manifest fetching, backend /init, browser resolution or local rules, and understand where consent choices are saved.
|
|
60
60
|
- [How consent works](./concepts/how-consent-works.md): What c15t decides on each page load, the difference between a permission and a recorded choice, and what happens when a visitor saves.
|
|
61
|
-
- [Consent modes](./concepts/modes.md): Reference for manifest(), hosted() and
|
|
61
|
+
- [Consent modes](./concepts/modes.md): Reference for manifest(), hosted() and local() in every c15t framework package, where each one resolves the visitor's policy, what it adds to first-load JavaScript, the build-time manifest fetch and its failure policy, and the backend URL variable each framework reads.
|
|
62
62
|
- [Policies](./concepts/policies.md): How policy models, prompts and scope decide what c15t asks visitors, where to change the rules, and why a banner may not appear.
|
|
63
63
|
|
|
64
64
|
## Guides
|
|
@@ -86,6 +86,7 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
86
86
|
- [Ahrefs Analytics](./integrations/ahrefs-analytics.md): Load Ahrefs Web Analytics only after measurement consent with the c15t ahrefsAnalytics helper, and check it in DevTools.
|
|
87
87
|
- [Amplitude](./integrations/amplitude.md): Load the Amplitude Browser SDK 2 only after measurement consent with the c15t amplitude helper, which opts the SDK out on revocation and back in on a new grant.
|
|
88
88
|
- [Custom integrations](./integrations/building-integrations.md): Gate a vendor that has no @c15t/integrations helper, or sync consent with an SDK your app already loads, using a c15t script configuration.
|
|
89
|
+
- [Clay](./integrations/clay.md): Load Clay web intent only after marketing consent and understand its storage and revocation limits.
|
|
89
90
|
- [Clearbit](./integrations/clearbit.md): Load the Clearbit enrichment tag only after marketing consent with the c15t clearbit helper, and check it in DevTools.
|
|
90
91
|
- [Cloudflare Web Analytics](./integrations/cloudflare-web-analytics.md): Load the Cloudflare Web Analytics beacon only after measurement consent with the c15t cloudflareWebAnalytics helper, and check it in DevTools.
|
|
91
92
|
- [Cloudflare Zaraz](./integrations/cloudflare-zaraz.md): Sync c15t permissions to Cloudflare Zaraz purposes with the c15t cloudflareZaraz bridge, which runs on every page without loading a script, and check the tools it controls.
|
|
@@ -110,7 +111,12 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
110
111
|
- [Mixpanel](./integrations/mixpanel-analytics.md): Load the Mixpanel SDK on every page with the c15t mixpanelAnalytics helper, which switches Mixpanel tracking on and off with measurement consent, and check it in DevTools.
|
|
111
112
|
- [OneDollarStats](./integrations/one-dollar-stats.md): Load the OneDollarStats tracker only after measurement consent with the c15t oneDollarStats helper, forward its data-attribute settings, and check it in DevTools.
|
|
112
113
|
- [OpenAI Pixel](./integrations/openai-pixel.md): Load the ChatGPT Ads Measurement Pixel only after marketing consent with the c15t openaiPixel helper, guard oaiq conversion calls, and check it in DevTools.
|
|
113
|
-
- [
|
|
114
|
+
- [Other ads and pixels](./integrations/other-ads-and-pixels.md): Consent-gated helpers for ad platforms and conversion pixels that don't need a full guide.
|
|
115
|
+
- [Other analytics tools](./integrations/other-analytics.md): Consent-gated helpers for analytics tools that don't need a full guide.
|
|
116
|
+
- [Other chat and support tools](./integrations/other-chat-and-support.md): Consent-gated helpers for chat and support tools that don't need a full guide.
|
|
117
|
+
- [Other email, SMS and marketing automation tools](./integrations/other-email-and-sms.md): Consent-gated helpers for email, SMS and marketing automation tools that don't need a full guide.
|
|
118
|
+
- [Experimentation and personalization tools](./integrations/other-experience.md): Consent-gated helpers for experimentation and personalization tools that don't need a full guide.
|
|
119
|
+
- [Integrations](./integrations/overview.md): Find all c15t integrations for analytics, tag managers, advertising, experimentation and personalization, email and SMS, chat and embedded content.
|
|
114
120
|
- [Pinterest Tag](./integrations/pinterest-tag.md): Load the Pinterest Tag only after marketing consent with the c15t pinterestTag helper, guard pintrk event calls, and check it in DevTools.
|
|
115
121
|
- [Pirsch](./integrations/pirsch.md): Load Pirsch Analytics only after measurement consent with the c15t pirsch helper, keep custom event bindings working, and check it in DevTools.
|
|
116
122
|
- [Plausible Analytics](./integrations/plausible-analytics.md): Load the Plausible Analytics tracker only after measurement consent with the c15t plausibleAnalytics helper, and check it in DevTools.
|
|
@@ -121,6 +127,7 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
121
127
|
- [Rybbit Analytics](./integrations/rybbit-analytics.md): Load Rybbit Analytics only after measurement consent with the c15t rybbitAnalytics helper, map its tracking options to data attributes, and check it in DevTools.
|
|
122
128
|
- [Segment](./integrations/segment.md): Load Segment Analytics.js only after measurement consent with the c15t segment helper, guard your own track and identify calls, and check it in DevTools.
|
|
123
129
|
- [Sentry](./integrations/sentry.md): Configure Sentry's CDN or your own SDK with consent for error monitoring, Session Replay and user data.
|
|
130
|
+
- [Shopify](./integrations/shopify.md): Send c15t consent to Shopify's Customer Privacy API from a Hydrogen storefront, so Shopify analytics wait for the visitor's choice and follow each later change.
|
|
124
131
|
- [Snapchat Pixel](./integrations/snapchat-pixel.md): Load the Snapchat Pixel only after marketing consent with the c15t snapchatPixel helper, guard snaptr event calls, and check it in DevTools.
|
|
125
132
|
- [TikTok Pixel](./integrations/tiktok-pixel.md): Load the TikTok Pixel only after marketing consent with the c15t tiktokPixel helper, guard ttq event calls, and check it in DevTools.
|
|
126
133
|
- [Umami Analytics](./integrations/umami-analytics.md): Load the Umami Analytics tracker only after measurement consent with the c15t umamiAnalytics helper, point it at a self-hosted instance, and check it in DevTools.
|
|
@@ -45,11 +45,11 @@ and subscribe to it from your components.
|
|
|
45
45
|
The backend supplies policies and stores consent records. Every setup above
|
|
46
46
|
works with each option; only the URL changes.
|
|
47
47
|
|
|
48
|
-
| Option | Use it when
|
|
49
|
-
| -------------------------------------------------------------------- |
|
|
50
|
-
| [Inth](https://inth.com) | You want hosted policies and consent records. The guides use this.
|
|
51
|
-
| [Self-hosted c15t backend](https://c15t.com/docs/self-host/overview) | You need to run the service and its database yourself.
|
|
52
|
-
|
|
|
48
|
+
| Option | Use it when |
|
|
49
|
+
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
50
|
+
| [Inth](https://inth.com) | You want hosted policies and consent records. The guides use this. |
|
|
51
|
+
| [Self-hosted c15t backend](https://c15t.com/docs/self-host/overview) | You need to run the service and its database yourself. |
|
|
52
|
+
| [Local mode](./modes.md#local) | Local development and tests. Policies live in your code and choices stay in the browser. c15t keeps no server-side record of consent. Not recommended for production environments. |
|
|
53
53
|
|
|
54
54
|
To use Inth, create a project, set its policy rules, add your site's origin to
|
|
55
55
|
its trusted origins, and copy the backend URL. The guides use the placeholder
|
|
@@ -60,10 +60,10 @@ including any path prefix.
|
|
|
60
60
|
|
|
61
61
|
Where consent resolves decides what the visitor's first HTML contains.
|
|
62
62
|
|
|
63
|
-
| Rendering | What the visitor gets
|
|
64
|
-
| -------------------------------------------- |
|
|
65
|
-
| The server resolves consent for each request | The server reads the visitor's cookie and location headers, so the browser starts with the answer.
|
|
66
|
-
| The browser resolves consent | The HTML is the same for everyone. After the page loads, the browser requests the policy, then shows the banner or runs gated scripts.
|
|
63
|
+
| Rendering | What the visitor gets |
|
|
64
|
+
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
65
|
+
| The server resolves consent for each request | The server reads the visitor's cookie and location headers, so the browser starts with the answer. The banner can be part of the HTML. In Next.js, TanStack Start, Nuxt and SvelteKit, scripts the visitor's consent already allows start before hydration. |
|
|
66
|
+
| The browser resolves consent | The HTML is the same for everyone. After the page loads, the browser requests the policy, then shows the banner or runs gated scripts. |
|
|
67
67
|
|
|
68
68
|
A static or prerendered page cannot contain one visitor's consent, because the
|
|
69
69
|
same HTML goes to everyone. Static sites still use Inth; the browser talks to it
|