@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.
Files changed (241) hide show
  1. package/AGENTS.md +9 -2
  2. package/dist/aggregate-components.js +1 -1
  3. package/dist/chunk-warming.js +1 -1
  4. package/dist/component-hooks/use-headless-iab-consent-ui.js +1 -1
  5. package/dist/component-hooks/use-panel-trigger.js +1 -1
  6. package/dist/components/consent-gate/atoms.js +1 -0
  7. package/dist/components/consent-gate/consent-gate.js +2 -0
  8. package/dist/components/consent-gate/index.js +2 -0
  9. package/dist/components/consent-preferences-link/consent-preferences-link.js +1 -1
  10. package/dist/components/iab-panel/atoms/purpose-item.js +1 -1
  11. package/dist/components/iab-panel/atoms/stack-item.js +1 -1
  12. package/dist/components/iab-panel/iab-panel.js +1 -1
  13. package/dist/components/iab-panel/index.js +1 -1
  14. package/dist/components/panel/atoms/overlay.js +1 -1
  15. package/dist/components/panel/atoms/root.js +1 -1
  16. package/dist/components/panel/index.js +1 -1
  17. package/dist/components/panel/panel.js +1 -1
  18. package/dist/components/panel-trigger/atoms/button.js +1 -1
  19. package/dist/components/panel-trigger/atoms/icon.js +1 -1
  20. package/dist/components/panel-trigger/atoms/root.js +1 -1
  21. package/dist/components/panel-trigger/atoms/trigger-icons.js +1 -0
  22. package/dist/components/panel-trigger/panel-trigger-toolbar.js +1 -1
  23. package/dist/components/preferences/atoms/accordion.js +1 -1
  24. package/dist/components/preferences/atoms/root.js +1 -1
  25. package/dist/components/preferences/atoms/vendor-list.js +1 -0
  26. package/dist/components/preferences/index.js +1 -1
  27. package/dist/components/prompt/policy-actions.js +1 -1
  28. package/dist/components/shared/primitives/button.js +1 -1
  29. package/dist/components/shared/ui/accordion/accordion.js +1 -1
  30. package/dist/components/shared/ui/collapsible/collapsible.js +1 -1
  31. package/dist/components/shared/ui/logo.js +1 -1
  32. package/dist/components/shared/ui/preference-item/preference-item.js +1 -1
  33. package/dist/components/shared/ui/switch/switch.js +1 -1
  34. package/dist/components/shared/ui/tabs/tabs.js +1 -1
  35. package/dist/consent-gate.js +2 -0
  36. package/dist/consent-theme.js +1 -0
  37. package/dist/draft.js +1 -1
  38. package/dist/external-iab-context.js +1 -1
  39. package/dist/headless.js +1 -1
  40. package/dist/hooks/use-committed-ref.js +2 -0
  41. package/dist/hooks.js +1 -1
  42. package/dist/iab/styles.tw3.css +1 -41
  43. package/dist/iab-context.js +1 -1
  44. package/dist/index.js +1 -1
  45. package/dist/kernel-selector.js +1 -0
  46. package/dist/module-hooks/iframe-blocker.js +1 -1
  47. package/dist/module-hooks/network-blocker.js +1 -1
  48. package/dist/module-hooks/network-hold.js +2 -0
  49. package/dist/module-hooks/persistence.js +1 -1
  50. package/dist/panel.js +1 -1
  51. package/dist/preferences.js +1 -2
  52. package/dist/provider.js +1 -1
  53. package/dist/styles.tw3.css +1 -43
  54. package/dist/ui-save.js +1 -1
  55. package/dist/utils/deferred-module.js +2 -0
  56. package/dist/version.js +1 -1
  57. package/dist-types/aggregate-components.d.ts +2 -2
  58. package/dist-types/chunk-warming.d.ts +41 -8
  59. package/dist-types/component-hooks/use-headless-iab-consent-ui.d.ts +2 -2
  60. package/dist-types/components/consent-gate/atoms.d.ts +11 -0
  61. package/dist-types/components/consent-gate/consent-gate.d.ts +2 -0
  62. package/dist-types/components/consent-gate/index.d.ts +41 -0
  63. package/dist-types/components/{frame → consent-gate}/types.d.ts +7 -7
  64. package/dist-types/components/consent-preferences-link/consent-preferences-link.d.ts +1 -1
  65. package/dist-types/components/consent-preferences-link/index.d.ts +1 -1
  66. package/dist-types/components/iab-panel/atoms/purpose-item.d.ts +5 -2
  67. package/dist-types/components/iab-panel/atoms/stack-item.d.ts +7 -2
  68. package/dist-types/components/iab-panel/atoms/vendor-list.d.ts +1 -1
  69. package/dist-types/components/iab-panel/iab-panel.d.ts +1 -1
  70. package/dist-types/components/iab-panel/index.d.ts +25 -24
  71. package/dist-types/components/iab-prompt/index.d.ts +17 -17
  72. package/dist-types/components/panel/atoms/card.d.ts +4 -4
  73. package/dist-types/components/panel/atoms/overlay.d.ts +1 -1
  74. package/dist-types/components/panel/index.d.ts +8 -7
  75. package/dist-types/components/panel/panel.d.ts +3 -3
  76. package/dist-types/components/panel-link/index.d.ts +1 -1
  77. package/dist-types/components/panel-trigger/atoms/button.d.ts +1 -1
  78. package/dist-types/components/panel-trigger/atoms/icon.d.ts +1 -1
  79. package/dist-types/components/panel-trigger/atoms/root.d.ts +2 -2
  80. package/dist-types/components/panel-trigger/atoms/toolbar.d.ts +2 -2
  81. package/dist-types/components/panel-trigger/atoms/trigger-icons.d.ts +20 -0
  82. package/dist-types/components/panel-trigger/index.d.ts +4 -4
  83. package/dist-types/components/panel-trigger/panel-trigger-toolbar.d.ts +1 -1
  84. package/dist-types/components/panel-trigger/panel-trigger.d.ts +9 -9
  85. package/dist-types/components/panel-trigger/types.d.ts +1 -1
  86. package/dist-types/components/preferences/atoms/accordion.d.ts +6 -4
  87. package/dist-types/components/preferences/atoms/button.d.ts +1 -1
  88. package/dist-types/components/preferences/atoms/footer.d.ts +1 -1
  89. package/dist-types/components/preferences/atoms/root.d.ts +1 -1
  90. package/dist-types/components/preferences/atoms/vendor-list.d.ts +23 -0
  91. package/dist-types/components/preferences/index.d.ts +14 -11
  92. package/dist-types/components/preferences/policy-actions.d.ts +2 -2
  93. package/dist-types/components/preferences/preferences.d.ts +1 -1
  94. package/dist-types/components/preferences/types.d.ts +1 -1
  95. package/dist-types/components/prompt/components.d.ts +3 -3
  96. package/dist-types/components/prompt/index.d.ts +11 -11
  97. package/dist-types/components/prompt/policy-actions.d.ts +2 -2
  98. package/dist-types/components/prompt/prompt.d.ts +1 -1
  99. package/dist-types/components/shared/policy-actions.d.ts +2 -2
  100. package/dist-types/components/shared/primitives/box.d.ts +1 -1
  101. package/dist-types/components/shared/primitives/button.d.ts +2 -2
  102. package/dist-types/components/shared/primitives/button.types.d.ts +1 -1
  103. package/dist-types/components/shared/ui/accordion/accordion.d.ts +3 -2
  104. package/dist-types/components/shared/ui/accordion/index.d.ts +2 -2
  105. package/dist-types/components/shared/ui/animated-collapse/index.d.ts +2 -2
  106. package/dist-types/components/shared/ui/branding.d.ts +1 -1
  107. package/dist-types/components/shared/ui/button/button.d.ts +1 -1
  108. package/dist-types/components/shared/ui/button/index.d.ts +2 -2
  109. package/dist-types/components/shared/ui/collapsible/collapsible.d.ts +1 -0
  110. package/dist-types/components/shared/ui/collapsible/index.d.ts +1 -1
  111. package/dist-types/components/shared/ui/dialog/index.d.ts +1 -1
  112. package/dist-types/components/shared/ui/logo.d.ts +0 -10
  113. package/dist-types/components/shared/ui/preference-item/index.d.ts +1 -1
  114. package/dist-types/components/shared/ui/preference-item/preference-item.d.ts +14 -0
  115. package/dist-types/components/shared/ui/switch/index.d.ts +2 -2
  116. package/dist-types/components/shared/ui/switch/switch.d.ts +2 -1
  117. package/dist-types/components/shared/ui/tabs/index.d.ts +1 -1
  118. package/dist-types/components/shared/ui/tabs/tabs.d.ts +1 -0
  119. package/dist-types/consent-gate.d.ts +1 -0
  120. package/dist-types/consent-theme.d.ts +38 -0
  121. package/dist-types/context/index.d.ts +3 -3
  122. package/dist-types/context/theme-context.d.ts +1 -1
  123. package/dist-types/draft.d.ts +96 -7
  124. package/dist-types/headless.d.ts +6 -7
  125. package/dist-types/hooks/use-committed-ref.d.ts +24 -0
  126. package/dist-types/hooks/use-headless-iab-consent-ui.d.ts +1 -1
  127. package/dist-types/hooks/use-iab-manager.d.ts +1 -1
  128. package/dist-types/hooks/use-theme.d.ts +1 -1
  129. package/dist-types/hooks.d.ts +30 -1
  130. package/dist-types/iab.d.ts +5 -5
  131. package/dist-types/index.d.ts +26 -25
  132. package/dist-types/kernel-selector.d.ts +66 -0
  133. package/dist-types/module-hooks/iframe-blocker.d.ts +27 -0
  134. package/dist-types/module-hooks/network-blocker.d.ts +23 -0
  135. package/dist-types/module-hooks/network-hold.d.ts +47 -0
  136. package/dist-types/module-hooks.d.ts +4 -4
  137. package/dist-types/panel-link.d.ts +1 -1
  138. package/dist-types/panel-trigger.d.ts +1 -1
  139. package/dist-types/panel.d.ts +13 -1
  140. package/dist-types/preferences.d.ts +12 -1
  141. package/dist-types/primitives/accordion.d.ts +1 -1
  142. package/dist-types/primitives/button.d.ts +1 -1
  143. package/dist-types/primitives/collapsible.d.ts +1 -1
  144. package/dist-types/primitives/dialog.d.ts +1 -1
  145. package/dist-types/primitives/preference-item.d.ts +1 -1
  146. package/dist-types/primitives/switch.d.ts +1 -1
  147. package/dist-types/primitives/tabs.d.ts +1 -1
  148. package/dist-types/primitives.d.ts +7 -7
  149. package/dist-types/prompt.d.ts +1 -1
  150. package/dist-types/provider.d.ts +62 -12
  151. package/dist-types/server/fetch-ssr-data.d.ts +1 -1
  152. package/dist-types/server/index.d.ts +5 -5
  153. package/dist-types/theme-provider.d.ts +2 -2
  154. package/dist-types/types/index.d.ts +3 -3
  155. package/dist-types/types/manager.d.ts +1 -1
  156. package/dist-types/types/theme/index.d.ts +1 -1
  157. package/dist-types/ui-config-context.d.ts +3 -1
  158. package/dist-types/ui-save.d.ts +21 -1
  159. package/dist-types/utils/deferred-module.d.ts +13 -0
  160. package/dist-types/utils/index.d.ts +4 -4
  161. package/dist-types/utils/merge-slot-props.d.ts +2 -2
  162. package/dist-types/utils/merge-styles.d.ts +1 -1
  163. package/dist-types/utils/theme-utils.d.ts +1 -1
  164. package/dist-types/version.d.ts +1 -1
  165. package/docs/README.md +9 -2
  166. package/docs/customization/overview.md +4 -3
  167. package/docs/customization/recipes.md +4 -2
  168. package/docs/customization/tokens.md +66 -3
  169. package/docs/frameworks/react/components/consent-dialog.md +46 -7
  170. package/docs/frameworks/react/components/{frame.md → consent-gate.md} +35 -31
  171. package/docs/frameworks/react/components/consent-manager-provider.md +35 -11
  172. package/docs/frameworks/react/components/consent-widget.md +48 -6
  173. package/docs/frameworks/react/concepts/consent-categories.md +38 -2
  174. package/docs/frameworks/react/hooks/{use-consent-manager/overview.md → overview.md} +7 -5
  175. package/docs/frameworks/react/iab/overview.md +121 -1
  176. package/docs/frameworks/react/network-blocker.md +146 -0
  177. package/docs/frameworks/react/script-loader.md +6 -0
  178. package/docs/frameworks/react/styling/overview.md +71 -22
  179. package/docs/guides/consent-state.md +327 -0
  180. package/docs/guides/deployment-modes.md +12 -0
  181. package/docs/guides/shared-consent-controls.md +158 -0
  182. package/docs/integrations/adobe-analytics.md +1 -1
  183. package/docs/integrations/ahrefs-analytics.md +1 -1
  184. package/docs/integrations/amplitude.md +1 -1
  185. package/docs/integrations/building-integrations.md +5 -0
  186. package/docs/integrations/clearbit.md +1 -1
  187. package/docs/integrations/cloudflare-web-analytics.md +1 -1
  188. package/docs/integrations/cloudflare-zaraz.md +399 -0
  189. package/docs/integrations/crisp.md +1 -1
  190. package/docs/integrations/databuddy.md +1 -1
  191. package/docs/integrations/fathom-analytics.md +1 -1
  192. package/docs/integrations/front-chat.md +322 -0
  193. package/docs/integrations/google-maps.md +21 -21
  194. package/docs/integrations/google-tag-manager.md +1 -1
  195. package/docs/integrations/google-tag.md +1 -1
  196. package/docs/integrations/granular-consent.md +210 -0
  197. package/docs/integrations/heap.md +1 -1
  198. package/docs/integrations/hightouch.md +1 -1
  199. package/docs/integrations/hotjar.md +1 -1
  200. package/docs/integrations/intercom.md +1 -1
  201. package/docs/integrations/linkedin-insights.md +1 -1
  202. package/docs/integrations/logrocket.md +1 -1
  203. package/docs/integrations/matomo-analytics.md +1 -1
  204. package/docs/integrations/meta-pixel.md +1 -1
  205. package/docs/integrations/microsoft-clarity.md +1 -1
  206. package/docs/integrations/microsoft-uet.md +1 -1
  207. package/docs/integrations/mixpanel-analytics.md +1 -1
  208. package/docs/integrations/one-dollar-stats.md +305 -0
  209. package/docs/integrations/openai-pixel.md +1 -1
  210. package/docs/integrations/overview.md +22 -18
  211. package/docs/integrations/pinterest-tag.md +321 -0
  212. package/docs/integrations/pirsch.md +1 -1
  213. package/docs/integrations/plausible-analytics.md +1 -1
  214. package/docs/integrations/posthog.md +1 -1
  215. package/docs/integrations/promptwatch.md +1 -1
  216. package/docs/integrations/reddit-pixel.md +1 -1
  217. package/docs/integrations/rudderstack.md +1 -1
  218. package/docs/integrations/rybbit-analytics.md +1 -1
  219. package/docs/integrations/segment.md +1 -1
  220. package/docs/integrations/snapchat-pixel.md +1 -1
  221. package/docs/integrations/tiktok-pixel.md +1 -1
  222. package/docs/integrations/umami-analytics.md +1 -1
  223. package/docs/integrations/vercel-analytics.md +1 -1
  224. package/docs/integrations/x-pixel.md +1 -1
  225. package/docs/integrations/youtube.md +27 -22
  226. package/docs/upgrade-v3.md +176 -1
  227. package/package.json +26 -16
  228. package/dist/component-hooks/use-manager.js +0 -2
  229. package/dist/components/frame/atoms.js +0 -1
  230. package/dist/components/frame/frame.js +0 -2
  231. package/dist/components/frame/index.js +0 -2
  232. package/dist/frame.js +0 -2
  233. package/dist-types/component-hooks/use-manager.d.ts +0 -40
  234. package/dist-types/components/frame/atoms.d.ts +0 -11
  235. package/dist-types/components/frame/frame.d.ts +0 -2
  236. package/dist-types/components/frame/index.d.ts +0 -24
  237. package/dist-types/frame.d.ts +0 -1
  238. package/readme.json +0 -48
  239. package/src/iab/styles.css +0 -11
  240. package/src/styles.css +0 -10
  241. /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 { Frame } from 'c15t/next';
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
- <Frame category={embedCategory}>
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
- </Frame>
49
+ </ConsentGate>
50
50
  );
