@c15t/react 3.1.0 → 3.2.0
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 +35 -5
- package/README.md +2 -2
- package/dist/component-hooks/use-consent-gate.js +2 -0
- package/dist/component-hooks/use-consent-labels.js +2 -0
- package/dist/component-hooks/use-consent-text-direction.js +2 -0
- package/dist/component-hooks/use-vendors-listed-under.js +2 -0
- package/dist/components/consent-gate/atoms.js +1 -1
- package/dist/components/consent-gate/consent-gate.js +1 -1
- package/dist/components/iab-prompt/atoms/root.js +1 -1
- package/dist/components/panel-trigger/atoms/toolbar.js +1 -1
- package/dist/components/preferences/atoms/button.js +1 -1
- package/dist/components/preferences/atoms/vendor-list.js +1 -1
- package/dist/components/prompt/atoms/root.js +1 -1
- package/dist/components/prompt/components.js +1 -1
- package/dist/components/prompt/policy-actions.js +1 -1
- package/dist/components/prompt/prompt.js +1 -1
- package/dist/components/prompt/surface-context.js +1 -1
- package/dist/components/prompt/use-banner-copy.js +1 -1
- package/dist/components/shared/streamed-surface.js +1 -1
- package/dist/headless.js +1 -1
- package/dist/index-parts/offline.js +1 -1
- package/dist/modes.js +1 -1
- package/dist/styles.tw3.css +2 -2
- package/dist/transports/offline.js +1 -1
- package/dist/version.js +1 -1
- package/dist-types/component-hooks/use-consent-gate.d.ts +102 -0
- package/dist-types/component-hooks/use-consent-labels.d.ts +32 -0
- package/dist-types/component-hooks/use-consent-text-direction.d.ts +22 -0
- package/dist-types/component-hooks/use-vendors-listed-under.d.ts +30 -0
- package/dist-types/components/prompt/atoms/root.d.ts +3 -3
- package/dist-types/components/prompt/prompt.d.ts +4 -3
- package/dist-types/components/prompt/surface-context.d.ts +1 -14
- package/dist-types/components/prompt/use-banner-copy.d.ts +8 -3
- package/dist-types/components/shared/streamed-surface.d.ts +47 -10
- package/dist-types/headless.d.ts +10 -1
- package/dist-types/hooks/use-iab-policy-guard.d.ts +17 -1
- package/dist-types/hooks/use-scroll-lock.d.ts +16 -2
- package/dist-types/index-parts/offline.d.ts +1 -1
- package/dist-types/modes.d.ts +1 -1
- package/dist-types/module-hooks/script-loader.d.ts +9 -0
- package/dist-types/provider.d.ts +3 -3
- package/dist-types/transports/offline.d.ts +2 -2
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +35 -5
- package/docs/concepts/choose-your-setup.md +9 -9
- package/docs/concepts/consent-state.md +81 -9
- package/docs/concepts/data-fetching.md +30 -23
- package/docs/concepts/modes.md +87 -35
- package/docs/customization/recipes.md +4 -4
- package/docs/customization/stylesheets.md +42 -3
- package/docs/customization/tailwind.md +17 -34
- package/docs/customization/translations.md +18 -12
- package/docs/frameworks/react/clear-on-revocation.md +3 -2
- package/docs/frameworks/react/components/consent-banner.md +3 -3
- package/docs/frameworks/react/components/consent-provider.md +29 -29
- package/docs/frameworks/react/gpp.md +1 -1
- package/docs/frameworks/react/headless.md +146 -19
- package/docs/frameworks/react/hooks.md +2 -1
- package/docs/frameworks/react/iab.md +8 -1
- package/docs/frameworks/react/quickstart.md +2 -2
- package/docs/frameworks/react/rendering.md +1 -1
- package/docs/frameworks/react/translations.md +9 -9
- package/docs/frameworks/react/troubleshooting.md +1 -1
- package/docs/frameworks/react/upgrade-v3.md +39 -32
- package/docs/frameworks/react/vendor-consent.md +5 -0
- package/docs/guides/banner-experiments.md +3 -3
- package/docs/guides/troubleshooting.md +3 -2
- package/docs/integrations/activecampaign.md +297 -0
- package/docs/integrations/ada.md +396 -0
- package/docs/integrations/adobe-analytics.md +2 -2
- package/docs/integrations/adobe-target.md +460 -0
- package/docs/integrations/adroll.md +336 -0
- package/docs/integrations/ahrefs-analytics.md +2 -2
- package/docs/integrations/amazon-ads.md +424 -0
- package/docs/integrations/amplitude.md +2 -2
- package/docs/integrations/appcues.md +368 -0
- package/docs/integrations/attentive.md +313 -0
- package/docs/integrations/building-integrations.md +29 -16
- package/docs/integrations/clay.md +305 -0
- package/docs/integrations/clearbit.md +3 -3
- package/docs/integrations/cloudflare-web-analytics.md +2 -2
- package/docs/integrations/cloudflare-zaraz.md +2 -2
- package/docs/integrations/crisp.md +2 -2
- package/docs/integrations/customer-io.md +369 -0
- package/docs/integrations/databuddy.md +127 -52
- package/docs/integrations/default-com.md +497 -0
- package/docs/integrations/dynamic-yield.md +373 -0
- package/docs/integrations/fathom-analytics.md +2 -2
- package/docs/integrations/front-chat.md +2 -2
- package/docs/integrations/fullstory.md +298 -0
- package/docs/integrations/gainsight-px.md +418 -0
- package/docs/integrations/google-maps.md +2 -2
- package/docs/integrations/google-tag-manager.md +59 -2
- package/docs/integrations/google-tag.md +2 -2
- package/docs/integrations/gorgias.md +365 -0
- package/docs/integrations/heap.md +2 -2
- package/docs/integrations/hightouch.md +2 -2
- package/docs/integrations/hotjar.md +40 -26
- package/docs/integrations/hubspot.md +529 -0
- package/docs/integrations/insider.md +550 -0
- package/docs/integrations/intercom.md +2 -2
- package/docs/integrations/klaviyo.md +2 -2
- package/docs/integrations/linkedin-insights.md +2 -2
- package/docs/integrations/liveintent.md +327 -0
- package/docs/integrations/logrocket.md +2 -2
- package/docs/integrations/lucky-orange.md +336 -0
- package/docs/integrations/marketo.md +309 -0
- package/docs/integrations/matomo-analytics.md +2 -2
- package/docs/integrations/meta-pixel.md +2 -2
- package/docs/integrations/microsoft-clarity.md +2 -2
- package/docs/integrations/microsoft-uet.md +2 -2
- package/docs/integrations/mixpanel-analytics.md +2 -2
- package/docs/integrations/one-dollar-stats.md +2 -2
- package/docs/integrations/openai-pixel.md +2 -2
- package/docs/integrations/optimizely.md +411 -0
- package/docs/integrations/oracle-eloqua.md +301 -0
- package/docs/integrations/overview.md +128 -81
- package/docs/integrations/pendo.md +339 -0
- package/docs/integrations/pinterest-tag.md +2 -2
- package/docs/integrations/pirsch.md +2 -2
- package/docs/integrations/plausible-analytics.md +2 -2
- package/docs/integrations/posthog.md +2 -2
- package/docs/integrations/promptwatch.md +2 -2
- package/docs/integrations/rb2b.md +363 -0
- package/docs/integrations/reddit-pixel.md +2 -2
- package/docs/integrations/rudderstack.md +2 -2
- package/docs/integrations/rybbit-analytics.md +2 -2
- package/docs/integrations/salesforce-pardot.md +342 -0
- package/docs/integrations/segment.md +2 -2
- package/docs/integrations/sentry.md +2 -2
- package/docs/integrations/shopify.md +323 -0
- package/docs/integrations/snapchat-pixel.md +2 -2
- package/docs/integrations/statable-analytics.md +345 -0
- package/docs/integrations/the-trade-desk.md +328 -0
- package/docs/integrations/tiktok-pixel.md +2 -2
- package/docs/integrations/umami-analytics.md +2 -2
- package/docs/integrations/vector.md +333 -0
- package/docs/integrations/vercel-analytics.md +2 -2
- package/docs/integrations/vercel-speed-insights.md +7 -2
- package/docs/integrations/wisepops.md +416 -0
- package/docs/integrations/x-pixel.md +2 -2
- package/docs/integrations/youtube.md +2 -2
- package/docs/integrations/zendesk.md +359 -0
- package/package.json +10 -32
- package/dist/components/prompt/resolve-banner-primary-actions.js +0 -1
- package/dist-types/components/prompt/resolve-banner-primary-actions.d.ts +0 -14
package/AGENTS.md
CHANGED
|
@@ -39,7 +39,7 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
39
39
|
- [Customize](./docs/frameworks/react/customize.md): Change the colors, fonts, layout, button styles and copy of the c15t banner and dialog in a React app with theme tokens, provider options and slots, and load the stylesheet yourself when you need to.
|
|
40
40
|
- [Embeds](./docs/frameworks/react/embeds.md): Keep YouTube videos, maps and other iframes out of a React page until their consent category is allowed, with ConsentGate or the iframe blocker in ConsentProvider.
|
|
41
41
|
- [IAB GPP](./docs/frameworks/react/gpp.md): Add the IAB Global Privacy Platform API (__gpp) to a React app with ConsentGPP from @c15t/react/gpp, so ad tech can read US state opt-outs and the TCF EU consent string.
|
|
42
|
-
- [Headless](./docs/frameworks/react/headless.md): Build a custom consent banner in React with the c15t/react/headless hooks inside your ConsentProvider.
|
|
42
|
+
- [Headless](./docs/frameworks/react/headless.md): Build a custom consent banner or embed gate in React with the c15t/react/headless hooks inside your ConsentProvider.
|
|
43
43
|
- [Hooks](./docs/frameworks/react/hooks.md): Gate features and save consent choices in React components with the focused hooks exported from c15t/react.
|
|
44
44
|
- [IAB TCF](./docs/frameworks/react/iab.md): Mount the IAB TCF banner and dialog inside a React ConsentProvider and configure the CMP ID, policy and vendor data.
|
|
45
45
|
- [Network blocker](./docs/frameworks/react/network-blocker.md): Hold fetch and XMLHttpRequest calls in a React app until their consent category is allowed, with networkBlocker rules in the ConsentProvider options.
|
|
@@ -56,9 +56,9 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
56
56
|
- [Choose your setup](./docs/concepts/choose-your-setup.md): Pick the c15t setup for your framework, rendering mode and hosting, and decide who runs the consent backend.
|
|
57
57
|
- [Consent categories](./docs/concepts/consent-categories.md): Assign scripts, embeds and features to c15t consent categories, and understand which categories the preference dialog shows.
|
|
58
58
|
- [Consent state reference](./docs/concepts/consent-state.md): How c15t saves choices, gates IAB vendors, hydrates server records and keeps browser tabs and storage in step.
|
|
59
|
-
- [Data fetching](./docs/concepts/data-fetching.md): Choose the recommended build-time policy snapshot or runtime manifest fetching, backend /init, browser resolution or
|
|
59
|
+
- [Data fetching](./docs/concepts/data-fetching.md): Choose the recommended build-time policy snapshot or runtime manifest fetching, backend /init, browser resolution or local rules, and understand where consent choices are saved.
|
|
60
60
|
- [How consent works](./docs/concepts/how-consent-works.md): What c15t decides on each page load, the difference between a permission and a recorded choice, and what happens when a visitor saves.
|
|
61
|
-
- [Consent modes](./docs/concepts/modes.md): Reference for manifest(), hosted() and
|
|
61
|
+
- [Consent modes](./docs/concepts/modes.md): Reference for manifest(), hosted() and local() in every c15t framework package, where each one resolves the visitor's policy, what it adds to first-load JavaScript, the build-time manifest fetch and its failure policy, and the backend URL variable each framework reads.
|
|
62
62
|
- [Policies](./docs/concepts/policies.md): How policy models, prompts and scope decide what c15t asks visitors, where to change the rules, and why a banner may not appear.
|
|
63
63
|
|
|
64
64
|
## Guides
|
|
@@ -82,27 +82,46 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
82
82
|
|
|
83
83
|
## Integrations
|
|
84
84
|
|
|
85
|
+
- [ActiveCampaign](./docs/integrations/activecampaign.md): Load ActiveCampaign after marketing consent, configure its tracking settings, and verify loading and withdrawal with c15t.
|
|
86
|
+
- [Ada](./docs/integrations/ada.md): Load Ada Messaging after functionality consent with the c15t ada helper, configure regional Agents, and stop the widget when consent is revoked.
|
|
85
87
|
- [Adobe Analytics](./docs/integrations/adobe-analytics.md): Load an Adobe Data Collection Tags property only after measurement consent with the c15t adobeAnalytics helper, and check its extensions in DevTools.
|
|
88
|
+
- [Adobe Target](./docs/integrations/adobe-target.md): Gate a self-hosted Adobe Target at.js download or Adobe Experience Platform Web SDK on experience consent, send consent updates and check revocation limits.
|
|
89
|
+
- [AdRoll](./docs/integrations/adroll.md): Load AdRoll with c15t after marketing consent and verify its loader, storage and revocation behavior.
|
|
86
90
|
- [Ahrefs Analytics](./docs/integrations/ahrefs-analytics.md): Load Ahrefs Web Analytics only after measurement consent with the c15t ahrefsAnalytics helper, and check it in DevTools.
|
|
91
|
+
- [Amazon Ads](./docs/integrations/amazon-ads.md): Load Amazon Ads with c15t after marketing consent and verify its loader, storage and revocation behavior.
|
|
87
92
|
- [Amplitude](./docs/integrations/amplitude.md): Load the Amplitude Browser SDK 2 only after measurement consent with the c15t amplitude helper, which opts the SDK out on revocation and back in on a new grant.
|
|
93
|
+
- [Appcues](./docs/integrations/appcues.md): Load Appcues onboarding flows after experience consent, configure US or EU accounts, and reset the visitor on revocation.
|
|
94
|
+
- [Attentive](./docs/integrations/attentive.md): Load the Attentive tag only after marketing consent with the c15t attentiveTag helper, and check its requests and storage in DevTools.
|
|
88
95
|
- [Custom integrations](./docs/integrations/building-integrations.md): Gate a vendor that has no @c15t/integrations helper, or sync consent with an SDK your app already loads, using a c15t script configuration.
|
|
96
|
+
- [Clay](./docs/integrations/clay.md): Load Clay web intent only after marketing consent and understand its storage and revocation limits.
|
|
89
97
|
- [Clearbit](./docs/integrations/clearbit.md): Load the Clearbit enrichment tag only after marketing consent with the c15t clearbit helper, and check it in DevTools.
|
|
90
98
|
- [Cloudflare Web Analytics](./docs/integrations/cloudflare-web-analytics.md): Load the Cloudflare Web Analytics beacon only after measurement consent with the c15t cloudflareWebAnalytics helper, and check it in DevTools.
|
|
91
99
|
- [Cloudflare Zaraz](./docs/integrations/cloudflare-zaraz.md): Sync c15t permissions to Cloudflare Zaraz purposes with the c15t cloudflareZaraz bridge, which runs on every page without loading a script, and check the tools it controls.
|
|
92
100
|
- [Crisp](./docs/integrations/crisp.md): Load the Crisp chat widget only after functionality consent with the c15t crisp helper, pass its runtime settings and check it in DevTools.
|
|
93
|
-
- [
|
|
101
|
+
- [Customer.io](./docs/integrations/customer-io.md): Load Customer.io Data Pipelines only after marketing consent with the c15t customerIo helper, set up a proxy, and check withdrawal.
|
|
102
|
+
- [Databuddy](./docs/integrations/databuddy.md): Load Databuddy only after measurement consent with the c15t databuddy helper, turn off tracking features you do not use, record sessions with the replay option, and check revocation in DevTools.
|
|
103
|
+
- [Default](./docs/integrations/default-com.md): Load the Default Pixel after measurement consent or the standalone Forms SDK after functionality consent, configure loading and understand withdrawal limits.
|
|
104
|
+
- [Dynamic Yield](./docs/integrations/dynamic-yield.md): Load Dynamic Yield personalization scripts after experience consent, set the page context and synchronize Active Cookie Consent with c15t.
|
|
94
105
|
- [Fathom Analytics](./docs/integrations/fathom-analytics.md): Load Fathom Analytics only after measurement consent with the c15t fathomAnalytics helper, set its SPA mode, and check it in DevTools.
|
|
95
106
|
- [Front Chat](./docs/integrations/front-chat.md): Load the Front Chat widget only after functionality consent with the c15t frontChat helper, forward CSP nonces, clear the session on revocation and check it in DevTools.
|
|
107
|
+
- [FullStory](./docs/integrations/fullstory.md): Load FullStory after measurement consent, configure its tracking settings, and verify loading and withdrawal with c15t.
|
|
108
|
+
- [Gainsight PX](./docs/integrations/gainsight-px.md): Gate Gainsight PX product analytics and in-app engagements on consent, configure the aptrinsic snippet and disable tracking when consent is withdrawn.
|
|
96
109
|
- [Google Maps](./docs/integrations/google-maps.md): Gate a Google Maps iframe embed with c15t v3 so the map loads only after the visitor allows its consent category, in Next.js, TanStack Start, React, Nuxt, Vue, Astro, Svelte, SvelteKit, HTML or JavaScript.
|
|
97
110
|
- [Google Tag](./docs/integrations/google-tag.md): Load gtag.js for Google Analytics or Google Ads before or after consent with c15t Consent Mode v2 signals, and verify the consent commands in DevTools.
|
|
98
111
|
- [Google Tag Manager](./docs/integrations/google-tag-manager.md): Load a Google Tag Manager container before or after consent with c15t Consent Mode v2 signals, configure consent checks inside the container, and verify both in DevTools.
|
|
112
|
+
- [Gorgias Chat](./docs/integrations/gorgias.md): Load Gorgias Chat after functionality consent, disable its Segment analytics when measurement is denied, and verify loading and revocation with c15t.
|
|
99
113
|
- [Heap](./docs/integrations/heap.md): Load the Heap config script and heap.js only after measurement consent with the c15t heap helper, and check it in DevTools.
|
|
100
114
|
- [Hightouch](./docs/integrations/hightouch.md): Load the Hightouch Events browser SDK only after measurement consent with the c15t hightouch helper, and check page events in DevTools.
|
|
101
115
|
- [Hotjar](./docs/integrations/hotjar.md): Load Hotjar only after measurement consent with the c15t hotjar helper, and check its loader and recordings in DevTools.
|
|
116
|
+
- [HubSpot](./docs/integrations/hubspot.md): Gate HubSpot's tracking code on marketing consent, forward c15t categories and enable chat only after functionality consent.
|
|
117
|
+
- [Insider One](./docs/integrations/insider.md): Load Insider One after consent with current user attributes, currency and page context through the c15t insiderTag helper.
|
|
102
118
|
- [Intercom](./docs/integrations/intercom.md): Load the Intercom messenger only after functionality consent with the c15t intercom helper, set its region and check it in DevTools.
|
|
103
119
|
- [Klaviyo](./docs/integrations/klaviyo.md): Load Klaviyo signup forms and onsite tracking only after marketing and measurement consent with the c15t klaviyo helper, gate your own events, and check it in DevTools.
|
|
104
120
|
- [LinkedIn Insight Tag](./docs/integrations/linkedin-insights.md): Load the LinkedIn Insight Tag only after marketing consent with the c15t linkedinInsights helper, guard lintrk conversion calls, and check it in DevTools.
|
|
121
|
+
- [LiveIntent](./docs/integrations/liveintent.md): Load LiveIntent with c15t after marketing consent and verify its loader, storage and revocation behavior.
|
|
105
122
|
- [LogRocket](./docs/integrations/logrocket.md): Load LogRocket session replay only after measurement consent with the c15t logRocket helper, including proxied setups, and check it in DevTools.
|
|
123
|
+
- [Lucky Orange](./docs/integrations/lucky-orange.md): Load Lucky Orange after measurement consent, configure its tracking settings, and verify loading and withdrawal with c15t.
|
|
124
|
+
- [Marketo Munchkin](./docs/integrations/marketo.md): Load Adobe Marketo Munchkin after marketing consent, configure its account and cookie options, and verify tracking and revocation with c15t.
|
|
106
125
|
- [Matomo Analytics](./docs/integrations/matomo-analytics.md): Load Matomo after measurement consent with the c15t matomoAnalytics helper, or use Matomo's own consent mode, and check each mode in DevTools.
|
|
107
126
|
- [Meta Pixel](./docs/integrations/meta-pixel.md): Load the Meta Pixel only after marketing consent with the c15t metaPixel helper, guard fbq event calls, and check it in DevTools.
|
|
108
127
|
- [Microsoft Clarity](./docs/integrations/microsoft-clarity.md): Load Microsoft Clarity only after measurement consent with the c15t clarity helper, send Consent V2 storage signals and check them in DevTools.
|
|
@@ -110,21 +129,32 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
110
129
|
- [Mixpanel](./docs/integrations/mixpanel-analytics.md): Load the Mixpanel SDK on every page with the c15t mixpanelAnalytics helper, which switches Mixpanel tracking on and off with measurement consent, and check it in DevTools.
|
|
111
130
|
- [OneDollarStats](./docs/integrations/one-dollar-stats.md): Load the OneDollarStats tracker only after measurement consent with the c15t oneDollarStats helper, forward its data-attribute settings, and check it in DevTools.
|
|
112
131
|
- [OpenAI Pixel](./docs/integrations/openai-pixel.md): Load the ChatGPT Ads Measurement Pixel only after marketing consent with the c15t openaiPixel helper, guard oaiq conversion calls, and check it in DevTools.
|
|
113
|
-
- [
|
|
132
|
+
- [Optimizely](./docs/integrations/optimizely.md): Load Optimizely Web Experimentation and Personalization after experience consent with c15t, choose a consent category and understand revocation limits.
|
|
133
|
+
- [Oracle Eloqua](./docs/integrations/oracle-eloqua.md): Load Oracle Eloqua after mapped category and vendor consent, configure its tracking settings, and verify loading and withdrawal with c15t.
|
|
134
|
+
- [Integrations](./docs/integrations/overview.md): Find c15t integrations for analytics, replay, monitoring, experimentation, personalization, ads, data, chat and embeds.
|
|
135
|
+
- [Pendo](./docs/integrations/pendo.md): Load Pendo after measurement consent, configure its tracking settings, and verify loading and withdrawal with c15t.
|
|
114
136
|
- [Pinterest Tag](./docs/integrations/pinterest-tag.md): Load the Pinterest Tag only after marketing consent with the c15t pinterestTag helper, guard pintrk event calls, and check it in DevTools.
|
|
115
137
|
- [Pirsch](./docs/integrations/pirsch.md): Load Pirsch Analytics only after measurement consent with the c15t pirsch helper, keep custom event bindings working, and check it in DevTools.
|
|
116
138
|
- [Plausible Analytics](./docs/integrations/plausible-analytics.md): Load the Plausible Analytics tracker only after measurement consent with the c15t plausibleAnalytics helper, and check it in DevTools.
|
|
117
139
|
- [PostHog](./docs/integrations/posthog.md): Load PostHog before or after measurement consent with the c15t posthog helper, choose its cookieless behavior, turn off PostHog modules you do not use, and sync consent with an SDK you already initialize.
|
|
118
140
|
- [Promptwatch](./docs/integrations/promptwatch.md): Load the Promptwatch attribution client only after measurement consent with the c15t promptwatch helper, and check it in DevTools.
|
|
141
|
+
- [RB2B](./docs/integrations/rb2b.md): Load RB2B only after marketing consent with the c15t rb2b helper, and check its loader URL, page views and revocation.
|
|
119
142
|
- [Reddit Pixel](./docs/integrations/reddit-pixel.md): Load the Reddit Pixel only after marketing consent with the c15t redditPixel helper, guard rdt conversion calls, and check it in DevTools.
|
|
120
143
|
- [RudderStack](./docs/integrations/rudderstack.md): Load the RudderStack JavaScript SDK after measurement consent with the c15t rudderstack helper, or map c15t categories to destination consent IDs, and check each mode.
|
|
121
144
|
- [Rybbit Analytics](./docs/integrations/rybbit-analytics.md): Load Rybbit Analytics only after measurement consent with the c15t rybbitAnalytics helper, map its tracking options to data attributes, and check it in DevTools.
|
|
145
|
+
- [Salesforce Account Engagement](./docs/integrations/salesforce-pardot.md): Gate Salesforce Account Engagement tracking on marketing consent, configure its consent API or classic Pardot snippet, and verify revocation with c15t.
|
|
122
146
|
- [Segment](./docs/integrations/segment.md): Load Segment Analytics.js only after measurement consent with the c15t segment helper, guard your own track and identify calls, and check it in DevTools.
|
|
123
147
|
- [Sentry](./docs/integrations/sentry.md): Configure Sentry's CDN or your own SDK with consent for error monitoring, Session Replay and user data.
|
|
148
|
+
- [Shopify](./docs/integrations/shopify.md): Send c15t consent to Shopify's Customer Privacy API from a Hydrogen storefront, so Shopify analytics wait for the visitor's choice and follow each later change.
|
|
124
149
|
- [Snapchat Pixel](./docs/integrations/snapchat-pixel.md): Load the Snapchat Pixel only after marketing consent with the c15t snapchatPixel helper, guard snaptr event calls, and check it in DevTools.
|
|
150
|
+
- [Statable](./docs/integrations/statable-analytics.md): Load Statable analytics after measurement consent with the c15t statableAnalytics helper, configure its ingestion endpoint, and verify requests and browser storage.
|
|
151
|
+
- [The Trade Desk](./docs/integrations/the-trade-desk.md): Load The Trade Desk with c15t after marketing consent and verify its loader, storage and revocation behavior.
|
|
125
152
|
- [TikTok Pixel](./docs/integrations/tiktok-pixel.md): Load the TikTok Pixel only after marketing consent with the c15t tiktokPixel helper, guard ttq event calls, and check it in DevTools.
|
|
126
153
|
- [Umami Analytics](./docs/integrations/umami-analytics.md): Load the Umami Analytics tracker only after measurement consent with the c15t umamiAnalytics helper, point it at a self-hosted instance, and check it in DevTools.
|
|
154
|
+
- [Vector](./docs/integrations/vector.md): Load the Vector pixel only after marketing consent with the c15t vector helper, and check its queue, storage and revocation.
|
|
127
155
|
- [Vercel Analytics](./docs/integrations/vercel-analytics.md): Load the Vercel Web Analytics script only after measurement consent with the c15t vercelAnalytics helper, choose the debug script, and check it in DevTools.
|
|
128
156
|
- [Vercel Speed Insights](./docs/integrations/vercel-speed-insights.md): Load the Vercel Speed Insights collector only after measurement consent with the c15t vercelSpeedInsights helper, drop Web Vitals reports on revocation, and check it in DevTools.
|
|
157
|
+
- [Wisepops](./docs/integrations/wisepops.md): Load Wisepops popups, bars, embeds and notification feeds after marketing consent with c15t. Configure its site ID, cookie options and reload behavior.
|
|
129
158
|
- [X Pixel](./docs/integrations/x-pixel.md): Load the X Pixel only after marketing consent with the c15t xPixel helper, guard twq conversion events, and check it in DevTools.
|
|
130
159
|
- [YouTube](./docs/integrations/youtube.md): Gate YouTube embeds with c15t v3 in Next.js, TanStack Start, React, Nuxt, Vue, Astro, Svelte, SvelteKit or JavaScript.
|
|
160
|
+
- [Zendesk Messaging](./docs/integrations/zendesk.md): Load the Zendesk Messaging Web Widget after functionality consent, map measurement consent to its cookie ranges and clear widget storage on revocation.
|
package/README.md
CHANGED
|
@@ -29,13 +29,13 @@ c15t is used by [2,100+ sites](https://www.wappalyzer.com/technologies/cookie-co
|
|
|
29
29
|
- Headless hooks and compound components for a fully custom design
|
|
30
30
|
- Analytics, ads, and pixels follow each visitor's choice through @c15t/integrations: Google Tag Manager, Google Consent Mode v2, GA4, Meta Pixel, PostHog, and more
|
|
31
31
|
- IAB TCF 2.4 banner, dialog, and hooks through the @c15t/react/iab subpath
|
|
32
|
-
- Translations for
|
|
32
|
+
- Translations for 53 languages through @c15t/translations
|
|
33
33
|
|
|
34
34
|
## Prerequisites
|
|
35
35
|
|
|
36
36
|
- React 18 or 19
|
|
37
37
|
- Node.js 20.19 or later
|
|
38
|
-
- An [Inth project](https://inth.com) (free sign-up), a [self-hosted backend](https://c15t.com/docs/self-host/quickstart), or
|
|
38
|
+
- An [Inth project](https://inth.com) (free sign-up), a [self-hosted backend](https://c15t.com/docs/self-host/quickstart), or local mode for development and tests
|
|
39
39
|
|
|
40
40
|
## Installation
|
|
41
41
|
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{useCallback as e,useEffect as o,useMemo as t}from"react";import{useRegisterConsentCategories as s,useSetActiveUI as n}from"../hooks.js";import{useIsHydrated as l}from"../hooks/use-is-hydrated.js";import{useCategoryAllowed as i,useKernelSelector as r}from"../kernel-selector.js";import{useTranslations as c}from"./use-translations.js";let a="This content is unavailable under your region's consent policy.",p=function(e,o){let{consentGate:t,consentTypes:s}=e,n=s?.[o]?.title??o;return{actionLabel:t?.actionButton?.replace("{category}",n),categoryTitle:n,policyBlockedMessage:t?.policyBlocked??a,title:t?.title?t.title.replace("{category}",n):void 0}},u=function(a){let u,d=i(a),y=l(),m=r(e=>"strict"===e.policyRule.scopeMode&&"necessary"!==a&&!e.policyRule.scope.includes("*")&&!e.policyRule.scope.includes(a)),g=s(),_=n(),C=c();o(()=>{g([a])},[a,g]);let f=t(()=>p(C,a),[C,a]),k=e(()=>{_("dialog")},[_]);return t(()=>({...f,requestConsent:k,state:u}),[f,k,u=d?y?"granted":"pending":m?"policy-blocked":"denied"])};export{a as DEFAULT_POLICY_BLOCKED_MESSAGE,p as resolveConsentGateCopy,u as useConsentGate};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{resolveActionLabels as e,resolvePreferenceControlLabels as t}from"@c15t/core";import{useMemo as o}from"react";import{useTranslations as s}from"./use-translations.js";let r=function(){let r=s();return o(()=>({actions:e(r),preferenceControls:t(r)}),[r])};export{r as useConsentLabels};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{deniedVendorIds as e,vendorsListedUnder as r}from"@c15t/core";import{useMemo as o}from"react";import{useDeclaredVendors as s,useVendorChoice as t}from"../hooks.js";let n=function(n){let d=s(),i=t();return o(()=>r(d,n,e({vendorChoice:i,vendors:{declared:d,listVersion:null}})),[d,n,i])};export{n as useVendorsListedUnder};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Fragment as t,jsx as e,jsxs as o}from"react/jsx-runtime";import s from"@c15t/ui/styles/components/consent-gate";import{forwardRef as n}from"react";import{
|
|
1
|
+
import{Fragment as t,jsx as e,jsxs as o}from"react/jsx-runtime";import s from"@c15t/ui/styles/components/consent-gate";import{forwardRef as n}from"react";import{resolveConsentGateCopy as r}from"../../component-hooks/use-consent-gate.js";import{useTranslations as a}from"../../component-hooks/use-translations.js";import{useUIConfig as i}from"../../ui-config-context.js";import{getSlotProps as l,mergeSlotProps as m}from"../../utils/merge-slot-props.js";import{FIRST_PAINT_SHEETS as c}from"../shared/first-paint-sheets.js";import{Box as p}from"../shared/primitives/box.js";import{ConsentButton as d}from"../shared/primitives/button.js";import{SurfaceStyles as f,useSurfaceSheetsReady as u}from"../shared/surface-styles.js";let h=n(({children:n,...r},a)=>u(c,r.noStyle)?o(t,{children:[e(f,{sheets:c,noStyle:r.noStyle}),e(p,{ref:a,baseClassName:s.placeholder,"data-testid":"consent-gate-placeholder",slotKey:"consent-gate.root",...r,children:n})]}):null),g=n(({children:t,category:o,...n},i)=>{let l=a(),m=o?r(l,o).title:void 0;return e(p,{ref:i,baseClassName:s.title,"data-testid":"consent-gate-title",slotKey:"consent-gate.title",...n,children:t??m})}),y=n(({children:t,category:o,className:s,style:n,...c},p)=>{let f=a(),{components:u}=i(),h=m(l(u,"consent-gate.button"),{className:s,style:n}),g=r(f,o).actionLabel;return e(d,{mode:"stroke",size:"small",variant:"primary",...h,...c,ref:p,action:"open-consent-dialog",category:o,"data-testid":"consent-gate-button",children:t??g})});h.displayName="ConsentGateRoot",g.displayName="ConsentGateTitle",y.displayName="ConsentGateButton";export{y as ConsentGateButton,h as ConsentGateRoot,g as ConsentGateTitle};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{jsx as e,jsxs as o}from"react/jsx-runtime";import{forwardRef as
|
|
2
|
+
import{jsx as e,jsxs as o}from"react/jsx-runtime";import{forwardRef as t}from"react";import{useConsentGate as r}from"../../component-hooks/use-consent-gate.js";import{ConsentGateButton as l,ConsentGateRoot as n,ConsentGateTitle as c}from"./atoms.js";let a=({category:t,policyBlocked:r,policyBlockedMessage:a})=>o(n,{children:[e(c,{category:t,children:r?a:void 0}),r?null:e(l,{category:t})]}),i=t(({children:o,category:t,placeholder:l,noStyle:n,className:c,theme:i,...m},s)=>{let{state:d,policyBlockedMessage:p}=r(t);return e("div",{ref:s,className:c,...m,children:"granted"===d?o:"pending"===d?null:l||e(a,{category:t,policyBlocked:"policy-blocked"===d,policyBlockedMessage:p})})});i.displayName="ConsentGate";let m=i;export{m as ConsentGate};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{Fragment as e,jsx as t,jsxs as o}from"react/jsx-runtime";import r from"@c15t/ui/styles/components/iab-consent-banner";import{forwardRef as n,useMemo as s}from"react";import{ConsentTrackingContext as a}from"../../../context/consent-tracking-context.js";import{LocalThemeContext as i}from"../../../context/theme-context.js";import{useActiveUI as m,useModel as l,useTranslations as c}from"../../../hooks.js";import{useIABConsentManager as d}from"../../../hooks/use-iab-manager.js";import{useLateEntry as p}from"../../../hooks/use-late-entry.js";import{useTextDirection as b}from"../../../hooks/use-text-direction.js";import{useUIConfig as f}from"../../../ui-config-context.js";import{mergeSlotProps as u}from"../../../utils/merge-slot-props.js";import{IAB_FIRST_PAINT_SHEETS as h}from"../../shared/iab-first-paint-sheets.js";import{SurfaceStyles as j,useSurfaceSheetsReady as
|
|
2
|
+
import{Fragment as e,jsx as t,jsxs as o}from"react/jsx-runtime";import r from"@c15t/ui/styles/components/iab-consent-banner";import{forwardRef as n,useMemo as s}from"react";import{ConsentTrackingContext as a}from"../../../context/consent-tracking-context.js";import{LocalThemeContext as i}from"../../../context/theme-context.js";import{useActiveUI as m,useModel as l,useTranslations as c}from"../../../hooks.js";import{useIABConsentManager as d}from"../../../hooks/use-iab-manager.js";import{useLateEntry as p}from"../../../hooks/use-late-entry.js";import{useTextDirection as b}from"../../../hooks/use-text-direction.js";import{useUIConfig as f}from"../../../ui-config-context.js";import{mergeSlotProps as u}from"../../../utils/merge-slot-props.js";import{IAB_FIRST_PAINT_SHEETS as h}from"../../shared/iab-first-paint-sheets.js";import{SurfaceStyles as j,useSurfaceSheetsReady as x}from"../../shared/surface-styles.js";import{IABConsentBannerOverlay as y}from"./overlay.js";let g=["iab"],N=n(({children:n,className:s,style:a,className:i,disableAnimation:d,noStyle:N,models:k=g,...v},B)=>{let C=m(),{components:$}=f(),A=l(),I=c(),S=b(I?.language??"en"),P=x(h,N)&&null!==A&&"banner"===C&&k.includes(A),R=p(P)&&!d,E=u($?.["iab-banner"]?.root,{baseClassName:[r.root],className:s||i,noStyle:N,style:a,...v}),F=N?E.className||"":`${E.className||""} ${r.bannerVisible}${d?"":` ${r.bannerEntering}`}`;return P?o(e,{children:[t(j,{sheets:h,noStyle:N}),t(y,{}),o("div",{ref:B,...E,className:F,"data-position":"bottom-left","data-entry":R?"late":void 0,"data-testid":"iab-consent-banner-root","data-c15t-streamed":"",dir:S,tabIndex:-1,children:[n,t("span",{"data-c15t-stream-end":"",hidden:!0})]})]}):null}),k=({children:e,className:o,noStyle:r,disableAnimation:n,scrollLock:m,trapFocus:l,models:c,uiSource:p,...b})=>{let{policyBanner:f}=d({prompt:{scrollLock:m,trapFocus:l}}),u=f.blocking,h=s(()=>({disableAnimation:n,noStyle:r,scrollLock:u,trapFocus:u}),[n,r,u]),j=s(()=>({uiSource:p??"iab_banner"}),[p]);return t(a.Provider,{value:j,children:t(i.Provider,{value:h,children:t(N,{disableAnimation:n,className:o,noStyle:r,models:c,...b,children:e})})})};N.displayName="IABConsentBannerRootChildren";export{k as IABConsentBannerRoot};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{jsx as e}from"react/jsx-runtime";import{createElement as t,useLayoutEffect as o,useMemo as r,useRef as i,useState as n}from"react";import
|
|
2
|
+
import{jsx as e}from"react/jsx-runtime";import{createElement as t,useLayoutEffect as o,useMemo as r,useRef as i,useState as n}from"react";import l from"@c15t/ui/styles/components/consent-dialog-trigger";import{followDevToolsDock as s}from"@c15t/ui/utils/devtools-launcher";import{useConsentLabels as a}from"../../../component-hooks/use-consent-labels.js";import{useDevToolsLauncher as d}from"../../../devtools-launcher.js";import{usePolicyRule as c}from"../../../hooks.js";import{useTheme as f}from"../../../hooks/use-theme.js";import{useUIConfig as m}from"../../../ui-config-context.js";import{mergeSlotProps as g}from"../../../utils/merge-slot-props.js";import{TriggerIcon as u}from"./icon.js";import{useTriggerContext as p}from"./root.js";import{DevToolsIcon as b}from"./trigger-icons.js";let h={"bottom-left":l.bottomLeft,"bottom-right":l.bottomRight,"top-left":l.topLeft,"top-right":l.topRight},k={lg:l.lg,md:l.md,sm:l.sm},y={focusId:"devtools",icon:e(b,{}),id:"devtools",kind:"devtools",label:"c15t DevTools"},v=function(){let e=c(),{preferenceControls:t}=a();return r(()=>{let o=e.rights.includes("opt-out")?"opt-out":"preferences";return{label:"opt-out"===o&&e.i18n?.messageProfile!=="preferences"?t["opt-out"]:t.preferences,right:o,rights:e.rights.join(" ")}},[e.rights,e.i18n?.messageProfile,t])},I=function(e,t,o,r,i,n){let l=e.map(e=>({...e,focusId:`custom:${e.id}`,kind:"custom"}));return(n&&l.push(y),i)?[...l,{className:t.className,focusId:"preferences",icon:t.icon??"branding",id:"preferences",kind:"preferences",label:t.label??r,onSelect:t.onSelect,right:o,style:t.style}]:l},j=function(e,t,o){let r=e.find(e=>"preferences"===e.kind),i=e.find(e=>"devtools"===e.kind);if(!r&&!i)return e;let n=e.filter(e=>"custom"===e.kind),l="horizontal"===t?o.endsWith("left"):o.startsWith("top"),s=r?[r]:[],a=i?[i]:[];return l?[...s,...n,...a]:[...a,...n,...s]},N=({actions:a,preferences:c,size:b="md",orientation:y="horizontal",ariaLabel:N="Privacy controls",showPreferences:S=!0,className:w,style:x,noStyle:C=!1})=>{let{components:D}=m(),{disableAnimation:T,noStyle:A}=f(),{label:L,right:P,rights:R}=v(),{corner:z,isDragging:E,isSnapping:H,wasDragged:W,handlers:B,dragStyle:F,openDialog:K}=p(),M=d(),O=null!==M,U=M?.dock,V=i(null),$=r(()=>j(I(a,c,P,L,S,O),y,z),[a,z,L,y,c,P,O,S]);o(()=>{let e=V.current;if(U&&e&&!E)return s(e,z,U)},[z,U,E]);let q=$.find(e=>!e.disabled)?.focusId,[G,J]=n(q),Q=i(new Map),X=C||A,Y=g(D?.trigger?.toolbar,{baseClassName:[l.toolbar,"vertical"===y&&l.toolbarVertical,h[z],E&&l.dragging,H&&l.snapping],className:w,noStyle:X,style:x}),Z=g(D?.trigger?.toolbarItem,{baseClassName:[l.toolbarItem,k[b]],noStyle:X}),_=g(D?.trigger?.toolbarIcon,{baseClassName:l.toolbarIcon,noStyle:X}),ee=$.some(e=>e.focusId===G&&!e.disabled)?G:q;return e("div",{...Y,"aria-label":N,"aria-orientation":y,"data-corner":z,"data-c15t-trigger-toolbar":"true","data-c15t-trigger":"true","data-disable-animation":T?"":void 0,"data-dragging":E||void 0,"data-snapping":H||void 0,dir:"ltr",onKeyDown:e=>{let t,o="vertical"===y?"ArrowDown":"ArrowRight",r="vertical"===y?"ArrowUp":"ArrowLeft";if(e.key!==o&&e.key!==r&&"Home"!==e.key&&"End"!==e.key)return;let i=$.filter(e=>!e.disabled);if(0===i.length)return;e.preventDefault();let n=i.findIndex(e=>e.focusId===ee);t="Home"===e.key?0:"End"===e.key?i.length-1:e.key===o?(n+1)%i.length:(n-1+i.length)%i.length;let l=i[t];l&&(J(l.focusId),Q.current.get(l.focusId)?.focus())},ref:V,role:"toolbar",style:{...Y.style,...F},tabIndex:-1,...B,children:$.map(o=>t("button",{...Z,key:o.focusId,ref:e=>{e?Q.current.set(o.focusId,e):Q.current.delete(o.focusId)},"aria-label":o.label,"aria-expanded":"devtools"===o.kind?M?.isOpen:void 0,"aria-pressed":"custom"===o.kind?o.pressed:void 0,className:[Z.className,o.className].filter(Boolean).join(" "),"data-c15t-rights":"preferences"===o.kind?R:void 0,"data-c15t-trigger-action":o.kind,"data-c15t-trigger-item":o.id,"data-right":"preferences"===o.kind?o.right:void 0,disabled:o.disabled,onClick:e=>((e,t)=>{if(!(0!==e.detail&&W())){if("devtools"===t.kind)return void M?.toggle();t.onSelect?.(),"preferences"===t.kind&&K()}})(e,o),onFocus:()=>J(o.focusId),style:{...Z.style,...o.style},tabIndex:o.focusId===ee?0:-1,type:"button"},e("span",{..._,"aria-hidden":"true",children:e(u,{icon:o.icon,noStyle:X})})))})};N.displayName="ConsentDialogTriggerToolbar";export{N as TriggerToolbar};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as t}from"react/jsx-runtime";import{forwardRef as e}from"react";import{
|
|
1
|
+
import{jsx as t}from"react/jsx-runtime";import{forwardRef as e}from"react";import{useConsentLabels as n}from"../../../component-hooks/use-consent-labels.js";import{ConsentButton as o}from"../../shared/primitives/button.js";let s=e(({children:e,...s},c)=>{let i=n();return t(o,{ref:c,size:"small",action:"accept-consent",consentAction:"accept",...s,slotKey:"button.secondary","data-testid":"consent-widget-footer-accept-all-button",closeConsentBanner:!0,closeConsentDialog:!0,children:e??i.actions.accept})});s.displayName="ConsentWidgetAcceptAllButton";let c=e(({children:e,...s},c)=>{let i=n();return t(o,{ref:c,action:"open-consent-dialog",consentAction:"customize",...s,slotKey:"button.secondary","data-testid":"consent-widget-footer-customize-button",children:e??i.actions.customize})});c.displayName="ConsentWidgetCustomizeButton";let i=e(({children:e,...s},c)=>{let i=n();return t(o,{ref:c,action:"custom-consent",consentAction:"save",closeConsentDialog:!0,...s,slotKey:"button.primary","data-testid":"consent-widget-footer-save-button",children:e??i.actions.save})});i.displayName="ConsentWidgetSaveButton";let a=e(({children:e,...s},c)=>{let i=n();return t(o,{ref:c,size:"small",action:"reject-consent",consentAction:"reject",...s,slotKey:"button.secondary","data-testid":"consent-widget-reject-button",closeConsentBanner:!0,closeConsentDialog:!0,children:e??i.actions.reject})});a.displayName="ConsentWidgetRejectButton";let l=s,r=c,u=i,d=a;export{l as AcceptAllButton,s as ConsentWidgetAcceptAllButton,c as ConsentWidgetCustomizeButton,a as ConsentWidgetRejectButton,i as ConsentWidgetSaveButton,r as CustomizeButton,d as RejectButton,u as SaveButton};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as e,jsxs as t}from"react/jsx-runtime";import
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import n from"@c15t/ui/styles/components/vendor-list";import{useId as o,useState as r}from"react";import{useTranslations as i}from"../../../component-hooks/use-translations.js";import{useVendorsListedUnder as s}from"../../../component-hooks/use-vendors-listed-under.js";import{Box as l}from"../../shared/primitives/box.js";import{useConsentDraftSlice as d,useConsentDraftStore as a}from"../../../draft.js";import{useTheme as c}from"../../../hooks/use-theme.js";import*as h from"../../shared/ui/preference-item/index.js";import*as m from"../../shared/ui/switch/index.js";let y=({open:n})=>t("svg",{"aria-hidden":"true",fill:"none",focusable:"false",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"2",viewBox:"0 0 24 24",children:[e("title",{children:n?"Close":"Open"}),n?e("path",{d:"M5 12h14"}):e("path",{d:"M5 12h14M12 5v14"})]}),p={disabledByCategory:"Turn on this category to choose vendors.",privacyPolicy:"Privacy policy",switchLabel:"Allow {vendor}",title:"Vendors ({count})"},v=({category:n,categoryOn:o,checked:i,copy:s,labelId:d,noStyle:a,onCheckedChange:c,styles:p,vendor:v})=>{let[g,u]=r(!1),C=v.name??v.id,b=!0!==v.disabled,f=!!(v.description||v.privacyPolicyUrl);return t(h.Root,{className:p?.item,"data-testid":`consent-widget-vendor-item-${n}-${v.id}`,disabled:!f,noStyle:a,onOpenChange:u,open:g,slotKey:"vendor-list.item",children:[t(l,{noStyle:a,baseClassName:p?.header,slotKey:"vendor-list.header",children:[t(h.Trigger,{className:p?.trigger,"data-testid":`consent-widget-vendor-trigger-${n}-${v.id}`,noStyle:a,slotKey:"vendor-list.trigger",children:[e(h.Leading,{className:p?.arrow,noStyle:a,children:e(y,{open:g})}),e(l,{asChild:!0,noStyle:a,baseClassName:p?.name,slotKey:"vendor-list.name",children:e("span",{"data-testid":`consent-widget-vendor-name-${n}-${v.id}`,id:d,children:C})})]}),b?e(l,{noStyle:a,baseClassName:p?.control,slotKey:"vendor-list.control",children:e(m.Root,{"aria-label":s.switchLabel.replace("{vendor}",C),"aria-describedby":d,checked:i,"data-testid":`consent-widget-vendor-switch-${n}-${v.id}`,disabled:!o,onCheckedChange:c,size:"small"})}):null]}),f?t(h.Content,{className:p?.content,"data-testid":`consent-widget-vendor-content-${n}-${v.id}`,innerClassName:p?.contentInner,noStyle:a,slotKey:"vendor-list.content",children:[v.description?e(l,{asChild:!0,noStyle:a,baseClassName:p?.description,slotKey:"vendor-list.description",children:e("p",{children:v.description})}):null,v.privacyPolicyUrl?e(l,{asChild:!0,noStyle:a,baseClassName:p?.link,slotKey:"vendor-list.link",children:e("a",{href:v.privacyPolicyUrl,rel:"noopener noreferrer",target:"_blank",children:s.privacyPolicy})}):null]}):null]})},g=({category:r,className:h,noStyle:m,...y})=>{let g=s(r),u=a(),C=d(u,e=>!0===e.values[r]),b=d(u,e=>e.vendors),{consentManagerDialog:f}=i(),{noStyle:$}=c(),k=o(),w=m??$??!1;if(0===g.length)return null;let N={...p,...f.vendors},S=w?void 0:n,j=N.title.replace("{count}",String(g.length));return e(l,{asChild:!0,className:h,"data-testid":`consent-widget-vendor-list-${r}`,noStyle:w,baseClassName:S?.root,slotKey:"vendor-list.root",...y,children:t("section",{"aria-label":j,children:[C?null:e("p",{className:S?.hint,"data-testid":`consent-widget-vendor-hint-${r}`,children:N.disabledByCategory}),g.map(t=>e(v,{category:r,categoryOn:C,checked:b[t.id]??!0,copy:N,labelId:`${k}vendor-${r}-${t.id}`,noStyle:w,onCheckedChange:e=>u.setVendor(t.id,e),styles:S,vendor:t},t.id))]})})};export{g as ConsentWidgetVendorList};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{Fragment as o,jsx as t,jsxs as r}from"react/jsx-runtime";import e from"@c15t/ui/styles/components/consent-banner";import{forwardRef as
|
|
2
|
+
import{Fragment as o,jsx as t,jsxs as r}from"react/jsx-runtime";import e from"@c15t/ui/styles/components/consent-banner";import{forwardRef as s,useMemo as i}from"react";import{useHeadlessConsentUI as n}from"../../../component-hooks/use-headless-consent-ui.js";import{ConsentTrackingContext as a}from"../../../context/consent-tracking-context.js";import{LocalThemeContext as l}from"../../../context/theme-context.js";import{useActiveUI as m,useHasConsentUI as c,useModel as p,usePolicyRule as d,useTranslations as u}from"../../../hooks.js";import{useIABPolicyGuard as f}from"../../../hooks/use-iab-policy-guard.js";import{useLateEntry as h}from"../../../hooks/use-late-entry.js";import{useTextDirection as j}from"../../../hooks/use-text-direction.js";import{useUIConfig as b}from"../../../ui-config-context.js";import{defaultTranslationConfig as g}from"../../../utils/default-translation-config.js";import{mergeSlotProps as v}from"../../../utils/merge-slot-props.js";import{FIRST_PAINT_SHEETS as k}from"../../shared/first-paint-sheets.js";import{StreamedConsentSurface as y}from"../../shared/streamed-surface.js";import{SurfaceStyles as x,useSurfaceSheetsReady as N}from"../../shared/surface-styles.js";import{ConsentBannerSurfaceContext as S,useConsentBannerSurface as C}from"../surface-context.js";import{EarlyTapScript as $}from"./early-tap-script.js";import{Overlay as L}from"./overlay.js";let P=["opt-in","opt-out"],R=s(({asChild:s,children:i,className:n,style:a,className:l,disableAnimation:y,noStyle:S,models:R=P,...B},F)=>{f();let A=m(),{components:E}=b(),V=c(),q=p()??"opt-in",w=d(),z=C(),D=u(),G=j(D?.language??g.defaultLanguage),H=N(k,S)&&V&&"banner"===A&&R.includes(q),I=h(H)&&!y,J=v(E?.banner?.root,{baseClassName:e.root,className:n||l,noStyle:S,style:a,...B}),K=S?J.className||"":`${J.className||""} ${y?"":`${e.bannerVisible} ${e.bannerEntering}`}`;return H?r(o,{children:[t($,{}),t(x,{sheets:k,noStyle:S}),t(L,{}),t("div",{ref:F,...J,className:K,"data-variant":z.variant,"data-position":z.position,"data-blocking":z.blocking?"true":void 0,"data-prompt":w.prompt,"data-model":w.model,"data-entry":I?"late":void 0,"data-testid":"consent-banner-root",dir:G,children:i})]}):null}),B=({children:o,className:r,noStyle:e,disableAnimation:s,scrollLock:m,trapFocus:c,models:p,uiSource:d,variant:u,position:f,blocking:h,...j})=>{let{banner:b}=n({prompt:{blocking:h,position:f,scrollLock:m,trapFocus:c,variant:u}}),g=b.scrollLock,v=b.trapFocus,k=i(()=>({disableAnimation:s,noStyle:e,scrollLock:g,trapFocus:v}),[s,e,g,v]),y=i(()=>({blocking:b.blocking,position:b.position,positionSource:b.positionSource,variant:b.variant}),[b.blocking,b.position,b.positionSource,b.variant]),x=i(()=>({uiSource:d??"banner"}),[d]);return t(a.Provider,{value:x,children:t(l.Provider,{value:k,children:t(S.Provider,{value:y,children:t(R,{disableAnimation:s,className:r,noStyle:e,models:p,...j,children:o})})})})};R.displayName="ConsentBannerRootChildren";let F=o=>t(y,{children:t(B,{...o})}),A=F;export{F as ConsentBannerRoot,A as Root};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as e,jsxs as
|
|
1
|
+
import{jsx as e,jsxs as n}from"react/jsx-runtime";import t from"@c15t/ui/styles/components/consent-actions";import o from"@c15t/ui/styles/components/consent-banner";import{forwardRef as s,isValidElement as r,useRef as a}from"react";import{useConsentLabels as i}from"../../component-hooks/use-consent-labels.js";import{useHeadlessConsentUI as l}from"../../component-hooks/use-headless-consent-ui.js";import{useComposedRefs as c}from"../shared/libs/compose-refs.js";import{Slot as d}from"../shared/libs/slot.js";import{usePolicyRule as m,useSetActiveUI as p}from"../../hooks.js";import{useFocusTrap as u}from"../../hooks/use-focus-trap.js";import{useTheme as b}from"../../hooks/use-theme.js";import{useUIConfig as h}from"../../ui-config-context.js";import{getSlotProps as C,mergeSlotProps as f}from"../../utils/merge-slot-props.js";import{Box as B}from"../shared/primitives/box.js";import{ConsentButton as y}from"../shared/primitives/button.js";import{InlineLegalLinks as g}from"../shared/primitives/legal-links/index.js";import{useConsentBannerSurface as j}from"./surface-context.js";import{useBannerCopy as N}from"./use-banner-copy.js";let k=s(({children:n,asChild:t,...s},a)=>{let{title:i}=N();return e(B,{ref:a,baseClassName:o.title,"data-testid":"consent-banner-title",slotKey:"banner.title",...s,asChild:!0,children:t&&r(n)?n:e("h2",{children:n??i})})});k.displayName="ConsentBannerTitle";let x=s(({children:t,legalLinks:s,asChild:a,className:i,style:l,noStyle:c,...m},p)=>{let{description:u}=N(),{components:C}=h(),{noStyle:B}=b(),y="banner",j=f(C?.description?.[y],{baseClassName:o.description,className:i,"data-context":y,"data-testid":"consent-banner-description",noStyle:c??B,style:l,...m});return a&&r(t)?e(d,{ref:p,...j,children:t}):n("div",{ref:p,...j,children:[t??u,e(g,{links:s,context:"banner",testIdPrefix:"consent-banner-legal-link"})]})});x.displayName="ConsentBannerDescription";let R=s(({children:n,className:t,style:s,...r},a)=>{let{components:i}=h(),{noStyle:l}=b(),c=f(i?.banner?.actions,{baseClassName:t,noStyle:l,style:s,...r});return e(B,{ref:a,baseClassName:o.footer,"data-testid":"consent-banner-footer",slotKey:"banner.footer",...c,children:n})});R.displayName="ConsentBannerFooter";let S=s(({children:n,...t},s)=>{let{blocking:r}=j(),{title:i}=N(),l=a(null),d=c(l,s);return u(r,l),e(B,{ref:d,tabIndex:-1,baseClassName:o.card,"data-testid":"consent-banner-card",slotKey:"banner.card","aria-label":t["aria-label"]||i,"aria-modal":r?"true":void 0,role:r?"dialog":"region",...t,children:n})});S.displayName="ConsentBannerCard";let v=s(({children:n,...t},s)=>e(B,{ref:s,baseClassName:o.header,"data-testid":"consent-banner-header",slotKey:"banner.header",...t,children:n}));v.displayName="ConsentBannerHeader";let A=s(({children:n,...o},s)=>e(B,{ref:s,baseClassName:t.actionGroup,"data-testid":"consent-banner-footer-sub-group",slotKey:"banner.actionGroup",...o,children:n}));A.displayName="ConsentBannerFooterSubGroup";let z=s(({children:n,...t},o)=>{let s=i();return e(y,{ref:o,action:"reject-consent",consentAction:"reject","data-testid":"consent-banner-reject-button",closeConsentBanner:!0,...t,children:n??s.actions.reject})});z.displayName="ConsentBannerRejectButton";let D=s(({children:n,...t},o)=>{let s=i();return e(y,{ref:o,action:"open-consent-dialog",consentAction:"customize","data-testid":"consent-banner-customize-button",...t,children:n??s.actions.customize})});D.displayName="ConsentBannerCustomizeButton";let F=s(({children:n,...t},o)=>{let s=i(),{noStyle:r}=b();return e(y,{ref:o,action:"accept-consent",consentAction:"accept","data-testid":"consent-banner-accept-button",closeConsentBanner:!0,noStyle:r,...t,children:n??s.actions.accept})});F.displayName="ConsentBannerAcceptButton";let K=s(({children:n,...t},o)=>{let s=i(),{noStyle:r}=b();return e(y,{ref:o,action:"dismiss-notice",consentAction:"dismiss","data-action":"dismiss","data-testid":"consent-banner-dismiss-button",noStyle:r,...t,children:n??s.actions.dismiss})});K.displayName="ConsentBannerDismissButton";let G=s(({right:n,children:t,asChild:s,className:r,style:a,noStyle:l,onClick:c,...u},B)=>{let y=i(),g=m(),{components:j}=h(),{noStyle:N}=b(),k=p(),x=y.preferenceControls[n];return e(s?d:"button",{ref:B,type:s?void 0:"button",...f(C(j,"banner.rightLink"),{baseClassName:o.rightLink,className:r,noStyle:l??N,style:a}),"data-action":"right","data-right":n,"data-c15t-rights":g.rights.join(" "),"data-testid":`consent-banner-right-link-${n}`,onClick:e=>{c?.(e),e.defaultPrevented||k("dialog")},...u,children:t??x})});G.displayName="ConsentBannerRightLink";let L=s(({rights:n,children:t,...s},r)=>{let{banner:a}=l(),i=(n??a.preferenceControls).filter(e=>"disclosure"!==e);return void 0===t&&0===i.length?null:e(B,{ref:r,baseClassName:o.rights,"data-testid":"consent-banner-rights",slotKey:"banner.rights",...s,children:t??i.map(n=>e(G,{right:n},n))})});L.displayName="ConsentBannerRights";let H=k,T=x,I=R,P=A,$=S,q=v,w=z,E=D,J=F,M=K,O=L,Q=G;export{J as AcceptButton,$ as Card,F as ConsentBannerAcceptButton,S as ConsentBannerCard,D as ConsentBannerCustomizeButton,x as ConsentBannerDescription,K as ConsentBannerDismissButton,R as ConsentBannerFooter,A as ConsentBannerFooterSubGroup,v as ConsentBannerHeader,z as ConsentBannerRejectButton,G as ConsentBannerRightLink,L as ConsentBannerRights,k as ConsentBannerTitle,E as CustomizeButton,T as Description,M as DismissButton,I as Footer,P as FooterSubGroup,q as Header,w as RejectButton,Q as RightLink,O as Rights,H as Title};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{jsx as t}from"react/jsx-runtime";import{useHeadlessConsentUI as
|
|
2
|
+
import{jsx as t}from"react/jsx-runtime";import{useHeadlessConsentUI as e}from"../../component-hooks/use-headless-consent-ui.js";import{PolicyActionsRenderer as n}from"../shared/policy-actions.js";import{ConsentBannerAcceptButton as o,ConsentBannerCustomizeButton as s,ConsentBannerDismissButton as r,ConsentBannerFooter as c,ConsentBannerFooterSubGroup as a,ConsentBannerRejectButton as i,ConsentBannerRights as u}from"./components.js";let d=function(e,n){let{key:c,consentAction:a,...u}=n;switch(e){case"accept":return t(o,{consentAction:a,"data-testid":"consent-banner-accept-button",...u},c);case"reject":return t(i,{consentAction:a,"data-testid":"consent-banner-reject-button",...u},c);case"customize":return t(s,{consentAction:a,"data-testid":"consent-banner-customize-button",...u},c);case"dismiss":return t(r,{consentAction:a,"data-testid":"consent-banner-dismiss-button",...u},c);case"save":return null;default:throw Error(`Unhandled consent banner action: ${e}`)}},m=({children:o,renderAction:s})=>{let{banner:r}=e();return t(n,{state:r,leading:void 0===o?t(u,{rights:r.preferenceControls}):o,Footer:c,FooterSubGroup:a,classNames:{},renderAction:s,renderDefaultAction:d})},l=m;export{m as ConsentBannerPolicyActions,l as PolicyActions};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{jsx as t,jsxs as n}from"react/jsx-runtime";import e from"@c15t/ui/styles/components/consent-actions";import r from"@c15t/ui/styles/components/consent-banner";import{Fragment as o}from"react";import{useHeadlessConsentUI as i}from"../../component-hooks/use-headless-consent-ui.js";import{Box as s}from"../shared/primitives/box.js";import{BrandingLink as a}from"../shared/ui/branding.js";import{useComponentConfig as c}from"../../hooks/use-component-config.js";import{useIABPolicyGuard as l}from"../../hooks/use-iab-policy-guard.js";import{
|
|
2
|
+
import{jsx as t,jsxs as n}from"react/jsx-runtime";import e from"@c15t/ui/styles/components/consent-actions";import r from"@c15t/ui/styles/components/consent-banner";import{Fragment as o}from"react";import{useHeadlessConsentUI as i}from"../../component-hooks/use-headless-consent-ui.js";import{Box as s}from"../shared/primitives/box.js";import{BrandingLink as a}from"../shared/ui/branding.js";import{useComponentConfig as c}from"../../hooks/use-component-config.js";import{useIABPolicyGuard as l}from"../../hooks/use-iab-policy-guard.js";import{StreamedConsentSurface as d}from"../shared/streamed-surface.js";import{ConsentBannerRoot as m}from"./atoms/root.js";import{ConsentBannerAcceptButton as u,ConsentBannerCard as p,ConsentBannerCustomizeButton as h,ConsentBannerDescription as b,ConsentBannerDismissButton as f,ConsentBannerFooter as y,ConsentBannerFooterSubGroup as g,ConsentBannerHeader as j,ConsentBannerRejectButton as k,ConsentBannerRights as A,ConsentBannerTitle as v}from"./components.js";import{ErrorBoundary as N}from"./error-boundary.js";let S=({noStyle:d,disableAnimation:S,scrollLock:w,trapFocus:C,title:L,description:x,rejectButtonText:z,customizeButtonText:F,acceptButtonText:P,dismissButtonText:B,legalLinks:$,hideBranding:G=!1,layout:E,direction:K,primaryButton:R,models:U,uiSource:q,variant:D,position:H,blocking:I})=>{l();let{banner:J}=i({prompt:{blocking:I,direction:K,layout:E,position:H,primaryActions:"string"==typeof R?[R]:R,scrollLock:w,trapFocus:C,variant:D}}),M=c({disableAnimation:S,noStyle:d,scrollLock:J.scrollLock,trapFocus:J.trapFocus}),{orderedActions:O}=J,Q=new Set(O),T=J.actionGroups,V=J.direction,{shouldFillActions:W}=J,X=(n,e)=>{if(!Q.has(n))return null;let r=J.primaryActions.includes(n);switch(n){case"reject":return t(k,{consentAction:"reject",isPrimary:r,className:e,"data-action":"reject","data-testid":"consent-banner-reject-button",children:z});case"accept":return t(u,{consentAction:"accept",isPrimary:r,className:e,"data-action":"accept","data-testid":"consent-banner-accept-button",children:P});case"customize":return t(h,{consentAction:"customize",isPrimary:r,className:e,"data-action":"customize","data-testid":"consent-banner-customize-button",children:F});case"dismiss":return t(f,{consentAction:"dismiss",isPrimary:r,className:e,"data-action":"dismiss","data-testid":"consent-banner-dismiss-button",children:B});case"save":return null;default:throw Error(`Unhandled consent banner button type: ${n}`)}};return t(N,{fallback:t("div",{children:"Something went wrong with the Consent Banner."}),children:t(m,{...M,models:U,uiSource:q,variant:D,position:H,blocking:I,children:n(s,{baseClassName:r.cardShell,slotKey:"banner.cardShell",children:[t(a,{hideBranding:G,variant:"banner-tag",slotContext:"banner","data-testid":"consent-banner-branding"}),n(p,{children:[n(j,{children:[t(v,{children:L}),t(b,{legalLinks:$,children:x})]}),n(y,{className:e.actionRoot,"data-direction":V,"data-fill":!!W||void 0,"data-split":T.length>1&&!W||void 0,children:[t(A,{rights:J.preferenceControls}),T.map((n,r)=>{if(Array.isArray(n)){let i=n.filter(t=>Q.has(t));if(0===i.length)return null;let s=n.join("-");return t(g,{className:e.actionGroup,"data-direction":V,"data-fill":!!W||void 0,children:i.map(n=>t(o,{children:X(n)},n))},s?`group-${s}`:`group-${r}`)}return Q.has(n)?t(o,{children:X(n)},n):null})]})]})]})})})},w=n=>t(d,{children:t(S,{...n})});export{w as ConsentBanner};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{createContext as
|
|
2
|
+
import{createContext as n,useContext as e}from"react";let t={blocking:!1,position:"bottom-left",positionSource:"default",variant:"floating"},o=n(t),r=function(){return e(o)};export{o as ConsentBannerSurfaceContext,t as DEFAULT_CONSENT_BANNER_SURFACE,r as useConsentBannerSurface};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{useTranslations as
|
|
2
|
+
import{resolvePromptCopy as o}from"@c15t/core";import{useMemo as r}from"react";import{useTranslations as e}from"../../component-hooks/use-translations.js";import{usePolicyRule as t}from"../../hooks.js";let n=function(){let n=e(),{prompt:s}=t();return r(()=>({...o(n,s),prompt:s}),[n,s])};export{n as useBannerCopy};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{jsx as e}from"react/jsx-runtime";import{HydrationSnapshotContext as r,StreamedPrefetchContext as t}from"../../context.js";import{useKernel as o}from"../../kernel-selector.js";import*as
|
|
2
|
+
import{jsx as e}from"react/jsx-runtime";import{HydrationSnapshotContext as r,StreamedPrefetchContext as t}from"../../context.js";import{useKernel as o}from"../../kernel-selector.js";import*as n from"react";let l="u"<typeof document?n.useEffect:n.useLayoutEffect,u=function(e){if("fulfilled"===e.status)return e.value;throw e},a=function(e){let{use:r}=n;return r?r(e):u(e)},s=({children:n,streamed:u})=>{let s=o(),d=a(u.settled),c=u.snapshotFor(d);return l(()=>{u.adopt(d)},[u,d]),e(r.Provider,{value:c===s.getServerSnapshot()?null:c,children:e(t.Provider,{value:void 0,children:n})})},d=({children:r})=>{let o=(0,n.useContext)(t);return o?e(n.Suspense,{fallback:null,children:e(s,{streamed:o,children:r})}):r};export{d as StreamedConsentSurface,u as readRecorded};
|
package/dist/headless.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{defaultTranslationConfig,detectBrowserLanguage,mergeTranslationConfigs,prepareTranslationConfig}from"@c15t/core";export{useConsentDialogTrigger}from"./component-hooks/use-panel-trigger.js";export{useHeadlessConsentUI}from"./component-hooks/use-headless-consent-ui.js";export{useTranslations}from"./component-hooks/use-translations.js";export{useColorScheme}from"./hooks/use-color-scheme.js";export{useFocusTrap}from"./hooks/use-focus-trap.js";
|
|
1
|
+
export{defaultTranslationConfig,detectBrowserLanguage,mergeTranslationConfigs,prepareTranslationConfig,resolveActionLabels,resolvePreferenceControlLabels,resolvePromptCopy}from"@c15t/core";export{useConsentLabels}from"./component-hooks/use-consent-labels.js";export{useConsentTextDirection}from"./component-hooks/use-consent-text-direction.js";export{useConsentGate}from"./component-hooks/use-consent-gate.js";export{useConsentDialogTrigger}from"./component-hooks/use-panel-trigger.js";export{useHeadlessConsentUI}from"./component-hooks/use-headless-consent-ui.js";export{useTranslations}from"./component-hooks/use-translations.js";export{useVendorsListedUnder}from"./component-hooks/use-vendors-listed-under.js";export{useBannerCopy}from"./components/prompt/use-banner-copy.js";export{StreamedConsentSurface}from"./components/shared/streamed-surface.js";export{useColorScheme}from"./hooks/use-color-scheme.js";export{useFocusTrap}from"./hooks/use-focus-trap.js";export{useIABPolicyGuard}from"./hooks/use-iab-policy-guard.js";export{useScrollLock}from"./hooks/use-scroll-lock.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{offline}from"../transports/offline.js";
|
|
1
|
+
export{local,offline}from"../transports/offline.js";
|
package/dist/modes.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{hosted}from"./transports/hosted.js";export{manifest}from"./transports/manifest.js";export{offline}from"./transports/offline.js";
|
|
1
|
+
export{hosted}from"./transports/hosted.js";export{manifest}from"./transports/manifest.js";export{local,offline}from"./transports/offline.js";
|