@c15t/nextjs 2.0.0-rc.7 → 2.0.0-rc.8
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/README.md +7 -0
- package/dist/iab/styles.css +12 -1
- package/dist/iab/styles.tw3.css +14 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/styles.css +10 -1
- package/dist/styles.tw3.css +13 -1
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/dist-types/headless.d.ts +1 -1
- package/dist-types/index.d.ts +2 -2
- package/dist-types/libs/browser-initial-data.d.ts +2 -2
- package/dist-types/libs/initial-data.d.ts +1 -1
- package/dist-types/types.d.ts +3 -3
- package/dist-types/version.d.ts +1 -1
- package/docs/building-headless-components.md +40 -22
- package/docs/callbacks.md +76 -9
- package/docs/components/consent-banner.md +83 -9
- package/docs/components/consent-dialog.md +12 -2
- package/docs/components/consent-manager-provider.md +3 -1
- package/docs/components/consent-widget.md +61 -8
- package/docs/concepts/client-modes.md +16 -4
- package/docs/concepts/initialization-flow.md +9 -2
- package/docs/concepts/policy-packs.md +2 -2
- package/docs/hooks/use-consent-manager/overview.md +17 -3
- package/docs/hooks/use-ssr-status.md +1 -1
- package/docs/hooks/use-translations.md +1 -0
- package/docs/iab/consent-banner.md +2 -5
- package/docs/iab/consent-dialog.md +3 -6
- package/docs/iab/overview.md +11 -5
- package/docs/integrations/building-integrations.md +405 -0
- package/docs/integrations/databuddy.md +22 -5
- package/docs/integrations/google-tag-manager.md +2 -2
- package/docs/integrations/google-tag.md +2 -29
- package/docs/integrations/linkedin-insights.md +1 -1
- package/docs/integrations/meta-pixel.md +1 -1
- package/docs/integrations/microsoft-uet.md +1 -1
- package/docs/integrations/overview.md +18 -2
- package/docs/integrations/posthog.md +39 -17
- package/docs/integrations/tiktok-pixel.md +1 -1
- package/docs/integrations/x-pixel.md +1 -1
- package/docs/optimization.md +68 -9
- package/docs/policy-packs.md +7 -7
- package/docs/quickstart.md +11 -5
- package/docs/script-loader.md +22 -1
- package/docs/server-side.md +1 -1
- package/docs/styling/tailwind.md +23 -17
- package/iab/styles.css +1 -0
- package/package.json +10 -8
- package/readme.json +4 -0
- package/src/iab/styles.css +6 -4
- package/src/iab/styles.tw3.css +8 -4
- package/src/styles.css +3 -3
- package/src/styles.tw3.css +7 -4
- package/styles.css +1 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: PostHog
|
|
3
3
|
description: PostHog is an open-source product analytics platform for tracking user behavior, session replays, feature flags, and A/B testing. It supports cookieless tracking, allowing analytics to continue even without cookie consent.
|
|
4
|
-
lastModified:
|
|
4
|
+
lastModified: 2026-04-08
|
|
5
5
|
|
|
6
6
|
icon: posthog
|
|
7
7
|
---
|
|
@@ -25,7 +25,7 @@ This is the recommended approach if you're using the Posthog JS SDK, this is com
|
|
|
25
25
|
posthog.opt_out_capturing() // Avoids accidental tracking without consent till c15t has loaded
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
2. **
|
|
28
|
+
2. **Sync settled consent once, then subscribe to real changes** The recommended PostHog SDK approach uses two phases: run one initial sync after c15t has finished resolving consent, then subscribe to future real preference changes with subscribeToConsentChanges().
|
|
29
29
|
|
|
30
30
|
> ℹ️ Info:
|
|
31
31
|
>
|
|
@@ -35,20 +35,38 @@ This is the recommended approach if you're using the Posthog JS SDK, this is com
|
|
|
35
35
|
import { getOrCreateConsentRuntime } from 'c15t';
|
|
36
36
|
import { posthog } from 'posthog-js';
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
function syncPostHogMeasurementConsent(hasMeasurementConsent: boolean) {
|
|
39
|
+
if (hasMeasurementConsent) {
|
|
40
|
+
posthog.opt_in_capturing();
|
|
41
|
+
} else {
|
|
42
|
+
posthog.opt_out_capturing();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const runtime = getOrCreateConsentRuntime({
|
|
39
47
|
mode: 'hosted',
|
|
40
48
|
callbacks: {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
+
onBannerFetched() {
|
|
50
|
+
syncPostHogMeasurementConsent(
|
|
51
|
+
runtime.consentStore.getState().has('measurement')
|
|
52
|
+
);
|
|
53
|
+
},
|
|
54
|
+
},
|
|
49
55
|
});
|
|
56
|
+
|
|
57
|
+
runtime.consentStore
|
|
58
|
+
.getState()
|
|
59
|
+
.subscribeToConsentChanges(({ allowedCategories }) => {
|
|
60
|
+
syncPostHogMeasurementConsent(
|
|
61
|
+
allowedCategories.includes('measurement')
|
|
62
|
+
);
|
|
63
|
+
});
|
|
50
64
|
```
|
|
51
65
|
|
|
66
|
+
> ℹ️ Info:
|
|
67
|
+
>
|
|
68
|
+
> Avoid using onConsentSet plus manual deduplication for PostHog. subscribeToConsentChanges() already gives you the exact change-only semantics most analytics SDKs need.
|
|
69
|
+
|
|
52
70
|
## PostHog Script Implementation
|
|
53
71
|
|
|
54
72
|
If you want to load posthog via a script tag it's recommended to use this approach.
|
|
@@ -80,8 +98,13 @@ By default c15t will always load the script regardless of consent. This is becau
|
|
|
80
98
|
posthog({
|
|
81
99
|
id: 'phc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
|
82
100
|
apiHost: 'https://eu.i.posthog.com',
|
|
83
|
-
|
|
84
|
-
|
|
101
|
+
scriptUrl: 'https://eu-assets.i.posthog.com/static/array.js',
|
|
102
|
+
initOptions: {
|
|
103
|
+
api_host: 'https://eu.i.posthog.com',
|
|
104
|
+
ui_host: 'https://eu.i.posthog.com',
|
|
105
|
+
autocapture: false,
|
|
106
|
+
person_profiles: 'identified_only',
|
|
107
|
+
}
|
|
85
108
|
})
|
|
86
109
|
```
|
|
87
110
|
|
|
@@ -92,10 +115,9 @@ By default c15t will always load the script regardless of consent. This is becau
|
|
|
92
115
|
|Property|Type|Description|Default|Required|
|
|
93
116
|
|:--|:--|:--|:--|:--:|
|
|
94
117
|
|id|string|Your posthog id, begins with 'phc\_'.|-|✅ Required|
|
|
95
|
-
|apiHost|string|Your posthog api host.|'https\://eu.i.posthog.com'
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
|script|Script \|undefined|Override or extend the default script values. Options: \`id\`: 'posthog-consent'; \`category\`: 'measurement'|-|Optional|
|
|
118
|
+
|apiHost|string \|undefined|Your posthog api host.|'https\://eu.i.posthog.com'|Optional|
|
|
119
|
+
|scriptUrl|string \|undefined|The PostHog array loader URL.|-|Optional|
|
|
120
|
+
|initOptions|Record\<string, unknown> \|undefined|PostHog init options passed to \`posthog.init(...)\`.|-|Optional|
|
|
99
121
|
|
|
100
122
|
### Script
|
|
101
123
|
|
|
@@ -31,7 +31,7 @@ tiktokPixel({
|
|
|
31
31
|
|Property|Type|Description|Default|Required|
|
|
32
32
|
|:--|:--|:--|:--|:--:|
|
|
33
33
|
|pixelId|string|Your TikTok Pixel ID|-|✅ Required|
|
|
34
|
-
|
|
|
34
|
+
|scriptSrc|string \|undefined|TikTok Pixel loader base URL.|-|Optional|
|
|
35
35
|
|
|
36
36
|
### Script
|
|
37
37
|
|
|
@@ -37,7 +37,7 @@ xPixelEvent('tw-xxxx-xxxx', { value: 10.00, currency: 'USD' });
|
|
|
37
37
|
|Property|Type|Description|Default|Required|
|
|
38
38
|
|:--|:--|:--|:--|:--:|
|
|
39
39
|
|pixelId|string|Your X Pixel ID|-|✅ Required|
|
|
40
|
-
|
|
|
40
|
+
|scriptSrc|string \|undefined|X Pixel loader URL.|-|Optional|
|
|
41
41
|
|
|
42
42
|
### Script
|
|
43
43
|
|
package/docs/optimization.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Optimization
|
|
3
3
|
description: Improve c15t startup performance in Next.js with rewrites, static prefetching, and rendering tradeoffs.
|
|
4
|
-
lastModified: 2026-
|
|
4
|
+
lastModified: 2026-04-09
|
|
5
5
|
---
|
|
6
6
|
Use this guide when you care about banner visibility speed, route static-ness, and reducing backend round-trip cost.
|
|
7
7
|
|
|
@@ -48,7 +48,7 @@ Why this helps:
|
|
|
48
48
|
|
|
49
49
|
|Goal|Strategy|Tradeoff|
|
|
50
50
|
|--|--|--|
|
|
51
|
-
|Keep routes fully static|`C15tPrefetch
|
|
51
|
+
|Keep routes fully static|`C15tPrefetch`|Still client-side fetch, but starts earlier|
|
|
52
52
|
|Fastest first banner on dynamic routes|`fetchInitialData()` in a Server Component (do not await)|Route becomes dynamic because of `next/headers`|
|
|
53
53
|
|Simplest setup|Client-only init (no prefetch)|Banner appears later on slow networks|
|
|
54
54
|
|
|
@@ -60,9 +60,72 @@ In production benchmarks with a same-origin rewrite, prefetching strategies show
|
|
|
60
60
|
|Browser prefetch|\~1.3x faster|\~2.6x earlier|\~1.25x faster|
|
|
61
61
|
|Server prefetch|\~2x faster|before page loads|\~1.9x faster|
|
|
62
62
|
|
|
63
|
+
### Dynamic Routes: Fetch On The Server And Stream
|
|
64
|
+
|
|
65
|
+
Use `fetchInitialData()` in a Server Component when you want the fastest first banner and can accept the route becoming dynamic.
|
|
66
|
+
|
|
67
|
+
```tsx title="app/layout.tsx"
|
|
68
|
+
import { fetchInitialData } from '@c15t/nextjs';
|
|
69
|
+
import ConsentManager from '@/components/consent-manager';
|
|
70
|
+
|
|
71
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
72
|
+
const ssrData = fetchInitialData({
|
|
73
|
+
backendURL: process.env.NEXT_PUBLIC_C15T_URL!,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<html lang="en">
|
|
78
|
+
<body>
|
|
79
|
+
<ConsentManager ssrData={ssrData}>{children}</ConsentManager>
|
|
80
|
+
</body>
|
|
81
|
+
</html>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```tsx title="components/consent-manager/provider.tsx"
|
|
87
|
+
'use client';
|
|
88
|
+
|
|
89
|
+
import { type ReactNode } from 'react';
|
|
90
|
+
import {
|
|
91
|
+
ConsentManagerProvider,
|
|
92
|
+
ConsentBanner,
|
|
93
|
+
ConsentDialog,
|
|
94
|
+
type InitialDataPromise,
|
|
95
|
+
} from '@c15t/nextjs';
|
|
96
|
+
|
|
97
|
+
export default function ConsentManager({
|
|
98
|
+
children,
|
|
99
|
+
ssrData,
|
|
100
|
+
}: {
|
|
101
|
+
children: ReactNode;
|
|
102
|
+
ssrData?: InitialDataPromise;
|
|
103
|
+
}) {
|
|
104
|
+
return (
|
|
105
|
+
<ConsentManagerProvider
|
|
106
|
+
options={{
|
|
107
|
+
mode: 'hosted',
|
|
108
|
+
backendURL: '/api/c15t',
|
|
109
|
+
store: { ssrData },
|
|
110
|
+
}}
|
|
111
|
+
>
|
|
112
|
+
<ConsentBanner />
|
|
113
|
+
<ConsentDialog />
|
|
114
|
+
{children}
|
|
115
|
+
</ConsentManagerProvider>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
> ℹ️ **Info:**
|
|
121
|
+
> Do not await fetchInitialData(). Pass the unresolved Promise to the provider so Next.js can stream the route while /init runs in parallel.
|
|
122
|
+
>
|
|
123
|
+
> ℹ️ **Info:**
|
|
124
|
+
> For fetchInitialData(), prefer a direct backend URL such as https\://your-instance.c15t.dev instead of a rewrite to avoid an extra server-side proxy hop. See Server-Side Data Fetching for the full flow.
|
|
125
|
+
|
|
63
126
|
### Static Routes: Start Fetch Early In The Browser
|
|
64
127
|
|
|
65
|
-
Use `C15tPrefetch` in your layout
|
|
128
|
+
Use `C15tPrefetch` in your layout. Matching prefetched data is consumed automatically by the runtime during first store initialization.
|
|
66
129
|
|
|
67
130
|
```tsx title="app/layout.tsx"
|
|
68
131
|
import { C15tPrefetch } from '@c15t/nextjs';
|
|
@@ -92,7 +155,6 @@ import {
|
|
|
92
155
|
ConsentManagerProvider,
|
|
93
156
|
ConsentBanner,
|
|
94
157
|
ConsentDialog,
|
|
95
|
-
getPrefetchedInitialData,
|
|
96
158
|
} from '@c15t/nextjs';
|
|
97
159
|
|
|
98
160
|
export default function ConsentManagerClient({ children }: { children: React.ReactNode }) {
|
|
@@ -101,10 +163,7 @@ export default function ConsentManagerClient({ children }: { children: React.Rea
|
|
|
101
163
|
options={{
|
|
102
164
|
mode: 'hosted',
|
|
103
165
|
backendURL: '/api/c15t',
|
|
104
|
-
|
|
105
|
-
backendURL: '/api/c15t',
|
|
106
|
-
overrides: { country: 'DE', region: 'BE', language: 'de' },
|
|
107
|
-
}),
|
|
166
|
+
overrides: { country: 'DE', region: 'BE', language: 'de' },
|
|
108
167
|
}}
|
|
109
168
|
>
|
|
110
169
|
<ConsentBanner />
|
|
@@ -119,7 +178,7 @@ export default function ConsentManagerClient({ children }: { children: React.Rea
|
|
|
119
178
|
> C15tPrefetch uses Next.js beforeInteractive script loading, so the /init request can start before hydration. In App Router streaming output, this may appear as Next.js script bootstrap data (for example self.\_\_next\_s.push(...)) instead of a literal \<head>\<script> tag.
|
|
120
179
|
>
|
|
121
180
|
> ℹ️ **Info:**
|
|
122
|
-
> If
|
|
181
|
+
> If overrides.gpc conflicts with the browser's ambient GPC signal, the prefetched entry is not reused and c15t falls back to a normal client /init.
|
|
123
182
|
|
|
124
183
|
## Keep The Provider Mounted Across Navigation
|
|
125
184
|
|
package/docs/policy-packs.md
CHANGED
|
@@ -6,7 +6,7 @@ Policy packs configure how c15t handles regional consent — which model (opt-in
|
|
|
6
6
|
|
|
7
7
|
**For most apps, you just need a `ConsentManagerProvider` pointing at your backend with presets configured there.** The frontend receives the resolved policy via the `/init` response — no client-side policy config required.
|
|
8
8
|
|
|
9
|
-
When a backend isn't available — local development, static previews, Storybook, or as a resilience fallback — you can pass policies directly to the provider via `offlinePolicy.policyPacks` and c15t resolves them locally.
|
|
9
|
+
When a backend isn't available — local development, static previews, Storybook, automated tests, or as a resilience fallback during a temporary outage — you can pass policies directly to the provider via `offlinePolicy.policyPacks` and c15t resolves them locally.
|
|
10
10
|
|
|
11
11
|
> ℹ️ **Info:**
|
|
12
12
|
> For QA and testing, use the c15t DevTools to simulate different regions and policy responses against your real backend, rather than switching to offline mode.
|
|
@@ -29,9 +29,9 @@ When using consent.io or a self-hosted backend, the provider connects automatica
|
|
|
29
29
|
|
|
30
30
|
The backend resolves the correct policy based on the visitor's geo data and returns it in the `/init` response. Configure your presets on the backend side.
|
|
31
31
|
|
|
32
|
-
## Offline Presets (Fallback)
|
|
32
|
+
## Offline Presets (Development and Fallback)
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
Use offline presets mainly for local development, Storybook, deterministic tests, or temporary backend outages:
|
|
35
35
|
|
|
36
36
|
```tsx
|
|
37
37
|
import { policyPackPresets } from '@c15t/react';
|
|
@@ -109,7 +109,7 @@ For production Next.js apps, you can optionally hydrate the first `/init` respon
|
|
|
109
109
|
|
|
110
110
|
## Offline / Fallback
|
|
111
111
|
|
|
112
|
-
For local development,
|
|
112
|
+
For local development, previews, automated tests, or when the backend is temporarily unreachable, pass policies directly:
|
|
113
113
|
|
|
114
114
|
```tsx title="components/consent-manager/provider.tsx"
|
|
115
115
|
'use client';
|
|
@@ -150,7 +150,7 @@ export function ConsentManager({ children }: { children: ReactNode }) {
|
|
|
150
150
|
## Provider Shape
|
|
151
151
|
|
|
152
152
|
Configure packs through `offlinePolicy.policyPacks`. Add `offlinePolicy.i18n`
|
|
153
|
-
when you want
|
|
153
|
+
when you want local previews or fallback behavior to mirror hosted policy-profile language behavior:
|
|
154
154
|
|
|
155
155
|
```tsx
|
|
156
156
|
<ConsentManagerProvider
|
|
@@ -209,7 +209,7 @@ With that setup, offline mode resolves language the same way as hosted mode:
|
|
|
209
209
|
|`offlinePolicy: { policyPacks: [] }`|Explicit no-banner mode|
|
|
210
210
|
|Non-empty pack, no match, no default|Explicit no-banner mode|
|
|
211
211
|
|
|
212
|
-
Omitting the option gives you a safe opt-in default for local development and outage scenarios. Providing it tells c15t you want
|
|
212
|
+
Omitting the option gives you a safe opt-in default for local development and outage scenarios. Providing it tells c15t you want deterministic preview or fallback behavior exactly as configured.
|
|
213
213
|
|
|
214
214
|
## QA and Debugging
|
|
215
215
|
|
|
@@ -221,7 +221,7 @@ For deeper inspection:
|
|
|
221
221
|
* Open the DevTools Policy panel to inspect matcher resolution and fingerprints
|
|
222
222
|
* Compare your frontend preview with the backend `/init` response before shipping
|
|
223
223
|
|
|
224
|
-
If you need fully deterministic resolution without a backend (
|
|
224
|
+
If you need fully deterministic resolution without a backend during testing or preview work (for example, in automated tests or Storybook), pair `offlinePolicy.policyPacks` with `overrides`:
|
|
225
225
|
|
|
226
226
|
```tsx
|
|
227
227
|
options={{
|
package/docs/quickstart.md
CHANGED
|
@@ -33,15 +33,17 @@ availableIn:
|
|
|
33
33
|
|yarn|`yarn add @c15t/nextjs`|
|
|
34
34
|
|bun|`bun add @c15t/nextjs`|
|
|
35
35
|
|
|
36
|
-
2. **Import styles** Import the prebuilt component stylesheet in your
|
|
36
|
+
2. **Import styles** Import the prebuilt component stylesheet in your app-level CSS entrypoint. This is required for styled components to render correctly.
|
|
37
37
|
|
|
38
|
-
```
|
|
39
|
-
import
|
|
38
|
+
```css
|
|
39
|
+
@import "@c15t/nextjs/styles.css";
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
Keeping the c15t stylesheet in your global CSS entrypoint makes layer and cascade order explicit. JS/TSX side-effect imports can load in a different order across framework and Tailwind tooling, which makes style regressions harder to debug.
|
|
43
|
+
|
|
42
44
|
> ℹ️ Info:
|
|
43
45
|
>
|
|
44
|
-
> If you are using the headless API or fully custom styling, you can skip this import.
|
|
46
|
+
> If you are using the headless API or fully custom styling, you can skip this import. Your root layout should continue importing ./globals.css as usual.
|
|
45
47
|
|
|
46
48
|
3. **Create ConsentManager components** Create a provider component with the consent UI and a wrapper that re-exports it. This initializes the consent store and makes consent state available to all child components.
|
|
47
49
|
|
|
@@ -85,7 +87,11 @@ availableIn:
|
|
|
85
87
|
|
|
86
88
|
> ℹ️ Info:
|
|
87
89
|
>
|
|
88
|
-
>
|
|
90
|
+
> Hosted mode is the recommended production setup because the backend resolves jurisdiction and policy, keeps durable consent records, and lets c15t recover from temporary network failures by re-syncing later.
|
|
91
|
+
>
|
|
92
|
+
> ℹ️ Info:
|
|
93
|
+
>
|
|
94
|
+
> Don't have a backend yet? You can use mode: 'offline' for local-only consent storage, but it gives up backend audit history, server-side consent awareness, and automatic jurisdiction detection. Review the browser-only storage consequences before choosing it for production.
|
|
89
95
|
|
|
90
96
|
4. **Mount ConsentManager at the app root** Wrap your app tree with ConsentManager so all routes/components can access consent state.
|
|
91
97
|
|
package/docs/script-loader.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Gate third-party scripts behind consent - load Google Analytics, Me
|
|
|
4
4
|
---
|
|
5
5
|
The script loader manages third-party scripts based on consent state. Scripts are defined in the provider's `scripts` option and are automatically loaded when their required consent category is granted, and unloaded when consent is revoked.
|
|
6
6
|
|
|
7
|
-
c15t has a collection of premade scripts available
|
|
7
|
+
c15t has a collection of premade scripts available in `@c15t/scripts`. Check the [integrations overview](/docs/integrations/overview) first before manually building a script.
|
|
8
8
|
|
|
9
9
|
|Package manager|Command|
|
|
10
10
|
|:--|:--|
|
|
@@ -15,6 +15,12 @@ c15t has a collection of premade scripts available on the @c15t/scripts package.
|
|
|
15
15
|
|
|
16
16
|
> ℹ️ **Info:**
|
|
17
17
|
> We recommend using the pre-built integrations when possible.
|
|
18
|
+
>
|
|
19
|
+
> ℹ️ **Info:**
|
|
20
|
+
> If you need a vendor we do not ship yet, see the custom integration guide. It covers both one-off Script objects and reusable manifest-backed integrations.
|
|
21
|
+
>
|
|
22
|
+
> ℹ️ **Info:**
|
|
23
|
+
> For app-specific scripts, use a plain Script object. For reusable integrations, prefer a manifest-backed helper so startup phases, consent signaling, and future server-side loading support stay structured.
|
|
18
24
|
|
|
19
25
|
## Basic Usage
|
|
20
26
|
|
|
@@ -47,6 +53,21 @@ export function ConsentManager({ children }: { children: ReactNode }) {
|
|
|
47
53
|
}
|
|
48
54
|
```
|
|
49
55
|
|
|
56
|
+
## Choose the Right Approach
|
|
57
|
+
|
|
58
|
+
* Use a plain `Script` for one-off app code.
|
|
59
|
+
* Use a manifest-backed helper in `@c15t/scripts` for reusable integrations, contributions, or anything that needs structured startup behavior.
|
|
60
|
+
|
|
61
|
+
If you are building something reusable, start with the [custom integration guide](/docs/integrations/building-integrations) before using raw callbacks.
|
|
62
|
+
|
|
63
|
+
## Reusable Integrations
|
|
64
|
+
|
|
65
|
+
For app-specific use, raw `Script` objects are usually enough.
|
|
66
|
+
|
|
67
|
+
For reusable integrations, c15t uses a manifest-backed model in `@c15t/scripts`. That keeps startup phases, consent signaling, and vendor-specific boot logic structured instead of hidden inside large callback bodies.
|
|
68
|
+
|
|
69
|
+
If you are building an integration for multiple apps or contributing upstream, use the [custom integration guide](/docs/integrations/building-integrations).
|
|
70
|
+
|
|
50
71
|
## Script Types
|
|
51
72
|
|
|
52
73
|
### Standard Scripts
|
package/docs/server-side.md
CHANGED
|
@@ -29,7 +29,7 @@ const ssrData = fetchInitialData({
|
|
|
29
29
|
> Do not await fetchInitialData() in Server Components. Pass the Promise directly to your client component so Next.js can stream the page while the consent data loads in parallel.
|
|
30
30
|
>
|
|
31
31
|
> ℹ️ **Info:**
|
|
32
|
-
> Need fully static routes? Use C15tPrefetch in your layout
|
|
32
|
+
> Need fully static routes? Use C15tPrefetch in your layout. Matching prefetched data is consumed automatically by the runtime instead of using fetchInitialData(). See Optimization.
|
|
33
33
|
|
|
34
34
|
### How Streaming Works
|
|
35
35
|
|
package/docs/styling/tailwind.md
CHANGED
|
@@ -6,41 +6,47 @@ c15t works with Tailwind CSS out of the box. Use the `slots` theme option to app
|
|
|
6
6
|
|
|
7
7
|
## Setup
|
|
8
8
|
|
|
9
|
-
Import the standard c15t stylesheet once
|
|
9
|
+
Import the standard c15t stylesheet once in your app-level CSS entrypoint:
|
|
10
10
|
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
import
|
|
11
|
+
```css
|
|
12
|
+
/* React: src/index.css */
|
|
13
|
+
@import "@c15t/react/styles.css";
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
import
|
|
15
|
+
/* Next.js: app/globals.css */
|
|
16
|
+
@import "@c15t/nextjs/styles.css";
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
Keeping the c15t stylesheet in your global CSS entrypoint makes layer and cascade order explicit. JS/TSX side-effect imports can load in a different order across framework and Tailwind tooling, which makes style regressions harder to debug.
|
|
20
|
+
|
|
19
21
|
### Tailwind v4
|
|
20
22
|
|
|
21
|
-
Tailwind v4 automatically scans your source files. Import Tailwind normally. c15t component styles join Tailwind's `components` layer automatically, so no extra c15t-specific layer declaration is needed:
|
|
23
|
+
Tailwind v4 automatically scans your source files. Import Tailwind normally, then place the c15t stylesheet immediately after it. c15t component styles join Tailwind's `components` layer automatically, so no extra c15t-specific layer declaration is needed:
|
|
22
24
|
|
|
23
|
-
```css
|
|
25
|
+
```css title="src/index.css"
|
|
24
26
|
@import "tailwindcss";
|
|
27
|
+
@import "@c15t/react/styles.css";
|
|
25
28
|
```
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
```css title="app/globals.css"
|
|
31
|
+
@import "tailwindcss";
|
|
32
|
+
@import "@c15t/nextjs/styles.css";
|
|
33
|
+
```
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
### Tailwind v3
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
import '@c15t/react/styles.tw3.css';
|
|
33
|
-
import './globals.css';
|
|
34
|
-
```
|
|
37
|
+
Import the Tailwind 3-compatible c15t stylesheet after `@tailwind components;` and before `@tailwind utilities;`:
|
|
35
38
|
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
```css title="src/index.css"
|
|
40
|
+
@tailwind base;
|
|
41
|
+
@tailwind components;
|
|
42
|
+
@import "@c15t/react/styles.tw3.css";
|
|
43
|
+
@tailwind utilities;
|
|
39
44
|
```
|
|
40
45
|
|
|
41
46
|
```css title="app/globals.css"
|
|
42
47
|
@tailwind base;
|
|
43
48
|
@tailwind components;
|
|
49
|
+
@import "@c15t/nextjs/styles.tw3.css";
|
|
44
50
|
@tailwind utilities;
|
|
45
51
|
```
|
|
46
52
|
|
package/iab/styles.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "../dist/iab/styles.css";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c15t/nextjs",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.8",
|
|
4
4
|
"description": "Developer-first CMP for Next.js: cookie banner, consent manager, preferences centre. GDPR ready with minimal setup and rich customization.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nextjs",
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
"type": "module",
|
|
34
34
|
"exports": {
|
|
35
35
|
"./styles.css": "./dist/styles.css",
|
|
36
|
-
"./styles.tw3.css": "./
|
|
36
|
+
"./styles.tw3.css": "./dist/styles.tw3.css",
|
|
37
37
|
"./iab/styles.css": "./dist/iab/styles.css",
|
|
38
|
-
"./iab/styles.tw3.css": "./
|
|
38
|
+
"./iab/styles.tw3.css": "./dist/iab/styles.tw3.css",
|
|
39
39
|
"./headless": {
|
|
40
40
|
"types": "./dist-types/headless.d.ts",
|
|
41
41
|
"import": "./dist/headless.js",
|
|
@@ -60,6 +60,8 @@
|
|
|
60
60
|
"docs",
|
|
61
61
|
"dist-types",
|
|
62
62
|
"client",
|
|
63
|
+
"styles.css",
|
|
64
|
+
"iab",
|
|
63
65
|
"src/styles.css",
|
|
64
66
|
"src/styles.tw3.css",
|
|
65
67
|
"src/iab/styles.css",
|
|
@@ -67,10 +69,10 @@
|
|
|
67
69
|
],
|
|
68
70
|
"scripts": {
|
|
69
71
|
"prebuild": "genversion --esm --semi src/version.ts",
|
|
70
|
-
"build": "bun prebuild && rslib build && bun ../../scripts/agent-docs/generate-package-docs.ts @c15t/nextjs",
|
|
72
|
+
"build": "bun prebuild && rslib build && bun ../../scripts/normalize-dist-types.mjs && bun scripts/generate-distribution-css.ts && bun ../../scripts/agent-docs/generate-package-docs.ts @c15t/nextjs",
|
|
71
73
|
"build:agent-docs": "bun ../../scripts/agent-docs/generate-package-docs.ts @c15t/nextjs",
|
|
72
74
|
"check-types": "bun prebuild && tsc --noEmit",
|
|
73
|
-
"dev": "bun prebuild && rslib build",
|
|
75
|
+
"dev": "bun prebuild && rslib build && bun ../../scripts/normalize-dist-types.mjs && bun scripts/generate-distribution-css.ts",
|
|
74
76
|
"fmt": "bun biome format --write . && bun biome check --formatter-enabled=false --linter-enabled=false --write",
|
|
75
77
|
"lint": "bun biome lint ./src",
|
|
76
78
|
"prepack": "cd ../.. && bunx turbo run build --filter=@c15t/nextjs",
|
|
@@ -78,9 +80,9 @@
|
|
|
78
80
|
"test:watch": "bun prebuild && vitest --passWithNoTests"
|
|
79
81
|
},
|
|
80
82
|
"dependencies": {
|
|
81
|
-
"@c15t/react": "2.0.0-rc.
|
|
82
|
-
"@c15t/translations": "2.0.0-rc.
|
|
83
|
-
"c15t": "2.0.0-rc.
|
|
83
|
+
"@c15t/react": "2.0.0-rc.8",
|
|
84
|
+
"@c15t/translations": "2.0.0-rc.8",
|
|
85
|
+
"c15t": "2.0.0-rc.8"
|
|
84
86
|
},
|
|
85
87
|
"devDependencies": {
|
|
86
88
|
"@c15t/typescript-config": "0.0.1-beta.1",
|
package/readme.json
CHANGED
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
"",
|
|
22
22
|
"```bash\npnpm add @c15t/nextjs\n```",
|
|
23
23
|
"",
|
|
24
|
+
"Then add the prebuilt stylesheet to your app-level CSS entrypoint:",
|
|
25
|
+
"",
|
|
26
|
+
"```css\n/* app/globals.css */\n@import \"@c15t/nextjs/styles.css\";\n```",
|
|
27
|
+
"",
|
|
24
28
|
"To manually install, follow the guide in our [docs – manual setup](https://c15t.com/docs/frameworks/nextjs/quickstart#manual-setup)."
|
|
25
29
|
],
|
|
26
30
|
"usage": [
|
package/src/iab/styles.css
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @c15t/nextjs — IAB TCF component styles.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Add this stylesheet to the same global CSS entrypoint as your base c15t styles
|
|
5
|
+
* when using IAB consent components in Next.js. Do not import either stylesheet
|
|
6
|
+
* from JS/TSX.
|
|
6
7
|
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* import
|
|
8
|
+
* Usage (app/globals.css):
|
|
9
|
+
* @import "@c15t/nextjs/styles.css";
|
|
10
|
+
* @import "@c15t/nextjs/iab/styles.css";
|
|
9
11
|
*/
|
|
10
12
|
@import "@c15t/react/iab/styles.css";
|
package/src/iab/styles.tw3.css
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @c15t/nextjs/iab — Tailwind 3-compatible IAB component styles.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Add this stylesheet to the same global CSS entrypoint as your base c15t styles.
|
|
5
|
+
* Do not import either stylesheet from JS/TSX files.
|
|
6
6
|
*
|
|
7
|
-
* Usage:
|
|
8
|
-
*
|
|
7
|
+
* Usage (app/globals.css):
|
|
8
|
+
* @tailwind base;
|
|
9
|
+
* @tailwind components;
|
|
10
|
+
* @import "@c15t/nextjs/styles.tw3.css";
|
|
11
|
+
* @import "@c15t/nextjs/iab/styles.tw3.css";
|
|
12
|
+
* @tailwind utilities;
|
|
9
13
|
*/
|
|
10
14
|
@import "@c15t/react/iab/styles.tw3.css";
|
package/src/styles.css
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @c15t/nextjs — Non-IAB prebuilt component styles.
|
|
3
3
|
*
|
|
4
|
-
* Import this stylesheet once
|
|
4
|
+
* Import this stylesheet once from your app-level CSS entrypoint when using
|
|
5
5
|
* prebuilt (styled) consent components.
|
|
6
6
|
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* import
|
|
7
|
+
* Usage (app/globals.css):
|
|
8
|
+
* @import "@c15t/nextjs/styles.css";
|
|
9
9
|
*/
|
|
10
10
|
@import "@c15t/react/styles.css";
|
package/src/styles.tw3.css
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @c15t/nextjs — Tailwind 3-compatible prebuilt component styles.
|
|
3
3
|
*
|
|
4
|
-
* Import this stylesheet
|
|
5
|
-
*
|
|
4
|
+
* Import this stylesheet in the same global CSS entrypoint as Tailwind 3,
|
|
5
|
+
* after `@tailwind components;` and before `@tailwind utilities;`.
|
|
6
6
|
*
|
|
7
|
-
* Usage:
|
|
8
|
-
*
|
|
7
|
+
* Usage (app/globals.css):
|
|
8
|
+
* @tailwind base;
|
|
9
|
+
* @tailwind components;
|
|
10
|
+
* @import "@c15t/nextjs/styles.tw3.css";
|
|
11
|
+
* @tailwind utilities;
|
|
9
12
|
*/
|
|
10
13
|
@import "@c15t/react/styles.tw3.css";
|
package/styles.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "./dist/styles.css";
|