51
51
  }
52
52
  ```
53
53
 
54
- `Frame` keeps the iframe absent while permission is denied and removes it
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 { Frame } from 'c15t/tanstack-start';
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
- <Frame category={embedCategory}>
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
- </Frame>
75
+ </ConsentGate>
76
76
  );
77
77
  }
78
78
  ```
79
79
 
80
- `Frame` keeps the iframe absent while permission is denied and removes it
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 { Frame } from 'c15t/react';
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
- <Frame category={embedCategory}>
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
- </Frame>
101
+ </ConsentGate>
102
102
  );
103
103
  }
104
104
  ```
105
105
 
106
- `Frame` keeps the iframe absent while permission is denied and removes it
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 '@c15t/astro/client';
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 { Frame } from '@c15t/svelte';
226
+ import { ConsentGate } from '@c15t/svelte';
227
227
  import { embedCategory, embedURL, embedTitle, embedAspectRatio } from './embed-config';
228
228
  </script>
229
229
 
230
- <Frame category={embedCategory}>
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
- </Frame>
241
+ </ConsentGate>
242
242
  ```
243
243
 
244
- The Svelte `Frame` waits until the browser is mounted and the category is
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 { Frame } from '@c15t/svelte';
255
+ import { ConsentGate } from '@c15t/svelte';
256
256
  import { embedCategory, embedURL, embedTitle, embedAspectRatio } from '../embed-config';
