@c15t/react 2.0.0-rc.9 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -20
- package/dist/components/consent-banner/consent-banner.cjs +1 -1
- package/dist/components/consent-banner/consent-banner.js +1 -1
- package/dist/components/consent-dialog/atoms/card.cjs +1 -1
- package/dist/components/consent-dialog/atoms/card.js +1 -1
- package/dist/components/consent-dialog/atoms/overlay.cjs +1 -1
- package/dist/components/consent-dialog/atoms/overlay.js +1 -1
- package/dist/components/consent-widget/atoms/root.cjs +1 -1
- package/dist/components/consent-widget/atoms/root.js +1 -1
- package/dist/components/consent-widget/consent-widget.cjs +1 -1
- package/dist/components/consent-widget/consent-widget.js +1 -1
- package/dist/components/iab-consent-banner/iab-consent-banner.cjs +1 -1
- package/dist/components/iab-consent-banner/iab-consent-banner.js +1 -1
- package/dist/components/iab-consent-dialog/iab-consent-dialog.cjs +1 -1
- package/dist/components/iab-consent-dialog/iab-consent-dialog.js +1 -1
- package/dist/components/shared/ui/branding.cjs +1 -1
- package/dist/components/shared/ui/branding.js +1 -1
- package/dist/hooks/index.cjs +1 -1
- package/dist/iab/styles.tw3.css +54 -11
- package/dist/index.cjs +1 -1
- package/dist/styles.tw3.css +70 -10
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/dist-types/components/consent-dialog/atoms/card.d.ts +1 -0
- package/dist-types/components/consent-dialog/atoms/overlay.d.ts +8 -16
- package/dist-types/components/consent-dialog/index.d.ts +2 -1
- package/dist-types/components/consent-widget/atoms/root.d.ts +0 -5
- package/dist-types/components/shared/ui/branding.d.ts +5 -1
- package/dist-types/components/shared/ui/logo.d.ts +10 -0
- package/dist-types/types/consent-manager.d.ts +2 -2
- package/dist-types/version.d.ts +1 -1
- package/docs/ai-agents.md +111 -0
- package/docs/building-headless-components.md +118 -16
- package/docs/components/consent-banner.md +1 -30
- package/docs/components/consent-dialog.md +4 -3
- package/docs/components/consent-manager-provider.md +13 -13
- package/docs/components/consent-widget.md +1 -28
- package/docs/components/dev-tools.md +33 -0
- package/docs/concepts/client-modes.md +1 -1
- package/docs/concepts/policy-packs.md +1 -1
- package/docs/hooks/use-consent-manager/overview.md +18 -2
- package/docs/iab/consent-banner.md +8 -6
- package/docs/iab/consent-dialog.md +8 -6
- package/docs/iab/overview.md +13 -12
- package/docs/iab/use-gvl-data.md +11 -199
- package/docs/internationalization.md +1 -1
- package/docs/optimization.md +35 -1
- package/docs/policy-packs.md +1 -1
- package/docs/quickstart.md +12 -9
- package/docs/styling/color-scheme.md +1 -1
- package/docs/styling/css-variables.md +1 -1
- package/docs/styling/overview.md +11 -4
- package/docs/styling/slots.md +7 -3
- package/docs/styling/tailwind.md +5 -1
- package/docs/styling/tokens.md +3 -1
- package/iab/styles.tw3.css +1 -0
- package/package.json +28 -15
- package/readme.json +4 -4
- package/styles.tw3.css +1 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Provides the overlay backdrop component for the consent management interface.
|
|
4
4
|
* Implements accessible modal behavior with animation support.
|
|
5
5
|
*/
|
|
6
|
-
import { type
|
|
6
|
+
import { type CSSProperties, type HTMLAttributes } from 'react';
|
|
7
7
|
import type { ThemeValue } from '../../../types/theme';
|
|
8
8
|
/**
|
|
9
9
|
* Props for the Overlay component.
|
|
@@ -15,25 +15,17 @@ import type { ThemeValue } from '../../../types/theme';
|
|
|
15
15
|
*
|
|
16
16
|
* @public
|
|
17
17
|
*/
|
|
18
|
-
|
|
19
|
-
* Props for the Overlay component.
|
|
20
|
-
*
|
|
21
|
-
* @remarks
|
|
22
|
-
* Extends {@link PropsWithChildren} so that the overlay can optionally wrap
|
|
23
|
-
* its compound components (e.g. `ConsentDialog.Card`). This resolves
|
|
24
|
-
* TypeScript errors when consumers nest elements inside
|
|
25
|
-
* `<ConsentDialog.Root>`.
|
|
26
|
-
*/
|
|
27
|
-
export type OverlayProps = PropsWithChildren<{
|
|
18
|
+
export interface OverlayProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {
|
|
28
19
|
/**
|
|
29
20
|
* Custom styles to override default overlay styling.
|
|
30
21
|
*
|
|
31
22
|
* @remarks
|
|
32
|
-
* -
|
|
23
|
+
* - Accepts normal React inline styles
|
|
24
|
+
* - Also accepts the legacy string class name or object with className and style properties
|
|
33
25
|
* - Styles are merged with theme styles and default styles
|
|
34
26
|
* - Useful for customizing overlay appearance while maintaining functionality
|
|
35
27
|
*/
|
|
36
|
-
style?: ThemeValue;
|
|
28
|
+
style?: CSSProperties | ThemeValue;
|
|
37
29
|
/**
|
|
38
30
|
* Disables default styling when true.
|
|
39
31
|
*
|
|
@@ -43,7 +35,7 @@ export type OverlayProps = PropsWithChildren<{
|
|
|
43
35
|
* - Maintains functionality without visual opinions
|
|
44
36
|
*/
|
|
45
37
|
noStyle?: boolean;
|
|
46
|
-
}
|
|
47
|
-
declare const ConsentDialogOverlay:
|
|
48
|
-
declare const Overlay:
|
|
38
|
+
}
|
|
39
|
+
declare const ConsentDialogOverlay: import("react").ForwardRefExoticComponent<OverlayProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
40
|
+
declare const Overlay: import("react").ForwardRefExoticComponent<OverlayProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
49
41
|
export { ConsentDialogOverlay, Overlay };
|
|
@@ -60,7 +60,8 @@ export interface ConsentDialogCompoundComponent extends FC<ConsentDialogProps> {
|
|
|
60
60
|
* theme: {
|
|
61
61
|
* slots: {
|
|
62
62
|
* consentDialogCard: 'rounded-3xl shadow-xl',
|
|
63
|
-
*
|
|
63
|
+
* consentWidgetFooter: 'gap-3 pt-6',
|
|
64
|
+
* consentDialogTag: 'shadow-none',
|
|
64
65
|
* },
|
|
65
66
|
* },
|
|
66
67
|
* }}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @packageDocumentation
|
|
3
|
-
* Provides the root component for the consent management interface.
|
|
4
|
-
* Implements context provider pattern with theme support and state management.
|
|
5
|
-
*/
|
|
6
1
|
import type { FC, ReactNode } from 'react';
|
|
7
2
|
import { type ThemeContextValue } from '../../../context/theme-context';
|
|
8
3
|
/**
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { Branding } from 'c15t';
|
|
2
2
|
import type { SVGProps } from 'react';
|
|
3
|
+
import type { CSSPropertiesWithVars } from '../../../types/theme';
|
|
3
4
|
export type ResolvedBranding = 'c15t' | 'inth' | 'none';
|
|
4
5
|
export type BrandingVariant = 'footer' | 'dialog-tag' | 'banner-tag';
|
|
6
|
+
export type BrandingThemeKey = 'consentBannerTag' | 'consentDialogTag' | 'consentWidgetTag' | 'iabConsentBannerTag' | 'iabConsentDialogTag';
|
|
5
7
|
type BrandingProps = {
|
|
6
8
|
hideBranding: boolean;
|
|
7
9
|
variant?: BrandingVariant;
|
|
10
|
+
themeKey?: BrandingThemeKey;
|
|
8
11
|
className?: string;
|
|
12
|
+
style?: CSSPropertiesWithVars;
|
|
9
13
|
'data-testid'?: string;
|
|
10
14
|
};
|
|
11
15
|
type BrandingFullLogoProps = {
|
|
@@ -19,5 +23,5 @@ export declare function resolveBranding(branding: Branding | string): ResolvedBr
|
|
|
19
23
|
export declare function getBrandingHref(branding: Branding | string, refParam?: string): string;
|
|
20
24
|
export declare function BrandingFullLogo({ branding, className, }: BrandingFullLogoProps): import("react/jsx-runtime").JSX.Element;
|
|
21
25
|
export declare function BrandingCompactLogo({ branding, ...props }: BrandingCompactLogoProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
-
export declare function BrandingLink({ hideBranding, variant, className, 'data-testid': testId, }: BrandingProps): import("react/jsx-runtime").JSX.Element | null;
|
|
26
|
+
export declare function BrandingLink({ hideBranding, variant, themeKey, className, style, 'data-testid': testId, }: BrandingProps): import("react/jsx-runtime").JSX.Element | null;
|
|
23
27
|
export {};
|
|
@@ -21,6 +21,16 @@ export declare const InthLogo: (props: SVGProps<SVGSVGElement> & IconProps) => i
|
|
|
21
21
|
* INTH icon-only mark for compact placements like floating triggers.
|
|
22
22
|
*/
|
|
23
23
|
export declare const InthIconOnly: (props: SVGProps<SVGSVGElement> & IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
/**
|
|
25
|
+
* Wordmark logo for the hosted consent product (inth.com).
|
|
26
|
+
*
|
|
27
|
+
* Used in marketing surfaces such as the optional banner attribution and
|
|
28
|
+
* the consent dialog footer. Render inside a flow where its native
|
|
29
|
+
* 595x97 viewBox can scale freely (e.g. an `inline-block` parent).
|
|
30
|
+
*
|
|
31
|
+
* @param title - Accessible title announced to screen readers. Defaults to "Consent".
|
|
32
|
+
* @param titleId - DOM id for the SVG `<title>` element. Must be unique on the page when rendered more than once.
|
|
33
|
+
*/
|
|
24
34
|
export declare const ConsentLogo: ({ title, titleId, ...props }: SVGProps<SVGSVGElement> & IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
25
35
|
/**
|
|
26
36
|
* Consent icon only (without text).
|
|
@@ -16,7 +16,7 @@ export interface ReactUIOptions extends UIOptions {
|
|
|
16
16
|
* In offline mode this also includes `offlinePolicy` configuration for
|
|
17
17
|
* local policy previews.
|
|
18
18
|
*
|
|
19
|
-
* @see {@link https://
|
|
19
|
+
* @see {@link https://c15t.com/docs/frameworks/react/policy-packs}
|
|
20
20
|
*/
|
|
21
21
|
export type ConsentManagerOptions = BaseConsentManagerOptions & ReactUIOptions;
|
|
22
22
|
/**
|
|
@@ -33,7 +33,7 @@ export interface ConsentManagerProviderProps {
|
|
|
33
33
|
* Configuration options for the consent manager.
|
|
34
34
|
* This includes core, React, store, and translation settings.
|
|
35
35
|
*
|
|
36
|
-
* @see {@link https://
|
|
36
|
+
* @see {@link https://c15t.com/docs/frameworks/react/components/consent-manager-provider}
|
|
37
37
|
*/
|
|
38
38
|
options: ConsentManagerOptions;
|
|
39
39
|
}
|
package/dist-types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.0.
|
|
1
|
+
export declare const version = "2.0.2";
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AI Agents
|
|
3
|
+
description: Integrate c15t with AI coding assistants using the docs bundled in each package and c15t agent skills. Give agents version-matched local docs for consent management, banners, script loading, callbacks, and integrations.
|
|
4
|
+
lastModified: 2026-03-24
|
|
5
|
+
---
|
|
6
|
+
## Bundled Docs
|
|
7
|
+
|
|
8
|
+
Every supported c15t package now ships docs inside the installed package itself.
|
|
9
|
+
|
|
10
|
+
### Where to find them
|
|
11
|
+
|
|
12
|
+
* `node_modules/c15t/docs/README.md`
|
|
13
|
+
* `node_modules/@c15t/react/docs/README.md`
|
|
14
|
+
* `node_modules/@c15t/nextjs/docs/README.md`
|
|
15
|
+
* `node_modules/@c15t/backend/docs/README.md`
|
|
16
|
+
|
|
17
|
+
Start with the package `README.md`, then follow its linked pages for the relevant workflow.
|
|
18
|
+
|
|
19
|
+
These docs are version-matched to the exact c15t package version in your project, including generated reference content like prop and type tables.
|
|
20
|
+
|
|
21
|
+
### Why use them
|
|
22
|
+
|
|
23
|
+
If your app uses multiple c15t packages, use the docs from each relevant installed package instead of relying on stale model knowledge.
|
|
24
|
+
|
|
25
|
+
### Agent philosophy
|
|
26
|
+
|
|
27
|
+
When an AI tool is helping with c15t behavior, it should read the installed c15t docs first and use model knowledge second. That keeps consent flows, script gating, banner behavior, and integrations aligned with the exact version you have installed.
|
|
28
|
+
|
|
29
|
+
### Customization ladder for agents
|
|
30
|
+
|
|
31
|
+
When an agent is working on consent UI, it should choose the lowest-power tool that solves the task:
|
|
32
|
+
|
|
33
|
+
1. Start with the pre-built component and its existing props or provider options
|
|
34
|
+
2. Use `theme` tokens for semantic visual changes
|
|
35
|
+
3. Use `theme.slots` for targeted styling of specific parts
|
|
36
|
+
4. Use CSS variables or className-level overrides only when integrating with external styles
|
|
37
|
+
5. Use compound components only when the markup order must change
|
|
38
|
+
6. Use `noStyle` only when c15t structure is still correct but all styling must be replaced
|
|
39
|
+
7. Use headless hooks only when markup and behavior both need to be rebuilt
|
|
40
|
+
|
|
41
|
+
For common tasks:
|
|
42
|
+
|
|
43
|
+
* Banner footer background -> `theme.colors.surfaceHover`
|
|
44
|
+
* Banner card background -> `theme.colors.surface`
|
|
45
|
+
* Banner card/footer/title tweaks -> banner slots
|
|
46
|
+
* Stock action styling -> `theme.consentActions`
|
|
47
|
+
* Copy changes -> `ConsentManagerProvider.options.i18n`
|
|
48
|
+
|
|
49
|
+
If a token appears not to work, the agent should verify the token-to-component mapping before suggesting CSS overrides, `!important`, `noStyle`, or headless mode.
|
|
50
|
+
|
|
51
|
+
***
|
|
52
|
+
|
|
53
|
+
## Agent Skills
|
|
54
|
+
|
|
55
|
+
c15t publishes agent skills that give AI coding assistants deep knowledge of c15t's APIs, components, and configuration. Skills are reusable workflows and tool-specific guidance, not version-matched local docs.
|
|
56
|
+
|
|
57
|
+
### Installation
|
|
58
|
+
|
|
59
|
+
Via the c15t CLI:
|
|
60
|
+
|
|
61
|
+
|Package manager|Command|
|
|
62
|
+
|:--|:--|
|
|
63
|
+
|npm|`npx @c15t/cli install-skills`|
|
|
64
|
+
|pnpm|`pnpm dlx @c15t/cli install-skills`|
|
|
65
|
+
|yarn|`yarn dlx @c15t/cli install-skills`|
|
|
66
|
+
|bun|`bunx @c15t/cli install-skills`|
|
|
67
|
+
|
|
68
|
+
Or directly:
|
|
69
|
+
|
|
70
|
+
|Package manager|Command|
|
|
71
|
+
|:--|:--|
|
|
72
|
+
|npm|`npx skills add c15t/skills`|
|
|
73
|
+
|pnpm|`pnpm dlx skills add c15t/skills`|
|
|
74
|
+
|yarn|`yarn dlx skills add c15t/skills`|
|
|
75
|
+
|bun|`bunx skills add c15t/skills`|
|
|
76
|
+
|
|
77
|
+
### What skills provide
|
|
78
|
+
|
|
79
|
+
* **Styling customization** — strict escalation guidance across props, tokens, slots, CSS variables, compound components, `noStyle`, and headless
|
|
80
|
+
* **Internationalization** — translation setup, locale routing integration
|
|
81
|
+
* **Script management** — configuring third-party scripts with consent categories
|
|
82
|
+
* **Component setup** — ConsentBanner, ConsentDialog, provider configuration
|
|
83
|
+
|
|
84
|
+
### Supported tools
|
|
85
|
+
|
|
86
|
+
* Claude Code
|
|
87
|
+
* Cursor
|
|
88
|
+
* GitHub Copilot (via `.github/skills`)
|
|
89
|
+
* Any agent that supports the skills format
|
|
90
|
+
|
|
91
|
+
***
|
|
92
|
+
|
|
93
|
+
## When to use which
|
|
94
|
+
|
|
95
|
+
Use bundled docs when:
|
|
96
|
+
|
|
97
|
+
* Your agent can read files in the local project
|
|
98
|
+
* You want version-matched docs from the installed c15t packages
|
|
99
|
+
* You want a package-local README that tells the agent which detailed docs to read first
|
|
100
|
+
* You want concrete guidance for consent management, cookie banners, consent dialogs, preference centers, script loading, callbacks, and integrations
|
|
101
|
+
|
|
102
|
+
Use agent skills when:
|
|
103
|
+
|
|
104
|
+
* Your tool supports the skills ecosystem
|
|
105
|
+
* You want reusable workflows and tool-specific guidance that can point back to the installed package README files
|
|
106
|
+
|
|
107
|
+
Use both when:
|
|
108
|
+
|
|
109
|
+
* Your tool supports both local file context and skills
|
|
110
|
+
* You want local package docs plus reusable setup and configuration help
|
|
111
|
+
* You want the bundled package docs as the source of truth plus a reusable decision tree for customization
|
|
@@ -4,11 +4,11 @@ description: Build policy-aware custom consent components in React using the hea
|
|
|
4
4
|
---
|
|
5
5
|
Building custom consent UI is easier now because c15t exposes multiple layers of policy-aware primitives instead of forcing you to reconstruct banner rules by hand.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Think of customization as a ladder:
|
|
8
8
|
|
|
9
9
|
* stock component props for the shortest path
|
|
10
|
-
* `ConsentBanner.PolicyActions` and `ConsentWidget.PolicyActions`
|
|
11
|
-
* `useHeadlessConsentUI()`
|
|
10
|
+
* `ConsentBanner.PolicyActions` and `ConsentWidget.PolicyActions` when you want custom structure but still want c15t to resolve policy-aware actions
|
|
11
|
+
* `useHeadlessConsentUI()` when you need fully manual action rendering, custom controls, or non-standard flow
|
|
12
12
|
|
|
13
13
|
> ⚠️ **Warning:**
|
|
14
14
|
> Headless is the last step in the customization ladder. Use this guide only when pre-built components, tokens, slots, compound components, and noStyle are no longer sufficient.
|
|
@@ -26,6 +26,29 @@ The split is intentional: `@c15t/ui` owns pure policy-action resolution, while t
|
|
|
26
26
|
> ℹ️ **Info:**
|
|
27
27
|
> This guide is about building your own components while still respecting resolved policy-pack behavior. For the general headless overview, see Headless Mode.
|
|
28
28
|
|
|
29
|
+
## Choose the Smallest Layer That Solves the Job
|
|
30
|
+
|
|
31
|
+
Start with the smallest API surface that still gives you the behavior you need:
|
|
32
|
+
|
|
33
|
+
* Stay with stock components when you only need theming, spacing, copy, or legal-link changes
|
|
34
|
+
* Use `ConsentBanner.PolicyActions` or `ConsentWidget.PolicyActions` when you want a custom compound-component layout but still want grouped actions, ordering, and primary emphasis to come from policy
|
|
35
|
+
* Add `renderAction` when the grouping is still correct but you want to remap actions to stock c15t button compounds
|
|
36
|
+
* Reach for `useHeadlessConsentUI()` only when you need custom button elements, need to map `actionGroups` yourself, wire non-button controls, or coordinate the consent UI with a more custom state machine
|
|
37
|
+
|
|
38
|
+
This order matters because every step down the ladder gives you more control, but also makes it easier for your UI to drift away from the resolved policy if you stop using the provided state.
|
|
39
|
+
|
|
40
|
+
## Before You Build Headless UI
|
|
41
|
+
|
|
42
|
+
Do not use headless mode for problems that are still inside the stock component model:
|
|
43
|
+
|
|
44
|
+
* Use `layout`, `direction`, `primaryButton`, and `legalLinks` before you rebuild banner markup
|
|
45
|
+
* Use `theme.consentActions` before you swap out stock actions
|
|
46
|
+
* Use tokens such as `colors.surface` and `colors.surfaceHover` before raw CSS overrides
|
|
47
|
+
* Use slots such as `consentBannerCard`, `consentBannerFooter`, and `consentDialogCard` before compound components
|
|
48
|
+
* Use `ConsentManagerProvider.options.i18n` before rebuilding UI just to change text
|
|
49
|
+
|
|
50
|
+
A good rule: if the stock banner or dialog structure is still correct, you probably do not need headless mode.
|
|
51
|
+
|
|
29
52
|
## What the Headless Tooling Gives You
|
|
30
53
|
|
|
31
54
|
The main win is that your custom UI can stay aligned with policy packs without duplicating policy logic in your components.
|
|
@@ -40,9 +63,63 @@ The main win is that your custom UI can stay aligned with policy packs without d
|
|
|
40
63
|
* UI profile and scroll-lock hints
|
|
41
64
|
* whether the banner or dialog should currently be visible
|
|
42
65
|
|
|
66
|
+
The hook also gives you the policy-aware action helpers you are expected to call:
|
|
67
|
+
|
|
68
|
+
* `performBannerAction('accept' | 'reject')`
|
|
69
|
+
* `performDialogAction('accept' | 'reject')`
|
|
70
|
+
* `saveCustomPreferences()` for the dialog `customize` action
|
|
71
|
+
* `openDialog()`, `openBanner()`, and `closeUI()` for surface visibility
|
|
72
|
+
|
|
43
73
|
That means your component mostly focuses on markup and design-system concerns instead of re-implementing policy interpretation.
|
|
44
74
|
|
|
45
|
-
For most compound-component layouts, start with `ConsentBanner.PolicyActions` or `ConsentWidget.PolicyActions`. They render stock c15t buttons and translations by default, and `renderAction` is only needed when you want to override
|
|
75
|
+
For most compound-component layouts, start with `ConsentBanner.PolicyActions` or `ConsentWidget.PolicyActions`. They render stock c15t buttons and translations by default, and `renderAction` is only needed when you want to override which stock compound renders for each action. Reach for manual `actionGroups` mapping when you need action rendering that no longer fits the stock button compounds.
|
|
76
|
+
|
|
77
|
+
## Policy-Aware Compound Components First
|
|
78
|
+
|
|
79
|
+
If your goal is "custom layout, same policy behavior", start here before dropping to manual `actionGroups` rendering:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { ConsentBanner } from '@c15t/react';
|
|
83
|
+
|
|
84
|
+
export function BannerShell() {
|
|
85
|
+
return (
|
|
86
|
+
<ConsentBanner.Root>
|
|
87
|
+
<ConsentBanner.Card>
|
|
88
|
+
<ConsentBanner.Header>
|
|
89
|
+
<ConsentBanner.Title />
|
|
90
|
+
<ConsentBanner.Description />
|
|
91
|
+
</ConsentBanner.Header>
|
|
92
|
+
<ConsentBanner.PolicyActions />
|
|
93
|
+
</ConsentBanner.Card>
|
|
94
|
+
</ConsentBanner.Root>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Use `renderAction` only when you want to remap actions to stock button compounds while keeping the same policy-driven grouping and ordering:
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { ConsentBanner } from '@c15t/react';
|
|
103
|
+
|
|
104
|
+
export function BannerActionsWithCustomMapping() {
|
|
105
|
+
return (
|
|
106
|
+
<ConsentBanner.PolicyActions
|
|
107
|
+
renderAction={(action, props) => {
|
|
108
|
+
const { key, ...buttonProps } = props;
|
|
109
|
+
|
|
110
|
+
switch (action) {
|
|
111
|
+
case 'accept':
|
|
112
|
+
return <ConsentBanner.AcceptButton key={key} {...buttonProps} />;
|
|
113
|
+
case 'reject':
|
|
114
|
+
return <ConsentBanner.RejectButton key={key} {...buttonProps} />;
|
|
115
|
+
case 'customize':
|
|
116
|
+
return <ConsentBanner.CustomizeButton key={key} {...buttonProps} />;
|
|
117
|
+
}
|
|
118
|
+
}}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
```
|
|
46
123
|
|
|
47
124
|
> ℹ️ **Info:**
|
|
48
125
|
> For custom layouts built from c15t compound components, prefer ConsentBanner.PolicyActions and ConsentWidget.PolicyActions. The examples below intentionally use manual actionGroups mapping to show the fully headless escape hatch.
|
|
@@ -86,9 +163,20 @@ export function ConsentManager({ children }: { children: ReactNode }) {
|
|
|
86
163
|
import { useHeadlessConsentUI, useTranslations } from '@c15t/react/headless';
|
|
87
164
|
|
|
88
165
|
export function CustomConsentBanner() {
|
|
89
|
-
const { banner, openDialog,
|
|
166
|
+
const { banner, openDialog, performBannerAction } = useHeadlessConsentUI();
|
|
90
167
|
const translations = useTranslations();
|
|
91
168
|
|
|
169
|
+
function getActionLabel(action: (typeof banner.allowedActions)[number]) {
|
|
170
|
+
switch (action) {
|
|
171
|
+
case 'accept':
|
|
172
|
+
return translations.common.acceptAll;
|
|
173
|
+
case 'reject':
|
|
174
|
+
return translations.common.rejectAll;
|
|
175
|
+
case 'customize':
|
|
176
|
+
return translations.common.customize;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
92
180
|
if (!banner.isVisible) return null;
|
|
93
181
|
|
|
94
182
|
return (
|
|
@@ -111,14 +199,10 @@ export function CustomConsentBanner() {
|
|
|
111
199
|
openDialog();
|
|
112
200
|
return;
|
|
113
201
|
}
|
|
114
|
-
void
|
|
202
|
+
void performBannerAction(action);
|
|
115
203
|
}}
|
|
116
204
|
>
|
|
117
|
-
{action
|
|
118
|
-
? translations.common.acceptAll
|
|
119
|
-
: action === 'reject'
|
|
120
|
-
? translations.common.rejectAll
|
|
121
|
-
: translations.common.customize}
|
|
205
|
+
{getActionLabel(action)}
|
|
122
206
|
</button>
|
|
123
207
|
))}
|
|
124
208
|
</div>
|
|
@@ -149,6 +233,17 @@ export function CustomConsentDialog() {
|
|
|
149
233
|
} = useConsentManager();
|
|
150
234
|
const translations = useTranslations();
|
|
151
235
|
|
|
236
|
+
function getActionLabel(action: (typeof dialog.allowedActions)[number]) {
|
|
237
|
+
switch (action) {
|
|
238
|
+
case 'accept':
|
|
239
|
+
return translations.common.acceptAll;
|
|
240
|
+
case 'reject':
|
|
241
|
+
return translations.common.rejectAll;
|
|
242
|
+
case 'customize':
|
|
243
|
+
return translations.common.save;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
152
247
|
if (!dialog.isVisible) return null;
|
|
153
248
|
|
|
154
249
|
const displayedTypes = consentTypes.filter(
|
|
@@ -197,11 +292,7 @@ export function CustomConsentDialog() {
|
|
|
197
292
|
void performDialogAction(action);
|
|
198
293
|
}}
|
|
199
294
|
>
|
|
200
|
-
{action
|
|
201
|
-
? translations.common.acceptAll
|
|
202
|
-
: action === 'reject'
|
|
203
|
-
? translations.common.rejectAll
|
|
204
|
-
: translations.common.save}
|
|
295
|
+
{getActionLabel(action)}
|
|
205
296
|
</button>
|
|
206
297
|
))}
|
|
207
298
|
</div>
|
|
@@ -212,6 +303,17 @@ export function CustomConsentDialog() {
|
|
|
212
303
|
}
|
|
213
304
|
```
|
|
214
305
|
|
|
306
|
+
## What Headless Is Not For
|
|
307
|
+
|
|
308
|
+
Headless mode is not the recommended path for:
|
|
309
|
+
|
|
310
|
+
* changing the banner footer background
|
|
311
|
+
* rounding the stock banner card
|
|
312
|
+
* restyling stock banner or dialog buttons
|
|
313
|
+
* changing consent copy
|
|
314
|
+
|
|
315
|
+
Those should stay in the pre-built stack with tokens, slots, `theme.consentActions`, and provider `i18n`.
|
|
316
|
+
|
|
215
317
|
## What a Policy-Aware Headless Component Should Respect
|
|
216
318
|
|
|
217
319
|
When you build custom banner or dialog components, make sure they use:
|
|
@@ -241,36 +241,7 @@ renderAction={(action, props) => {
|
|
|
241
241
|
/>
|
|
242
242
|
```
|
|
243
243
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
```tsx
|
|
247
|
-
import { ConsentBanner, useTranslations } from '@c15t/react';
|
|
248
|
-
|
|
249
|
-
export function CustomBannerActions() {
|
|
250
|
-
const { common } = useTranslations();
|
|
251
|
-
|
|
252
|
-
return (
|
|
253
|
-
<ConsentBanner.PolicyActions
|
|
254
|
-
renderAction={(action, props) => (
|
|
255
|
-
<button
|
|
256
|
-
key={props.key}
|
|
257
|
-
type="button"
|
|
258
|
-
className={props.isPrimary ? 'btn-primary' : 'btn-secondary'}
|
|
259
|
-
style={props.style}
|
|
260
|
-
>
|
|
261
|
-
{action === 'accept'
|
|
262
|
-
? common.acceptAll
|
|
263
|
-
: action === 'reject'
|
|
264
|
-
? common.rejectAll
|
|
265
|
-
: common.customize}
|
|
266
|
-
</button>
|
|
267
|
-
)}
|
|
268
|
-
/>
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
For maximum control, use `useHeadlessConsentUI()` and render `banner.actionGroups` manually.
|
|
244
|
+
`renderAction` is still meant for stock button compounds. If you want completely custom button elements and click handling, use `useHeadlessConsentUI()` and render `banner.actionGroups` manually instead of `ConsentBanner.PolicyActions`.
|
|
274
245
|
|
|
275
246
|
If you only need styling changes, stay with tokens and slots instead of rebuilding the banner layout.
|
|
276
247
|
|
|
@@ -75,7 +75,7 @@ Add a floating button that lets users re-open the dialog after dismissing the ba
|
|
|
75
75
|
|
|
76
76
|
## Branding
|
|
77
77
|
|
|
78
|
-
Hide the c15t branding
|
|
78
|
+
Hide the c15t branding tag:
|
|
79
79
|
|
|
80
80
|
```tsx
|
|
81
81
|
<ConsentDialog hideBranding />
|
|
@@ -84,7 +84,7 @@ Hide the c15t branding in the dialog footer:
|
|
|
84
84
|
## Styling First
|
|
85
85
|
|
|
86
86
|
> ℹ️ **Info:**
|
|
87
|
-
> If you are only changing visuals, stay with the stock dialog and use the theme system first. Start with tokens and slots such as consentDialogCard,
|
|
87
|
+
> If you are only changing visuals, stay with the stock dialog and use the theme system first. Start with tokens and slots such as consentDialogCard, consentWidgetFooter, and consentDialogTag. See Styling Overview.
|
|
88
88
|
|
|
89
89
|
```tsx
|
|
90
90
|
<ConsentManagerProvider
|
|
@@ -97,7 +97,8 @@ Hide the c15t branding in the dialog footer:
|
|
|
97
97
|
slots: {
|
|
98
98
|
consentDialogCard: 'rounded-[32px] shadow-xl',
|
|
99
99
|
consentDialogHeader: 'gap-3',
|
|
100
|
-
|
|
100
|
+
consentWidgetFooter: 'gap-3 pt-6',
|
|
101
|
+
consentDialogTag: 'shadow-none',
|
|
101
102
|
},
|
|
102
103
|
},
|
|
103
104
|
}}
|
|
@@ -36,15 +36,15 @@ export default function ConsentManager({ children }: { children: ReactNode }) {
|
|
|
36
36
|
|Property|Type|Description|Default|Required|
|
|
37
37
|
|:--|:--|:--|:--|:--:|
|
|
38
38
|
|enabled|boolean \|undefined|Whether c15t should be active.|true|Optional|
|
|
39
|
-
|callbacks|[Callbacks \|undefined](https://
|
|
40
|
-
|scripts|[Script \|undefined](https://
|
|
39
|
+
|callbacks|[Callbacks \|undefined](https://c15t.com/docs/frameworks/react/callbacks)|Event callbacks for consent actions.|-|Optional|
|
|
40
|
+
|scripts|[Script \|undefined](https://c15t.com/docs/frameworks/react/script-loader)|Dynamically load scripts based on consent state.|-|Optional|
|
|
41
41
|
|legalLinks|Object \|undefined|Configuration for the legal links.|-|Optional|
|
|
42
42
|
|storageConfig|StorageConfig \|undefined|Storage configuration for consent persistence.|-|Optional|
|
|
43
43
|
|user|User \|undefined|The user's information. Usually your own internal ID for the user from your auth provider.|-|Optional|
|
|
44
44
|
|overrides|Overrides \|undefined|Forcefully set values like country, region, language for the consent manager. These values will override the values detected from the browser.|-|Optional|
|
|
45
|
-
|networkBlocker|[NetworkBlockerConfig \|undefined](https://
|
|
46
|
-
|iab|[IABConfig \|undefined](https://
|
|
47
|
-
|ssrData|[Object \|undefined](https://
|
|
45
|
+
|networkBlocker|[NetworkBlockerConfig \|undefined](https://c15t.com/docs/frameworks/react/network-blocker)|Configuration for the network request blocker.|-|Optional|
|
|
46
|
+
|iab|[IABConfig \|undefined](https://c15t.com/docs/frameworks/react/iab/overview)|IAB TCF 2.3 configuration.|-|Optional|
|
|
47
|
+
|ssrData|[Object \|undefined](https://c15t.com/docs/frameworks/react/server-side)|SSR-prefetched data for hydration.|-|Optional|
|
|
48
48
|
|
|
49
49
|
#### `callbacks` Callbacks
|
|
50
50
|
|
|
@@ -146,9 +146,9 @@ IAB TCF 2.3 configuration.
|
|
|
146
146
|
|
|
147
147
|
|Property|Type|Description|Default|Required|
|
|
148
148
|
|:--|:--|:--|:--|:--:|
|
|
149
|
-
|enabled|boolean|Enable IAB TCF 2.3 mode. Note: Only works in 'hosted' client mode (legacy alias: 'c15t') because it requires a backend. Options: Fetch GVL from gvl.
|
|
149
|
+
|enabled|boolean|Enable IAB TCF 2.3 mode. Note: Only works in 'hosted' client mode (legacy alias: 'c15t') because it requires a backend. Options: Fetch GVL from gvl.inth.app; Initialize \_\_tcfapi CMP API; Generate TC Strings for IAB compliance|-|✅ Required|
|
|
150
150
|
|\_module|IABModule \|undefined|IAB runtime module injected by \`@c15t/iab\`.|-|Optional|
|
|
151
|
-
|cmpId|number \|undefined|CMP ID registered with IAB Europe. When using
|
|
151
|
+
|cmpId|number \|undefined|CMP ID registered with IAB Europe. When using inth.com as the backend, this is automatically provided via the \`/init\` endpoint — no client-side configuration needed. Only set this if you self-host and have your own CMP registration. A valid (non-zero) CMP ID is required for IAB TCF compliance.|-|Optional|
|
|
152
152
|
|cmpVersion|string \|number \|undefined|CMP version. When omitted, defaults to package version from \`\~/cmp-defaults\` (which uses \~/version).|-|Optional|
|
|
153
153
|
|vendors|number\[] \|undefined|IAB-registered vendor IDs to include (optional). Used to scope the vendor list when fetching GVL or when hosted fallback paths are used (e.g. if GVL fetch fails).|-|Optional|
|
|
154
154
|
|customVendors|NonIABVendor \|undefined|Custom vendors not registered with IAB. These are displayed separately in the consent UI with a note that they have different privacy practices than IAB vendors.|-|Optional|
|
|
@@ -171,8 +171,8 @@ SSR-prefetched data for hydration.
|
|
|
171
171
|
|Property|Type|Description|Default|Required|
|
|
172
172
|
|:--|:--|:--|:--|:--:|
|
|
173
173
|
|i18n|I18nConfig \|undefined|Preferred i18n configuration in c15t v2.|-|Optional|
|
|
174
|
-
|translations|[TranslationConfig \|undefined](https://
|
|
175
|
-
|consentCategories|[AllConsentNames \|undefined](https://
|
|
174
|
+
|translations|[TranslationConfig \|undefined](https://c15t.com/docs/frameworks/react/internationalization)|Translation configuration to seed the store with.|-|Optional|
|
|
175
|
+
|consentCategories|[AllConsentNames \|undefined](https://c15t.com/docs/frameworks/react/concepts/consent-categories)|Consent categories to show in the consent banner.|-|Optional|
|
|
176
176
|
|
|
177
177
|
#### `i18n` I18nConfig
|
|
178
178
|
|
|
@@ -198,12 +198,12 @@ Translation configuration to seed the store with.
|
|
|
198
198
|
|
|
199
199
|
|Property|Type|Description|Default|Required|
|
|
200
200
|
|:--|:--|:--|:--|:--:|
|
|
201
|
-
|theme|[Theme \|undefined](https://
|
|
201
|
+
|theme|[Theme \|undefined](https://c15t.com/docs/frameworks/react/styling/tokens)|Visual theme to apply.|-|Optional|
|
|
202
202
|
|disableAnimation|boolean \|undefined|Whether to disable animations.|false|Optional|
|
|
203
203
|
|scrollLock|boolean \|undefined|Whether to lock scroll when dialogs are open.|false|Optional|
|
|
204
204
|
|trapFocus|boolean \|undefined|Whether to trap focus within dialogs.|true|Optional|
|
|
205
|
-
|colorScheme|["light" \|"dark" \|"system" \|undefined](https://
|
|
206
|
-
|noStyle|[boolean \|undefined](https://
|
|
205
|
+
|colorScheme|["light" \|"dark" \|"system" \|undefined](https://c15t.com/docs/frameworks/react/styling/color-scheme)|Color scheme preference. With this option, you can force the theme to be light, dark or system. Otherwise, the theme will be detected if you have '.dark' classname in your document.|-|Optional|
|
|
206
|
+
|noStyle|[boolean \|undefined](https://c15t.com/docs/frameworks/react/headless)|Whether to disable default styles.|false|Optional|
|
|
207
207
|
|
|
208
208
|
#### `theme` Theme
|
|
209
209
|
|
|
@@ -392,7 +392,7 @@ Read the full guide at [Policy Packs](/docs/frameworks/react/policy-packs) and t
|
|
|
392
392
|
|Property|Type|Description|Default|Required|
|
|
393
393
|
|:--|:--|:--|:--|:--:|
|
|
394
394
|
|children|ReactNode|React children to render within the provider.|-|✅ Required|
|
|
395
|
-
|options|[ConsentManagerOptions](https://
|
|
395
|
+
|options|[ConsentManagerOptions](https://c15t.com/docs/frameworks/react/components/consent-manager-provider)|Configuration options for the consent manager. This includes core, React, store, and translation settings.|-|✅ Required|
|
|
396
396
|
|
|
397
397
|
#### `options` ConsentManagerOptions
|
|
398
398
|
|
|
@@ -117,34 +117,7 @@ renderAction={(action, props) => {
|
|
|
117
117
|
/>
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
```tsx
|
|
123
|
-
import { ConsentWidget, useTranslations } from '@c15t/react';
|
|
124
|
-
|
|
125
|
-
export function CustomWidgetActions() {
|
|
126
|
-
const { common } = useTranslations();
|
|
127
|
-
|
|
128
|
-
return (
|
|
129
|
-
<ConsentWidget.PolicyActions
|
|
130
|
-
renderAction={(action, props) => (
|
|
131
|
-
<button
|
|
132
|
-
key={props.key}
|
|
133
|
-
type="button"
|
|
134
|
-
className={props.isPrimary ? 'btn-primary' : 'btn-secondary'}
|
|
135
|
-
style={props.style}
|
|
136
|
-
>
|
|
137
|
-
{action === 'accept'
|
|
138
|
-
? common.acceptAll
|
|
139
|
-
: action === 'reject'
|
|
140
|
-
? common.rejectAll
|
|
141
|
-
: common.save}
|
|
142
|
-
</button>
|
|
143
|
-
)}
|
|
144
|
-
/>
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
```
|
|
120
|
+
`renderAction` is still meant for stock button compounds. If you want completely custom button elements and handlers, use `useHeadlessConsentUI()` and render `dialog.actionGroups` manually instead of `ConsentWidget.PolicyActions`.
|
|
148
121
|
|
|
149
122
|
For a fixed footer layout, render `ConsentWidget.Footer` and `ConsentWidget.FooterSubGroup` manually instead of using `ConsentWidget.PolicyActions`.
|
|
150
123
|
|
|
@@ -54,6 +54,39 @@ export function ConsentManager({ children }: { children: ReactNode }) {
|
|
|
54
54
|
|**Events**|Timeline of consent events and state changes|
|
|
55
55
|
|**Actions**|Buttons to trigger consent actions (accept all, reject all, reset)|
|
|
56
56
|
|
|
57
|
+
## TanStack Devtools
|
|
58
|
+
|
|
59
|
+
`@c15t/dev-tools/tanstack` exposes a panel component and plugin factory that match TanStack Devtools' plugin API, so c15t can sit beside Query and Router without a custom mount adapter:
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
import * as React from 'react';
|
|
63
|
+
import { useRouter } from '@tanstack/react-router';
|
|
64
|
+
import { TanStackDevtools } from '@tanstack/react-devtools';
|
|
65
|
+
import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools';
|
|
66
|
+
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools';
|
|
67
|
+
import { c15tDevtools } from '@c15t/dev-tools/tanstack';
|
|
68
|
+
|
|
69
|
+
export function AppDevtools() {
|
|
70
|
+
const router = useRouter();
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<TanStackDevtools
|
|
74
|
+
plugins={[
|
|
75
|
+
{
|
|
76
|
+
name: 'TanStack Query',
|
|
77
|
+
render: <ReactQueryDevtoolsPanel />,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'TanStack Router',
|
|
81
|
+
render: <TanStackRouterDevtoolsPanel router={router} />,
|
|
82
|
+
},
|
|
83
|
+
c15tDevtools(),
|
|
84
|
+
]}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
57
90
|
## Props
|
|
58
91
|
|
|
59
92
|
### C15TDevToolsProps
|