@c15t/scripts 3.0.0-alpha.0 → 3.0.0-alpha.2
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 +7 -0
- package/README.md +4 -3
- package/dist/e2e-test-utils.js +5 -3
- package/dist/engine/runtime.js +14 -3
- package/dist/events.js +218 -0
- package/dist/registry.js +40 -0
- package/dist/vendors/ads-and-pixels/pinterest-tag.js +123 -0
- package/dist/vendors/analytics/google-tag.js +14 -2
- package/dist/vendors/analytics/microsoft-clarity.js +4 -1
- package/dist/vendors/analytics/one-dollar-stats.js +30 -0
- package/dist/vendors/analytics/segment.js +10 -1
- package/dist/vendors/functional/front-chat.js +64 -0
- package/dist/vendors/tag-managers/cloudflare-zaraz.js +98 -0
- package/dist/vendors/tag-managers/google-tag-manager.js +17 -3
- package/dist-types/__tests__/helpers.d.ts +2 -2
- package/dist-types/engine/compile.d.ts +1 -1
- package/dist-types/engine/runtime.d.ts +1 -1
- package/dist-types/events.d.ts +46 -0
- package/dist-types/registry.d.ts +36 -0
- package/dist-types/resolve.d.ts +1 -1
- package/dist-types/vendors/_shared/install-builders.d.ts +1 -1
- package/dist-types/vendors/ads-and-pixels/pinterest-tag.d.ts +295 -0
- package/dist-types/vendors/analytics/adobe-analytics.d.ts +1 -1
- package/dist-types/vendors/analytics/google-tag.d.ts +3 -1
- package/dist-types/vendors/analytics/matomo-analytics.d.ts +1 -1
- package/dist-types/vendors/analytics/one-dollar-stats.d.ts +39 -0
- package/dist-types/vendors/analytics/segment.d.ts +7 -1
- package/dist-types/vendors/functional/front-chat.d.ts +62 -0
- package/dist-types/vendors/tag-managers/cloudflare-zaraz.d.ts +39 -0
- package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +3 -1
- package/docs/README.md +7 -0
- package/docs/customization/overview.md +4 -3
- package/docs/customization/recipes.md +4 -2
- package/docs/customization/tokens.md +66 -3
- package/docs/frameworks/javascript/script-loader.md +53 -0
- package/docs/frameworks/next/script-loader.md +60 -12
- package/docs/frameworks/react/script-loader.md +14 -0
- package/docs/guides/consent-state.md +327 -0
- package/docs/guides/deployment-modes.md +12 -0
- package/docs/guides/shared-consent-controls.md +158 -0
- package/docs/integrations/adobe-analytics.md +1 -1
- package/docs/integrations/ahrefs-analytics.md +1 -1
- package/docs/integrations/amplitude.md +1 -1
- package/docs/integrations/building-integrations.md +5 -0
- package/docs/integrations/clear-on-revocation.md +167 -0
- package/docs/integrations/clearbit.md +1 -1
- package/docs/integrations/cloudflare-web-analytics.md +1 -1
- package/docs/integrations/cloudflare-zaraz.md +399 -0
- package/docs/integrations/crisp.md +1 -1
- package/docs/integrations/databuddy.md +1 -1
- package/docs/integrations/fathom-analytics.md +1 -1
- package/docs/integrations/front-chat.md +322 -0
- package/docs/integrations/google-maps.md +21 -21
- package/docs/integrations/google-tag-manager.md +1 -1
- package/docs/integrations/google-tag.md +1 -1
- package/docs/integrations/granular-consent.md +210 -0
- package/docs/integrations/heap.md +1 -1
- package/docs/integrations/hightouch.md +1 -1
- package/docs/integrations/hotjar.md +1 -1
- package/docs/integrations/intercom.md +1 -1
- package/docs/integrations/linkedin-insights.md +1 -1
- package/docs/integrations/logrocket.md +1 -1
- package/docs/integrations/matomo-analytics.md +1 -1
- package/docs/integrations/meta-pixel.md +1 -1
- package/docs/integrations/microsoft-clarity.md +1 -1
- package/docs/integrations/microsoft-uet.md +1 -1
- package/docs/integrations/mixpanel-analytics.md +1 -1
- package/docs/integrations/one-dollar-stats.md +305 -0
- package/docs/integrations/openai-pixel.md +1 -1
- package/docs/integrations/overview.md +22 -18
- package/docs/integrations/pinterest-tag.md +321 -0
- package/docs/integrations/pirsch.md +1 -1
- package/docs/integrations/plausible-analytics.md +1 -1
- package/docs/integrations/posthog.md +1 -1
- package/docs/integrations/promptwatch.md +1 -1
- package/docs/integrations/reddit-pixel.md +1 -1
- package/docs/integrations/rudderstack.md +1 -1
- package/docs/integrations/rybbit-analytics.md +1 -1
- package/docs/integrations/segment.md +1 -1
- package/docs/integrations/snapchat-pixel.md +1 -1
- package/docs/integrations/tiktok-pixel.md +1 -1
- package/docs/integrations/umami-analytics.md +1 -1
- package/docs/integrations/vercel-analytics.md +1 -1
- package/docs/integrations/x-pixel.md +1 -1
- package/docs/integrations/youtube.md +27 -22
- package/docs/upgrade-v3.md +176 -1
- package/package.json +30 -2
- package/readme.json +0 -19
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Script } from '@c15t/core';
|
|
2
|
+
/** The classic script from OneDollarStats' installation instructions. */
|
|
3
|
+
export declare const ONE_DOLLAR_STATS_SCRIPT_SRC = "https://assets.onedollarstats.com/stonks.js";
|
|
4
|
+
/** OneDollarStats is loaded only after measurement consent is granted. */
|
|
5
|
+
export declare const oneDollarStatsManifest: {
|
|
6
|
+
readonly kind: "c15t.vendor-manifest";
|
|
7
|
+
readonly schemaVersion: 1;
|
|
8
|
+
readonly category: 'measurement';
|
|
9
|
+
readonly install: [{
|
|
10
|
+
readonly defer: true;
|
|
11
|
+
readonly src: "https://assets.onedollarstats.com/stonks.js";
|
|
12
|
+
readonly type: 'loadScript';
|
|
13
|
+
}];
|
|
14
|
+
readonly vendor: 'one-dollar-stats';
|
|
15
|
+
};
|
|
16
|
+
export interface OneDollarStatsOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Bare hostname, such as `docs.example.com`. Overrides the event hostname
|
|
19
|
+
* on every host, including production. Required for local dev mode.
|
|
20
|
+
*/
|
|
21
|
+
hostname?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Tracker settings forwarded as `data-*` attributes. Use string values,
|
|
24
|
+
* e.g. `devmode: 'true'`, `autocollect: 'false'`, or a custom `url`.
|
|
25
|
+
* Setting `'hash-routing': 'false'` omits the presence-based attribute.
|
|
26
|
+
*/
|
|
27
|
+
[setting: string]: string | undefined;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a consent-gated OneDollarStats script. No API key is required.
|
|
31
|
+
* The tracker reads data attributes from `document.currentScript` and
|
|
32
|
+
* handles client-side navigation itself.
|
|
33
|
+
*
|
|
34
|
+
* @param options - Tracker settings without the `data-` prefix.
|
|
35
|
+
* @returns The OneDollarStats script configuration.
|
|
36
|
+
* @throws {Error} When hostname is not a bare host, or a setting name is not
|
|
37
|
+
* a valid attribute name or its value is not a string.
|
|
38
|
+
*/
|
|
39
|
+
export declare const oneDollarStats: (options?: OneDollarStatsOptions) => Script;
|
|
@@ -131,6 +131,10 @@ export declare const segmentManifest: {
|
|
|
131
131
|
}];
|
|
132
132
|
readonly category: 'measurement';
|
|
133
133
|
readonly install: [{
|
|
134
|
+
readonly path: ["analytics", "_loadOptions"];
|
|
135
|
+
readonly type: 'setGlobalPath';
|
|
136
|
+
readonly value: '{{loadOptions}}';
|
|
137
|
+
}, {
|
|
134
138
|
readonly global: 'analytics';
|
|
135
139
|
readonly method: 'page';
|
|
136
140
|
readonly type: 'callGlobal';
|
|
@@ -142,6 +146,8 @@ export declare const segmentManifest: {
|
|
|
142
146
|
readonly vendor: 'segment';
|
|
143
147
|
};
|
|
144
148
|
export interface SegmentOptions {
|
|
149
|
+
/** Options consumed by Analytics.js on initialization. */
|
|
150
|
+
loadOptions?: Record<string, unknown>;
|
|
145
151
|
/** Your Segment write key. */
|
|
146
152
|
writeKey: string;
|
|
147
153
|
/** Queue the initial `analytics.page()` call during setup. */
|
|
@@ -155,4 +161,4 @@ export interface SegmentOptions {
|
|
|
155
161
|
* @param options - The options for the Segment script.
|
|
156
162
|
* @returns The Segment script configuration.
|
|
157
163
|
*/
|
|
158
|
-
export declare const segment: ({ writeKey, trackPageView, scriptUrl, }: SegmentOptions) => Script;
|
|
164
|
+
export declare const segment: ({ writeKey, loadOptions, trackPageView, scriptUrl, }: SegmentOptions) => Script;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Script } from '@c15t/core';
|
|
2
|
+
declare global {
|
|
3
|
+
interface Window {
|
|
4
|
+
FrontChat?: (command: string, options?: Record<string, unknown>) => unknown;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
/** Front Chat loader and consent-gated widget initialisation. */
|
|
8
|
+
export declare const frontChatManifest: {
|
|
9
|
+
readonly kind: "c15t.vendor-manifest";
|
|
10
|
+
readonly schemaVersion: 1;
|
|
11
|
+
readonly category: 'functionality';
|
|
12
|
+
readonly install: [{
|
|
13
|
+
readonly async: true;
|
|
14
|
+
readonly src: '{{scriptSrc}}';
|
|
15
|
+
readonly type: 'loadScript';
|
|
16
|
+
}];
|
|
17
|
+
readonly onLoadGranted: [{
|
|
18
|
+
readonly args: ["init", "{{initOptions}}"];
|
|
19
|
+
readonly global: 'FrontChat';
|
|
20
|
+
readonly type: 'callGlobal';
|
|
21
|
+
}];
|
|
22
|
+
readonly vendor: 'front-chat';
|
|
23
|
+
};
|
|
24
|
+
export interface FrontChatOptions {
|
|
25
|
+
/** Public chat ID from the Front channel's installation snippet. */
|
|
26
|
+
chatId: string;
|
|
27
|
+
/** Show Front's default launcher. @default true */
|
|
28
|
+
useDefaultLauncher?: boolean;
|
|
29
|
+
/** Custom or proxied Front Chat bundle URL. */
|
|
30
|
+
scriptSrc?: string;
|
|
31
|
+
/** CSP nonce forwarded to the loader and Front's generated scripts. */
|
|
32
|
+
nonce?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates a Front Chat script gated on functionality consent.
|
|
36
|
+
*
|
|
37
|
+
* Keep c15t's default reload-on-revocation behaviour enabled to stop an
|
|
38
|
+
* already-running widget. Removing its loader cannot unload the SDK.
|
|
39
|
+
*
|
|
40
|
+
* @param options - Front channel and launcher configuration.
|
|
41
|
+
* @returns The Front Chat script configuration.
|
|
42
|
+
* @throws {Error} When chatId is missing or empty. Copy the public ID from
|
|
43
|
+
* the Front channel's installation snippet.
|
|
44
|
+
* @example
|
|
45
|
+
* frontChat({ chatId: 'YOUR_FRONT_CHAT_ID' });
|
|
46
|
+
* @see https://help.front.com/en/articles/2049
|
|
47
|
+
*/
|
|
48
|
+
export declare const frontChat: (options: FrontChatOptions) => Script;
|
|
49
|
+
/**
|
|
50
|
+
* Requests widget removal and session cleanup through Front's SDK.
|
|
51
|
+
*
|
|
52
|
+
* Optionally call it from `onBeforeConsentRevocationReload`. Front does not
|
|
53
|
+
* provide a completion promise, so this does not guarantee cleanup before
|
|
54
|
+
* navigation.
|
|
55
|
+
* Safe to call during SSR or before the SDK loads.
|
|
56
|
+
*
|
|
57
|
+
* @returns Nothing.
|
|
58
|
+
* @example
|
|
59
|
+
* shutdownFrontChat();
|
|
60
|
+
* @see https://dev.frontapp.com/docs/chat-sdk-reference
|
|
61
|
+
*/
|
|
62
|
+
export declare const shutdownFrontChat: () => void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AllConsentNames, Script } from '@c15t/core';
|
|
2
|
+
/** The Zaraz Consent API methods used by the bridge. */
|
|
3
|
+
export interface ZarazConsentApi {
|
|
4
|
+
APIReady: boolean;
|
|
5
|
+
modal?: unknown;
|
|
6
|
+
getAll: () => Record<string, boolean>;
|
|
7
|
+
set: (permissions: Record<string, boolean>) => void;
|
|
8
|
+
sendQueuedEvents: () => void;
|
|
9
|
+
}
|
|
10
|
+
export interface CloudflareZarazOptions {
|
|
11
|
+
/** Map c15t categories to purpose IDs from the Zaraz dashboard. */
|
|
12
|
+
purposes: Partial<Record<AllConsentNames, readonly string[]>>;
|
|
13
|
+
/** Hide the currently visible Zaraz modal. Disable auto-display in Zaraz too. @default true */
|
|
14
|
+
hideBuiltInModal?: boolean;
|
|
15
|
+
/** Replay Zaraz's queued pageview events after a denied purpose becomes allowed. @default true */
|
|
16
|
+
sendQueuedEvents?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Called once after the first successful synchronization. With automatic
|
|
19
|
+
* pageviews disabled in Zaraz, send the initial Pageview from this callback.
|
|
20
|
+
*/
|
|
21
|
+
onReady?: () => void;
|
|
22
|
+
/** Called when synchronization fails. Retried on the next consent update or readiness event. */
|
|
23
|
+
onError?: (error: unknown) => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Synchronize c15t effective permissions with externally loaded Zaraz tools.
|
|
27
|
+
* Does not load Zaraz or configure tools. Unmapped Zaraz purposes are denied.
|
|
28
|
+
* Disable automatic pageviews and send the first Pageview from onReady to avoid
|
|
29
|
+
* running tools with a stale Zaraz consent cookie before synchronization.
|
|
30
|
+
*
|
|
31
|
+
* @param options - Purpose mapping and synchronization callbacks.
|
|
32
|
+
* @returns A callback-only script for the existing c15t script loader.
|
|
33
|
+
* @throws {Error} If the mapping is empty, contains blank IDs, or maps an ID twice.
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* cloudflareZaraz({ purposes: { measurement: ['analytics-purpose'] } });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare const cloudflareZaraz: (options: CloudflareZarazOptions) => Script;
|
|
@@ -54,6 +54,8 @@ export declare const googleTagManagerManifest: {
|
|
|
54
54
|
readonly vendor: 'google-tag-manager';
|
|
55
55
|
};
|
|
56
56
|
export interface GoogleTagManagerOptions {
|
|
57
|
+
/** Container queue name. Defaults to dataLayer. */
|
|
58
|
+
dataLayer?: string;
|
|
57
59
|
/**
|
|
58
60
|
* Your Google Tag Manager container ID. Begins with 'GTM-'.
|
|
59
61
|
* @example `GTM-1234XXX`
|
|
@@ -91,4 +93,4 @@ export interface GoogleTagManagerOptions {
|
|
|
91
93
|
* @param options - The options for the Google Tag Manager script.
|
|
92
94
|
* @returns The Google Tag Manager script.
|
|
93
95
|
*/
|
|
94
|
-
export declare const googleTagManager: ({ id, updateEventName, consentMapping, }: GoogleTagManagerOptions) => Script;
|
|
96
|
+
export declare const googleTagManager: ({ id, dataLayer, updateEventName, consentMapping, }: GoogleTagManagerOptions) => Script;
|
package/docs/README.md
CHANGED
|
@@ -30,6 +30,7 @@ These docs describe v3. Start with Inth hosted setup, identify the framework, ro
|
|
|
30
30
|
- [Understand consent state](./guides/consent-state.md): Distinguish policy resolution, effective permissions, explicit choices, notices and privacy signals.
|
|
31
31
|
- [Data fetching and transports](./guides/data-fetching.md): Choose cached manifests, backend init or offline policy resolution, and understand where consent records are saved.
|
|
32
32
|
- [Choose a deployment mode](./guides/deployment-modes.md): Choose who runs your consent backend, then select manifest, init or offline resolution for your deployment.
|
|
33
|
+
- [Share consent controls across frameworks](./guides/shared-consent-controls.md): Use the same c15t script lifecycle, external consent source, and event controls in every framework.
|
|
33
34
|
- [Troubleshoot consent](./guides/troubleshooting.md): Diagnose missing banners, early vendor requests, lost choices and hydration differences.
|
|
34
35
|
- [Verify consent before shipping](./guides/verify-consent.md): Test requests, policy resolution, persistence, navigation and preference changes in a production build.
|
|
35
36
|
|
|
@@ -47,14 +48,18 @@ These docs describe v3. Start with Inth hosted setup, identify the framework, ro
|
|
|
47
48
|
- [Ahrefs Analytics](./integrations/ahrefs-analytics.md): Configure Ahrefs Analytics with c15t v3, understand measurement permission and verify loading and revocation.
|
|
48
49
|
- [Amplitude](./integrations/amplitude.md): Configure Amplitude with c15t v3, understand measurement permission and verify loading and revocation.
|
|
49
50
|
- [Custom integrations](./integrations/building-integrations.md): Define loading, initialization and consent-change behavior for a vendor without a helper.
|
|
51
|
+
- [Clear on revocation](./integrations/clear-on-revocation.md): Remove configured first-party cookies and Web Storage keys when their consent category is denied.
|
|
50
52
|
- [Clearbit](./integrations/clearbit.md): Configure Clearbit with c15t v3, understand marketing permission and verify loading and revocation.
|
|
51
53
|
- [Cloudflare Web Analytics](./integrations/cloudflare-web-analytics.md): Configure Cloudflare Web Analytics with c15t v3, understand measurement permission and verify loading and revocation.
|
|
54
|
+
- [Cloudflare Zaraz](./integrations/cloudflare-zaraz.md): Synchronize c15t permissions with Zaraz purposes while Cloudflare manages your tools.
|
|
52
55
|
- [Crisp](./integrations/crisp.md): Configure Crisp with c15t v3, understand functionality permission and verify loading and revocation.
|
|
53
56
|
- [Databuddy](./integrations/databuddy.md): Configure Databuddy's initial and updated consent state with c15t v3.
|
|
54
57
|
- [Fathom Analytics](./integrations/fathom-analytics.md): Configure Fathom Analytics with c15t v3, understand measurement permission and verify loading and revocation.
|
|
58
|
+
- [Front Chat](./integrations/front-chat.md): Load the Front Chat widget with functionality permission, forward CSP nonces and clear the session on revocation.
|
|
55
59
|
- [Google Maps](./integrations/google-maps.md): Prevent a map iframe from mounting before the required permission.
|
|
56
60
|
- [Google Tag](./integrations/google-tag.md): Configure gtag with c15t Consent Mode signals and understand its loading behavior.
|
|
57
61
|
- [Google Tag Manager](./integrations/google-tag-manager.md): Load GTM with c15t consent signals and verify the tags inside your container.
|
|
62
|
+
- [Granular consent](./integrations/granular-consent.md): Let visitors grant a category and still turn one vendor off, without adopting IAB TCF.
|
|
58
63
|
- [Heap](./integrations/heap.md): Configure Heap with c15t v3, understand measurement permission and verify loading and revocation.
|
|
59
64
|
- [Hightouch](./integrations/hightouch.md): Configure Hightouch with c15t v3, understand measurement permission and verify loading and revocation.
|
|
60
65
|
- [Hotjar](./integrations/hotjar.md): Configure Hotjar with c15t v3, understand measurement permission and verify loading and revocation.
|
|
@@ -66,8 +71,10 @@ These docs describe v3. Start with Inth hosted setup, identify the framework, ro
|
|
|
66
71
|
- [Microsoft Clarity](./integrations/microsoft-clarity.md): Configure Microsoft Clarity with c15t v3, understand measurement permission and verify loading and revocation.
|
|
67
72
|
- [Microsoft UET](./integrations/microsoft-uet.md): Configure Microsoft UET with c15t v3, understand marketing permission and verify loading and revocation.
|
|
68
73
|
- [Mixpanel](./integrations/mixpanel-analytics.md): Configure Mixpanel with c15t v3, understand measurement permission and verify loading and revocation.
|
|
74
|
+
- [OneDollarStats](./integrations/one-dollar-stats.md): Load the OneDollarStats tracker with measurement permission, forward its settings and verify loading and revocation.
|
|
69
75
|
- [OpenAI Pixel](./integrations/openai-pixel.md): Configure the OpenAI Measurement Pixel for ChatGPT Ads with c15t v3, manage marketing permission and verify conversion delivery.
|
|
70
76
|
- [Overview](./integrations/overview.md): Find all c15t integrations for analytics, tag managers, advertising, chat and embedded content.
|
|
77
|
+
- [Pinterest Tag](./integrations/pinterest-tag.md): Configure the Pinterest Tag with c15t v3, track typed events and verify marketing permission, revocation and reload.
|
|
71
78
|
- [Pirsch](./integrations/pirsch.md): Configure Pirsch with c15t v3, understand measurement permission and verify loading and revocation.
|
|
72
79
|
- [Plausible Analytics](./integrations/plausible-analytics.md): Configure Plausible Analytics with c15t v3, understand measurement permission and verify loading and revocation.
|
|
73
80
|
- [PostHog](./integrations/posthog.md): Choose PostHog loading and cookieless behavior, configure the region, and synchronize v3 permissions.
|
|
@@ -34,10 +34,11 @@ layout can be restored by the policy renderer.
|
|
|
34
34
|
## Use the adapter's configuration shape
|
|
35
35
|
|
|
36
36
|
React and Next.js accept provider `theme`, `presentation` and `components`
|
|
37
|
-
options. Vue and Nuxt expose their own shared configuration, including CSS
|
|
37
|
+
options, and render theme tokens with `ConsentTheme` on the server. Vue and Nuxt expose their own shared configuration, including CSS
|
|
38
38
|
`tokens` and component slots. Svelte accepts its provider options and theme
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
slots; SvelteKit renders the token CSS from a server `load`. Astro serializes
|
|
40
|
+
integration options, renders the theme tokens on the server and uses the
|
|
41
|
+
selected adapter for dialogs. Do not move a configuration object between frameworks without checking
|
|
41
42
|
the target types.
|
|
42
43
|
|
|
43
44
|
Read [tokens and CSS](./tokens.md),
|
|
@@ -26,8 +26,10 @@ export const brandTheme = defineTheme({
|
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
Install `@c15t/ui` to use `defineTheme` directly.
|
|
30
|
-
|
|
29
|
+
Install `@c15t/ui` to use `defineTheme` directly. Render
|
|
30
|
+
`<ConsentTheme theme={brandTheme} />` on the server for the tokens, and pass
|
|
31
|
+
`brandTheme` as `theme` in your existing React or Next.js provider options for
|
|
32
|
+
the action styles. Keep your Inth mode and script
|
|
31
33
|
configuration. The theme source above is also imported by the runnable example,
|
|
32
34
|
so the rendered result and the documentation use the same values.
|
|
33
35
|
|
|
@@ -11,10 +11,53 @@ React, Next.js and Svelte provide `styles.css`. Import the adapter's stylesheet
|
|
|
11
11
|
at the app's global entry point. Vue includes styles in its components; Astro
|
|
12
12
|
adds styles through its integration.
|
|
13
13
|
|
|
14
|
+
The stylesheet blocks rendering, so it carries only what a first paint can
|
|
15
|
+
show: the default tokens, every c15t CSS variable, and the rules for the
|
|
16
|
+
banner, `ConsentDialogTrigger` and the `ConsentGate` placeholder. The consent
|
|
17
|
+
dialog and preference widget bring their own rules. Each rule reaches the page
|
|
18
|
+
once.
|
|
19
|
+
|
|
14
20
|
```tsx
|
|
15
21
|
import 'c15t/react/styles.css';
|
|
16
22
|
```
|
|
17
23
|
|
|
24
|
+
| File | Holds | Loaded by |
|
|
25
|
+
| -------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
26
|
+
| `styles.css` or `styles.tw3.css` | Default tokens, all variables, banner, trigger and `ConsentGate` rules | Your app, once |
|
|
27
|
+
| `@c15t/ui/styles/dialog.css` | Dialog and preference widget rules | The dialog component, with its lazy chunk |
|
|
28
|
+
| `@c15t/ui/styles/primitives.css` | Rules for the `@c15t/ui/styles/primitives` class maps | Svelte's `styles.css`, or your app if it renders those class maps |
|
|
29
|
+
| `iab/styles.css` | IAB TCF banner and dialog rules and variables | Your app, after `styles.css` |
|
|
30
|
+
|
|
31
|
+
In React, Next.js and TanStack Start, the dialog's module imports
|
|
32
|
+
`@c15t/ui/styles/dialog.css`. The bundler emits it with the dialog's chunk and
|
|
33
|
+
loads it before that chunk runs, so the dialog never renders unstyled. The
|
|
34
|
+
chunk loads after first paint, by the time the dialog first opens. Do not
|
|
35
|
+
import `dialog.css` yourself. The `@c15t/react/components/consent-dialog`,
|
|
36
|
+
`/components/consent-widget`, `/primitives`, `/primitives/*` and `/iab` entry
|
|
37
|
+
points import it as soon as you import them, because they render dialog parts
|
|
38
|
+
outside the lazy chunk.
|
|
39
|
+
|
|
40
|
+
These modules import the stylesheet through `@c15t/ui/styles/dialog`. Under
|
|
41
|
+
the `node` export condition that module imports nothing, so server code that
|
|
42
|
+
loads `@c15t/react` with plain Node, such as the Pages Router or an SSR build
|
|
43
|
+
that keeps dependencies external, does not fail on the `.css` file. In your
|
|
44
|
+
own components, import `@c15t/ui/styles/dialog` rather than the `.css` file
|
|
45
|
+
if the module can run on the server.
|
|
46
|
+
|
|
47
|
+
Svelte loads its dialog with the page, so `c15t/svelte/styles.css` also
|
|
48
|
+
imports the dialog and primitive rules. Astro injects the banner rules; the
|
|
49
|
+
React and Svelte dialog islands import the rest, and Astro links those
|
|
50
|
+
stylesheets on every page, so in Astro the dialog rules still block rendering.
|
|
51
|
+
Vue components import their own stylesheets.
|
|
52
|
+
|
|
53
|
+
The dialog rules sit in `@layer components` and declare no variables, so
|
|
54
|
+
tokens from `theme`, variables you override in your own CSS, and Tailwind 4
|
|
55
|
+
utilities still win over them even though they load later. If you import
|
|
56
|
+
`styles.css` into a named layer, such as `@import 'c15t/react/styles.css'
|
|
57
|
+
layer(c15t)`, the dialog rules still join the top-level `components` layer.
|
|
58
|
+
List `components` in your layer order statement, for example
|
|
59
|
+
`@layer c15t, components, app;`, so it does not land after your own layers.
|
|
60
|
+
|
|
18
61
|
The standard stylesheet places rules in `@layer components`. For Tailwind 3,
|
|
19
62
|
use the `styles.tw3.css` entry instead of the standard stylesheet, between the
|
|
20
63
|
components and utilities directives in your Tailwind entry:
|
|
@@ -26,6 +69,18 @@ components and utilities directives in your Tailwind entry:
|
|
|
26
69
|
@tailwind utilities;
|
|
27
70
|
```
|
|
28
71
|
|
|
72
|
+
Tailwind 3 also processes the dialog stylesheet the bundler loads, and it
|
|
73
|
+
rejects a stylesheet that uses `@layer components` without its own
|
|
74
|
+
`@tailwind components` directive. Add the c15t plugin before `tailwindcss` in
|
|
75
|
+
your PostCSS config. It removes the layer wrapper from c15t's stylesheets so
|
|
76
|
+
Tailwind 3 accepts them and its preflight does not override them:
|
|
77
|
+
|
|
78
|
+
```js title="postcss.config.mjs"
|
|
79
|
+
export default {
|
|
80
|
+
plugins: ['@c15t/ui/postcss-tailwind3', 'tailwindcss', 'autoprefixer'],
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
29
84
|
Do not load both c15t stylesheet variants. For Tailwind 4 or unlayered CSS,
|
|
30
85
|
inspect layer order before reaching for `!important`.
|
|
31
86
|
|
|
@@ -48,9 +103,17 @@ export const theme = defineTheme({
|
|
|
48
103
|
});
|
|
49
104
|
```
|
|
50
105
|
|
|
51
|
-
Install `@c15t/ui` if importing its theme helper directly.
|
|
52
|
-
|
|
53
|
-
|
|
106
|
+
Install `@c15t/ui` if importing its theme helper directly. The browser does
|
|
107
|
+
not turn tokens into CSS. In React and Next.js, render
|
|
108
|
+
`<ConsentTheme theme={theme} />` where the app renders on the server, and pass
|
|
109
|
+
`theme` in your provider options for `consentActions`. Elsewhere, call
|
|
110
|
+
`generateThemeCSS(theme)` from `@c15t/ui/theme` on the server or at build time
|
|
111
|
+
and put the result in a `<style>` element or your stylesheet. See
|
|
112
|
+
[React styling](https://c15t.com/docs/frameworks/react/styling/overview) and
|
|
113
|
+
[Next.js styling](https://c15t.com/docs/frameworks/next/styling/overview).
|
|
114
|
+
|
|
115
|
+
`consentActions` selects styling by action role. A per-action entry overrides
|
|
116
|
+
`primary`, which overrides `default`.
|
|
54
117
|
|
|
55
118
|
## Target a prompt with CSS
|
|
56
119
|
|
|
@@ -45,3 +45,56 @@ assuming all helpers have the same network behavior.
|
|
|
45
45
|
The loader exposes `updateScripts`, `getLoadedScriptIds` and `dispose`.
|
|
46
46
|
Unloading an element cannot reverse requests or code that already ran. Test
|
|
47
47
|
revocation and vendor cleanup with [verification](../../guides/verify-consent.md).
|
|
48
|
+
|
|
49
|
+
## Dispose integration resources
|
|
50
|
+
|
|
51
|
+
Ordinary scripts keep their mounted resource when `updateScripts` receives a
|
|
52
|
+
fresh object with the same ID and unchanged element configuration. New callback
|
|
53
|
+
functions alone do not reload the vendor or send a temporary denial. Changing
|
|
54
|
+
the source, inline code or element attributes starts a new loading lifecycle.
|
|
55
|
+
Consent conditions are reevaluated on every configuration update. Pending
|
|
56
|
+
load and error events use the latest registered callbacks and consent state.
|
|
57
|
+
Setting `persistAfterConsentRevoked` to `false` removes an owned retained element
|
|
58
|
+
when the script no longer has consent.
|
|
59
|
+
|
|
60
|
+
Custom script configurations can use `onDispose(info)` to release event
|
|
61
|
+
listeners or other resources. Adding this hook opts the configuration into an
|
|
62
|
+
object-owned lifecycle: replacing the object disposes its resources and starts
|
|
63
|
+
again, even with the same ID. Keep these objects stable across framework
|
|
64
|
+
rerenders. The loader also calls the hook when the configuration is removed or
|
|
65
|
+
the loader is disposed, including configurations that never loaded.
|
|
66
|
+
`info.element` contains the last loaded or retained element when available,
|
|
67
|
+
even when configuration removal has already detached it.
|
|
68
|
+
|
|
69
|
+
Duplicate references receive one cleanup per registration. Re-registering a
|
|
70
|
+
removed object starts a new lifecycle. Updates requested from lifecycle
|
|
71
|
+
callbacks run after the current pass; if several are requested, the latest
|
|
72
|
+
configuration wins. Disposal stops further reconciliation. A callback feedback
|
|
73
|
+
loop exceeding 100 consecutive passes disposes the loader and reports an
|
|
74
|
+
`error` debug event. Avoid callbacks that keep changing consent or replacing
|
|
75
|
+
their own configuration.
|
|
76
|
+
|
|
77
|
+
`onBeforeLoad` prepares a loading attempt. If a callback changes consent or
|
|
78
|
+
replaces configurations, the loader cancels that attempt before loading and
|
|
79
|
+
reevaluates the latest state. A still-eligible script can retry preparation
|
|
80
|
+
with a new element and updated consent. Make `onBeforeLoad` safe to repeat;
|
|
81
|
+
use `onLoad` for initialization that requires a completed load. This also
|
|
82
|
+
applies to callback-only scripts, whose `onLoad` is skipped when preparation
|
|
83
|
+
invalidates the current pass.
|
|
84
|
+
|
|
85
|
+
Consent revocation alone does not call `onDispose`. Use `onConsentChange` for
|
|
86
|
+
vendor opt-out commands. Cleanup errors are reported through the loader's debug
|
|
87
|
+
events and do not prevent other configurations from being cleaned up.
|
|
88
|
+
|
|
89
|
+
## Clear stored tracking data
|
|
90
|
+
|
|
91
|
+
Script gating does not remove cookies or Web Storage entries that a script
|
|
92
|
+
already wrote. Configure [clear on revocation](../../integrations/clear-on-revocation.md)
|
|
93
|
+
on your runtime, or attach its module to your existing kernel, to remove
|
|
94
|
+
declared data when its category is denied.
|
|
95
|
+
|
|
96
|
+
## Shared lifecycle controls
|
|
97
|
+
|
|
98
|
+
See [shared consent controls](../../guides/shared-consent-controls.md) for external CMPs,
|
|
99
|
+
preference delegation, withdrawal reloads, and application events. These controls
|
|
100
|
+
use the same core runtime across frameworks.
|
|
@@ -108,26 +108,26 @@ do not add a second provider. Keep your site's content and footer inside it.
|
|
|
108
108
|
|
|
109
109
|
## Pass prepared consent through your router
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
In the App Router, the root layout from the
|
|
112
|
+
[App Router guide](https://c15t.com/docs/frameworks/next/app-router) passes the pending
|
|
113
|
+
`resolveConsent` result to this wrapper. This partial example is that call;
|
|
114
|
+
keep the `html`, `body` and stylesheet from your existing layout:
|
|
115
115
|
|
|
116
116
|
```tsx
|
|
117
|
-
import type { ReactNode } from 'react';
|
|
118
117
|
import { resolveConsent } from 'c15t/next/server';
|
|
119
118
|
import { consentConfig } from '../c15t.config';
|
|
120
119
|
import { Consent } from '../components/consent';
|
|
121
120
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
121
|
+
// Inside the existing synchronous root layout:
|
|
122
|
+
const state = resolveConsent({ config: consentConfig });
|
|
123
|
+
|
|
124
|
+
<Consent state={state}>{children}</Consent>
|
|
126
125
|
```
|
|
127
126
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
[
|
|
127
|
+
No script loads until the browser has applied the resolved policy and the
|
|
128
|
+
visitor's choice allows it. With the
|
|
129
|
+
[awaited layout](https://c15t.com/docs/frameworks/next/app-router#render-the-banner-in-the-server-html),
|
|
130
|
+
pass the awaited result from `ResolvedConsent` to the same wrapper instead.
|
|
131
131
|
|
|
132
132
|
Pages Router passes `state={pageProps.consentState ?? {}}` to this wrapper
|
|
133
133
|
in `_app.tsx`. Keep `getServerSideProps` and its `c15t/next/pages` helper.
|
|
@@ -166,3 +166,51 @@ with DevTools, or follow [verification](../../guides/verify-consent.md) in your
|
|
|
166
166
|
Use [custom integrations](../../integrations/building-integrations.md) for an
|
|
167
167
|
unlisted vendor. Google helpers have a separate
|
|
168
168
|
[Consent Mode contract](../../integrations/google-tag-manager.md).
|
|
169
|
+
|
|
170
|
+
## Granular consent
|
|
171
|
+
|
|
172
|
+
A visitor can grant marketing and still turn one vendor off. Declare the
|
|
173
|
+
vendors next to the scripts in `lib/scripts.ts`, with the `vendor` slug each
|
|
174
|
+
script already carries, and pass both to `ConsentRoot`:
|
|
175
|
+
|
|
176
|
+
```ts title="lib/scripts.ts"
|
|
177
|
+
import type { Vendor } from 'c15t';
|
|
178
|
+
|
|
179
|
+
export const vendors: Vendor[] = [
|
|
180
|
+
{
|
|
181
|
+
id: 'x-pixel',
|
|
182
|
+
name: 'X Pixel',
|
|
183
|
+
category: 'marketing',
|
|
184
|
+
privacyPolicyUrl: 'https://x.com/privacy',
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
```tsx title="components/consent.tsx"
|
|
190
|
+
import { scripts, vendors } from '../lib/scripts';
|
|
191
|
+
|
|
192
|
+
<ConsentRoot state={state} config={consentConfig} scripts={scripts} vendors={vendors}>
|
|
193
|
+
{children}
|
|
194
|
+
</ConsentRoot>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The preference center lists each vendor under its category with a switch.
|
|
198
|
+
Integrations from `@c15t/scripts` set `vendor` to their manifest slug, so
|
|
199
|
+
`xPixel()` needs no extra wiring; give a hand-written script the same slug
|
|
200
|
+
in its `vendor` field. A backend manifest can declare vendors too. See
|
|
201
|
+
[granular consent](../../integrations/granular-consent.md) for storage,
|
|
202
|
+
bulk actions and the hooks a custom control uses.
|
|
203
|
+
|
|
204
|
+
## Clear stored tracking data
|
|
205
|
+
|
|
206
|
+
Script gating does not remove cookies or Web Storage entries that a script
|
|
207
|
+
already wrote. Add `clearOnRevocation` to your `ConsentRoot` or provider
|
|
208
|
+
options to remove declared data when its category is denied. See
|
|
209
|
+
[clear on revocation](../../integrations/clear-on-revocation.md) for configuration
|
|
210
|
+
and browser limits.
|
|
211
|
+
|
|
212
|
+
## Shared lifecycle controls
|
|
213
|
+
|
|
214
|
+
See [shared consent controls](../../guides/shared-consent-controls.md) for external CMPs,
|
|
215
|
+
preference delegation, withdrawal reloads, and application events. These controls
|
|
216
|
+
use the same core runtime across frameworks.
|
|
@@ -53,3 +53,17 @@ Use [custom integrations](../../integrations/building-integrations.md) for an
|
|
|
53
53
|
unlisted vendor and [verification](../../guides/verify-consent.md) for the network
|
|
54
54
|
checks. Google helpers have a separate
|
|
55
55
|
[Consent Mode contract](../../integrations/google-tag-manager.md).
|
|
56
|
+
|
|
57
|
+
## Clear stored tracking data
|
|
58
|
+
|
|
59
|
+
Script gating does not remove cookies or Web Storage entries that a script
|
|
60
|
+
already wrote. Add `clearOnRevocation` to `ConsentProvider.options` to remove
|
|
61
|
+
declared data when its category is denied. See
|
|
62
|
+
[clear on revocation](../../integrations/clear-on-revocation.md) for configuration
|
|
63
|
+
and browser limits.
|
|
64
|
+
|
|
65
|
+
## Shared lifecycle controls
|
|
66
|
+
|
|
67
|
+
See [shared consent controls](../../guides/shared-consent-controls.md) for external CMPs,
|
|
68
|
+
preference delegation, withdrawal reloads, and application events. These controls
|
|
69
|
+
use the same core runtime across frameworks.
|