257
257
  </script>
258
258
 
259
- <Frame category={embedCategory}>
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
- </Frame>
270
+ </ConsentGate>
271
271
  ```
272
272
 
273
- The Svelte `Frame` waits until the browser is mounted and the category is
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 `Frame` components provide a blocked-state placeholder and
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.
@@ -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 '@c15t/astro/components/consent-banner.astro';
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.1",
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/frame.d.ts",
136
- "import": "./dist/frame.js",
137
- "default": "./dist/frame.js"
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/frame/index.d.ts",
195
- "import": "./dist/components/frame/index.js",
196
- "default": "./dist/components/frame/index.js"
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.1",
237
- "@c15t/dev-tools": "3.0.0-alpha.1",
238
- "@c15t/iab": "3.0.0-alpha.1",
239
- "@c15t/schema": "3.0.0-alpha.0",
240
- "@c15t/translations": "3.0.0-alpha.0",
241
- "@c15t/ui": "3.0.0-alpha.1",
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.1",
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": "^19.0.0 || ^19.0.0-rc || ^18.0.0 || ^17.0.0 || ^16.8.0",
256
- "react-dom": "^19.0.0 || ^19.0.0-rc || ^18.0.0 || ^17.0.0 || ^16.8.0"
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,2 +0,0 @@
1
- "use client";
2
- export*from"./components/frame/index.js";
@@ -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,2 +0,0 @@
1
- import type { FrameProps } from './types';
2
- export declare const Frame: import("react").ForwardRefExoticComponent<Omit<FrameProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
@@ -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 };
@@ -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
- }
@@ -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';