@c15t/nextjs 2.0.0-rc.4 → 2.0.0-rc.6
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/dist/headless.cjs +1 -1
- package/dist/iab/styles.css +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/libs/browser-initial-data.cjs +1 -0
- package/dist/libs/browser-initial-data.js +1 -0
- package/dist/libs/initial-data.cjs +1 -1
- package/dist/libs/initial-data.js +1 -1
- package/dist/styles.css +1 -0
- package/dist/types.cjs +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/dist-types/headless.d.ts +1 -0
- package/{dist → dist-types}/index.d.ts +4 -3
- package/dist-types/libs/browser-initial-data.d.ts +9 -0
- package/{dist → dist-types}/libs/initial-data.d.ts +1 -2
- package/dist-types/types.d.ts +38 -0
- package/dist-types/version.d.ts +1 -0
- package/docs/README.md +73 -0
- package/docs/building-headless-components.md +250 -0
- package/docs/callbacks.md +117 -0
- package/docs/components/consent-banner.md +174 -0
- package/docs/components/consent-dialog-link.md +59 -0
- package/docs/components/consent-dialog-trigger.md +103 -0
- package/docs/components/consent-dialog.md +137 -0
- package/docs/components/consent-manager-provider.md +423 -0
- package/docs/components/consent-widget.md +78 -0
- package/docs/components/dev-tools.md +63 -0
- package/docs/components/frame.md +73 -0
- package/docs/concepts/client-modes.md +163 -0
- package/docs/concepts/consent-categories.md +97 -0
- package/docs/concepts/consent-models.md +116 -0
- package/docs/concepts/cookie-management.md +122 -0
- package/docs/concepts/glossary.md +23 -0
- package/docs/concepts/initialization-flow.md +141 -0
- package/docs/concepts/policy-packs.md +229 -0
- package/docs/headless.md +184 -0
- package/docs/hooks/use-color-scheme.md +40 -0
- package/docs/hooks/use-consent-manager/checking-consent.md +94 -0
- package/docs/hooks/use-consent-manager/location-info.md +95 -0
- package/docs/hooks/use-consent-manager/overview.md +390 -0
- package/docs/hooks/use-consent-manager/setting-consent.md +92 -0
- package/docs/hooks/use-draggable.md +57 -0
- package/docs/hooks/use-focus-trap.md +41 -0
- package/docs/hooks/use-reduced-motion.md +35 -0
- package/docs/hooks/use-ssr-status.md +31 -0
- package/docs/hooks/use-text-direction.md +49 -0
- package/docs/hooks/use-translations.md +117 -0
- package/docs/iab/consent-banner.md +95 -0
- package/docs/iab/consent-dialog.md +135 -0
- package/docs/iab/overview.md +119 -0
- package/docs/iab/use-gvl-data.md +208 -0
- package/docs/iframe-blocking.md +107 -0
- package/docs/integrations/databuddy.md +186 -0
- package/docs/integrations/google-tag-manager.md +153 -0
- package/docs/integrations/google-tag.md +149 -0
- package/docs/integrations/linkedin-insights.md +109 -0
- package/docs/integrations/meta-pixel.md +342 -0
- package/docs/integrations/microsoft-uet.md +112 -0
- package/docs/integrations/overview.md +89 -0
- package/docs/integrations/posthog.md +177 -0
- package/docs/integrations/tiktok-pixel.md +113 -0
- package/docs/integrations/x-pixel.md +143 -0
- package/docs/internationalization.md +197 -0
- package/docs/network-blocker.md +178 -0
- package/docs/optimization.md +156 -0
- package/docs/policy-packs.md +246 -0
- package/docs/quickstart.md +155 -0
- package/docs/script-loader.md +300 -0
- package/docs/server-side.md +171 -0
- package/docs/styling/classnames.md +84 -0
- package/docs/styling/color-scheme.md +82 -0
- package/docs/styling/css-variables.md +92 -0
- package/docs/styling/overview.md +312 -0
- package/docs/styling/slots.md +93 -0
- package/docs/styling/tailwind.md +115 -0
- package/docs/styling/tokens.md +214 -0
- package/docs/troubleshooting.md +146 -0
- package/package.json +20 -13
- package/dist/headless.d.ts +0 -2
- package/dist/headless.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/libs/initial-data.d.ts.map +0 -1
- package/dist/types.d.ts +0 -16
- package/dist/types.d.ts.map +0 -1
- package/dist/version.d.ts +0 -2
- package/dist/version.d.ts.map +0 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Server-Side Data Fetching
|
|
3
|
+
description: Pre-fetch consent data in Server Components with fetchInitialData — eliminate the loading flash and enable streaming.
|
|
4
|
+
---
|
|
5
|
+
The `@c15t/nextjs` package provides `fetchInitialData`, a server-side function that fetches consent data before rendering. This enables SSR hydration — consent state is available immediately on page load without a client-side fetch, eliminating the consent banner flash.
|
|
6
|
+
|
|
7
|
+
> ℹ️ **Info:**
|
|
8
|
+
> SSR hydration is part of the initialization flow. When SSR data is available, the client skips the API fetch entirely.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { fetchInitialData } from '@c15t/nextjs';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## fetchInitialData
|
|
15
|
+
|
|
16
|
+
The primary function for fetching consent data on the server. It calls the c15t backend's `/init` endpoint with the user's request headers (resolved automatically from `next/headers`) and returns the initial consent data.
|
|
17
|
+
|
|
18
|
+
```ts title="app/layout.tsx"
|
|
19
|
+
import { fetchInitialData } from '@c15t/nextjs';
|
|
20
|
+
|
|
21
|
+
// In a Server Component — do NOT await
|
|
22
|
+
const ssrData = fetchInitialData({
|
|
23
|
+
backendURL: '/api/c15t',
|
|
24
|
+
debug: process.env.NODE_ENV === 'development',
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
> ℹ️ **Info:**
|
|
29
|
+
> Do not await fetchInitialData() in Server Components. Pass the Promise directly to your client component so Next.js can stream the page while the consent data loads in parallel.
|
|
30
|
+
>
|
|
31
|
+
> ℹ️ **Info:**
|
|
32
|
+
> Need fully static routes? Use C15tPrefetch in your layout and getPrefetchedInitialData() in your client provider instead of fetchInitialData(). See Optimization.
|
|
33
|
+
|
|
34
|
+
### How Streaming Works
|
|
35
|
+
|
|
36
|
+
The diagram below shows how the prefetch avoids blocking the page render. The server fires the `/init` request and immediately starts streaming HTML — the resolved consent data is sent as a later chunk once the backend responds.
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
sequenceDiagram
|
|
40
|
+
participant SC as Server Component
|
|
41
|
+
participant NR as Next.js Runtime
|
|
42
|
+
participant BR as Browser
|
|
43
|
+
participant BE as c15t Backend
|
|
44
|
+
|
|
45
|
+
SC->>BE: fetchInitialData() → GET /init
|
|
46
|
+
Note right of SC: Returns a Promise - (not awaited)
|
|
47
|
+
SC->>NR: Render page tree - (Promise passed as prop)
|
|
48
|
+
NR->>BR: Stream initial HTML
|
|
49
|
+
BR->>BR: Hydrate — no consent data yet
|
|
50
|
+
|
|
51
|
+
BE-->>NR: /init response resolves
|
|
52
|
+
NR->>BR: Stream resolved data chunk
|
|
53
|
+
BR->>BR: Provider receives SSR data - skips client-side /init fetch
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Options
|
|
57
|
+
|
|
58
|
+
|Property|Type|Description|Default|Required|
|
|
59
|
+
|:--|:--|:--|:--|:--:|
|
|
60
|
+
|nextCache|NextCacheOptions \|undefined|Optional Next.js cache controls for SSR init requests.|-|Optional|
|
|
61
|
+
|
|
62
|
+
#### `nextCache` NextCacheOptions
|
|
63
|
+
|
|
64
|
+
Optional Next.js cache controls for SSR init requests.
|
|
65
|
+
|
|
66
|
+
|Property|Type|Description|Default|Required|
|
|
67
|
+
|:--|:--|:--|:--|:--:|
|
|
68
|
+
|revalidateSeconds|number \|false \|undefined|Cache lifetime in seconds for the Next.js data cache. Set to false to disable Next.js caching for this call.|-|Optional|
|
|
69
|
+
|
|
70
|
+
### Return Value
|
|
71
|
+
|
|
72
|
+
Returns `Promise<SSRInitialData | undefined>`. The data includes the init response (jurisdiction, translations, consent model) and GVL data when IAB is configured.
|
|
73
|
+
|
|
74
|
+
### Passing SSR Data to the Provider
|
|
75
|
+
|
|
76
|
+
Pass the unresolved Promise to the provider's `ssrData` option via a client component:
|
|
77
|
+
|
|
78
|
+
```tsx title="components/consent-manager/index.tsx"
|
|
79
|
+
'use client';
|
|
80
|
+
|
|
81
|
+
import { type ReactNode } from 'react';
|
|
82
|
+
import { ConsentManagerProvider, ConsentBanner, ConsentDialog } from '@c15t/nextjs';
|
|
83
|
+
import type { InitialDataPromise } from '@c15t/nextjs';
|
|
84
|
+
|
|
85
|
+
export default function ConsentManager({
|
|
86
|
+
children,
|
|
87
|
+
ssrData,
|
|
88
|
+
}: {
|
|
89
|
+
children: ReactNode;
|
|
90
|
+
ssrData?: InitialDataPromise;
|
|
91
|
+
}) {
|
|
92
|
+
return (
|
|
93
|
+
<ConsentManagerProvider
|
|
94
|
+
options={{
|
|
95
|
+
mode: 'hosted',
|
|
96
|
+
backendURL: '/api/c15t',
|
|
97
|
+
store: { ssrData },
|
|
98
|
+
}}
|
|
99
|
+
>
|
|
100
|
+
<ConsentBanner />
|
|
101
|
+
<ConsentDialog />
|
|
102
|
+
{children}
|
|
103
|
+
</ConsentManagerProvider>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```tsx title="app/layout.tsx"
|
|
109
|
+
import { fetchInitialData } from '@c15t/nextjs';
|
|
110
|
+
import ConsentManager from '@/components/consent-manager';
|
|
111
|
+
|
|
112
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
113
|
+
const ssrData = fetchInitialData({
|
|
114
|
+
backendURL: '/api/c15t',
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<html lang="en">
|
|
119
|
+
<body>
|
|
120
|
+
<ConsentManager ssrData={ssrData}>
|
|
121
|
+
{children}
|
|
122
|
+
</ConsentManager>
|
|
123
|
+
</body>
|
|
124
|
+
</html>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## How Headers Are Resolved
|
|
130
|
+
|
|
131
|
+
Unlike `@c15t/react/server` where you must pass headers manually, `fetchInitialData` uses `next/headers` to automatically resolve the incoming request headers. This means geo-location headers from Vercel, Cloudflare, or AWS CloudFront are forwarded to the c15t backend without any extra configuration.
|
|
132
|
+
|
|
133
|
+
|Header|Source|Contains|
|
|
134
|
+
|--|--|--|
|
|
135
|
+
|`cf-ipcountry`|Cloudflare|Country code|
|
|
136
|
+
|`x-vercel-ip-country`|Vercel|Country code|
|
|
137
|
+
|`x-amz-cf-ipcountry`|AWS CloudFront|Country code|
|
|
138
|
+
|`x-vercel-ip-country-region`|Vercel|Region code|
|
|
139
|
+
|`accept-language`|Browser|Language preference|
|
|
140
|
+
|`x-forwarded-host`|Proxy|Original host|
|
|
141
|
+
|`x-forwarded-for`|Proxy|Client IP|
|
|
142
|
+
|
|
143
|
+
## Advanced: Using @c15t/react/server Directly
|
|
144
|
+
|
|
145
|
+
For advanced use cases (custom server frameworks, edge functions, or non-standard header resolution), the underlying utilities from `@c15t/react/server` are available:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
import {
|
|
149
|
+
fetchSSRData,
|
|
150
|
+
extractRelevantHeaders,
|
|
151
|
+
normalizeBackendURL,
|
|
152
|
+
validateBackendURL,
|
|
153
|
+
} from '@c15t/react/server';
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
See the [React Server-Side Utilities](/docs/frameworks/react/server-side) docs for full API details.
|
|
157
|
+
|
|
158
|
+
## Debugging SSR
|
|
159
|
+
|
|
160
|
+
Use the [useSSRStatus](/docs/frameworks/next/hooks/use-ssr-status) hook on the client to verify SSR data was consumed:
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
import { useSSRStatus } from '@c15t/nextjs';
|
|
164
|
+
|
|
165
|
+
function DebugSSR() {
|
|
166
|
+
const { ssrDataUsed, ssrSkippedReason } = useSSRStatus();
|
|
167
|
+
|
|
168
|
+
if (ssrDataUsed) return <span>SSR hydration successful</span>;
|
|
169
|
+
return <span>SSR skipped: {ssrSkippedReason ?? 'unknown'}</span>;
|
|
170
|
+
}
|
|
171
|
+
```
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Class Names
|
|
3
|
+
description: Style consent components using className props and per-slot className targeting via the theme.
|
|
4
|
+
---
|
|
5
|
+
## Component className
|
|
6
|
+
|
|
7
|
+
All consent components accept a `className` prop:
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
<ConsentBanner className="my-banner" />
|
|
11
|
+
<ConsentDialog className="my-dialog" />
|
|
12
|
+
<ConsentWidget className="my-widget" />
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Per-Slot className
|
|
16
|
+
|
|
17
|
+
Target individual component parts via the theme's `slots` object. Each slot accepts a string (className) or an object with `className` and `style`:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
const theme = {
|
|
21
|
+
slots: {
|
|
22
|
+
consentBannerTitle: 'text-xl font-semibold',
|
|
23
|
+
consentBannerDescription: 'text-sm text-gray-600',
|
|
24
|
+
consentBannerFooter: 'flex gap-3',
|
|
25
|
+
buttonPrimary: 'rounded-full px-6',
|
|
26
|
+
},
|
|
27
|
+
} satisfies Theme;
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Combining with CSS Modules
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import styles from './consent.module.css';
|
|
34
|
+
|
|
35
|
+
const theme = {
|
|
36
|
+
slots: {
|
|
37
|
+
consentBannerCard: styles.bannerCard,
|
|
38
|
+
consentBannerTitle: styles.bannerTitle,
|
|
39
|
+
buttonPrimary: styles.primaryButton,
|
|
40
|
+
},
|
|
41
|
+
} satisfies Theme;
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```css title="consent.module.css"
|
|
45
|
+
.bannerCard {
|
|
46
|
+
backdrop-filter: blur(12px);
|
|
47
|
+
background: rgba(255, 255, 255, 0.9);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.bannerTitle {
|
|
51
|
+
font-size: 1.25rem;
|
|
52
|
+
font-weight: 700;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.primaryButton {
|
|
56
|
+
border-radius: 9999px;
|
|
57
|
+
text-transform: uppercase;
|
|
58
|
+
letter-spacing: 0.05em;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## noStyle Mode
|
|
63
|
+
|
|
64
|
+
Use `noStyle` when you want to remove defaults and style from scratch:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
{/* Remove all styles from a specific component */}
|
|
68
|
+
<ConsentBanner noStyle />
|
|
69
|
+
|
|
70
|
+
{/* Remove all styles globally */}
|
|
71
|
+
<ConsentManagerProvider options={{ noStyle: true, ... }}>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
You can also set `noStyle` per-slot:
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
const theme = {
|
|
78
|
+
slots: {
|
|
79
|
+
consentBannerCard: { noStyle: true, className: 'my-custom-card' },
|
|
80
|
+
},
|
|
81
|
+
} satisfies Theme;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For full custom markup and behavior, continue to [Headless Mode](../headless).
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Color Scheme
|
|
3
|
+
description: Support light mode, dark mode, and system preference detection in consent components.
|
|
4
|
+
---
|
|
5
|
+
c15t supports light and dark mode through the theme's `colors` and `dark` token groups. The active color scheme is determined by one of three methods:
|
|
6
|
+
|
|
7
|
+
1. **Explicit setting** via the `colorScheme` option
|
|
8
|
+
2. **CSS class detection** - c15t checks for `.dark` on the document element
|
|
9
|
+
3. **System preference** - matches `prefers-color-scheme` media query
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
Set the color scheme on the provider:
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { type ReactNode } from 'react';
|
|
17
|
+
import { ConsentManagerProvider } from '@c15t/nextjs';
|
|
18
|
+
|
|
19
|
+
function ConsentManager({ children }: { children: ReactNode }) {
|
|
20
|
+
return (
|
|
21
|
+
<ConsentManagerProvider
|
|
22
|
+
options={{
|
|
23
|
+
mode: 'hosted',
|
|
24
|
+
backendURL: '/api/c15t',
|
|
25
|
+
colorScheme: 'system', // 'light' | 'dark' | 'system'
|
|
26
|
+
theme: {
|
|
27
|
+
colors: {
|
|
28
|
+
primary: '#6366f1',
|
|
29
|
+
surface: '#ffffff',
|
|
30
|
+
text: '#1f2937',
|
|
31
|
+
},
|
|
32
|
+
dark: {
|
|
33
|
+
primary: '#818cf8',
|
|
34
|
+
surface: '#1f2937',
|
|
35
|
+
text: '#f9fafb',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
{children}
|
|
41
|
+
</ConsentManagerProvider>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## useColorScheme Hook
|
|
47
|
+
|
|
48
|
+
For programmatic control over the color scheme:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { useColorScheme } from '@c15t/nextjs';
|
|
52
|
+
|
|
53
|
+
function ThemeToggle() {
|
|
54
|
+
// Pass the desired scheme - 'light', 'dark', 'system', or null (disable)
|
|
55
|
+
useColorScheme('system');
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
|Value|Behavior|
|
|
60
|
+
|--|--|
|
|
61
|
+
|`'light'`|Force light mode|
|
|
62
|
+
|`'dark'`|Force dark mode|
|
|
63
|
+
|`'system'`|Follow `prefers-color-scheme` media query|
|
|
64
|
+
|`null`|Disable - c15t won't manage color scheme|
|
|
65
|
+
|
|
66
|
+
## How Dark Mode Works
|
|
67
|
+
|
|
68
|
+
When dark mode is active, c15t applies the `dark` token values as CSS variable overrides. Only tokens specified in `dark` are overridden - unset tokens fall back to the `colors` values.
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
const theme = {
|
|
72
|
+
colors: {
|
|
73
|
+
surface: '#ffffff', // Light mode
|
|
74
|
+
text: '#1f2937', // Light mode
|
|
75
|
+
},
|
|
76
|
+
dark: {
|
|
77
|
+
surface: '#1f2937', // Dark mode override
|
|
78
|
+
text: '#f9fafb', // Dark mode override
|
|
79
|
+
// primary is NOT set - inherits from colors.primary
|
|
80
|
+
},
|
|
81
|
+
} satisfies Theme;
|
|
82
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: CSS Variables
|
|
3
|
+
description: Reference for all --c15t-* CSS custom properties generated by the theme system.
|
|
4
|
+
---
|
|
5
|
+
Every theme token is converted to a `--c15t-*` CSS custom property at runtime. You can override these variables in your stylesheet without using the JavaScript theme API.
|
|
6
|
+
|
|
7
|
+
## Variable Reference
|
|
8
|
+
|
|
9
|
+
### ThemeCSSVariables
|
|
10
|
+
|
|
11
|
+
|Property|Type|Description|Default|Required|
|
|
12
|
+
|:--|:--|:--|:--|:--:|
|
|
13
|
+
|--c15t-primary|string \|undefined|\`colors.primary\` (default: \`hsl(228, 100%, 60%)\`)|-|Optional|
|
|
14
|
+
|--c15t-primary-hover|string \|undefined|\`colors.primaryHover\` (default: \`hsl(228, 100%, 55%)\`)|-|Optional|
|
|
15
|
+
|--c15t-surface|string \|undefined|\`colors.surface\` (default: \`hsl(0, 0%, 100%)\`)|-|Optional|
|
|
16
|
+
|--c15t-surface-hover|string \|undefined|\`colors.surfaceHover\` (default: \`hsl(0, 0%, 98%)\`)|-|Optional|
|
|
17
|
+
|--c15t-border|string \|undefined|\`colors.border\` (default: \`hsl(0, 0%, 90%)\`)|-|Optional|
|
|
18
|
+
|--c15t-border-hover|string \|undefined|\`colors.borderHover\` (default: \`hsl(0, 0%, 85%)\`)|-|Optional|
|
|
19
|
+
|--c15t-text|string \|undefined|\`colors.text\` (default: \`hsl(0, 0%, 10%)\`)|-|Optional|
|
|
20
|
+
|--c15t-text-muted|string \|undefined|\`colors.textMuted\` (default: \`hsl(0, 0%, 40%)\`)|-|Optional|
|
|
21
|
+
|--c15t-text-on-primary|string \|undefined|\`colors.textOnPrimary\` (default: \`hsl(0, 0%, 100%)\`)|-|Optional|
|
|
22
|
+
|--c15t-overlay|string \|undefined|\`colors.overlay\` (default: \`hsla(0, 0%, 0%, 0.5)\`)|-|Optional|
|
|
23
|
+
|--c15t-switch-track|string \|undefined|\`colors.switchTrack\` (default: \`hsl(0, 0%, 85%)\`)|-|Optional|
|
|
24
|
+
|--c15t-switch-track-active|string \|undefined|\`colors.switchTrackActive\` (default: \`hsl(228, 100%, 60%)\`)|-|Optional|
|
|
25
|
+
|--c15t-switch-thumb|string \|undefined|\`colors.switchThumb\` (default: \`hsl(0, 0%, 100%)\`)|-|Optional|
|
|
26
|
+
|--c15t-font-family|string \|undefined|\`typography.fontFamily\` (default: \`system-ui, -apple-system, sans-serif\`)|-|Optional|
|
|
27
|
+
|--c15t-font-size-sm|string \|undefined|\`typography.fontSize.sm\` (default: \`0.875rem\`)|-|Optional|
|
|
28
|
+
|--c15t-font-size-base|string \|undefined|\`typography.fontSize.base\` (default: \`1rem\`)|-|Optional|
|
|
29
|
+
|--c15t-font-size-lg|string \|undefined|\`typography.fontSize.lg\` (default: \`1.125rem\`)|-|Optional|
|
|
30
|
+
|--c15t-font-weight-normal|string \|undefined|\`typography.fontWeight.normal\` (default: \`400\`)|-|Optional|
|
|
31
|
+
|--c15t-font-weight-medium|string \|undefined|\`typography.fontWeight.medium\` (default: \`500\`)|-|Optional|
|
|
32
|
+
|--c15t-font-weight-semibold|string \|undefined|\`typography.fontWeight.semibold\` (default: \`600\`)|-|Optional|
|
|
33
|
+
|--c15t-line-height-tight|string \|undefined|\`typography.lineHeight.tight\` (default: \`1.25\`)|-|Optional|
|
|
34
|
+
|--c15t-line-height-normal|string \|undefined|\`typography.lineHeight.normal\` (default: \`1.5\`)|-|Optional|
|
|
35
|
+
|--c15t-line-height-relaxed|string \|undefined|\`typography.lineHeight.relaxed\` (default: \`1.75\`)|-|Optional|
|
|
36
|
+
|--c15t-space-xs|string \|undefined|\`spacing.xs\` (default: \`0.25rem\`)|-|Optional|
|
|
37
|
+
|--c15t-space-sm|string \|undefined|\`spacing.sm\` (default: \`0.5rem\`)|-|Optional|
|
|
38
|
+
|--c15t-space-md|string \|undefined|\`spacing.md\` (default: \`1rem\`)|-|Optional|
|
|
39
|
+
|--c15t-space-lg|string \|undefined|\`spacing.lg\` (default: \`1.5rem\`)|-|Optional|
|
|
40
|
+
|--c15t-space-xl|string \|undefined|\`spacing.xl\` (default: \`2rem\`)|-|Optional|
|
|
41
|
+
|--c15t-radius-sm|string \|undefined|\`radius.sm\` (default: \`0.25rem\`)|-|Optional|
|
|
42
|
+
|--c15t-radius-md|string \|undefined|\`radius.md\` (default: \`0.5rem\`)|-|Optional|
|
|
43
|
+
|--c15t-radius-lg|string \|undefined|\`radius.lg\` (default: \`0.75rem\`)|-|Optional|
|
|
44
|
+
|--c15t-radius-full|string \|undefined|\`radius.full\` (default: \`9999px\`)|-|Optional|
|
|
45
|
+
|--c15t-shadow-sm|string \|undefined|\`shadows.sm\` (default: \`0 1px 2px hsla(0, 0%, 0%, 0.05)\`)|-|Optional|
|
|
46
|
+
|--c15t-shadow-md|string \|undefined|\`shadows.md\` (default: \`0 4px 12px hsla(0, 0%, 0%, 0.08)\`)|-|Optional|
|
|
47
|
+
|--c15t-shadow-lg|string \|undefined|\`shadows.lg\` (default: \`0 8px 24px hsla(0, 0%, 0%, 0.12)\`)|-|Optional|
|
|
48
|
+
|--c15t-duration-fast|string \|undefined|\`motion.duration.fast\` (default: \`100ms\`)|-|Optional|
|
|
49
|
+
|--c15t-duration-normal|string \|undefined|\`motion.duration.normal\` (default: \`200ms\`)|-|Optional|
|
|
50
|
+
|--c15t-duration-slow|string \|undefined|\`motion.duration.slow\` (default: \`300ms\`)|-|Optional|
|
|
51
|
+
|--c15t-easing|string \|undefined|\`motion.easing\` (default: \`cubic-bezier(0.4, 0, 0.2, 1)\`)|-|Optional|
|
|
52
|
+
|--c15t-easing-out|string \|undefined|\`motion.easingOut\` (default: \`cubic-bezier(0.215, 0.61, 0.355, 1)\`)|-|Optional|
|
|
53
|
+
|--c15t-easing-in-out|string \|undefined|\`motion.easingInOut\` (default: \`cubic-bezier(0.645, 0.045, 0.355, 1)\`)|-|Optional|
|
|
54
|
+
|--c15t-easing-spring|string \|undefined|\`motion.easingSpring\` (default: \`cubic-bezier(0.34, 1.56, 0.64, 1)\`)|-|Optional|
|
|
55
|
+
|
|
56
|
+
## Overriding Variables
|
|
57
|
+
|
|
58
|
+
Override in your stylesheet:
|
|
59
|
+
|
|
60
|
+
```css
|
|
61
|
+
:root {
|
|
62
|
+
--c15t-primary: #8b5cf6;
|
|
63
|
+
--c15t-surface: #fafafa;
|
|
64
|
+
--c15t-radius-md: 1rem;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Dark mode overrides */
|
|
68
|
+
.dark,
|
|
69
|
+
.c15t-dark {
|
|
70
|
+
--c15t-primary: #a78bfa;
|
|
71
|
+
--c15t-surface: #18181b;
|
|
72
|
+
--c15t-text: #fafafa;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Scoped Overrides
|
|
77
|
+
|
|
78
|
+
Target specific components by scoping variables:
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
<div className="checkout-consent">
|
|
82
|
+
<ConsentBanner />
|
|
83
|
+
</div>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```css
|
|
87
|
+
/* Only affect c15t components inside .checkout-consent */
|
|
88
|
+
.checkout-consent {
|
|
89
|
+
--c15t-surface: #f0f9ff;
|
|
90
|
+
--c15t-radius-lg: 1.5rem;
|
|
91
|
+
}
|
|
92
|
+
```
|