@c15t/react 3.0.0-alpha.1 → 3.0.0-alpha.3
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 +9 -2
- package/dist/aggregate-components.js +1 -1
- package/dist/chunk-warming.js +1 -1
- package/dist/component-hooks/use-headless-iab-consent-ui.js +1 -1
- package/dist/component-hooks/use-panel-trigger.js +1 -1
- package/dist/components/consent-gate/atoms.js +1 -0
- package/dist/components/consent-gate/consent-gate.js +2 -0
- package/dist/components/consent-gate/index.js +2 -0
- package/dist/components/consent-preferences-link/consent-preferences-link.js +1 -1
- package/dist/components/iab-panel/atoms/purpose-item.js +1 -1
- package/dist/components/iab-panel/atoms/stack-item.js +1 -1
- package/dist/components/iab-panel/iab-panel.js +1 -1
- package/dist/components/iab-panel/index.js +1 -1
- package/dist/components/panel/atoms/overlay.js +1 -1
- package/dist/components/panel/atoms/root.js +1 -1
- package/dist/components/panel/index.js +1 -1
- package/dist/components/panel/panel.js +1 -1
- package/dist/components/panel-trigger/atoms/button.js +1 -1
- package/dist/components/panel-trigger/atoms/icon.js +1 -1
- package/dist/components/panel-trigger/atoms/root.js +1 -1
- package/dist/components/panel-trigger/atoms/trigger-icons.js +1 -0
- package/dist/components/panel-trigger/panel-trigger-toolbar.js +1 -1
- package/dist/components/preferences/atoms/accordion.js +1 -1
- package/dist/components/preferences/atoms/root.js +1 -1
- package/dist/components/preferences/atoms/vendor-list.js +1 -0
- package/dist/components/preferences/index.js +1 -1
- package/dist/components/prompt/policy-actions.js +1 -1
- package/dist/components/shared/primitives/button.js +1 -1
- package/dist/components/shared/ui/accordion/accordion.js +1 -1
- package/dist/components/shared/ui/collapsible/collapsible.js +1 -1
- package/dist/components/shared/ui/logo.js +1 -1
- package/dist/components/shared/ui/preference-item/preference-item.js +1 -1
- package/dist/components/shared/ui/switch/switch.js +1 -1
- package/dist/components/shared/ui/tabs/tabs.js +1 -1
- package/dist/consent-gate.js +2 -0
- package/dist/consent-theme.js +1 -0
- package/dist/draft.js +1 -1
- package/dist/external-iab-context.js +1 -1
- package/dist/headless.js +1 -1
- package/dist/hooks/use-committed-ref.js +2 -0
- package/dist/hooks.js +1 -1
- package/dist/iab/styles.tw3.css +1 -41
- package/dist/iab-context.js +1 -1
- package/dist/index.js +1 -1
- package/dist/kernel-selector.js +1 -0
- package/dist/module-hooks/iframe-blocker.js +1 -1
- package/dist/module-hooks/network-blocker.js +1 -1
- package/dist/module-hooks/network-hold.js +2 -0
- package/dist/module-hooks/persistence.js +1 -1
- package/dist/panel.js +1 -1
- package/dist/preferences.js +1 -2
- package/dist/provider.js +1 -1
- package/dist/styles.tw3.css +1 -43
- package/dist/ui-save.js +1 -1
- package/dist/utils/deferred-module.js +2 -0
- package/dist/version.js +1 -1
- package/dist-types/aggregate-components.d.ts +2 -2
- package/dist-types/chunk-warming.d.ts +41 -8
- package/dist-types/component-hooks/use-headless-iab-consent-ui.d.ts +2 -2
- package/dist-types/components/consent-gate/atoms.d.ts +11 -0
- package/dist-types/components/consent-gate/consent-gate.d.ts +2 -0
- package/dist-types/components/consent-gate/index.d.ts +41 -0
- package/dist-types/components/{frame → consent-gate}/types.d.ts +7 -7
- package/dist-types/components/consent-preferences-link/consent-preferences-link.d.ts +1 -1
- package/dist-types/components/consent-preferences-link/index.d.ts +1 -1
- package/dist-types/components/iab-panel/atoms/purpose-item.d.ts +5 -2
- package/dist-types/components/iab-panel/atoms/stack-item.d.ts +7 -2
- package/dist-types/components/iab-panel/atoms/vendor-list.d.ts +1 -1
- package/dist-types/components/iab-panel/iab-panel.d.ts +1 -1
- package/dist-types/components/iab-panel/index.d.ts +25 -24
- package/dist-types/components/iab-prompt/index.d.ts +17 -17
- package/dist-types/components/panel/atoms/card.d.ts +4 -4
- package/dist-types/components/panel/atoms/overlay.d.ts +1 -1
- package/dist-types/components/panel/index.d.ts +8 -7
- package/dist-types/components/panel/panel.d.ts +3 -3
- package/dist-types/components/panel-link/index.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/button.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/icon.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/root.d.ts +2 -2
- package/dist-types/components/panel-trigger/atoms/toolbar.d.ts +2 -2
- package/dist-types/components/panel-trigger/atoms/trigger-icons.d.ts +20 -0
- package/dist-types/components/panel-trigger/index.d.ts +4 -4
- package/dist-types/components/panel-trigger/panel-trigger-toolbar.d.ts +1 -1
- package/dist-types/components/panel-trigger/panel-trigger.d.ts +9 -9
- package/dist-types/components/panel-trigger/types.d.ts +1 -1
- package/dist-types/components/preferences/atoms/accordion.d.ts +6 -4
- package/dist-types/components/preferences/atoms/button.d.ts +1 -1
- package/dist-types/components/preferences/atoms/footer.d.ts +1 -1
- package/dist-types/components/preferences/atoms/root.d.ts +1 -1
- package/dist-types/components/preferences/atoms/vendor-list.d.ts +23 -0
- package/dist-types/components/preferences/index.d.ts +14 -11
- package/dist-types/components/preferences/policy-actions.d.ts +2 -2
- package/dist-types/components/preferences/preferences.d.ts +1 -1
- package/dist-types/components/preferences/types.d.ts +1 -1
- package/dist-types/components/prompt/components.d.ts +3 -3
- package/dist-types/components/prompt/index.d.ts +11 -11
- package/dist-types/components/prompt/policy-actions.d.ts +2 -2
- package/dist-types/components/prompt/prompt.d.ts +1 -1
- package/dist-types/components/shared/policy-actions.d.ts +2 -2
- package/dist-types/components/shared/primitives/box.d.ts +1 -1
- package/dist-types/components/shared/primitives/button.d.ts +2 -2
- package/dist-types/components/shared/primitives/button.types.d.ts +1 -1
- package/dist-types/components/shared/ui/accordion/accordion.d.ts +3 -2
- package/dist-types/components/shared/ui/accordion/index.d.ts +2 -2
- package/dist-types/components/shared/ui/animated-collapse/index.d.ts +2 -2
- package/dist-types/components/shared/ui/branding.d.ts +1 -1
- package/dist-types/components/shared/ui/button/button.d.ts +1 -1
- package/dist-types/components/shared/ui/button/index.d.ts +2 -2
- package/dist-types/components/shared/ui/collapsible/collapsible.d.ts +1 -0
- package/dist-types/components/shared/ui/collapsible/index.d.ts +1 -1
- package/dist-types/components/shared/ui/dialog/index.d.ts +1 -1
- package/dist-types/components/shared/ui/logo.d.ts +0 -10
- package/dist-types/components/shared/ui/preference-item/index.d.ts +1 -1
- package/dist-types/components/shared/ui/preference-item/preference-item.d.ts +14 -0
- package/dist-types/components/shared/ui/switch/index.d.ts +2 -2
- package/dist-types/components/shared/ui/switch/switch.d.ts +2 -1
- package/dist-types/components/shared/ui/tabs/index.d.ts +1 -1
- package/dist-types/components/shared/ui/tabs/tabs.d.ts +1 -0
- package/dist-types/consent-gate.d.ts +1 -0
- package/dist-types/consent-theme.d.ts +38 -0
- package/dist-types/context/index.d.ts +3 -3
- package/dist-types/context/theme-context.d.ts +1 -1
- package/dist-types/draft.d.ts +96 -7
- package/dist-types/headless.d.ts +6 -7
- package/dist-types/hooks/use-committed-ref.d.ts +24 -0
- package/dist-types/hooks/use-headless-iab-consent-ui.d.ts +1 -1
- package/dist-types/hooks/use-iab-manager.d.ts +1 -1
- package/dist-types/hooks/use-theme.d.ts +1 -1
- package/dist-types/hooks.d.ts +30 -1
- package/dist-types/iab.d.ts +5 -5
- package/dist-types/index.d.ts +26 -25
- package/dist-types/kernel-selector.d.ts +66 -0
- package/dist-types/module-hooks/iframe-blocker.d.ts +27 -0
- package/dist-types/module-hooks/network-blocker.d.ts +23 -0
- package/dist-types/module-hooks/network-hold.d.ts +47 -0
- package/dist-types/module-hooks.d.ts +4 -4
- package/dist-types/panel-link.d.ts +1 -1
- package/dist-types/panel-trigger.d.ts +1 -1
- package/dist-types/panel.d.ts +13 -1
- package/dist-types/preferences.d.ts +12 -1
- package/dist-types/primitives/accordion.d.ts +1 -1
- package/dist-types/primitives/button.d.ts +1 -1
- package/dist-types/primitives/collapsible.d.ts +1 -1
- package/dist-types/primitives/dialog.d.ts +1 -1
- package/dist-types/primitives/preference-item.d.ts +1 -1
- package/dist-types/primitives/switch.d.ts +1 -1
- package/dist-types/primitives/tabs.d.ts +1 -1
- package/dist-types/primitives.d.ts +7 -7
- package/dist-types/prompt.d.ts +1 -1
- package/dist-types/provider.d.ts +62 -12
- package/dist-types/server/fetch-ssr-data.d.ts +1 -1
- package/dist-types/server/index.d.ts +5 -5
- package/dist-types/theme-provider.d.ts +2 -2
- package/dist-types/types/index.d.ts +3 -3
- package/dist-types/types/manager.d.ts +1 -1
- package/dist-types/types/theme/index.d.ts +1 -1
- package/dist-types/ui-config-context.d.ts +3 -1
- package/dist-types/ui-save.d.ts +21 -1
- package/dist-types/utils/deferred-module.d.ts +13 -0
- package/dist-types/utils/index.d.ts +4 -4
- package/dist-types/utils/merge-slot-props.d.ts +2 -2
- package/dist-types/utils/merge-styles.d.ts +1 -1
- package/dist-types/utils/theme-utils.d.ts +1 -1
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +9 -2
- package/docs/customization/overview.md +4 -3
- package/docs/customization/recipes.md +4 -2
- package/docs/customization/tokens.md +66 -3
- package/docs/frameworks/react/components/consent-dialog.md +46 -7
- package/docs/frameworks/react/components/{frame.md → consent-gate.md} +35 -31
- package/docs/frameworks/react/components/consent-manager-provider.md +35 -11
- package/docs/frameworks/react/components/consent-widget.md +48 -6
- package/docs/frameworks/react/concepts/consent-categories.md +38 -2
- package/docs/frameworks/react/hooks/{use-consent-manager/overview.md → overview.md} +7 -5
- package/docs/frameworks/react/iab/overview.md +121 -1
- package/docs/frameworks/react/network-blocker.md +146 -0
- package/docs/frameworks/react/script-loader.md +6 -0
- package/docs/frameworks/react/styling/overview.md +71 -22
- 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/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 +26 -16
- package/dist/component-hooks/use-manager.js +0 -2
- package/dist/components/frame/atoms.js +0 -1
- package/dist/components/frame/frame.js +0 -2
- package/dist/components/frame/index.js +0 -2
- package/dist/frame.js +0 -2
- package/dist-types/component-hooks/use-manager.d.ts +0 -40
- package/dist-types/components/frame/atoms.d.ts +0 -11
- package/dist-types/components/frame/frame.d.ts +0 -2
- package/dist-types/components/frame/index.d.ts +0 -24
- package/dist-types/frame.d.ts +0 -1
- package/readme.json +0 -48
- package/src/iab/styles.css +0 -11
- package/src/styles.css +0 -10
- /package/dist/components/{frame → consent-gate}/types.js +0 -0
|
@@ -33,12 +33,12 @@ Render this component inside your existing consent boundary or provider.
|
|
|
33
33
|
```tsx title="src/consent-embed.tsx"
|
|
34
34
|
'use client';
|
|
35
35
|
|
|
36
|
-
import {
|
|
36
|
+
import { ConsentGate } from 'c15t/next';
|
|
37
37
|
import { embedCategory, embedURL, embedTitle, embedAspectRatio } from './embed-config';
|
|
38
38
|
|
|
39
39
|
export function ConsentEmbed() {
|
|
40
40
|
return (
|
|
41
|
-
<
|
|
41
|
+
<ConsentGate category={embedCategory}>
|
|
42
42
|
<iframe
|
|
43
43
|
src={embedURL}
|
|
44
44
|
title={embedTitle}
|
|
@@ -46,12 +46,12 @@ export function ConsentEmbed() {
|
|
|
46
46
|
allowFullScreen
|
|
47
47
|
style={{ width: '100%', aspectRatio: embedAspectRatio, minHeight: 200, border: 0 }}
|
|
48
48
|
/>
|
|
49
|
-
</
|
|
49
|
+
</ConsentGate>
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
`
|
|
54
|
+
`ConsentGate` keeps the iframe absent while permission is denied and removes it
|
|
55
55
|
on revocation. Keep your existing consent styles and preferences dialog.
|
|
56
56
|
|
|
57
57
|
**TanStack Start**
|
|
@@ -59,12 +59,12 @@ on revocation. Keep your existing consent styles and preferences dialog.
|
|
|
59
59
|
Render this component inside your existing consent boundary or provider.
|
|
60
60
|
|
|
61
61
|
```tsx title="src/consent-embed.tsx"
|
|
62
|
-
import {
|
|
62
|
+
import { ConsentGate } from 'c15t/tanstack-start';
|
|
63
63
|
import { embedCategory, embedURL, embedTitle, embedAspectRatio } from './embed-config';
|
|
64
64
|
|
|
65
65
|
export function ConsentEmbed() {
|
|
66
66
|
return (
|
|
67
|
-
<
|
|
67
|
+
<ConsentGate category={embedCategory}>
|
|
68
68
|
<iframe
|
|
69
69
|
src={embedURL}
|
|
70
70
|
title={embedTitle}
|
|
@@ -72,12 +72,12 @@ export function ConsentEmbed() {
|
|
|
72
72
|
allowFullScreen
|
|
73
73
|
style={{ width: '100%', aspectRatio: embedAspectRatio, minHeight: 200, border: 0 }}
|
|
74
74
|
/>
|
|
75
|
-
</
|
|
75
|
+
</ConsentGate>
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
`
|
|
80
|
+
`ConsentGate` keeps the iframe absent while permission is denied and removes it
|
|
81
81
|
on revocation. Keep your existing consent styles and preferences dialog.
|
|
82
82
|
|
|
83
83
|
**React**
|
|
@@ -85,12 +85,12 @@ on revocation. Keep your existing consent styles and preferences dialog.
|
|
|
85
85
|
Render this component inside your existing consent boundary or provider.
|
|
86
86
|
|
|
87
87
|
```tsx title="src/consent-embed.tsx"
|
|
88
|
-
import {
|
|
88
|
+
import { ConsentGate } from 'c15t/react';
|
|
89
89
|
import { embedCategory, embedURL, embedTitle, embedAspectRatio } from './embed-config';
|
|
90
90
|
|
|
91
91
|
export function ConsentEmbed() {
|
|
92
92
|
return (
|
|
93
|
-
<
|
|
93
|
+
<ConsentGate category={embedCategory}>
|
|
94
94
|
<iframe
|
|
95
95
|
src={embedURL}
|
|
96
96
|
title={embedTitle}
|
|
@@ -98,12 +98,12 @@ export function ConsentEmbed() {
|
|
|
98
98
|
allowFullScreen
|
|
99
99
|
style={{ width: '100%', aspectRatio: embedAspectRatio, minHeight: 200, border: 0 }}
|
|
100
100
|
/>
|
|
101
|
-
</
|
|
101
|
+
</ConsentGate>
|
|
102
102
|
);
|
|
103
103
|
}
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
`
|
|
106
|
+
`ConsentGate` keeps the iframe absent while permission is denied and removes it
|
|
107
107
|
on revocation. Keep your existing consent styles and preferences dialog.
|
|
108
108
|
|
|
109
109
|
**Nuxt**
|
|
@@ -176,7 +176,7 @@ Add this component to pages using your consent-enabled base layout:
|
|
|
176
176
|
<c15t-consent-embed style="display: block"></c15t-consent-embed>
|
|
177
177
|
|
|
178
178
|
<script>
|
|
179
|
-
import { getConsentClient } from '
|
|
179
|
+
import { getConsentClient } from 'c15t/astro/client';
|
|
180
180
|
import { mountConsentEmbed } from '../consent-embed';
|
|
181
181
|
|
|
182
182
|
class ConsentEmbed extends HTMLElement {
|
|
@@ -223,11 +223,11 @@ The provider from your quickstart supplies its consent state.
|
|
|
223
223
|
|
|
224
224
|
```svelte title="src/ConsentEmbed.svelte"
|
|
225
225
|
<script lang="ts">
|
|
226
|
-
import {
|
|
226
|
+
import { ConsentGate } from '@c15t/svelte';
|
|
227
227
|
import { embedCategory, embedURL, embedTitle, embedAspectRatio } from './embed-config';
|
|
228
228
|
</script>
|
|
229
229
|
|
|
230
|
-
<
|
|
230
|
+
<ConsentGate category={embedCategory}>
|
|
231
231
|
<iframe
|
|
232
232
|
src={embedURL}
|
|
233
233
|
title={embedTitle}
|
|
@@ -238,10 +238,10 @@ The provider from your quickstart supplies its consent state.
|
|
|
238
238
|
style:min-height="200px"
|
|
239
239
|
style:border="0"
|
|
240
240
|
></iframe>
|
|
241
|
-
</
|
|
241
|
+
</ConsentGate>
|
|
242
242
|
```
|
|
243
243
|
|
|
244
|
-
The Svelte `
|
|
244
|
+
The Svelte `ConsentGate` waits until the browser is mounted and the category is
|
|
245
245
|
allowed. Its default placeholder opens preferences. Revocation removes the
|
|
246
246
|
iframe.
|
|
247
247
|
|
|
@@ -252,11 +252,11 @@ Keep the SvelteKit root provider and its server prefetch unchanged.
|
|
|
252
252
|
|
|
253
253
|
```svelte title="src/lib/ConsentEmbed.svelte"
|
|
254
254
|
<script lang="ts">
|
|
255
|
-
import {
|
|
255
|
+
import { ConsentGate } from '@c15t/svelte';
|
|
256
256
|
import { embedCategory, embedURL, embedTitle, embedAspectRatio } from '../embed-config';
|
|
257
257
|
</script>
|
|
258
258
|
|
|
259
|
-
<
|
|
259
|
+
<ConsentGate category={embedCategory}>
|
|
260
260
|
<iframe
|
|
261
261
|
src={embedURL}
|
|
262
262
|
title={embedTitle}
|
|
@@ -267,10 +267,10 @@ Keep the SvelteKit root provider and its server prefetch unchanged.
|
|
|
267
267
|
style:min-height="200px"
|
|
268
268
|
style:border="0"
|
|
269
269
|
></iframe>
|
|
270
|
-
</
|
|
270
|
+
</ConsentGate>
|
|
271
271
|
```
|
|
272
272
|
|
|
273
|
-
The Svelte `
|
|
273
|
+
The Svelte `ConsentGate` waits until the browser is mounted and the category is
|
|
274
274
|
allowed. Its default placeholder opens preferences. Revocation removes the
|
|
275
275
|
iframe.
|
|
276
276
|
|
|
@@ -380,7 +380,7 @@ Set playback options in the iframe URL. For example, append `start=36` to begin
|
|
|
380
380
|
[YouTube player parameters](https://developers.google.com/youtube/player_parameters)
|
|
381
381
|
and reserve at least a 200-by-200-pixel player area.
|
|
382
382
|
|
|
383
|
-
React and Svelte `
|
|
383
|
+
React and Svelte `ConsentGate` components provide a blocked-state placeholder and
|
|
384
384
|
consent action. Their `placeholder` APIs differ: React takes a node, Svelte
|
|
385
385
|
takes a snippet. Keep a clear way to reopen preferences when customizing them.
|
|
386
386
|
The Vue and browser examples show that action explicitly. `loading="lazy"` delays an
|
|
@@ -388,6 +388,11 @@ allowed iframe for performance; it does not implement consent gating.
|
|
|
388
388
|
|
|
389
389
|
## Consent behavior
|
|
390
390
|
|
|
391
|
+
Add `data-vendor="youtube"` next to `data-category` and declare a `youtube`
|
|
392
|
+
vendor in the runtime's `vendors` option or the backend manifest to let visitors
|
|
393
|
+
turn YouTube off while keeping the rest of the category on. See
|
|
394
|
+
[granular consent](./granular-consent.md).
|
|
395
|
+
|
|
391
396
|
Each example keeps the iframe absent until the category is allowed. After
|
|
392
397
|
permission, the iframe can load. Revoking permission removes the iframe and its
|
|
393
398
|
embedded document. Requests already sent cannot be recalled.
|
package/docs/upgrade-v3.md
CHANGED
|
@@ -5,6 +5,13 @@ description: Migrate policy configuration, consent records, callbacks, and
|
|
|
5
5
|
group: reference
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
## React version requirement
|
|
9
|
+
|
|
10
|
+
The v3 React and Next.js adapters require React and React DOM 18 or newer.
|
|
11
|
+
Upgrade both packages together before installing v3. Earlier alpha peer ranges
|
|
12
|
+
incorrectly allowed React 16 and 17 even though v3 already uses `useId` and
|
|
13
|
+
`useSyncExternalStore`, which those versions do not provide.
|
|
14
|
+
|
|
8
15
|
## Start with a policy rule
|
|
9
16
|
|
|
10
17
|
```ts
|
|
@@ -80,6 +87,115 @@ be true before a visitor acts. A notice dismissal updates `noticeDismissal` and
|
|
|
80
87
|
does not record consent. Global Privacy Control updates privacy signals and
|
|
81
88
|
configured opt-out directives without turning a browser signal into a choice.
|
|
82
89
|
|
|
90
|
+
## Replace `useConsentManager()`
|
|
91
|
+
|
|
92
|
+
`useConsentManager()` is gone from `c15t/react`, `c15t/next`,
|
|
93
|
+
`c15t/tanstack-start` and their `/headless` entries. It subscribed to the whole
|
|
94
|
+
consent snapshot, so every component that called it re-rendered on every
|
|
95
|
+
change, including changes to categories it never read. Call one hook per field
|
|
96
|
+
instead; each re-renders only when its own value changes.
|
|
97
|
+
|
|
98
|
+
Before, in v2 and earlier v3 alphas:
|
|
99
|
+
|
|
100
|
+
```tsx title="components/marketing-banner.tsx"
|
|
101
|
+
import { useConsentManager } from 'c15t/react';
|
|
102
|
+
|
|
103
|
+
export function MarketingBanner() {
|
|
104
|
+
const { activeUI, has, saveConsents } = useConsentManager();
|
|
105
|
+
if (activeUI !== 'banner' || has('marketing')) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
return <button type="button" onClick={() => void saveConsents('all')}>Accept</button>;
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
After:
|
|
113
|
+
|
|
114
|
+
```tsx title="components/marketing-banner.tsx"
|
|
115
|
+
import { useActiveUI, useConsent } from 'c15t/react';
|
|
116
|
+
import { useHeadlessConsentUI } from 'c15t/react/headless';
|
|
117
|
+
|
|
118
|
+
export function MarketingBanner() {
|
|
119
|
+
const activeUI = useActiveUI();
|
|
120
|
+
const marketing = useConsent('marketing');
|
|
121
|
+
const { performAction } = useHeadlessConsentUI();
|
|
122
|
+
if (activeUI !== 'banner' || marketing) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
return <button type="button" onClick={() => void performAction('accept')}>Accept</button>;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Import hooks from the same entry you used for `useConsentManager()`:
|
|
130
|
+
`c15t/next` and `c15t/next/headless` in Next.js, `c15t/tanstack-start` and
|
|
131
|
+
`c15t/tanstack-start/headless` in TanStack Start.
|
|
132
|
+
|
|
133
|
+
| `useConsentManager()` field | v3 replacement |
|
|
134
|
+
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
135
|
+
| `activeUI` | `useActiveUI()`. It returns `null` before the kernel picks a surface; the old field reported `'none'`. |
|
|
136
|
+
| `setActiveUI(ui)` | `useSetActiveUI()` |
|
|
137
|
+
| `has(category)` | `useConsent(category)`, one call per category at the top of the component |
|
|
138
|
+
| `consents` | `useConsents()` |
|
|
139
|
+
| `effectivePermissions` | `useEffectivePermissions()` |
|
|
140
|
+
| `explicitChoice` | `useExplicitChoice()` |
|
|
141
|
+
| `promptRequirement` | `usePromptRequirement()` |
|
|
142
|
+
| `noticeDismissal` | `useNoticeDismissal()` |
|
|
143
|
+
| `privacySignals` | `usePrivacySignals()` |
|
|
144
|
+
| `optOutDirectives` | `useOptOutDirectives()` |
|
|
145
|
+
| `restrictions` | `useRestrictions()` |
|
|
146
|
+
| `resolution` | `usePolicyResolution()` |
|
|
147
|
+
| `policyRule` | `usePolicyRule()` |
|
|
148
|
+
| `policyCategories` | `usePolicyCategories()`. The old list started with `'necessary'`; this one does not. |
|
|
149
|
+
| `policyScopeMode` | `usePolicyScopeMode()` |
|
|
150
|
+
| `policyBanner` | `usePromptPresentation()` |
|
|
151
|
+
| `policyDialog` | `usePreferencesPresentation()` |
|
|
152
|
+
| `model` | `useModel()`. It returns `null` while no policy matches; the old field reported `'opt-in'`. |
|
|
153
|
+
| `branding` | `useBranding()`. It returns `null` when unset; the old field reported `'c15t'`. |
|
|
154
|
+
| `iab` | `useIABSnapshot()` |
|
|
155
|
+
| `vendors` | `useDeclaredVendors()` |
|
|
156
|
+
| `vendorChoice` | `useVendorChoice()` |
|
|
157
|
+
| `getDisplayedVendors(category)` | `useDeclaredVendors()`, filtered to vendors whose category condition names the category |
|
|
158
|
+
| `subscribeToConsentChanges(listener)` | `useSubscribeToConsentChanges()`, or the provider's `onPermissionsChanged` callback |
|
|
159
|
+
| `updateConsentCategories(categories)` | `useRegisterConsentCategories()` |
|
|
160
|
+
| `translationConfig` | `useTranslations()` for the active strings |
|
|
161
|
+
| `selectedConsents`, `selectedConsentTypes` | `useConsentDraft().values` |
|
|
162
|
+
| `setSelectedConsent(name, value)` | `useConsentDraft().set(name, value)` |
|
|
163
|
+
| `selectedVendors` | `useConsentDraft().vendors`, or `useVendorDraft().vendors` |
|
|
164
|
+
| `setSelectedVendor(id, granted)` | `useConsentDraft().setVendor(id, granted)` |
|
|
165
|
+
| `resetDraft()` | `useConsentDraft().reset()` |
|
|
166
|
+
| `draftIsStale` | `useConsentDraft().isStale` |
|
|
167
|
+
| `consentCategories`, `consentTypes`, `getDisplayedConsents()` | `useConsentDraft().displayedCategories`, with labels from `useTranslations().consentTypes` |
|
|
168
|
+
| `saveConsents('all')` | `useHeadlessConsentUI().performAction('accept')` |
|
|
169
|
+
| `saveConsents('necessary')` | `useHeadlessConsentUI().performAction('reject')` |
|
|
170
|
+
| `saveConsents('custom')` | `useHeadlessConsentUI().performAction('save')` |
|
|
171
|
+
| `manager` | Nothing. It was always `null` in v3. |
|
|
172
|
+
|
|
173
|
+
The old hook kept one private draft per component, shared by its selection and
|
|
174
|
+
its save. `useConsentDraft()` and `useHeadlessConsentUI()` read the nearest
|
|
175
|
+
`ConsentDraftProvider` instead. When one component stages choices and another
|
|
176
|
+
saves them, or one component calls both hooks, render them inside the same
|
|
177
|
+
`ConsentDraftProvider`; without one, each hook keeps its own draft and a custom
|
|
178
|
+
save commits nothing you staged. `ConsentWidget` already provides one.
|
|
179
|
+
|
|
180
|
+
`useHeadlessConsentUI()` saves the way the stock buttons do: it closes the
|
|
181
|
+
surface after a successful save and refuses a draft that the policy made stale.
|
|
182
|
+
`useSaveConsents()` calls the kernel directly and does neither.
|
|
183
|
+
|
|
184
|
+
The CLI rewrites the common destructuring forms for you:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
c15t codemods use-consent-manager-to-hooks --dry-run --json
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
It replaces each field that has a one-hook equivalent, turns `has('marketing')`
|
|
191
|
+
calls with a literal category into `useConsent('marketing')`, and maps
|
|
192
|
+
`saveConsents('all' | 'necessary' | 'custom')` calls to
|
|
193
|
+
`useHeadlessConsentUI().saveCustomPreferences()`. Fields it cannot rewrite stay
|
|
194
|
+
on a `useConsentManager()` call under a `TODO(c15t v3)` comment that names the
|
|
195
|
+
replacement, so the build fails at each place that needs manual work. It also
|
|
196
|
+
marks components that now need a shared `ConsentDraftProvider`. Review the
|
|
197
|
+
result, then run it without `--dry-run`.
|
|
198
|
+
|
|
83
199
|
## Replace choice callbacks
|
|
84
200
|
|
|
85
201
|
```tsx
|
|
@@ -184,7 +300,7 @@ Notice acknowledgement uses `common.acknowledge`, falling back to
|
|
|
184
300
|
|
|
185
301
|
```astro
|
|
186
302
|
---
|
|
187
|
-
import ConsentBanner from '
|
|
303
|
+
import ConsentBanner from 'c15t/astro/components/consent-banner.astro';
|
|
188
304
|
---
|
|
189
305
|
|
|
190
306
|
<ConsentBanner dismissButtonText="Got it" />
|
|
@@ -252,6 +368,43 @@ TanStack Start (`c15t/tanstack-start`, `c15t/tanstack-start/server`):
|
|
|
252
368
|
`consentLoaderOptions`, `backendURL`, `initRoute` and `DEFAULT_INIT_ROUTE` are
|
|
253
369
|
unchanged.
|
|
254
370
|
|
|
371
|
+
## `Frame` is now `ConsentGate`
|
|
372
|
+
|
|
373
|
+
The component that mounts an embed only while its category is allowed is now
|
|
374
|
+
`ConsentGate` in React, Next.js, TanStack Start, Svelte and Vue. The old names
|
|
375
|
+
still work as deprecated aliases and will be removed in a later major release.
|
|
376
|
+
|
|
377
|
+
| v2 | v3 |
|
|
378
|
+
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
379
|
+
| `Frame`, `Frame.Root`, `Frame.Title`, `Frame.Button` | `ConsentGate`, `ConsentGate.Root`, `ConsentGate.Title`, `ConsentGate.Button` |
|
|
380
|
+
| `FrameProps`, `FrameCompoundComponent` | `ConsentGateProps`, `ConsentGateCompoundComponent` |
|
|
381
|
+
| `c15t/react/frame`, `c15t/react/components/frame` | `c15t/react/consent-gate`, `c15t/react/components/consent-gate` |
|
|
382
|
+
| Vue `ConsentFrame`, `@c15t/vue/runtime/components/consent-frame.vue` | `ConsentGate`, `@c15t/vue/runtime/components/consent-gate.vue` |
|
|
383
|
+
|
|
384
|
+
Props and behavior are unchanged. The placeholder keeps its `frame.*`
|
|
385
|
+
translation keys, `--frame-*` CSS custom properties and
|
|
386
|
+
`data-testid="frame-placeholder"`, so custom copy, styles and tests continue
|
|
387
|
+
to apply.
|
|
388
|
+
|
|
389
|
+
## Split dialog and widget entries are deferred
|
|
390
|
+
|
|
391
|
+
`c15t/react/consent-dialog` and `c15t/react/consent-widget` (and their
|
|
392
|
+
`@c15t/react/*` equivalents) now export the same deferred `ConsentDialog` and
|
|
393
|
+
`ConsentWidget` as `c15t/react`. The dialog's code loads when it first opens
|
|
394
|
+
instead of with every page. `<ConsentDialog />`, `<ConsentWidget />` and the
|
|
395
|
+
`ConsentDialog.<Part>` properties need no change.
|
|
396
|
+
|
|
397
|
+
The two entries no longer export the individual parts. Import those from the
|
|
398
|
+
component entries, which keep the old, eagerly bundled exports:
|
|
399
|
+
|
|
400
|
+
| Before | After |
|
|
401
|
+
| --------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
402
|
+
| `import { Card, Header } from 'c15t/react/consent-dialog'` | `import { Card, Header } from 'c15t/react/components/consent-dialog'` |
|
|
403
|
+
| `import { Accordion, Switch } from 'c15t/react/consent-widget'` | `import { Accordion, Switch } from 'c15t/react/components/consent-widget'` |
|
|
404
|
+
|
|
405
|
+
To keep the dialog in the first load so its first open needs no download,
|
|
406
|
+
import `ConsentDialog` from `c15t/react/components/consent-dialog`.
|
|
407
|
+
|
|
255
408
|
## Next.js RSC banner removal
|
|
256
409
|
|
|
257
410
|
The `@c15t/nextjs/rsc` entry (`c15t/next/rsc`) and its `RscConsentBanner`,
|
|
@@ -332,3 +485,25 @@ export function Banner() {
|
|
|
332
485
|
);
|
|
333
486
|
}
|
|
334
487
|
```
|
|
488
|
+
|
|
489
|
+
## Session reports in manifest mode
|
|
490
|
+
|
|
491
|
+
A host that resolves init from a cached manifest never calls `/init`, so a v3
|
|
492
|
+
backend could not count the visitors it served. From this release every
|
|
493
|
+
server-side resolution sends `POST /sessions` to the backend after the fact,
|
|
494
|
+
server-to-server and detached from the response: the Next.js, TanStack Start,
|
|
495
|
+
SvelteKit, Nuxt and Astro init routes, and the Next.js, TanStack Start and
|
|
496
|
+
Astro render-time prefetches. The browser makes no request.
|
|
497
|
+
|
|
498
|
+
This is a new outbound data flow from your server to the consent backend. The
|
|
499
|
+
report carries the manifest revision, the matched policy, the jurisdiction,
|
|
500
|
+
country, region, language and GPC signal, plus the visitor's user agent and
|
|
501
|
+
address as request headers. It carries no cookies and no identifier. Nothing is
|
|
502
|
+
stored on the backend; the report reaches a `sessions.onReport` sink and the
|
|
503
|
+
request log.
|
|
504
|
+
|
|
505
|
+
Reporting is on by default and needs an absolute backend URL. Set
|
|
506
|
+
`reportSessions: false` on the adapter to send none. Each report is one
|
|
507
|
+
resolution, not one visitor: a page view can produce a `render` report and a
|
|
508
|
+
`route` report, and nothing in them links the two. A consumer counting sessions
|
|
509
|
+
groups reports by the forwarded address and user agent within a window.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c15t/react",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.3",
|
|
4
4
|
"description": "React cookie banner, consent manager, preference center, and headless CMP components with IAB TCF and Consent Mode support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ccpa",
|
|
@@ -131,10 +131,15 @@
|
|
|
131
131
|
"import": "./dist/panel-trigger.js",
|
|
132
132
|
"default": "./dist/panel-trigger.js"
|
|
133
133
|
},
|
|
134
|
+
"./consent-gate": {
|
|
135
|
+
"types": "./dist-types/consent-gate.d.ts",
|
|
136
|
+
"import": "./dist/consent-gate.js",
|
|
137
|
+
"default": "./dist/consent-gate.js"
|
|
138
|
+
},
|
|
134
139
|
"./frame": {
|
|
135
|
-
"types": "./dist-types/
|
|
136
|
-
"import": "./dist/
|
|
137
|
-
"default": "./dist/
|
|
140
|
+
"types": "./dist-types/consent-gate.d.ts",
|
|
141
|
+
"import": "./dist/consent-gate.js",
|
|
142
|
+
"default": "./dist/consent-gate.js"
|
|
138
143
|
},
|
|
139
144
|
"./iab": {
|
|
140
145
|
"types": "./dist-types/iab.d.ts",
|
|
@@ -190,10 +195,15 @@
|
|
|
190
195
|
"import": "./dist/components/preferences/index.js",
|
|
191
196
|
"default": "./dist/components/preferences/index.js"
|
|
192
197
|
},
|
|
198
|
+
"./components/consent-gate": {
|
|
199
|
+
"types": "./dist-types/components/consent-gate/index.d.ts",
|
|
200
|
+
"import": "./dist/components/consent-gate/index.js",
|
|
201
|
+
"default": "./dist/components/consent-gate/index.js"
|
|
202
|
+
},
|
|
193
203
|
"./components/frame": {
|
|
194
|
-
"types": "./dist-types/components/
|
|
195
|
-
"import": "./dist/components/
|
|
196
|
-
"default": "./dist/components/
|
|
204
|
+
"types": "./dist-types/components/consent-gate/index.d.ts",
|
|
205
|
+
"import": "./dist/components/consent-gate/index.js",
|
|
206
|
+
"default": "./dist/components/consent-gate/index.js"
|
|
197
207
|
},
|
|
198
208
|
"./context": {
|
|
199
209
|
"types": "./dist-types/context/index.d.ts",
|
|
@@ -233,16 +243,16 @@
|
|
|
233
243
|
"test:watch": "bun prebuild && vitest"
|
|
234
244
|
},
|
|
235
245
|
"dependencies": {
|
|
236
|
-
"@c15t/core": "3.0.0-alpha.
|
|
237
|
-
"@c15t/dev-tools": "3.0.0-alpha.
|
|
238
|
-
"@c15t/iab": "3.0.0-alpha.
|
|
239
|
-
"@c15t/schema": "3.0.0-alpha.
|
|
240
|
-
"@c15t/translations": "3.0.0-alpha.
|
|
241
|
-
"@c15t/ui": "3.0.0-alpha.
|
|
246
|
+
"@c15t/core": "3.0.0-alpha.3",
|
|
247
|
+
"@c15t/dev-tools": "3.0.0-alpha.3",
|
|
248
|
+
"@c15t/iab": "3.0.0-alpha.3",
|
|
249
|
+
"@c15t/schema": "3.0.0-alpha.2",
|
|
250
|
+
"@c15t/translations": "3.0.0-alpha.2",
|
|
251
|
+
"@c15t/ui": "3.0.0-alpha.3",
|
|
242
252
|
"@types/google.maps": "3.65.3"
|
|
243
253
|
},
|
|
244
254
|
"devDependencies": {
|
|
245
|
-
"@c15t/backend": "3.0.0-alpha.
|
|
255
|
+
"@c15t/backend": "3.0.0-alpha.3",
|
|
246
256
|
"@c15t/conformance": "0.0.1",
|
|
247
257
|
"@c15t/typescript-config": "0.0.1",
|
|
248
258
|
"@c15t/vitest-config": "1.0.0",
|
|
@@ -252,8 +262,8 @@
|
|
|
252
262
|
"typescript": "7.0.2"
|
|
253
263
|
},
|
|
254
264
|
"peerDependencies": {
|
|
255
|
-
"react": "^
|
|
256
|
-
"react-dom": "^
|
|
265
|
+
"react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
|
|
266
|
+
"react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
|
257
267
|
},
|
|
258
268
|
"peerDependenciesMeta": {
|
|
259
269
|
"react": {
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import{evaluateConsent as e}from"@c15t/core";import{useCallback as t,useContext as a,useMemo as i}from"react";import{ProviderServicesContext as n}from"../context.js";import{useConsentManagerDraft as s}from"../draft.js";import{useActiveUI as r,useBranding as o,useConsents as l,useModel as p,usePolicyCategories as c,usePolicyScopeMode as u,usePreferencesPresentation as m,usePromptPresentation as d,useSetActiveUI as f,useSnapshot as y,useSubscribeToConsentChanges as g,useTranslations as v}from"../hooks.js";import{defaultTranslationConfig as C}from"../utils/default-translation-config.js";let T={},b=[{defaultValue:!0,description:"Required for basic site functionality",disabled:!0,display:!0,gdprType:1,name:"necessary"},{defaultValue:!1,description:"Enables enhanced features",display:!0,gdprType:2,name:"functionality"},{defaultValue:!1,description:"Analytics and performance measurement",display:!0,gdprType:4,name:"measurement"},{defaultValue:!1,description:"Improves your experience",display:!0,gdprType:3,name:"experience"},{defaultValue:!1,description:"Advertising and marketing",display:!0,gdprType:5,name:"marketing"}],x=function(){let x=y(),D=a(n),h=l(),R=r(),S=o(),V=p(),j=d(),k=c(),q=m(),w=u(),{draft:I,save:A}=s(),M=f(),O=g(),P=v(),_=i(()=>P?{...C,defaultLanguage:P.language,translations:{...C.translations,[P.language]:P.translations}}:C,[P]),B=i(()=>["necessary",...k],[k]),E=i(()=>[...D?.getConsentCategories()??B],[D,B]),L=t(()=>{let e=new Set(E);return b.filter(t=>e.has(t.name)).map(e=>({...e,display:!0}))},[E]),U=t(t=>e({category:t},x),[x]),z=t(e=>{M(e)},[M]),F=t(async(e,t)=>{"custom"===e?await A():await A("all"===e?"all":"none")},[A]),G=t((e,t)=>{E.includes(e)&&I.set(e,t)},[I,E]),H=t(e=>{},[]),J=t(e=>O(e),[O]);return{activeUI:R??"none",branding:S??"c15t",consentCategories:E,consentTypes:L(),consents:h,draftIsStale:I.isStale,effectivePermissions:x.effectivePermissions,explicitChoice:x.explicitChoice,getDisplayedConsents:L,has:U,iab:x.iab,manager:null,model:V??"opt-in",noticeDismissal:x.noticeDismissal,optOutDirectives:x.optOutDirectives,policyBanner:j??T,policyCategories:B,policyDialog:q??T,policyRule:x.policyRule,policyScopeMode:w,privacySignals:x.privacySignals,promptRequirement:x.promptRequirement,resetDraft:I.reset,resolution:x.resolution,restrictions:x.restrictions,saveConsents:F,selectedConsentTypes:I.values,selectedConsents:I.values,setActiveUI:z,setSelectedConsent:G,subscribeToConsentChanges:J,translationConfig:_,updateConsentCategories:H}};export{x as useConsentManager};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{jsx as e}from"react/jsx-runtime";import t from"@c15t/ui/styles/components/frame";import{forwardRef as r}from"react";import{useTranslations as a}from"../../component-hooks/use-translations.js";import{Box as o}from"../shared/primitives/box.js";import{ConsentButton as i}from"../shared/primitives/button.js";let m=r(({children:r,...a},i)=>e(o,{ref:i,baseClassName:t.placeholder,"data-testid":"frame-placeholder",...a,children:r})),l=r(({children:r,category:i,...m},l)=>{let{frame:s,consentTypes:n}=a(),p=i&&s?.title?s.title.replace("{category}",n?.[i]?.title??i):void 0;return e(o,{ref:l,baseClassName:t.title,...m,children:r??p})}),s=r(({children:t,category:r,...o},m)=>{let{frame:l,consentTypes:s}=a(),n=s?.[r]?.title??r,p=l?.actionButton?.replace("{category}",n);return e(i,{mode:"stroke",size:"small",variant:"primary",...o,ref:m,action:"open-consent-dialog",category:r,"data-testid":"frame-open-dialog",children:t??p})});m.displayName="FrameRoot",l.displayName="FrameTitle",s.displayName="FrameButton";export{s as FrameButton,m as FrameRoot,l as FrameTitle};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import{jsx as e,jsxs as o}from"react/jsx-runtime";import{forwardRef as r,useEffect as t}from"react";import{useConsentManager as i}from"../../component-hooks/use-manager.js";import{useTranslations as l}from"../../component-hooks/use-translations.js";import{FrameButton as n,FrameRoot as s,FrameTitle as c}from"./atoms.js";let a=({category:r,policyBlocked:t,policyBlockedMessage:i})=>o(s,{children:[e(c,{category:r,children:t?i??"This content is unavailable under your region's consent policy.":void 0}),t?null:e(n,{category:r})]}),m=r(({children:o,category:r,placeholder:n,noStyle:s,className:c,theme:m,...d},p)=>{let{has:y,updateConsentCategories:u,consentCategories:h,policyCategories:g,policyScopeMode:f}=i(),{frame:k}=l(),j=y(r),v=Array.isArray(g)&&g.length>0&&!g.includes("*")&&!g.includes(r);return t(()=>{h.includes(r)||u([...h,r])},[r,h,u]),e("div",{ref:p,className:c,...d,children:j?o:n||e(a,{category:r,policyBlocked:"strict"===f&&v,policyBlockedMessage:k?.policyBlocked})})});m.displayName="Frame";let d=m;export{d as Frame};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import{Frame as t}from"./frame.js";import*as e from"./atoms.js";let r=Object.assign(t,{Button:e.FrameButton,Root:e.FrameRoot,Title:e.FrameTitle});var a=e.FrameButton,m=e.FrameRoot,o=e.FrameTitle;export{a as FrameButton,m as FrameRoot,o as FrameTitle,r as Frame};
|
package/dist/frame.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { ActiveUI, AllConsentNames, ConsentState, ConsentType, HasCondition, Model, PromptPresentation, TranslationConfig } from '@c15t/core';
|
|
2
|
-
type SaveType = 'all' | 'custom' | 'necessary';
|
|
3
|
-
export declare const useConsentManager: () => {
|
|
4
|
-
activeUI: ActiveUI;
|
|
5
|
-
branding: import("@c15t/core").KernelBranding;
|
|
6
|
-
consentCategories: AllConsentNames[];
|
|
7
|
-
consentTypes: ConsentType[];
|
|
8
|
-
consents: ConsentState;
|
|
9
|
-
draftIsStale: boolean;
|
|
10
|
-
effectivePermissions: Readonly<ConsentState>;
|
|
11
|
-
explicitChoice: Readonly<import("@c15t/core").ExplicitChoice> | null;
|
|
12
|
-
getDisplayedConsents: () => ConsentType[];
|
|
13
|
-
has: (condition: HasCondition<AllConsentNames>) => boolean;
|
|
14
|
-
iab: Readonly<import("@c15t/core").KernelIABState> | null;
|
|
15
|
-
manager: null;
|
|
16
|
-
model: Model;
|
|
17
|
-
noticeDismissal: Readonly<import("@c15t/core").NoticeDismissal> | null;
|
|
18
|
-
optOutDirectives: readonly import("@c15t/core").PrivacyOptOut[];
|
|
19
|
-
policyBanner: PromptPresentation;
|
|
20
|
-
policyCategories: AllConsentNames[];
|
|
21
|
-
policyDialog: import("@c15t/core").PreferencesPresentation;
|
|
22
|
-
policyRule: Readonly<import("@c15t/core").ResolvedPolicyRule>;
|
|
23
|
-
policyScopeMode: import("@c15t/core").PolicyScopeMode;
|
|
24
|
-
privacySignals: import("@c15t/core").KernelPrivacySignals;
|
|
25
|
-
promptRequirement: Readonly<import("@c15t/core").PromptRequirement>;
|
|
26
|
-
resetDraft: () => void;
|
|
27
|
-
resolution: Readonly<import("@c15t/core").PolicyResolution>;
|
|
28
|
-
restrictions: Readonly<Partial<Record<import("@c15t/core").OptionalConsentCategory, readonly import("@c15t/core").RestrictionReason[]>>>;
|
|
29
|
-
saveConsents: (type: SaveType, _options?: {
|
|
30
|
-
uiSource?: string;
|
|
31
|
-
}) => Promise<void>;
|
|
32
|
-
selectedConsentTypes: Readonly<ConsentState>;
|
|
33
|
-
selectedConsents: Readonly<ConsentState>;
|
|
34
|
-
setActiveUI: (ui: ActiveUI) => void;
|
|
35
|
-
setSelectedConsent: (name: AllConsentNames, value: boolean) => void;
|
|
36
|
-
subscribeToConsentChanges: (listener: (state: ConsentState) => void) => () => void;
|
|
37
|
-
translationConfig: TranslationConfig;
|
|
38
|
-
updateConsentCategories: (_names: AllConsentNames[]) => void;
|
|
39
|
-
};
|
|
40
|
-
export {};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { AllConsentNames } from '@c15t/core';
|
|
2
|
-
import type { BoxProps } from '../shared/primitives/box';
|
|
3
|
-
import type { ConsentButtonProps } from '../shared/primitives/button.types';
|
|
4
|
-
declare const FrameRoot: import("react").ForwardRefExoticComponent<Omit<BoxProps, "slotKey"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
5
|
-
declare const FrameTitle: import("react").ForwardRefExoticComponent<Omit<BoxProps, "slotKey"> & {
|
|
6
|
-
category?: AllConsentNames;
|
|
7
|
-
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
8
|
-
declare const FrameButton: import("react").ForwardRefExoticComponent<Omit<ConsentButtonProps, "slotKey"> & {
|
|
9
|
-
category: AllConsentNames;
|
|
10
|
-
} & import("react").RefAttributes<HTMLButtonElement>>;
|
|
11
|
-
export { FrameButton, FrameRoot, FrameTitle };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { FrameCompoundComponent } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* The Frame component that provides consent-gated content rendering
|
|
4
|
-
*
|
|
5
|
-
* @remarks
|
|
6
|
-
* Acts as a consent boundary for embedded content (iframes, videos, third-party widgets).
|
|
7
|
-
* Conditionally renders children based on user consent, displaying a placeholder when
|
|
8
|
-
* permission is not granted.
|
|
9
|
-
* Supports custom styling via `theme` or complete style override with `noStyle` as well as a custom placeholder.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```tsx
|
|
13
|
-
* <Frame category="marketing">
|
|
14
|
-
* <iframe src="https://www.youtube.com/embed/MtN1YnoL46Q?si=JYIFKdENwls43H-r" />
|
|
15
|
-
* </Frame>
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* @see {@link FrameTheme} for theme options
|
|
19
|
-
* @see {@link AllConsentNames} for consent categories
|
|
20
|
-
*/
|
|
21
|
-
declare const Frame: FrameCompoundComponent;
|
|
22
|
-
export { FrameButton, FrameRoot, FrameTitle } from './atoms';
|
|
23
|
-
export type { FrameCompoundComponent, FrameProps } from './types';
|
|
24
|
-
export { Frame };
|
package/dist-types/frame.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './components/frame';
|
package/readme.json
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"title": "@c15t/react: React Consent Components",
|
|
3
|
-
"description": "React cookie banner, consent manager, preference center, and headless CMP components for modern React apps.",
|
|
4
|
-
"features": [
|
|
5
|
-
"Works with React 19, 18, 17, and 16.8",
|
|
6
|
-
"Full 'use client' support for React Server Components",
|
|
7
|
-
"Prebuilt and fully customizable cookie banner, consent dialog, and preference center UI",
|
|
8
|
-
"Headless hooks for custom consent flows",
|
|
9
|
-
"Minimal configuration with TypeScript-first design",
|
|
10
|
-
"Comprehensive Consent Management Platform (CMP)",
|
|
11
|
-
"IAB TCF 2.3 UI and hooks through the @c15t/react/iab subpath",
|
|
12
|
-
"Google Tag Manager, Google Consent Mode v2, Meta Pixel, and analytics integrations through @c15t/scripts",
|
|
13
|
-
"Built-in internationalization support",
|
|
14
|
-
"Seamless consent storage and tracking"
|
|
15
|
-
],
|
|
16
|
-
"prerequisites": [
|
|
17
|
-
"React 16.8 or later",
|
|
18
|
-
"Node.js 20.19 or later",
|
|
19
|
-
"A hosted [c15t instance](https://inth.com) (free sign-up), [self-hosted deployment](https://c15t.com/docs/self-host/quickstart), or offline mode for local-only storage"
|
|
20
|
-
],
|
|
21
|
-
"manualInstallation": [
|
|
22
|
-
"",
|
|
23
|
-
"```bash\npnpm add @c15t/react\n```",
|
|
24
|
-
"",
|
|
25
|
-
"Then add the prebuilt stylesheet to your app-level CSS entrypoint:",
|
|
26
|
-
"",
|
|
27
|
-
"```css\n/* src/index.css */\n@import \"@c15t/react/styles.css\";\n```",
|
|
28
|
-
"",
|
|
29
|
-
"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.",
|
|
30
|
-
"",
|
|
31
|
-
"To manually install, follow the guide in our [docs – manual setup](https://c15t.com/docs/frameworks/react/quickstart#manual-setup)."
|
|
32
|
-
],
|
|
33
|
-
"usage": [
|
|
34
|
-
"Import `ConsentManagerProvider` in your app's root component",
|
|
35
|
-
"Add `ConsentBanner` and `ConsentDialog` components",
|
|
36
|
-
"Customize styling and behavior to fit your app",
|
|
37
|
-
"For full implementation details, see the [React quickstart docs](https://c15t.com/docs/frameworks/react/quickstart)",
|
|
38
|
-
|
|
39
|
-
"```tsx\n// App.tsx\nimport {\n ConsentManagerProvider,\n ConsentBanner,\n ConsentDialog,\n} from '@c15t/react'\n\nfunction App() {\n return (\n <ConsentManagerProvider>\n <YourApp />\n <ConsentBanner />\n <ConsentDialog />\n </ConsentManagerProvider>\n )\n}\n```"
|
|
40
|
-
],
|
|
41
|
-
"docsLink": "https://c15t.com/docs/frameworks/react/quickstart",
|
|
42
|
-
"quickStartLink": "https://c15t.com/docs/frameworks/react/quickstart",
|
|
43
|
-
"showCLIGeneration": true,
|
|
44
|
-
"customSections": {
|
|
45
|
-
"Deployment Modes": "- **Hosted on inth.com**: Hosted c15t backend for policy storage, audit history, and hosted infrastructure\n- **Self-hosted backend**: Use @c15t/backend when you need full infrastructure control\n- **Offline mode**: Browser-only consent storage for local development, demos, previews, static sites, or fallback scenarios",
|
|
46
|
-
"Popular Integrations": "- Google Tag Manager with Google Consent Mode v2\n- Google Analytics 4 and Google Ads through gtag.js\n- Meta Pixel, TikTok Pixel, LinkedIn Insights, Microsoft UET, X Pixel, Reddit Pixel, and Snapchat Pixel\n- PostHog, Segment, Mixpanel, Microsoft Clarity, Hotjar, Plausible, Fathom, Matomo, Umami, and Vercel Analytics\n- Intercom and Crisp chat widgets"
|
|
47
|
-
}
|
|
48
|
-
}
|
package/src/iab/styles.css
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
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';
|