@c15t/react 3.0.0-alpha.1 → 3.0.0-alpha.10
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 +96 -70
- package/README.md +21 -17
- package/SKILL.md +34 -0
- package/dist/aggregate-components.js +1 -1
- package/dist/chunk-warming.js +1 -1
- package/dist/component-hooks/use-headless-consent-ui.js +1 -1
- package/dist/component-hooks/use-headless-iab-consent-ui.js +1 -1
- package/dist/component-hooks/use-panel-trigger.js +1 -1
- package/dist/components/consent-gate/atoms.js +1 -0
- package/dist/components/consent-gate/consent-gate.js +2 -0
- package/dist/components/consent-gate/frame.js +2 -0
- package/dist/components/consent-gate/index.js +2 -0
- package/dist/components/consent-preferences-link/consent-preferences-link.js +1 -1
- package/dist/components/iab-panel/atoms/card.js +1 -1
- package/dist/components/iab-panel/atoms/feature-item.js +2 -0
- package/dist/components/iab-panel/atoms/header.js +1 -1
- package/dist/components/iab-panel/atoms/purpose-item.js +1 -1
- package/dist/components/iab-panel/atoms/root.js +1 -1
- package/dist/components/iab-panel/atoms/stack-item.js +1 -1
- package/dist/components/iab-panel/atoms/vendor-list.js +1 -1
- package/dist/components/iab-panel/hooks/use-gvl-data.js +1 -1
- package/dist/components/iab-panel/iab-panel.js +1 -1
- package/dist/components/iab-panel/index.js +1 -1
- package/dist/components/iab-prompt/atoms/overlay.js +1 -1
- package/dist/components/iab-prompt/atoms/root.js +1 -1
- package/dist/components/panel/atoms/card.js +1 -1
- package/dist/components/panel/atoms/overlay.js +1 -1
- package/dist/components/panel/atoms/root.js +1 -1
- package/dist/components/panel/panel.js +1 -1
- package/dist/components/panel-trigger/atoms/button.js +1 -1
- package/dist/components/panel-trigger/atoms/icon.js +1 -1
- package/dist/components/panel-trigger/atoms/root.js +1 -1
- package/dist/components/panel-trigger/atoms/toolbar.js +1 -1
- package/dist/components/panel-trigger/atoms/trigger-icons.js +1 -0
- package/dist/components/panel-trigger/panel-trigger-toolbar.js +1 -1
- package/dist/components/panel-trigger/panel-trigger.js +1 -1
- package/dist/components/preferences/atoms/accordion.js +1 -1
- package/dist/components/preferences/atoms/root.js +1 -1
- package/dist/components/preferences/atoms/vendor-list.js +1 -0
- package/dist/components/preferences/index.js +1 -1
- package/dist/components/prompt/atoms/early-tap-script.js +2 -0
- package/dist/components/prompt/atoms/overlay.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/shared/dialog-sheets.js +1 -0
- package/dist/components/shared/first-paint-sheets.js +1 -0
- package/dist/components/shared/iab-dialog-sheets.js +1 -0
- package/dist/components/shared/iab-first-paint-sheets.js +1 -0
- package/dist/components/shared/libs/compose-refs.js +1 -0
- package/dist/components/shared/libs/slot.js +1 -1
- package/dist/components/shared/primitives/button.js +1 -1
- package/dist/components/shared/primitives/legal-links/index.js +1 -1
- package/dist/components/shared/streamed-surface.js +2 -0
- package/dist/components/shared/surface-styles.js +2 -0
- package/dist/components/shared/ui/dialog/dialog.js +1 -1
- package/dist/components/shared/ui/icon.js +1 -1
- package/dist/components/shared/ui/logo.js +1 -1
- package/dist/components/shared/ui/preference-item/preference-item.js +1 -1
- package/dist/consent-gate.js +2 -0
- package/dist/consent-theme.js +1 -0
- package/dist/context/consent-tracking-context.js +1 -1
- package/dist/context/index.js +1 -1
- package/dist/context.js +1 -1
- package/dist/devtools-launcher.js +2 -0
- package/dist/devtools.js +1 -1
- package/dist/draft-context.js +2 -0
- package/dist/draft.js +1 -1
- package/dist/external-iab-context.js +1 -1
- package/dist/gpp.js +2 -0
- package/dist/headless.js +1 -1
- package/dist/hooks/use-color-scheme.js +1 -1
- package/dist/hooks/use-committed-ref.js +2 -0
- package/dist/hooks/use-focus-trap.js +1 -1
- package/dist/hooks/use-headless-iab-consent-ui.js +1 -1
- package/dist/hooks/use-iab-policy-guard.js +1 -0
- package/dist/hooks/use-late-entry.js +2 -0
- package/dist/hooks.js +1 -1
- package/dist/iab/styles.tw3.css +5 -45
- package/dist/iab-context.js +1 -1
- package/dist/index-parts/consent-banner.js +1 -0
- package/dist/index-parts/consent-dialog-link.js +1 -0
- package/dist/index-parts/consent-dialog-trigger.js +1 -0
- package/dist/index-parts/consent-dialog.js +1 -0
- package/dist/index-parts/consent-gate.js +1 -0
- package/dist/index-parts/core.js +1 -0
- package/dist/index-parts/draft.js +1 -0
- package/dist/index-parts/frame.js +1 -0
- package/dist/index-parts/hooks.js +1 -0
- package/dist/index-parts/hosted.js +1 -0
- package/dist/index-parts/module-hooks.js +1 -0
- package/dist/index-parts/offline.js +1 -0
- package/dist/index-parts/presets.js +1 -0
- package/dist/index-parts/provider.js +1 -0
- package/dist/index-parts/theme.js +1 -0
- package/dist/index-parts/translations.js +1 -0
- package/dist/index.js +1 -1
- package/dist/kernel-selector.js +1 -0
- package/dist/modes.js +1 -0
- package/dist/module-hooks/iframe-blocker.js +1 -1
- package/dist/module-hooks/network-blocker.js +1 -1
- package/dist/module-hooks/network-hold.js +2 -0
- package/dist/module-hooks/persistence.js +1 -1
- package/dist/panel-link.js +1 -1
- package/dist/panel-trigger.js +1 -1
- package/dist/panel.js +1 -1
- package/dist/postcss-tailwind3.js +1 -0
- package/dist/preferences.js +1 -2
- package/dist/provider.js +1 -1
- package/dist/server/fetch-ssr-data.js +1 -1
- package/dist/server/headers.js +1 -1
- package/dist/server/normalize-url.js +1 -1
- package/dist/styles.tw3.css +33 -51
- package/dist/transports/hosted.js +1 -0
- package/dist/transports/manifest.js +1 -0
- package/dist/transports/offline.js +1 -1
- package/dist/utils/deferred-module.js +2 -0
- package/dist/utils/merge-slot-props.js +1 -1
- package/dist/utils/theme-utils.js +1 -1
- package/dist/version.js +1 -1
- package/dist-types/aggregate-components.d.ts +2 -2
- package/dist-types/chunk-warming.d.ts +45 -8
- package/dist-types/component-hooks/use-headless-consent-ui.d.ts +5 -5
- package/dist-types/component-hooks/use-headless-iab-consent-ui.d.ts +2 -2
- package/dist-types/components/consent-gate/atoms.d.ts +11 -0
- package/dist-types/components/consent-gate/consent-gate.d.ts +2 -0
- package/dist-types/components/consent-gate/frame.d.ts +19 -0
- package/dist-types/components/consent-gate/index.d.ts +25 -0
- package/dist-types/components/{frame → consent-gate}/types.d.ts +7 -7
- package/dist-types/components/consent-preferences-link/consent-preferences-link.d.ts +1 -1
- package/dist-types/components/consent-preferences-link/index.d.ts +1 -1
- package/dist-types/components/iab-panel/atoms/feature-item.d.ts +28 -0
- package/dist-types/components/iab-panel/atoms/purpose-item.d.ts +5 -2
- package/dist-types/components/iab-panel/atoms/stack-item.d.ts +7 -2
- package/dist-types/components/iab-panel/atoms/vendor-list.d.ts +1 -1
- package/dist-types/components/iab-panel/iab-panel.d.ts +3 -3
- package/dist-types/components/iab-panel/index.d.ts +29 -26
- package/dist-types/components/iab-panel/use-iab-translations.d.ts +4 -0
- package/dist-types/components/iab-prompt/iab-prompt.d.ts +3 -3
- package/dist-types/components/iab-prompt/index.d.ts +19 -19
- package/dist-types/components/panel/atoms/card.d.ts +5 -4
- package/dist-types/components/panel/atoms/overlay.d.ts +1 -1
- package/dist-types/components/panel/index.d.ts +8 -8
- package/dist-types/components/panel/panel.d.ts +3 -3
- package/dist-types/components/panel-link/index.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/button.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/icon.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/root.d.ts +2 -2
- package/dist-types/components/panel-trigger/atoms/toolbar.d.ts +2 -2
- package/dist-types/components/panel-trigger/atoms/trigger-icons.d.ts +25 -0
- package/dist-types/components/panel-trigger/index.d.ts +4 -4
- package/dist-types/components/panel-trigger/panel-trigger-toolbar.d.ts +1 -1
- package/dist-types/components/panel-trigger/panel-trigger.d.ts +9 -17
- package/dist-types/components/panel-trigger/types.d.ts +1 -1
- package/dist-types/components/preferences/atoms/accordion.d.ts +6 -4
- package/dist-types/components/preferences/atoms/button.d.ts +1 -1
- package/dist-types/components/preferences/atoms/footer.d.ts +1 -1
- package/dist-types/components/preferences/atoms/root.d.ts +1 -1
- package/dist-types/components/preferences/atoms/vendor-list.d.ts +23 -0
- package/dist-types/components/preferences/index.d.ts +14 -12
- package/dist-types/components/preferences/policy-actions.d.ts +2 -2
- package/dist-types/components/preferences/preferences.d.ts +1 -1
- package/dist-types/components/preferences/types.d.ts +1 -1
- package/dist-types/components/prompt/atoms/early-tap-script.d.ts +17 -0
- package/dist-types/components/prompt/atoms/root.d.ts +4 -0
- package/dist-types/components/prompt/components.d.ts +9 -3
- package/dist-types/components/prompt/index.d.ts +12 -12
- package/dist-types/components/prompt/policy-actions.d.ts +2 -2
- package/dist-types/components/prompt/prompt.d.ts +5 -1
- package/dist-types/components/shared/dialog-sheets.d.ts +9 -0
- package/dist-types/components/shared/first-paint-sheets.d.ts +8 -0
- package/dist-types/components/shared/iab-dialog-sheets.d.ts +3 -0
- package/dist-types/components/shared/iab-first-paint-sheets.d.ts +3 -0
- package/dist-types/components/shared/libs/compose-refs.d.ts +20 -0
- package/dist-types/components/shared/policy-actions.d.ts +2 -2
- package/dist-types/components/shared/primitives/box.d.ts +1 -1
- package/dist-types/components/shared/primitives/button.d.ts +2 -2
- package/dist-types/components/shared/primitives/button.types.d.ts +1 -1
- package/dist-types/components/shared/streamed-surface.d.ts +23 -0
- package/dist-types/components/shared/surface-styles.d.ts +36 -0
- package/dist-types/components/shared/ui/accordion/accordion.d.ts +2 -2
- package/dist-types/components/shared/ui/accordion/index.d.ts +2 -2
- package/dist-types/components/shared/ui/animated-collapse/index.d.ts +2 -2
- package/dist-types/components/shared/ui/branding.d.ts +1 -1
- package/dist-types/components/shared/ui/button/button.d.ts +1 -1
- package/dist-types/components/shared/ui/button/index.d.ts +2 -2
- package/dist-types/components/shared/ui/collapsible/index.d.ts +1 -1
- package/dist-types/components/shared/ui/dialog/index.d.ts +1 -1
- package/dist-types/components/shared/ui/icon.d.ts +2 -1
- package/dist-types/components/shared/ui/logo.d.ts +0 -10
- package/dist-types/components/shared/ui/preference-item/index.d.ts +1 -1
- package/dist-types/components/shared/ui/preference-item/preference-item.d.ts +13 -0
- package/dist-types/components/shared/ui/switch/index.d.ts +2 -2
- package/dist-types/components/shared/ui/switch/switch.d.ts +1 -1
- package/dist-types/components/shared/ui/tabs/index.d.ts +1 -1
- package/dist-types/consent-gate.d.ts +1 -0
- package/dist-types/consent-theme.d.ts +38 -0
- package/dist-types/context/consent-tracking-context.d.ts +10 -0
- package/dist-types/context/index.d.ts +3 -3
- package/dist-types/context/theme-context.d.ts +3 -3
- package/dist-types/context.d.ts +25 -1
- package/dist-types/devtools-launcher.d.ts +29 -0
- package/dist-types/devtools.d.ts +13 -2
- package/dist-types/draft-context.d.ts +31 -0
- package/dist-types/draft.d.ts +81 -9
- package/dist-types/gpp.d.ts +27 -0
- package/dist-types/headless.d.ts +6 -7
- package/dist-types/hooks/use-committed-ref.d.ts +24 -0
- package/dist-types/hooks/use-focus-trap.d.ts +3 -1
- package/dist-types/hooks/use-headless-iab-consent-ui.d.ts +1 -1
- package/dist-types/hooks/use-iab-manager.d.ts +5 -5
- package/dist-types/hooks/use-iab-policy-guard.d.ts +35 -0
- package/dist-types/hooks/use-late-entry.d.ts +14 -0
- package/dist-types/hooks/use-theme.d.ts +1 -1
- package/dist-types/hooks.d.ts +106 -11
- package/dist-types/iab.d.ts +7 -7
- package/dist-types/index-parts/consent-banner.d.ts +7 -0
- package/dist-types/index-parts/consent-dialog-link.d.ts +7 -0
- package/dist-types/index-parts/consent-dialog-trigger.d.ts +7 -0
- package/dist-types/index-parts/consent-dialog.d.ts +7 -0
- package/dist-types/index-parts/consent-gate.d.ts +7 -0
- package/dist-types/index-parts/core.d.ts +7 -0
- package/dist-types/index-parts/draft.d.ts +7 -0
- package/dist-types/index-parts/frame.d.ts +7 -0
- package/dist-types/index-parts/hooks.d.ts +7 -0
- package/dist-types/index-parts/hosted.d.ts +7 -0
- package/dist-types/index-parts/module-hooks.d.ts +7 -0
- package/dist-types/index-parts/offline.d.ts +7 -0
- package/dist-types/index-parts/presets.d.ts +7 -0
- package/dist-types/index-parts/provider.d.ts +7 -0
- package/dist-types/index-parts/theme.d.ts +8 -0
- package/dist-types/index-parts/translations.d.ts +7 -0
- package/dist-types/index.d.ts +32 -28
- package/dist-types/kernel-selector.d.ts +68 -0
- package/dist-types/modes.d.ts +26 -0
- package/dist-types/module-hooks/iframe-blocker.d.ts +33 -1
- package/dist-types/module-hooks/network-blocker.d.ts +23 -0
- package/dist-types/module-hooks/network-hold.d.ts +47 -0
- package/dist-types/module-hooks.d.ts +4 -4
- package/dist-types/panel-link.d.ts +1 -1
- package/dist-types/panel-trigger.d.ts +1 -1
- package/dist-types/panel.d.ts +13 -1
- package/dist-types/postcss-tailwind3.d.ts +21 -0
- package/dist-types/preferences.d.ts +12 -1
- package/dist-types/primitives/accordion.d.ts +1 -1
- package/dist-types/primitives/button.d.ts +1 -1
- package/dist-types/primitives/collapsible.d.ts +1 -1
- package/dist-types/primitives/dialog.d.ts +1 -1
- package/dist-types/primitives/preference-item.d.ts +1 -1
- package/dist-types/primitives/switch.d.ts +1 -1
- package/dist-types/primitives/tabs.d.ts +1 -1
- package/dist-types/primitives.d.ts +7 -7
- package/dist-types/prompt.d.ts +1 -1
- package/dist-types/provider.d.ts +169 -28
- package/dist-types/server/fetch-ssr-data.d.ts +1 -1
- package/dist-types/server/headers.d.ts +14 -4
- package/dist-types/server/index.d.ts +5 -5
- package/dist-types/server/normalize-url.d.ts +14 -7
- package/dist-types/server/types.d.ts +12 -1
- package/dist-types/theme-provider.d.ts +2 -2
- package/dist-types/transports/hosted.d.ts +36 -0
- package/dist-types/transports/manifest.d.ts +48 -0
- package/dist-types/transports/offline.d.ts +7 -16
- package/dist-types/types/index.d.ts +3 -3
- package/dist-types/types/manager.d.ts +1 -1
- package/dist-types/types/theme/index.d.ts +1 -1
- package/dist-types/ui-config-context.d.ts +14 -2
- package/dist-types/utils/deferred-module.d.ts +13 -0
- package/dist-types/utils/index.d.ts +4 -4
- package/dist-types/utils/merge-slot-props.d.ts +17 -3
- package/dist-types/utils/merge-styles.d.ts +1 -1
- package/dist-types/utils/theme-utils.d.ts +18 -3
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +96 -70
- package/docs/assets/v3/bottom-bar.png +0 -0
- package/docs/assets/v3/brand-card.png +0 -0
- package/docs/assets/v3/brand-preferences.png +0 -0
- package/docs/assets/v3/choice-wall.png +0 -0
- package/docs/assets/v3/headless-bar-html.png +0 -0
- package/docs/assets/v3/headless-bar-mobile.png +0 -0
- package/docs/assets/v3/headless-bar.png +0 -0
- package/docs/assets/v3/slim-bar.png +0 -0
- package/docs/concepts/choose-your-setup.md +138 -0
- package/docs/concepts/consent-categories.md +84 -0
- package/docs/concepts/consent-state.md +421 -0
- package/docs/concepts/data-fetching.md +270 -0
- package/docs/concepts/how-consent-works.md +123 -0
- package/docs/concepts/modes.md +278 -0
- package/docs/{frameworks/react/concepts/policy-presets.md → concepts/policies.md} +8 -60
- package/docs/customization/class-names.md +202 -0
- package/docs/customization/dark-mode.md +157 -0
- package/docs/customization/motion.md +128 -0
- package/docs/customization/overview.md +68 -33
- package/docs/customization/recipes.md +838 -47
- package/docs/customization/slots.md +217 -35
- package/docs/customization/stylesheets.md +248 -0
- package/docs/customization/tailwind.md +863 -0
- package/docs/customization/tokens.md +167 -36
- package/docs/customization/translations.md +87 -3
- package/docs/frameworks/react/callbacks.md +118 -0
- package/docs/frameworks/react/clear-on-revocation.md +106 -0
- package/docs/frameworks/react/components/consent-banner.md +48 -27
- package/docs/frameworks/react/components/consent-dialog-link.md +13 -11
- package/docs/frameworks/react/components/consent-dialog-trigger.md +86 -76
- package/docs/frameworks/react/components/consent-dialog.md +111 -58
- package/docs/frameworks/react/components/{frame.md → consent-gate.md} +70 -49
- package/docs/frameworks/react/components/consent-provider.md +140 -0
- package/docs/frameworks/react/components/consent-widget.md +69 -24
- package/docs/frameworks/react/components/dev-tools.md +76 -85
- package/docs/frameworks/react/components.md +113 -0
- package/docs/frameworks/react/compose.md +354 -0
- package/docs/frameworks/react/content-security-policy.md +143 -0
- package/docs/frameworks/react/customize.md +258 -0
- package/docs/frameworks/react/embeds.md +89 -0
- package/docs/frameworks/react/gpp.md +163 -0
- package/docs/frameworks/react/headless.md +4 -4
- package/docs/frameworks/react/hooks.md +70 -0
- package/docs/frameworks/react/iab.md +259 -0
- package/docs/frameworks/react/network-blocker.md +140 -0
- package/docs/frameworks/react/quickstart.md +220 -102
- package/docs/frameworks/react/rendering.md +263 -0
- package/docs/frameworks/react/scripts.md +114 -0
- package/docs/frameworks/react/translations.md +155 -0
- package/docs/frameworks/react/troubleshooting.md +188 -61
- package/docs/frameworks/react/upgrade-v3.md +651 -0
- package/docs/frameworks/react/vendor-consent.md +188 -0
- package/docs/guides/banner-experiments.md +672 -0
- package/docs/guides/troubleshooting.md +192 -54
- package/docs/guides/verify-consent.md +96 -49
- package/docs/integrations/adobe-analytics.md +177 -183
- package/docs/integrations/ahrefs-analytics.md +162 -178
- package/docs/integrations/amplitude.md +172 -180
- package/docs/integrations/building-integrations.md +137 -33
- package/docs/integrations/clearbit.md +164 -178
- package/docs/integrations/cloudflare-web-analytics.md +166 -180
- package/docs/integrations/cloudflare-zaraz.md +333 -0
- package/docs/integrations/crisp.md +174 -182
- package/docs/integrations/databuddy.md +167 -197
- package/docs/integrations/fathom-analytics.md +168 -180
- package/docs/integrations/front-chat.md +308 -0
- package/docs/integrations/google-maps.md +142 -108
- package/docs/integrations/google-tag-manager.md +258 -185
- package/docs/integrations/google-tag.md +226 -182
- package/docs/integrations/heap.md +173 -179
- package/docs/integrations/hightouch.md +171 -181
- package/docs/integrations/hotjar.md +169 -179
- package/docs/integrations/intercom.md +193 -177
- package/docs/integrations/klaviyo.md +473 -0
- package/docs/integrations/linkedin-insights.md +184 -174
- package/docs/integrations/logrocket.md +170 -180
- package/docs/integrations/matomo-analytics.md +198 -202
- package/docs/integrations/meta-pixel.md +198 -174
- package/docs/integrations/microsoft-clarity.md +173 -179
- package/docs/integrations/microsoft-uet.md +158 -178
- package/docs/integrations/mixpanel-analytics.md +165 -184
- package/docs/integrations/one-dollar-stats.md +292 -0
- package/docs/integrations/openai-pixel.md +214 -325
- package/docs/integrations/overview.md +152 -83
- package/docs/integrations/pinterest-tag.md +315 -0
- package/docs/integrations/pirsch.md +179 -183
- package/docs/integrations/plausible-analytics.md +182 -182
- package/docs/integrations/posthog.md +323 -264
- package/docs/integrations/promptwatch.md +164 -178
- package/docs/integrations/reddit-pixel.md +195 -181
- package/docs/integrations/rudderstack.md +211 -210
- package/docs/integrations/rybbit-analytics.md +181 -184
- package/docs/integrations/segment.md +192 -178
- package/docs/integrations/sentry.md +402 -0
- package/docs/integrations/snapchat-pixel.md +196 -180
- package/docs/integrations/tiktok-pixel.md +181 -174
- package/docs/integrations/umami-analytics.md +173 -182
- package/docs/integrations/vercel-analytics.md +176 -181
- package/docs/integrations/x-pixel.md +186 -174
- package/docs/integrations/youtube.md +150 -111
- package/package.json +48 -17
- package/dist/component-hooks/use-manager.js +0 -2
- package/dist/components/frame/atoms.js +0 -1
- package/dist/components/frame/frame.js +0 -2
- package/dist/components/frame/index.js +0 -2
- package/dist/frame.js +0 -2
- package/dist/ui-save.js +0 -1
- package/dist-types/component-hooks/use-manager.d.ts +0 -40
- package/dist-types/components/frame/atoms.d.ts +0 -11
- package/dist-types/components/frame/frame.d.ts +0 -2
- package/dist-types/components/frame/index.d.ts +0 -24
- package/dist-types/frame.d.ts +0 -1
- package/dist-types/ui-save.d.ts +0 -5
- package/docs/assets/v3/brand-bar.png +0 -0
- package/docs/assets/v3/mobile-card.png +0 -0
- package/docs/assets/v3/preferences.png +0 -0
- package/docs/frameworks/react/components/consent-manager-provider.md +0 -71
- package/docs/frameworks/react/concepts/consent-categories.md +0 -33
- package/docs/frameworks/react/hooks/use-consent-manager/overview.md +0 -58
- package/docs/frameworks/react/iab/overview.md +0 -53
- package/docs/frameworks/react/script-loader.md +0 -63
- package/docs/frameworks/react/styling/overview.md +0 -217
- package/docs/guides/consent-state.md +0 -60
- package/docs/guides/data-fetching.md +0 -163
- package/docs/guides/deployment-modes.md +0 -63
- package/docs/integrations/clear-on-revocation.md +0 -167
- package/docs/upgrade-v3.md +0 -334
- package/readme.json +0 -48
- package/src/iab/styles.css +0 -11
- package/src/styles.css +0 -10
- /package/dist/components/{frame → consent-gate}/types.js +0 -0
|
@@ -1,33 +1,22 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Theme tokens
|
|
3
|
-
description:
|
|
4
|
-
|
|
2
|
+
title: Theme tokens
|
|
3
|
+
description: Change c15t's colors, type, radius, spacing, shadows and motion
|
|
4
|
+
with theme tokens, and see every --c15t-* variable with its default.
|
|
5
5
|
group: customization
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Where tokens come from
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
components and utilities directives in your Tailwind entry:
|
|
21
|
-
|
|
22
|
-
```css
|
|
23
|
-
@tailwind base;
|
|
24
|
-
@tailwind components;
|
|
25
|
-
@import 'c15t/react/styles.tw3.css';
|
|
26
|
-
@tailwind utilities;
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Do not load both c15t stylesheet variants. For Tailwind 4 or unlayered CSS,
|
|
30
|
-
inspect layer order before reaching for `!important`.
|
|
10
|
+
c15t's components take their colors from `--c15t-*` CSS variables, and most
|
|
11
|
+
of their fonts, radii, spacing, shadows and motion too. c15t's rules set the
|
|
12
|
+
defaults. You change them with a theme object or with CSS, and every part
|
|
13
|
+
that reads a token changes with it. Some values are still fixed for one
|
|
14
|
+
component, such as button padding, the radius of the "Secured by" tag and
|
|
15
|
+
several font sizes and weights, so a token change does not move them. Restyle
|
|
16
|
+
those parts through [slots](./slots.md) or your own CSS.
|
|
17
|
+
[Stylesheets and CSS layers](./stylesheets.md)
|
|
18
|
+
covers how c15t loads its rules, and [dark mode](./dark-mode.md)
|
|
19
|
+
covers the dark set of tokens.
|
|
31
20
|
|
|
32
21
|
## Set semantic values together
|
|
33
22
|
|
|
@@ -39,18 +28,117 @@ readable in each state.
|
|
|
39
28
|
import { defineTheme } from '@c15t/ui/theme';
|
|
40
29
|
|
|
41
30
|
export const theme = defineTheme({
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
31
|
+
colors: { primary: '#2f6f4e' },
|
|
32
|
+
radius: { lg: '4px' },
|
|
33
|
+
consentActions: {
|
|
34
|
+
primary: { variant: 'primary', mode: 'filled' },
|
|
35
|
+
dismiss: { variant: 'neutral', mode: 'stroke' },
|
|
36
|
+
},
|
|
48
37
|
});
|
|
49
38
|
```
|
|
50
39
|
|
|
51
|
-
Install `@c15t/ui` if importing its theme helper directly.
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
Install `@c15t/ui` if importing its theme helper directly. Where the theme
|
|
41
|
+
goes depends on the framework:
|
|
42
|
+
|
|
43
|
+
| Framework | Tokens | `consentActions` |
|
|
44
|
+
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
45
|
+
| Next.js, TanStack Start, React | `<ConsentTheme theme={theme} />`, rendered on the server where the app has one | `theme` in the provider options |
|
|
46
|
+
| Nuxt, Vue | `theme` or `tokens` in the module or plugin options | Not available |
|
|
47
|
+
| Astro | `theme` in the integration options | The same `theme` |
|
|
48
|
+
| Svelte, SvelteKit | `generateThemeCSS(theme)` from `@c15t/ui/theme` on the server, in a `<style>` element, or `--c15t-*` variables in your stylesheet | `theme` on `ConsentProvider` (Svelte) or `ConsentRoot` (SvelteKit) |
|
|
49
|
+
| HTML, JavaScript | `ui.theme` | Not available |
|
|
50
|
+
|
|
51
|
+
React and Svelte providers do not turn tokens in their `theme` option into
|
|
52
|
+
CSS, and warn in development when a theme holds tokens but the page has no
|
|
53
|
+
`<style id="c15t-theme">`. Your framework's customize page shows the full
|
|
54
|
+
setup.
|
|
55
|
+
|
|
56
|
+
`consentActions` selects styling by action role. A per-action entry overrides
|
|
57
|
+
`primary`, which overrides `default`.
|
|
58
|
+
|
|
59
|
+
## Combine a generated theme with your own CSS
|
|
60
|
+
|
|
61
|
+
`generateThemeCSS` writes its variables on `:root:root` and
|
|
62
|
+
`.c15t-theme-root.c15t-theme-root`, more specific than c15t's defaults. The
|
|
63
|
+
theme therefore overrides the defaults whether its
|
|
64
|
+
`<style>` element comes before or after c15t's rules. The same output backs
|
|
65
|
+
`ConsentTheme` in React, Next.js and TanStack Start, Astro's `theme` option and
|
|
66
|
+
the script tag's `ui.theme`.
|
|
67
|
+
|
|
68
|
+
A `--c15t-*` variable you set on plain `:root` in your own CSS loses to a
|
|
69
|
+
generated theme that sets the same variable, even when your rule loads later.
|
|
70
|
+
Put the value in the theme, or raise your selector:
|
|
71
|
+
|
|
72
|
+
```css
|
|
73
|
+
:root:root {
|
|
74
|
+
--c15t-primary: #2f6f4e;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Scoped rules such as `[data-prompt] { --c15t-primary: ... }` set the variable
|
|
79
|
+
on the banner element itself, so they still apply inside it.
|
|
80
|
+
|
|
81
|
+
## Every token
|
|
82
|
+
|
|
83
|
+
Every framework uses the same tokens. A theme object, such as `ConsentTheme`'s
|
|
84
|
+
`theme`, Astro's and Vue's `theme` or the script tag's `ui.theme`, takes the
|
|
85
|
+
theme key, such as `radius.lg`. Vue and Nuxt `tokens` take the CSS variable
|
|
86
|
+
name without the leading `--`, such as `c15t-radius-lg`. A stylesheet sets the
|
|
87
|
+
CSS variable itself. Your framework's customize page shows where each one goes.
|
|
88
|
+
[Motion and animation](./motion.md) explains the duration and
|
|
89
|
+
easing tokens.
|
|
90
|
+
|
|
91
|
+
| CSS variable | Theme key | Default |
|
|
92
|
+
| ----------------------------- | -------------------------------- | ----------------------------------------------- |
|
|
93
|
+
| `--c15t-primary` | `colors.primary` | `hsl(228, 100%, 60%)` |
|
|
94
|
+
| `--c15t-primary-hover` | `colors.primaryHover` | `hsl(228, 100%, 55%)` |
|
|
95
|
+
| `--c15t-surface` | `colors.surface` | `hsl(0, 0%, 100%)` |
|
|
96
|
+
| `--c15t-surface-hover` | `colors.surfaceHover` | `hsl(0, 0%, 98%)` |
|
|
97
|
+
| `--c15t-border` | `colors.border` | `hsl(0, 0%, 90%)` |
|
|
98
|
+
| `--c15t-border-hover` | `colors.borderHover` | `hsl(0, 0%, 85%)` |
|
|
99
|
+
| `--c15t-text` | `colors.text` | `hsl(0, 0%, 10%)` |
|
|
100
|
+
| `--c15t-text-muted` | `colors.textMuted` | `hsl(0, 0%, 40%)` |
|
|
101
|
+
| `--c15t-text-on-primary` | `colors.textOnPrimary` | auto-derived from `colors.primary` when omitted |
|
|
102
|
+
| `--c15t-overlay` | `colors.overlay` | `hsla(0, 0%, 0%, 0.5)` |
|
|
103
|
+
| `--c15t-switch-track` | `colors.switchTrack` | `hsl(0, 0%, 85%)` |
|
|
104
|
+
| `--c15t-switch-track-active` | `colors.switchTrackActive` | `colors.primary` |
|
|
105
|
+
| `--c15t-switch-thumb` | `colors.switchThumb` | `hsl(0, 0%, 100%)` |
|
|
106
|
+
| `--c15t-font-family` | `typography.fontFamily` | `system-ui, -apple-system, sans-serif` |
|
|
107
|
+
| `--c15t-font-size-sm` | `typography.fontSize.sm` | `0.875rem` |
|
|
108
|
+
| `--c15t-font-size-base` | `typography.fontSize.base` | `1rem` |
|
|
109
|
+
| `--c15t-font-size-lg` | `typography.fontSize.lg` | `1.125rem` |
|
|
110
|
+
| `--c15t-font-weight-normal` | `typography.fontWeight.normal` | `400` |
|
|
111
|
+
| `--c15t-font-weight-medium` | `typography.fontWeight.medium` | `500` |
|
|
112
|
+
| `--c15t-font-weight-semibold` | `typography.fontWeight.semibold` | `600` |
|
|
113
|
+
| `--c15t-line-height-tight` | `typography.lineHeight.tight` | `1.25` |
|
|
114
|
+
| `--c15t-line-height-normal` | `typography.lineHeight.normal` | `1.5` |
|
|
115
|
+
| `--c15t-line-height-relaxed` | `typography.lineHeight.relaxed` | `1.75` |
|
|
116
|
+
| `--c15t-space-xs` | `spacing.xs` | `0.25rem` |
|
|
117
|
+
| `--c15t-space-sm` | `spacing.sm` | `0.5rem` |
|
|
118
|
+
| `--c15t-space-md` | `spacing.md` | `1rem` |
|
|
119
|
+
| `--c15t-space-lg` | `spacing.lg` | `1.5rem` |
|
|
120
|
+
| `--c15t-space-xl` | `spacing.xl` | `2rem` |
|
|
121
|
+
| `--c15t-radius-sm` | `radius.sm` | `0.25rem` |
|
|
122
|
+
| `--c15t-radius-md` | `radius.md` | `0.5rem` |
|
|
123
|
+
| `--c15t-radius-lg` | `radius.lg` | `0.75rem` |
|
|
124
|
+
| `--c15t-radius-full` | `radius.full` | `9999px` |
|
|
125
|
+
| `--c15t-shadow-sm` | `shadows.sm` | `0 1px 2px hsla(0, 0%, 0%, 0.05)` |
|
|
126
|
+
| `--c15t-shadow-md` | `shadows.md` | `0 4px 12px hsla(0, 0%, 0%, 0.08)` |
|
|
127
|
+
| `--c15t-shadow-lg` | `shadows.lg` | `0 8px 24px hsla(0, 0%, 0%, 0.12)` |
|
|
128
|
+
| `--c15t-duration-fast` | `motion.duration.fast` | `80ms` |
|
|
129
|
+
| `--c15t-duration-normal` | `motion.duration.normal` | `150ms` |
|
|
130
|
+
| `--c15t-duration-slow` | `motion.duration.slow` | `200ms` |
|
|
131
|
+
| `--c15t-easing` | `motion.easing` | `cubic-bezier(0.4, 0, 0.2, 1)` |
|
|
132
|
+
| `--c15t-easing-out` | `motion.easingOut` | `cubic-bezier(0.215, 0.61, 0.355, 1)` |
|
|
133
|
+
| `--c15t-easing-in` | `motion.easingIn` | `cubic-bezier(0.55, 0.055, 0.675, 0.19)` |
|
|
134
|
+
| `--c15t-easing-in-out` | `motion.easingInOut` | `cubic-bezier(0.645, 0.045, 0.355, 1)` |
|
|
135
|
+
| `--c15t-easing-spring` | `motion.easingSpring` | `cubic-bezier(0.34, 1.56, 0.64, 1)` |
|
|
136
|
+
|
|
137
|
+
The radius tokens round different parts. `radius.lg` rounds the banner card,
|
|
138
|
+
the preference dialog, `ConsentGate` placeholders and the floating trigger.
|
|
139
|
+
`radius.md` rounds buttons, accordions, tabs and the vendor list.
|
|
140
|
+
`radius.sm` rounds small parts inside the banner and dialog. To give the banner
|
|
141
|
+
and its buttons the same 4px corners, set both `lg` and `md`.
|
|
54
142
|
|
|
55
143
|
## Target a prompt with CSS
|
|
56
144
|
|
|
@@ -63,8 +151,9 @@ entry overrides `primary`, which overrides `default`.
|
|
|
63
151
|
```
|
|
64
152
|
|
|
65
153
|
Use attributes exposed by the rendered component, not guessed class names.
|
|
66
|
-
|
|
67
|
-
|
|
154
|
+
The script tag's banner has no `data-prompt` or `data-model`. Test the prompt
|
|
155
|
+
and the preferences dialog separately because tokens scoped to one prompt do
|
|
156
|
+
not automatically reach a portaled dialog.
|
|
68
157
|
|
|
69
158
|
| Size variable | Default | Target |
|
|
70
159
|
| ----------------------------------- | ------- | ------------- |
|
|
@@ -72,5 +161,47 @@ one prompt do not automatically reach a portaled dialog.
|
|
|
72
161
|
| `--consent-banner-widget-max-width` | `20rem` | Widget |
|
|
73
162
|
| `--consent-banner-wall-max-width` | `30rem` | Choice wall |
|
|
74
163
|
|
|
164
|
+
The banner footer lays out its actions by the card's width, not the
|
|
165
|
+
viewport's. With the default `compact` profile, a card narrower than 22rem
|
|
166
|
+
puts Reject and Accept on one row and Customize on a full-width row below
|
|
167
|
+
them, on any screen size.
|
|
168
|
+
|
|
75
169
|
Test long translations and small screens after changing width or typography.
|
|
76
170
|
A compact banner must still fit the required actions.
|
|
171
|
+
|
|
172
|
+
## Restyle the "Secured by" tag
|
|
173
|
+
|
|
174
|
+
The tag sits on the edge of the banner and dialog cards and uses the primary
|
|
175
|
+
color by default. Set these variables on `:root`, or on an element that
|
|
176
|
+
contains the tag. The dialog renders in a portal, so a variable set on the
|
|
177
|
+
banner does not reach the dialog's tag.
|
|
178
|
+
|
|
179
|
+
| Variable | Default | Target |
|
|
180
|
+
| -------------------------------------------- | --------------------------------------- | -------------------------------------- |
|
|
181
|
+
| `--consent-branding-tag-background-color` | `var(--c15t-primary)` | Tag background |
|
|
182
|
+
| `--consent-branding-tag-border-color` | `--c15t-primary` mixed 14% toward black | Tag border |
|
|
183
|
+
| `--consent-branding-tag-text-color` | `var(--c15t-text-on-primary, #fff)` | "Secured by" and the wordmark |
|
|
184
|
+
| `--consent-branding-tag-mark-color` | The text color | c15t mark or inth logo |
|
|
185
|
+
| `--consent-branding-tag-shadow` | Inset highlight and a 1px drop shadow | Tag shadow |
|
|
186
|
+
| `--consent-branding-tag-attached-edge-width` | `0px` | Border on the edge that meets the card |
|
|
187
|
+
|
|
188
|
+
The stylesheet does not declare these variables. Each default resolves on the
|
|
189
|
+
tag, so a `--c15t-primary` you scope to a banner still colors the tag.
|
|
190
|
+
|
|
191
|
+
This makes the tag look like a tab of the card:
|
|
192
|
+
|
|
193
|
+
```css
|
|
194
|
+
:root {
|
|
195
|
+
--consent-branding-tag-background-color: var(--c15t-surface);
|
|
196
|
+
--consent-branding-tag-border-color: var(--c15t-border);
|
|
197
|
+
--consent-branding-tag-text-color: var(--c15t-text-muted);
|
|
198
|
+
--consent-branding-tag-mark-color: var(--c15t-primary);
|
|
199
|
+
--consent-branding-tag-shadow: none;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The edge that meets the card has no border by default. Above the banner the
|
|
204
|
+
tag overlaps the card's top border by 1px and covers it. Below the dialog the
|
|
205
|
+
tag starts under the card's bottom border. Set
|
|
206
|
+
`--consent-branding-tag-attached-edge-width: 1px` to draw that edge. It is
|
|
207
|
+
drawn over the card's border, so the two borders do not stack.
|
|
@@ -27,9 +27,52 @@ i18n: {
|
|
|
27
27
|
|
|
28
28
|
Supply the same message keys in each supported locale. A one-off component prop
|
|
29
29
|
such as `dismissButtonText` is useful for one banner; use translations for a
|
|
30
|
-
site-wide change. Astro's serializable integration options
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
site-wide change. Astro's serializable integration options have their own
|
|
31
|
+
types, so verify that shape before copying a React object. The Vue plugin and
|
|
32
|
+
Nuxt module have no `i18n` option; their copy comes from the backend.
|
|
33
|
+
|
|
34
|
+
## Load only the languages you use
|
|
35
|
+
|
|
36
|
+
c15t bundles English. Every other language it ships is a separate entry point
|
|
37
|
+
in `@c15t/translations`, named by its language code. Importing one registers
|
|
38
|
+
c15t's built-in copy for that language. Offline mode can then switch to it,
|
|
39
|
+
and your messages that repeat its wording don't hide backend edits. Import
|
|
40
|
+
them in the file that configures the provider, so they load in the browser:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import '@c15t/translations/de';
|
|
44
|
+
import '@c15t/translations/fr';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Each entry also exports that copy as `translations`, if you want to read a
|
|
48
|
+
string or build your messages from it:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { translations as de } from '@c15t/translations/de';
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The entries are `bg`, `cs`, `cy`, `da`, `de`, `el`, `es`, `et`, `fi`, `fr`,
|
|
55
|
+
`ga`, `gu`, `he`, `hi`, `hr`, `hu`, `id`, `is`, `it`, `lb`, `lt`, `lv`, `mt`,
|
|
56
|
+
`nb`, `nl`, `nn`, `pl`, `pt`, `rm`, `ro`, `sk`, `sl`, `sv` and `zh`.
|
|
57
|
+
`@c15t/translations/all` still loads every language at once. The `c15t`
|
|
58
|
+
package doesn't re-export these entries, so add `@c15t/translations` to your
|
|
59
|
+
dependencies.
|
|
60
|
+
|
|
61
|
+
## Combine messages with backend copy
|
|
62
|
+
|
|
63
|
+
With a backend or a manifest, the copy it sends for the visitor's language is
|
|
64
|
+
the base. Your `i18n.messages` for that language replace it key by key, and
|
|
65
|
+
keys you leave out keep the backend's wording, including copy edited in your
|
|
66
|
+
Inth project. c15t looks up messages for the exact language first, then for
|
|
67
|
+
its primary language, so `de-AT` uses your `de` messages when there is no
|
|
68
|
+
`de-AT` entry. Messages for other languages are not applied.
|
|
69
|
+
|
|
70
|
+
A key only overrides the backend when your text differs from c15t's built-in
|
|
71
|
+
wording for that language. So passing a stock bundle to enable a language
|
|
72
|
+
keeps backend edits visible, while a key you actually reworded stays pinned
|
|
73
|
+
in code. c15t only recognizes the built-in wording of English and of the
|
|
74
|
+
languages you [import](#load-only-the-languages-you-use), such as
|
|
75
|
+
`@c15t/translations/de` or `@c15t/translations/all`.
|
|
33
76
|
|
|
34
77
|
## Write labels that describe the action
|
|
35
78
|
|
|
@@ -41,6 +84,47 @@ The notice acknowledgement uses `common.acknowledge`, with `common.dismiss` as
|
|
|
41
84
|
a fallback for older translation bundles. Keep the displayed label and the
|
|
42
85
|
command's effect aligned.
|
|
43
86
|
|
|
87
|
+
## Translate the ConsentGate placeholder
|
|
88
|
+
|
|
89
|
+
The `ConsentGate` placeholder reads the `consentGate` section:
|
|
90
|
+
|
|
91
|
+
| Key | Where it shows |
|
|
92
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
93
|
+
| `consentGate.title` | The placeholder text. `{category}` is replaced by the category's translated title. |
|
|
94
|
+
| `consentGate.actionButton` | The button that opens preferences, with the same `{category}` replacement. |
|
|
95
|
+
| `consentGate.policyBlocked` | React and Vue show it in place of the title, with no button, when a strict policy leaves the category out of scope. |
|
|
96
|
+
|
|
97
|
+
Earlier versions called this section `frame`. Copy under `frame` in
|
|
98
|
+
`i18n.messages` or custom translations still applies. c15t reads it as `consentGate`, a key set under `consentGate`
|
|
99
|
+
wins over the same key under `frame`, and c15t logs a warning once outside
|
|
100
|
+
production. Rename the section to `consentGate` to remove the warning.
|
|
101
|
+
|
|
102
|
+
## Show right-to-left languages
|
|
103
|
+
|
|
104
|
+
c15t sets `dir="rtl"` on its surfaces when the resolved language is Arabic,
|
|
105
|
+
Hebrew, Persian, Urdu, Pashto, Sindhi, Kurdish or Dhivehi. It matches the
|
|
106
|
+
primary language, so `ar-EG` counts as Arabic. Hebrew is the only
|
|
107
|
+
right-to-left translation c15t ships. For the others, supply your own
|
|
108
|
+
messages or the copy from your Inth project.
|
|
109
|
+
|
|
110
|
+
What follows the direction:
|
|
111
|
+
|
|
112
|
+
* Text, headings and the button row in the banner, the preference dialog and
|
|
113
|
+
the preference widget flow right to left.
|
|
114
|
+
* A floating or widget banner in its default corner moves to the mirrored
|
|
115
|
+
corner, so `bottom-left` becomes `bottom-right`. A `position` you set
|
|
116
|
+
yourself stays where you put it.
|
|
117
|
+
* The HTML script tag, `@c15t/browser` and Astro's banner also set `lang` on
|
|
118
|
+
their surfaces. React, Vue and Svelte set `dir` only, so set `lang` on
|
|
119
|
+
`<html>` yourself.
|
|
120
|
+
|
|
121
|
+
What does not follow yet:
|
|
122
|
+
|
|
123
|
+
* The IAB TCF dialog aligns several labels, indents and borders to the left.
|
|
124
|
+
* The floating `ConsentDialogTrigger` keeps the corner you give it.
|
|
125
|
+
|
|
126
|
+
Test right-to-left pages with a real translation before you ship them.
|
|
127
|
+
|
|
44
128
|
## Test more than English
|
|
45
129
|
|
|
46
130
|
Try the longest labels you support at a narrow width, with browser zoom and
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Callbacks
|
|
3
|
+
description: Run code in a React app when a visitor records a consent choice,
|
|
4
|
+
when permissions change, when a request fails and before the revocation
|
|
5
|
+
reload, with the ConsentProvider callbacks option.
|
|
6
|
+
group: frameworks
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Pass callbacks to the provider
|
|
10
|
+
|
|
11
|
+
Keep the callbacks in their own module:
|
|
12
|
+
|
|
13
|
+
```ts title="src/consent-callbacks.ts"
|
|
14
|
+
import type { ConsentProviderCallbacks } from 'c15t/react';
|
|
15
|
+
|
|
16
|
+
export const callbacks = {
|
|
17
|
+
// Right before the page reloads because a save withdrew a permission.
|
|
18
|
+
onBeforeConsentRevocationReload: ({ preferences }) => {
|
|
19
|
+
console.info('Reloading with', preferences);
|
|
20
|
+
},
|
|
21
|
+
// The visitor clicked Accept all, Reject all or Save.
|
|
22
|
+
onChoiceRecorded: ({ confirmed, snapshot }) => {
|
|
23
|
+
console.info('Choice recorded', confirmed, snapshot.explicitChoice);
|
|
24
|
+
},
|
|
25
|
+
// A consent command failed, such as a save the backend rejected.
|
|
26
|
+
onError: ({ error }) => {
|
|
27
|
+
console.error('c15t', error);
|
|
28
|
+
},
|
|
29
|
+
// Permissions changed for any reason: a choice, an expired choice, a new
|
|
30
|
+
// policy or a privacy signal.
|
|
31
|
+
onPermissionsChanged: ({ previous, snapshot }) => {
|
|
32
|
+
console.info('Permissions', previous, snapshot.effectivePermissions);
|
|
33
|
+
},
|
|
34
|
+
} satisfies ConsentProviderCallbacks;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Pass them in the `ConsentProvider` options, in the file that renders the
|
|
38
|
+
provider, such as `src/consent.tsx` from the
|
|
39
|
+
[quickstart](./quickstart.md):
|
|
40
|
+
|
|
41
|
+
```tsx title="src/consent.tsx"
|
|
42
|
+
<ConsentProvider options={{ mode, scripts, callbacks }}>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The provider subscribes the callbacks after it mounts, so they run in the
|
|
46
|
+
browser. If you render on the server, server rendering never calls them. The
|
|
47
|
+
provider calls the latest `callbacks` object it received, so a new object on
|
|
48
|
+
a later render takes effect without a remount. Defining the object at module
|
|
49
|
+
level, as above, keeps it the same across renders.
|
|
50
|
+
|
|
51
|
+
When you pass your own `runtime` to `ConsentProvider`, the provider does not
|
|
52
|
+
wire `callbacks` or `reloadOnConsentRevoked` from its options. Pass them to
|
|
53
|
+
`createConsentRuntime` instead.
|
|
54
|
+
|
|
55
|
+
## Available callbacks
|
|
56
|
+
|
|
57
|
+
| Callback | Runs when | Receives |
|
|
58
|
+
| --------------------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
59
|
+
| `onChoiceRecorded` | The visitor clicks Accept All, Reject All or Save Settings, in the stock UI or through `useSaveConsents()`. | `snapshot`, the state after the choice; `confirmed`, the categories this action recorded; `actionAt`, the time as a millisecond timestamp |
|
|
60
|
+
| `onPermissionsChanged` | Any effective permission changes value. | `snapshot`, the state after the change; `previous`, the permissions before it |
|
|
61
|
+
| `onError` | A consent command fails, such as a failed `/init` request or a save the backend rejects. | `error`, a message string |
|
|
62
|
+
| `onBeforeConsentRevocationReload` | A save withdrew a granted category or vendor, right before c15t reloads the page. | `preferences`, the permissions after the save |
|
|
63
|
+
|
|
64
|
+
The type for the whole object is `ConsentProviderCallbacks` from `c15t/react`.
|
|
65
|
+
Callbacks run after c15t updates its state, so `snapshot` and hooks such as
|
|
66
|
+
`useConsent()` already hold the new values.
|
|
67
|
+
|
|
68
|
+
## onChoiceRecorded or onPermissionsChanged
|
|
69
|
+
|
|
70
|
+
`onChoiceRecorded` runs only for a visitor's action. `onPermissionsChanged`
|
|
71
|
+
runs whenever effective permissions change, whatever the cause:
|
|
72
|
+
|
|
73
|
+
| Event | `onChoiceRecorded` | `onPermissionsChanged` |
|
|
74
|
+
| --------------------------------------------------------- | ------------------ | ---------------------------- |
|
|
75
|
+
| Visitor accepts, rejects or saves | Yes | Yes, if a permission changed |
|
|
76
|
+
| A policy resolves and allows categories before any choice | No | Yes |
|
|
77
|
+
| Global Privacy Control turns off a grant | No | Yes |
|
|
78
|
+
| A recorded choice expires | No | Yes |
|
|
79
|
+
| Visitor dismisses a notice | No | No |
|
|
80
|
+
|
|
81
|
+
Use `onChoiceRecorded` for consent analytics and audit trails, because it
|
|
82
|
+
fires only when the visitor chose. Use `onPermissionsChanged` to start or stop
|
|
83
|
+
your own code. Never treat it as proof that the visitor agreed to anything,
|
|
84
|
+
and never save consent from it.
|
|
85
|
+
[How consent works](../../concepts/how-consent-works.md#a-permission-is-not-a-recorded-choice)
|
|
86
|
+
explains the difference.
|
|
87
|
+
|
|
88
|
+
Dismissing a notice records no choice and changes no permission. Read it with
|
|
89
|
+
`useNoticeDismissal()` instead. For consent inside one component, use the
|
|
90
|
+
[hooks](./hooks.md), which re-render the component when
|
|
91
|
+
consent changes.
|
|
92
|
+
|
|
93
|
+
## Before a revocation reload
|
|
94
|
+
|
|
95
|
+
Removing a script tag cannot stop code that already ran, so c15t reloads the
|
|
96
|
+
page after an accept, reject or save turns off a category or vendor that was
|
|
97
|
+
granted. The reload waits for the save request to finish. Right before it,
|
|
98
|
+
`onBeforeConsentRevocationReload` runs synchronously. Use it to call a
|
|
99
|
+
vendor's shutdown API or flush queued events. Keep it short, because the
|
|
100
|
+
reload does not wait for promises.
|
|
101
|
+
|
|
102
|
+
A choice that expires, a new policy and a privacy signal change permissions
|
|
103
|
+
without a visitor action, so they do not reload the page.
|
|
104
|
+
|
|
105
|
+
To handle revocation yourself, set `reloadOnConsentRevoked: false` in the
|
|
106
|
+
provider options. Code the visitor turned off then keeps running until the
|
|
107
|
+
next full page load, and `onBeforeConsentRevocationReload` never runs.
|
|
108
|
+
|
|
109
|
+
## Verify
|
|
110
|
+
|
|
111
|
+
1. Add the callbacks from this page, open the console and DevTools Network,
|
|
112
|
+
clear site data and reload under a policy that shows a banner.
|
|
113
|
+
2. Click **Accept All**. `onChoiceRecorded` and `onPermissionsChanged` both log,
|
|
114
|
+
and the save request to your backend appears in Network.
|
|
115
|
+
3. Reload. `onChoiceRecorded` does not log again.
|
|
116
|
+
4. Open Privacy settings, turn off a category you allowed and save.
|
|
117
|
+
`onBeforeConsentRevocationReload` logs, then the page reloads. After the
|
|
118
|
+
reload, that category's vendor requests are absent from Network.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Clear on revocation
|
|
3
|
+
description: Delete the first-party cookies and Web Storage keys a consent
|
|
4
|
+
category owns in a React app when that category is denied, with the
|
|
5
|
+
clearOnRevocation option on ConsentProvider.
|
|
6
|
+
group: frameworks
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Configure cleanup
|
|
10
|
+
|
|
11
|
+
Gating stops new requests, but it leaves the cookies and storage keys a vendor
|
|
12
|
+
already wrote. List the ones each optional category owns and add them to the
|
|
13
|
+
provider options in `src/consent.tsx`. When that category is denied, c15t
|
|
14
|
+
deletes them:
|
|
15
|
+
|
|
16
|
+
```tsx title="src/consent.tsx (partial)"
|
|
17
|
+
import type { ClearOnRevocationConfig } from 'c15t';
|
|
18
|
+
|
|
19
|
+
const clearOnRevocation: ClearOnRevocationConfig = {
|
|
20
|
+
measurement: { cookies: ['_ga', '_ga_*'], localStorage: ['analytics:*'] },
|
|
21
|
+
marketing: { cookies: ['_fbp'], sessionStorage: ['campaign-id'] },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
<ConsentProvider options={{ mode, scripts, clearOnRevocation }}>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The provider reads `clearOnRevocation` once, when it mounts; remount it to
|
|
28
|
+
change the list. A provider that borrows a `runtime` does not read it.
|
|
29
|
+
Configure cleanup on the runtime owner instead, with
|
|
30
|
+
`createConsentRuntime({ clearOnRevocation })`.
|
|
31
|
+
|
|
32
|
+
## Name cookies and keys
|
|
33
|
+
|
|
34
|
+
Each optional category takes three lists. Without `clearOnRevocation`, c15t
|
|
35
|
+
deletes nothing, and `necessary` cannot be configured.
|
|
36
|
+
|
|
37
|
+
| Field | Takes |
|
|
38
|
+
| ---------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
39
|
+
| `cookies` | Cookie names, prefixes ending in `*` such as `'_ga_*'`, or `{ name, domain?, path?, partitioned? }` objects. |
|
|
40
|
+
| `localStorage` | Keys, or prefixes ending in `*`. |
|
|
41
|
+
| `sessionStorage` | Keys, or prefixes ending in `*`. |
|
|
42
|
+
|
|
43
|
+
Use an exact name, or a prefix followed by `*`. `_ga_*` matches `_ga_ABC123`
|
|
44
|
+
but not `_ga`, so list both. Regular expressions, a `*` anywhere but the end,
|
|
45
|
+
and a bare `*` are not supported. Cookie names are matched as written,
|
|
46
|
+
without URL decoding.
|
|
47
|
+
|
|
48
|
+
By default c15t tries the current host and its parent domains, and the
|
|
49
|
+
current path and its parents. For a cookie set on a specific scope, use an
|
|
50
|
+
object:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const cookies = [
|
|
54
|
+
{ name: 'analytics-id', domain: 'example.com', path: '/' },
|
|
55
|
+
{ name: 'checkout-metrics', domain: '', path: '/checkout' },
|
|
56
|
+
{ name: 'partitioned-metrics', partitioned: true },
|
|
57
|
+
];
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
An empty `domain` means a host-only cookie. A `domain` or `path` you set
|
|
61
|
+
replaces the automatic attempts for that field. Partitioned cookies need
|
|
62
|
+
`partitioned: true`. A prefix only finds cookies the current page can read,
|
|
63
|
+
so use an exact name for a cookie on another path.
|
|
64
|
+
|
|
65
|
+
c15t never deletes its own consent records, even when a pattern matches
|
|
66
|
+
them.
|
|
67
|
+
|
|
68
|
+
## When cleanup runs
|
|
69
|
+
|
|
70
|
+
* On the first page load after the policy resolves, for every denied
|
|
71
|
+
category. This covers a new opt-in visitor and a returning visitor whose
|
|
72
|
+
choice expired.
|
|
73
|
+
* Whenever a category changes from allowed to denied, after a saved refusal,
|
|
74
|
+
expiry, a policy change or a Global Privacy Control signal.
|
|
75
|
+
|
|
76
|
+
Cleanup does not run during server rendering, while the policy is still
|
|
77
|
+
loading, on draft switch changes in the dialog, or when the provider
|
|
78
|
+
unmounts. It runs once per change and does not poll. Under an opt-out
|
|
79
|
+
policy, an expired choice that stays allowed deletes nothing. If a resolved
|
|
80
|
+
policy later falls back to denial after a failed request, cleanup deletes
|
|
81
|
+
the data, and a successful retry cannot restore it.
|
|
82
|
+
|
|
83
|
+
Switching off one vendor inside an allowed category deletes nothing, because
|
|
84
|
+
the category stays allowed.
|
|
85
|
+
|
|
86
|
+
## Browser limits
|
|
87
|
+
|
|
88
|
+
c15t can delete first-party cookies that JavaScript can read, and keys in
|
|
89
|
+
the current origin's `localStorage` and `sessionStorage`. It cannot delete
|
|
90
|
+
`HttpOnly` cookies or another origin's data; expire those from your server.
|
|
91
|
+
A vendor SDK still running on the page can write its cookies again, which is
|
|
92
|
+
one reason c15t reloads the page after a revocation. Deletion failures do
|
|
93
|
+
not block the consent update. See
|
|
94
|
+
[MDN on cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies).
|
|
95
|
+
|
|
96
|
+
## Verify cleanup
|
|
97
|
+
|
|
98
|
+
1. Allow measurement and let Google Analytics run. In DevTools Application,
|
|
99
|
+
Cookies shows `_ga` and a `_ga_<id>` cookie.
|
|
100
|
+
2. Open Privacy settings, turn measurement off and save. c15t reloads the
|
|
101
|
+
page. Both cookies are gone, and `analytics:*` keys are gone from Local
|
|
102
|
+
storage.
|
|
103
|
+
3. Reload. The cookies do not come back, because Google Analytics no longer
|
|
104
|
+
loads.
|
|
105
|
+
4. If you listed a cookie with an explicit `domain` or `path`, repeat step 2
|
|
106
|
+
and check that the cookie is gone from that scope too.
|