@c15t/react 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 +9 -0
- package/dist/components/consent-banner/consent-banner.cjs +1 -1
- package/dist/components/consent-banner/consent-banner.js +1 -1
- package/dist/components/consent-banner/index.cjs +1 -1
- package/dist/components/consent-banner/index.js +1 -1
- package/dist/components/consent-banner/policy-actions.cjs +1 -0
- package/dist/components/consent-banner/policy-actions.js +1 -0
- package/dist/components/consent-dialog/atoms/card.cjs +1 -1
- package/dist/components/consent-dialog/atoms/card.js +1 -1
- package/dist/components/consent-dialog-trigger/atoms/icon.cjs +1 -1
- package/dist/components/consent-dialog-trigger/atoms/icon.js +1 -1
- package/dist/components/consent-widget/atoms/footer.cjs +1 -1
- package/dist/components/consent-widget/atoms/footer.js +1 -1
- package/dist/components/consent-widget/consent-widget.cjs +1 -1
- package/dist/components/consent-widget/consent-widget.js +1 -1
- package/dist/components/consent-widget/index.cjs +1 -1
- package/dist/components/consent-widget/index.js +1 -1
- package/dist/components/consent-widget/policy-actions.cjs +1 -0
- package/dist/components/consent-widget/policy-actions.js +1 -0
- package/dist/components/iab-consent-banner/iab-consent-banner.cjs +1 -1
- package/dist/components/iab-consent-banner/iab-consent-banner.js +1 -1
- package/dist/components/iab-consent-dialog/iab-consent-dialog.cjs +1 -1
- package/dist/components/iab-consent-dialog/iab-consent-dialog.js +1 -1
- package/dist/components/shared/policy-actions.cjs +1 -0
- package/dist/components/shared/policy-actions.js +1 -0
- package/dist/components/shared/ui/branding.cjs +1 -0
- package/dist/components/shared/ui/branding.js +1 -0
- package/dist/components/shared/ui/logo.cjs +1 -1
- package/dist/components/shared/ui/logo.js +1 -1
- package/dist/components/shared/ui/switch/index.cjs +1 -1
- package/dist/components/shared/ui/switch/index.js +1 -1
- package/dist/hooks/index.cjs +1 -1
- package/dist/hooks/use-consent-manager.cjs +1 -1
- package/dist/hooks/use-consent-manager.js +1 -1
- package/dist/hooks/use-headless-consent-ui.cjs +1 -1
- package/dist/hooks/use-headless-consent-ui.js +1 -1
- package/dist/iab/styles.css +11 -1
- package/dist/iab/styles.tw3.css +14 -1
- package/dist/providers/consent-manager-provider.cjs +1 -1
- package/dist/providers/consent-manager-provider.js +1 -1
- package/dist/server/fetch-ssr-data.cjs +1 -1
- package/dist/server/fetch-ssr-data.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/components/consent-banner/atoms/root.d.ts +1 -1
- package/dist-types/components/consent-banner/consent-banner.d.ts +7 -2
- package/dist-types/components/consent-banner/index.d.ts +3 -0
- package/dist-types/components/consent-banner/policy-actions.d.ts +11 -0
- package/dist-types/components/consent-dialog/atoms/card.d.ts +7 -2
- package/dist-types/components/consent-dialog/atoms/root.d.ts +1 -1
- package/dist-types/components/consent-dialog/consent-dialog.d.ts +1 -1
- package/dist-types/components/consent-dialog-trigger/atoms/icon.d.ts +1 -1
- package/dist-types/components/consent-dialog-trigger/types.d.ts +1 -1
- package/dist-types/components/consent-widget/index.d.ts +3 -0
- package/dist-types/components/consent-widget/policy-actions.d.ts +11 -0
- package/dist-types/components/frame/atoms.d.ts +1 -1
- package/dist-types/components/frame/types.d.ts +1 -1
- package/dist-types/components/iab-consent-banner/atoms/root.d.ts +1 -1
- package/dist-types/components/iab-consent-banner/iab-consent-banner.d.ts +1 -1
- package/dist-types/components/iab-consent-dialog/atoms/root.d.ts +1 -1
- package/dist-types/components/iab-consent-dialog/atoms/vendor-list.d.ts +1 -1
- package/dist-types/components/iab-consent-dialog/iab-consent-dialog.d.ts +1 -1
- package/dist-types/components/shared/policy-actions.d.ts +29 -0
- package/dist-types/components/shared/primitives/button.d.ts +1 -1
- package/dist-types/components/shared/primitives/button.types.d.ts +1 -1
- package/dist-types/components/shared/primitives/legal-links/index.d.ts +1 -1
- package/dist-types/components/shared/ui/accordion/accordion.d.ts +2 -2
- package/dist-types/components/shared/ui/accordion/accordion.types.d.ts +1 -1
- package/dist-types/components/shared/ui/branding.d.ts +23 -0
- package/dist-types/components/shared/ui/button/button.d.ts +1 -1
- package/dist-types/components/shared/ui/logo.d.ts +8 -0
- package/dist-types/components/shared/ui/preference-item/preference-item.d.ts +1 -1
- package/dist-types/components/shared/ui/switch/index.d.ts +1 -1
- package/dist-types/components/shared/ui/switch/switch.d.ts +1 -1
- package/dist-types/components/shared/ui/switch/switch.types.d.ts +1 -1
- package/dist-types/components/shared/ui/tabs/tabs.d.ts +1 -1
- package/dist-types/context/consent-manager-context.d.ts +1 -1
- package/dist-types/headless.d.ts +1 -1
- package/dist-types/hooks/use-component-config.d.ts +1 -1
- package/dist-types/hooks/use-consent-manager.d.ts +1 -1
- package/dist-types/hooks/use-headless-consent-ui.d.ts +1 -1
- package/dist-types/hooks/use-ssr-status.d.ts +2 -1
- package/dist-types/hooks/use-translations.d.ts +1 -1
- package/dist-types/index.d.ts +2 -2
- package/dist-types/server/fetch-ssr-data.d.ts +1 -1
- package/dist-types/server/init-cache-key.d.ts +1 -1
- package/dist-types/server/types.d.ts +1 -1
- package/dist-types/types/consent-manager.d.ts +1 -1
- package/dist-types/types/theme/style-keys.d.ts +1 -1
- package/dist-types/types/theme/style-types.d.ts +2 -2
- package/dist-types/utils/cn.d.ts +1 -1
- package/dist-types/utils/theme-utils.d.ts +1 -1
- 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 +2 -6
- package/docs/policy-packs.md +7 -7
- package/docs/quickstart.md +11 -5
- package/docs/script-loader.md +22 -1
- package/docs/styling/tailwind.md +23 -17
- package/iab/styles.css +1 -0
- package/package.json +13 -11
- package/readme.json +6 -0
- package/src/iab/styles.css +11 -0
- package/src/iab/styles.tw3.css +8 -4
- package/src/styles.css +10 -0
- package/src/styles.tw3.css +7 -4
- package/styles.css +1 -0
- package/dist/components/shared/libs/policy-actions.cjs +0 -1
- package/dist/components/shared/libs/policy-actions.js +0 -1
- package/dist-types/components/shared/libs/policy-actions.d.ts +0 -26
|
@@ -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
|
@@ -50,7 +50,7 @@ const prefetchScript = buildPrefetchScript({
|
|
|
50
50
|
</head>
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
Then
|
|
53
|
+
Then initialize your provider normally. Matching prefetched data is consumed automatically by the runtime during first store initialization:
|
|
54
54
|
|
|
55
55
|
```tsx
|
|
56
56
|
import {
|
|
@@ -58,7 +58,6 @@ import {
|
|
|
58
58
|
ConsentBanner,
|
|
59
59
|
ConsentDialog,
|
|
60
60
|
} from '@c15t/react';
|
|
61
|
-
import { getPrefetchedInitialData } from 'c15t';
|
|
62
61
|
|
|
63
62
|
export default function App({ children }: { children: React.ReactNode }) {
|
|
64
63
|
return (
|
|
@@ -66,9 +65,6 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|
|
66
65
|
options={{
|
|
67
66
|
mode: 'hosted',
|
|
68
67
|
backendURL: '/api/c15t',
|
|
69
|
-
ssrData: getPrefetchedInitialData({
|
|
70
|
-
backendURL: '/api/c15t',
|
|
71
|
-
}),
|
|
72
68
|
}}
|
|
73
69
|
>
|
|
74
70
|
<ConsentBanner />
|
|
@@ -80,7 +76,7 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|
|
80
76
|
```
|
|
81
77
|
|
|
82
78
|
> ℹ️ **Info:**
|
|
83
|
-
> If
|
|
79
|
+
> 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.
|
|
84
80
|
|
|
85
81
|
## Keep The Provider Mounted Across Navigation
|
|
86
82
|
|
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';
|
|
@@ -105,7 +105,7 @@ export function ConsentManager({ children }: { children: ReactNode }) {
|
|
|
105
105
|
|
|
106
106
|
## Offline / Fallback
|
|
107
107
|
|
|
108
|
-
For local development,
|
|
108
|
+
For local development, previews, automated tests, or when the backend is temporarily unreachable, pass policies directly:
|
|
109
109
|
|
|
110
110
|
```tsx
|
|
111
111
|
import type { ReactNode } from 'react';
|
|
@@ -144,7 +144,7 @@ export function ConsentManager({ children }: { children: ReactNode }) {
|
|
|
144
144
|
## Provider Shape
|
|
145
145
|
|
|
146
146
|
Configure packs through `offlinePolicy.policyPacks`. Add `offlinePolicy.i18n`
|
|
147
|
-
when you want
|
|
147
|
+
when you want local previews or fallback behavior to mirror hosted policy-profile language behavior:
|
|
148
148
|
|
|
149
149
|
```tsx
|
|
150
150
|
<ConsentManagerProvider
|
|
@@ -203,7 +203,7 @@ With that setup, offline mode resolves language the same way as hosted mode:
|
|
|
203
203
|
|`offlinePolicy: { policyPacks: [] }`|Explicit no-banner mode|
|
|
204
204
|
|Non-empty pack, no match, no default|Explicit no-banner mode|
|
|
205
205
|
|
|
206
|
-
Omitting the option gives you a safe opt-in default for local development and outage scenarios. Providing it tells c15t you want
|
|
206
|
+
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.
|
|
207
207
|
|
|
208
208
|
## QA and Debugging
|
|
209
209
|
|
|
@@ -215,7 +215,7 @@ For deeper inspection:
|
|
|
215
215
|
* Open the DevTools Policy panel to inspect matcher resolution and fingerprints
|
|
216
216
|
* Compare your frontend preview with the backend `/init` response before shipping
|
|
217
217
|
|
|
218
|
-
If you need fully deterministic resolution without a backend (
|
|
218
|
+
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`:
|
|
219
219
|
|
|
220
220
|
```tsx
|
|
221
221
|
options={{
|
package/docs/quickstart.md
CHANGED
|
@@ -33,15 +33,17 @@ availableIn:
|
|
|
33
33
|
|yarn|`yarn add @c15t/react`|
|
|
34
34
|
|bun|`bun add @c15t/react`|
|
|
35
35
|
|
|
36
|
-
2. **Import styles** Import the prebuilt component stylesheet
|
|
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/react/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. src/main.tsx should keep importing ./index.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
|
|
|
@@ -81,7 +83,11 @@ availableIn:
|
|
|
81
83
|
|
|
82
84
|
> ℹ️ Info:
|
|
83
85
|
>
|
|
84
|
-
>
|
|
86
|
+
> 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.
|
|
87
|
+
>
|
|
88
|
+
> ℹ️ Info:
|
|
89
|
+
>
|
|
90
|
+
> 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.
|
|
85
91
|
|
|
86
92
|
4. **Mount ConsentManager at the app root** Wrap your existing app tree with ConsentManager so all routes/components can access consent state.
|
|
87
93
|
|
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/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/react",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.8",
|
|
4
4
|
"description": "Developer-first CMP for React: cookie banner, consent manager, preferences centre. GDPR ready with minimal setup and rich customization",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
"type": "module",
|
|
33
33
|
"exports": {
|
|
34
34
|
"./styles.css": "./dist/styles.css",
|
|
35
|
-
"./styles.tw3.css": "./
|
|
35
|
+
"./styles.tw3.css": "./dist/styles.tw3.css",
|
|
36
36
|
"./iab/styles.css": "./dist/iab/styles.css",
|
|
37
|
-
"./iab/styles.tw3.css": "./
|
|
37
|
+
"./iab/styles.tw3.css": "./dist/iab/styles.tw3.css",
|
|
38
38
|
"./primitives": {
|
|
39
|
-
"types": "./dist/primitives.d.ts",
|
|
39
|
+
"types": "./dist-types/primitives.d.ts",
|
|
40
40
|
"import": "./dist/primitives.js",
|
|
41
41
|
"require": "./dist/primitives.cjs"
|
|
42
42
|
},
|
|
43
43
|
"./primitives/*": {
|
|
44
|
-
"types": "./dist/primitives/*.d.ts",
|
|
44
|
+
"types": "./dist-types/primitives/*.d.ts",
|
|
45
45
|
"import": "./dist/primitives/*.js",
|
|
46
46
|
"require": "./dist/primitives/*.cjs"
|
|
47
47
|
},
|
|
@@ -139,17 +139,19 @@
|
|
|
139
139
|
"docs",
|
|
140
140
|
"dist-types",
|
|
141
141
|
"client",
|
|
142
|
+
"styles.css",
|
|
143
|
+
"iab",
|
|
142
144
|
"src/styles.tw3.css",
|
|
143
145
|
"src/iab/styles.tw3.css",
|
|
144
146
|
"!dist/mockServiceWorker.js"
|
|
145
147
|
],
|
|
146
148
|
"scripts": {
|
|
147
149
|
"prebuild": "genversion --esm --semi src/version.ts",
|
|
148
|
-
"build": "bun prebuild && rslib build && bun run clean:dist:test-artifacts && bun ../../scripts/agent-docs/generate-package-docs.ts @c15t/react",
|
|
150
|
+
"build": "bun prebuild && rslib build && bun ../../scripts/normalize-dist-types.mjs && bun scripts/generate-distribution-css.ts && bun run clean:dist:test-artifacts && bun ../../scripts/agent-docs/generate-package-docs.ts @c15t/react",
|
|
149
151
|
"build:agent-docs": "bun ../../scripts/agent-docs/generate-package-docs.ts @c15t/react",
|
|
150
152
|
"check-types": "bun prebuild && tsc --noEmit",
|
|
151
153
|
"clean:dist:test-artifacts": "bun --eval \"import { rmSync } from 'node:fs'; rmSync('dist/mockServiceWorker.js', { force: true });\"",
|
|
152
|
-
"dev": "bun prebuild && rslib build",
|
|
154
|
+
"dev": "bun prebuild && rslib build && bun ../../scripts/normalize-dist-types.mjs && bun scripts/generate-distribution-css.ts",
|
|
153
155
|
"fmt": "bun biome format --write . && bun biome check --formatter-enabled=false --linter-enabled=false --write",
|
|
154
156
|
"lint": "bun biome lint ./src",
|
|
155
157
|
"prepack": "cd ../.. && bunx turbo run build --filter=@c15t/react",
|
|
@@ -162,13 +164,13 @@
|
|
|
162
164
|
"not op_mini all"
|
|
163
165
|
],
|
|
164
166
|
"dependencies": {
|
|
165
|
-
"@c15t/ui": "2.0.0-rc.
|
|
166
|
-
"c15t": "2.0.0-rc.
|
|
167
|
+
"@c15t/ui": "2.0.0-rc.8",
|
|
168
|
+
"c15t": "2.0.0-rc.8",
|
|
167
169
|
"clsx": "2.1.1"
|
|
168
170
|
},
|
|
169
171
|
"devDependencies": {
|
|
170
|
-
"@c15t/backend": "2.0.0-rc.
|
|
171
|
-
"@c15t/iab": "2.0.0-rc.
|
|
172
|
+
"@c15t/backend": "2.0.0-rc.8",
|
|
173
|
+
"@c15t/iab": "2.0.0-rc.8",
|
|
172
174
|
"@c15t/typescript-config": "0.0.1-beta.1",
|
|
173
175
|
"@c15t/vitest-config": "1.0.0",
|
|
174
176
|
"@iabtechlabtcf/core": "^1.5.20",
|
package/readme.json
CHANGED
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
"",
|
|
22
22
|
"```bash\npnpm add @c15t/react\n```",
|
|
23
23
|
"",
|
|
24
|
+
"Then add the prebuilt stylesheet to your app-level CSS entrypoint:",
|
|
25
|
+
"",
|
|
26
|
+
"```css\n/* src/index.css */\n@import \"@c15t/react/styles.css\";\n```",
|
|
27
|
+
"",
|
|
28
|
+
"If you use the prebuilt IAB TCF UI, also import `@c15t/react/iab/styles.css`. It is published separately so non-IAB apps do not ship those component rules.",
|
|
29
|
+
"",
|
|
24
30
|
"To manually install, follow the guide in our [docs – manual setup](https://c15t.com/docs/frameworks/react/quickstart#manual-setup)."
|
|
25
31
|
],
|
|
26
32
|
"usage": [
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @c15t/react — IAB TCF component styles.
|
|
3
|
+
*
|
|
4
|
+
* Add this stylesheet to the same global CSS entrypoint as your base c15t styles
|
|
5
|
+
* when using IAB consent components. Do not import either stylesheet from JS/TSX.
|
|
6
|
+
*
|
|
7
|
+
* Usage (src/index.css):
|
|
8
|
+
* @import "@c15t/react/styles.css";
|
|
9
|
+
* @import "@c15t/react/iab/styles.css";
|
|
10
|
+
*/
|
|
11
|
+
@import "@c15t/ui/iab/styles.css";
|
package/src/iab/styles.tw3.css
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @c15t/react/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 (src/index.css):
|
|
8
|
+
* @tailwind base;
|
|
9
|
+
* @tailwind components;
|
|
10
|
+
* @import "@c15t/react/styles.tw3.css";
|
|
11
|
+
* @import "@c15t/react/iab/styles.tw3.css";
|
|
12
|
+
* @tailwind utilities;
|
|
9
13
|
*/
|
|
10
14
|
@import "@c15t/ui/iab/styles.tw3.css";
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @c15t/react — Non-IAB prebuilt component styles.
|
|
3
|
+
*
|
|
4
|
+
* Import this stylesheet once from your app-level CSS entrypoint
|
|
5
|
+
* when using prebuilt (styled) consent components.
|
|
6
|
+
*
|
|
7
|
+
* Usage (src/index.css):
|
|
8
|
+
* @import "@c15t/react/styles.css";
|
|
9
|
+
*/
|
|
10
|
+
@import "@c15t/ui/styles.css";
|
package/src/styles.tw3.css
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @c15t/react — 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 (src/index.css):
|
|
8
|
+
* @tailwind base;
|
|
9
|
+
* @tailwind components;
|
|
10
|
+
* @import "@c15t/react/styles.tw3.css";
|
|
11
|
+
* @tailwind utilities;
|
|
9
12
|
*/
|
|
10
13
|
@import "@c15t/ui/styles.tw3.css";
|
package/styles.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "./dist/styles.css";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";const __rslib_import_meta_url__="u"<typeof document?new(require("url".replace("",""))).URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href;var __webpack_require__={};__webpack_require__.d=(e,o)=>{for(var r in o)__webpack_require__.o(o,r)&&!__webpack_require__.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:o[r]})},__webpack_require__.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),__webpack_require__.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__={};__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{flattenPolicyActionGroups:()=>flattenPolicyActionGroups,hasPolicyHints:()=>hasPolicyHints,resolvePolicyActionGroups:()=>resolvePolicyActionGroups,resolvePolicyAllowedActions:()=>resolvePolicyAllowedActions,resolvePolicyDirection:()=>resolvePolicyDirection,resolvePolicyOrderedActions:()=>resolvePolicyOrderedActions,resolvePolicyPrimaryActions:()=>resolvePolicyPrimaryActions,resolvePolicyUiProfile:()=>resolvePolicyUiProfile,shouldFillPolicyActions:()=>shouldFillPolicyActions});const DEFAULT_POLICY_ACTIONS=["reject","accept","customize"];function dedupeActions(e){return e&&0!==e.length?[...new Set(e)]:[]}function resolvePolicyAllowedActions(e){let o=dedupeActions(e.allowedActions);return o.length>0?o:[...DEFAULT_POLICY_ACTIONS]}function flattenPolicyActionGroups(e){return e&&0!==e.length?e.flatMap(e=>Array.isArray(e)?e:[e]):[]}function resolvePolicyActionGroups(e){let o=dedupeActions(e.allowedActions);if(0===o.length)return[];if(!e.layout||0===e.layout.length)return[[...o]];let r=new Set(o),i=[],t=new Set;for(let o of e.layout){let e=dedupeActions(Array.isArray(o)?o:[o]).filter(e=>!(!r.has(e)||t.has(e))&&(t.add(e),!0));e.length>0&&i.push(e)}return i.length>0?i:[[...o]]}function resolvePolicyOrderedActions(e){return flattenPolicyActionGroups(resolvePolicyActionGroups({allowedActions:e.allowedActions,layout:e.layout}))}function resolvePolicyPrimaryActions(e){let o=e.orderedActions.includes("customize")?["customize"]:[];if(!e.primaryActions||0===e.primaryActions.length)return o;let r=e.primaryActions.filter(o=>e.orderedActions.includes(o));return r.length>0?r:o}function resolvePolicyDirection(e){return"column"===e?"column":"row"}function resolvePolicyUiProfile(e){return"balanced"===e||"compact"===e||"strict"===e?e:"compact"}function shouldFillPolicyActions(e){let o=resolvePolicyUiProfile(e.uiProfile),r=new Set(e.actionGroups.flat()).size,i=e.actionGroups.length>1,t="column"===e.direction;return"strict"===o||"balanced"===o&&(r<=2||3===r&&(i||t))}function hasPolicyHints(e){return!!e&&Object.values(e).some(e=>Array.isArray(e)?e.length>0:void 0!==e)}for(var __rspack_i in exports.flattenPolicyActionGroups=__webpack_exports__.flattenPolicyActionGroups,exports.hasPolicyHints=__webpack_exports__.hasPolicyHints,exports.resolvePolicyActionGroups=__webpack_exports__.resolvePolicyActionGroups,exports.resolvePolicyAllowedActions=__webpack_exports__.resolvePolicyAllowedActions,exports.resolvePolicyDirection=__webpack_exports__.resolvePolicyDirection,exports.resolvePolicyOrderedActions=__webpack_exports__.resolvePolicyOrderedActions,exports.resolvePolicyPrimaryActions=__webpack_exports__.resolvePolicyPrimaryActions,exports.resolvePolicyUiProfile=__webpack_exports__.resolvePolicyUiProfile,exports.shouldFillPolicyActions=__webpack_exports__.shouldFillPolicyActions,__webpack_exports__)-1===["flattenPolicyActionGroups","hasPolicyHints","resolvePolicyActionGroups","resolvePolicyAllowedActions","resolvePolicyDirection","resolvePolicyOrderedActions","resolvePolicyPrimaryActions","resolvePolicyUiProfile","shouldFillPolicyActions"].indexOf(__rspack_i)&&(exports[__rspack_i]=__webpack_exports__[__rspack_i]);Object.defineProperty(exports,"__esModule",{value:!0});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
let t=["reject","accept","customize"];function e(t){return t&&0!==t.length?[...new Set(t)]:[]}function o(o){let n=e(o.allowedActions);return n.length>0?n:[...t]}function n(t){return t&&0!==t.length?t.flatMap(t=>Array.isArray(t)?t:[t]):[]}function r(t){let o=e(t.allowedActions);if(0===o.length)return[];if(!t.layout||0===t.layout.length)return[[...o]];let n=new Set(o),r=[],l=new Set;for(let o of t.layout){let t=e(Array.isArray(o)?o:[o]).filter(t=>!(!n.has(t)||l.has(t))&&(l.add(t),!0));t.length>0&&r.push(t)}return r.length>0?r:[[...o]]}function l(t){return n(r({allowedActions:t.allowedActions,layout:t.layout}))}function i(t){let e=t.orderedActions.includes("customize")?["customize"]:[];if(!t.primaryActions||0===t.primaryActions.length)return e;let o=t.primaryActions.filter(e=>t.orderedActions.includes(e));return o.length>0?o:e}function c(t){return"column"===t?"column":"row"}function u(t){return"balanced"===t||"compact"===t||"strict"===t?t:"compact"}function s(t){let e=u(t.uiProfile),o=new Set(t.actionGroups.flat()).size,n=t.actionGroups.length>1,r="column"===t.direction;return"strict"===e||"balanced"===e&&(o<=2||3===o&&(n||r))}function a(t){return!!t&&Object.values(t).some(t=>Array.isArray(t)?t.length>0:void 0!==t)}export{n as flattenPolicyActionGroups,a as hasPolicyHints,r as resolvePolicyActionGroups,o as resolvePolicyAllowedActions,c as resolvePolicyDirection,l as resolvePolicyOrderedActions,i as resolvePolicyPrimaryActions,u as resolvePolicyUiProfile,s as shouldFillPolicyActions};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { PolicyUiAction, PolicyUiActionDirection, PolicyUiActionGroup, PolicyUiProfile, PolicyUiSurfaceConfig } from '../../../../../core/dist-types/index.d.ts';
|
|
2
|
-
export type { PolicyUiAction, PolicyUiActionDirection, PolicyUiActionGroup, PolicyUiProfile, PolicyUiSurfaceConfig, };
|
|
3
|
-
export declare function resolvePolicyAllowedActions(params: {
|
|
4
|
-
allowedActions?: PolicyUiAction[];
|
|
5
|
-
}): PolicyUiAction[];
|
|
6
|
-
export declare function flattenPolicyActionGroups(layout?: PolicyUiActionGroup[]): PolicyUiAction[];
|
|
7
|
-
export declare function resolvePolicyActionGroups(params: {
|
|
8
|
-
allowedActions: PolicyUiAction[];
|
|
9
|
-
layout?: PolicyUiActionGroup[];
|
|
10
|
-
}): PolicyUiAction[][];
|
|
11
|
-
export declare function resolvePolicyOrderedActions(params: {
|
|
12
|
-
allowedActions: PolicyUiAction[];
|
|
13
|
-
layout?: PolicyUiActionGroup[];
|
|
14
|
-
}): PolicyUiAction[];
|
|
15
|
-
export declare function resolvePolicyPrimaryActions(params: {
|
|
16
|
-
orderedActions: PolicyUiAction[];
|
|
17
|
-
primaryActions?: PolicyUiAction[];
|
|
18
|
-
}): PolicyUiAction[];
|
|
19
|
-
export declare function resolvePolicyDirection(direction?: PolicyUiActionDirection): PolicyUiActionDirection;
|
|
20
|
-
export declare function resolvePolicyUiProfile(profile?: PolicyUiProfile): PolicyUiProfile;
|
|
21
|
-
export declare function shouldFillPolicyActions(params: {
|
|
22
|
-
uiProfile?: PolicyUiProfile;
|
|
23
|
-
actionGroups: PolicyUiAction[][];
|
|
24
|
-
direction?: PolicyUiActionDirection;
|
|
25
|
-
}): boolean;
|
|
26
|
-
export declare function hasPolicyHints(surface?: PolicyUiSurfaceConfig): boolean;
|