@el7ven/cookie-kit 0.2.15
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 +201 -0
- package/dist/styles/index.css +744 -0
- package/package.json +64 -0
- package/src/core/index.js +232 -0
- package/src/core/index.test.js +90 -0
- package/src/core/version.js +29 -0
- package/src/index.js +67 -0
- package/src/js/CookieConsent.js +618 -0
- package/src/js/components/index.js +1 -0
- package/src/js/index.js +53 -0
- package/src/js/index.test.js +42 -0
- package/src/js/version.js +29 -0
- package/src/react/CookieConsent.tsx +152 -0
- package/src/react/CookieDrawer.tsx +233 -0
- package/src/react/components/index.js +2 -0
- package/src/react/index.js +89 -0
- package/src/react/index.test.js +62 -0
- package/src/react/types.ts +47 -0
- package/src/react/version.js +29 -0
- package/src/vue/CookieConsent.vue +180 -0
- package/src/vue/CookieDrawer.vue +203 -0
- package/src/vue/components/index.js +2 -0
- package/src/vue/composables/useCookieConsent.js +182 -0
- package/src/vue/index.js +58 -0
- package/src/vue/index.test.js +40 -0
- package/src/vue/version.js +29 -0
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
import { initCookieKit } from './index.js'
|
|
2
|
+
|
|
3
|
+
class CookieConsent extends HTMLElement {
|
|
4
|
+
constructor() {
|
|
5
|
+
super()
|
|
6
|
+
this.config = this.parseConfig()
|
|
7
|
+
this.cookieKit = null
|
|
8
|
+
this.isVisible = false
|
|
9
|
+
this.isSettingsMode = false
|
|
10
|
+
this.currentTab = 'privacy'
|
|
11
|
+
this.categories = { ...this.config.categories }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
connectedCallback() {
|
|
15
|
+
this.cookieKit = initCookieKit(this.config)
|
|
16
|
+
this.setupEventListeners()
|
|
17
|
+
this.checkConsentAndRender()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
parseConfig() {
|
|
21
|
+
const configAttr = this.getAttribute('config')
|
|
22
|
+
if (configAttr) {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(configAttr)
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.warn('CookieConsent: Invalid config attribute, using defaults')
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
categories: {
|
|
32
|
+
necessary: { required: true, enabled: true, name: 'Essential Cookies' },
|
|
33
|
+
analytics: { required: false, enabled: false, name: 'Analytics Cookies' },
|
|
34
|
+
marketing: { required: false, enabled: false, name: 'Marketing Cookies' }
|
|
35
|
+
},
|
|
36
|
+
consentExpireDays: 365,
|
|
37
|
+
version: '0.2.0',
|
|
38
|
+
mode: 'gdpr',
|
|
39
|
+
theme: 'light'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setupEventListeners() {
|
|
44
|
+
// Listen to consent changes
|
|
45
|
+
if (this.cookieKit?.on) {
|
|
46
|
+
this.cookieKit.on('consentChanged', ({ consent }) => {
|
|
47
|
+
this.isVisible = !consent.hasConsented
|
|
48
|
+
this.render()
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
checkConsentAndRender() {
|
|
54
|
+
this.isVisible = !this.cookieKit.hasConsent()
|
|
55
|
+
this.render()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
showSettings() {
|
|
59
|
+
this.isSettingsMode = true
|
|
60
|
+
this.render()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
hideSettings() {
|
|
64
|
+
this.isSettingsMode = false
|
|
65
|
+
this.render()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
selectTab(tabId) {
|
|
69
|
+
this.currentTab = tabId
|
|
70
|
+
this.render()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
toggleCategory(categoryId) {
|
|
74
|
+
const category = this.categories[categoryId]
|
|
75
|
+
if (category) {
|
|
76
|
+
this.categories[categoryId] = { ...category, enabled: !category.enabled }
|
|
77
|
+
this.render()
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
handleAcceptAll() {
|
|
82
|
+
this.cookieKit.acceptAll()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
handleRejectAll() {
|
|
86
|
+
this.cookieKit.rejectAll()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
handleAcceptSelection() {
|
|
90
|
+
// Save current category states
|
|
91
|
+
Object.keys(this.categories).forEach(id => {
|
|
92
|
+
const isEnabled = this.categories[id]?.enabled
|
|
93
|
+
if (isEnabled !== undefined) {
|
|
94
|
+
this.cookieKit.acceptCategory(id, isEnabled)
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getCategoryTitle(categoryId) {
|
|
100
|
+
return this.categories[categoryId]?.name || categoryId
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getCategoryDescription(categoryId) {
|
|
104
|
+
return this.categories[categoryId]?.description || `Description for ${categoryId} cookies.`
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
getEnabledSettingsTabs() {
|
|
108
|
+
return ['privacy', ...Object.keys(this.categories).filter(id =>
|
|
109
|
+
this.categories[id]?.enabled
|
|
110
|
+
)]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
render() {
|
|
114
|
+
if (!this.isVisible) {
|
|
115
|
+
this.innerHTML = ''
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const isEssentialBanner = this.config.mode === 'essential'
|
|
120
|
+
const enabledSettingsTabs = this.getEnabledSettingsTabs()
|
|
121
|
+
const theme = this.config.theme || this.getAttribute('theme') || 'light'
|
|
122
|
+
|
|
123
|
+
this.innerHTML = `
|
|
124
|
+
<style>
|
|
125
|
+
${this.getStyles()}
|
|
126
|
+
</style>
|
|
127
|
+
|
|
128
|
+
<div class="cookie-consent" data-cookie-kit-theme="${theme}">
|
|
129
|
+
<!-- Backdrop -->
|
|
130
|
+
${!isEssentialBanner ? '<div class="cookie-drawer__backdrop"></div>' : ''}
|
|
131
|
+
|
|
132
|
+
<!-- Drawer -->
|
|
133
|
+
<div class="cookie-drawer__content-wrapper ${this.isSettingsMode ? 'cookie-drawer__content-wrapper--settings' : 'cookie-drawer__content-wrapper--banner'} cookie-drawer__content-wrapper--bottom">
|
|
134
|
+
<div class="cookie-drawer__content" role="dialog" aria-modal="true">
|
|
135
|
+
<!-- Header -->
|
|
136
|
+
<div class="cookie-drawer__header">
|
|
137
|
+
<h3 class="cookie-drawer__title">
|
|
138
|
+
${this.isSettingsMode
|
|
139
|
+
? 'Cookie Settings'
|
|
140
|
+
: (this.config.mode === 'essential'
|
|
141
|
+
? 'Essential Cookies'
|
|
142
|
+
: 'Cookie Consent')
|
|
143
|
+
}
|
|
144
|
+
</h3>
|
|
145
|
+
${!this.isSettingsMode && !isEssentialBanner ? `
|
|
146
|
+
<div class="cookie-drawer__message">
|
|
147
|
+
We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies.
|
|
148
|
+
</div>
|
|
149
|
+
` : ''}
|
|
150
|
+
${this.isSettingsMode ? `
|
|
151
|
+
<button class="cookie-drawer__close" aria-label="Close">
|
|
152
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
153
|
+
<path d="M6.40013 18.3079L5.69238 17.6001L11.2924 12.0001L5.69238 6.40013L6.40013 5.69238L12.0001 11.2924L17.6001 5.69238L18.3079 6.40013L12.7079 12.0001L18.3079 17.6001L17.6001 18.3079L12.0001 12.7079L6.40013 18.3079Z" fill="#0D0B3D"/>
|
|
154
|
+
</svg>
|
|
155
|
+
</button>
|
|
156
|
+
` : ''}
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<!-- Essential Banner -->
|
|
160
|
+
${!this.isSettingsMode && isEssentialBanner ? `
|
|
161
|
+
<div class="cookie-drawer__banner">
|
|
162
|
+
<div class="cookie-drawer__essential">
|
|
163
|
+
<div class="cookie-drawer__message cookie-drawer__message--essential">
|
|
164
|
+
We use essential cookies to make our site work. By using our site, you accept our use of essential cookies.
|
|
165
|
+
</div>
|
|
166
|
+
<div class="cookie-drawer__actions">
|
|
167
|
+
<button class="cookie-drawer__button cookie-drawer__button--primary" data-action="accept-all">
|
|
168
|
+
Accept
|
|
169
|
+
</button>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
` : ''}
|
|
174
|
+
|
|
175
|
+
<!-- GDPR Banner/Settings -->
|
|
176
|
+
${(!this.isSettingsMode || !isEssentialBanner) ? `
|
|
177
|
+
<div class="cookie-drawer__body">
|
|
178
|
+
<!-- Banner Mode -->
|
|
179
|
+
${!this.isSettingsMode ? `
|
|
180
|
+
<div class="cookie-drawer__banner">
|
|
181
|
+
<div class="cookie-drawer__message">
|
|
182
|
+
We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies.
|
|
183
|
+
</div>
|
|
184
|
+
<div class="cookie-drawer__actions">
|
|
185
|
+
<button class="cookie-drawer__button cookie-drawer__button--secondary" data-action="reject-all">
|
|
186
|
+
Reject All
|
|
187
|
+
</button>
|
|
188
|
+
<button class="cookie-drawer__button cookie-drawer__button--primary" data-action="accept-all">
|
|
189
|
+
Accept All
|
|
190
|
+
</button>
|
|
191
|
+
<button class="cookie-drawer__button cookie-drawer__button--link" data-action="open-settings">
|
|
192
|
+
Customize
|
|
193
|
+
</button>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
` : ''}
|
|
197
|
+
|
|
198
|
+
<!-- Settings Mode -->
|
|
199
|
+
${this.isSettingsMode ? `
|
|
200
|
+
<div class="cookie-drawer__settings">
|
|
201
|
+
<!-- Tabs -->
|
|
202
|
+
${enabledSettingsTabs.length > 1 ? `
|
|
203
|
+
<div class="cookie-drawer__tabs">
|
|
204
|
+
${enabledSettingsTabs.map(tab => `
|
|
205
|
+
<button class="cookie-drawer__tab ${this.currentTab === tab ? 'cookie-drawer__tab--active' : ''}" data-tab="${tab}">
|
|
206
|
+
${this.getCategoryTitle(tab)}
|
|
207
|
+
</button>
|
|
208
|
+
`).join('')}
|
|
209
|
+
</div>
|
|
210
|
+
` : ''}
|
|
211
|
+
|
|
212
|
+
<!-- Tab Content -->
|
|
213
|
+
<div class="cookie-drawer__tab-content">
|
|
214
|
+
${this.currentTab === 'privacy' ? `
|
|
215
|
+
<div class="cookie-drawer__privacy">
|
|
216
|
+
<h4>Privacy Policy</h4>
|
|
217
|
+
<p>Learn about how we use cookies and protect your privacy.</p>
|
|
218
|
+
</div>
|
|
219
|
+
` : `
|
|
220
|
+
<div class="cookie-drawer__category">
|
|
221
|
+
<div class="cookie-drawer__category-header">
|
|
222
|
+
<h4>${this.getCategoryTitle(this.currentTab)}</h4>
|
|
223
|
+
<label class="cookie-drawer__toggle">
|
|
224
|
+
<input
|
|
225
|
+
type="checkbox"
|
|
226
|
+
${this.categories[this.currentTab]?.enabled ? 'checked' : ''}
|
|
227
|
+
${this.categories[this.currentTab]?.required ? 'disabled' : ''}
|
|
228
|
+
data-category="${this.currentTab}"
|
|
229
|
+
/>
|
|
230
|
+
<span class="cookie-drawer__toggle-slider"></span>
|
|
231
|
+
</label>
|
|
232
|
+
</div>
|
|
233
|
+
<div class="cookie-drawer__category-description">
|
|
234
|
+
${this.getCategoryDescription(this.currentTab)}
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
`}
|
|
238
|
+
</div>
|
|
239
|
+
|
|
240
|
+
<!-- Settings Actions -->
|
|
241
|
+
<div class="cookie-drawer__settings-actions">
|
|
242
|
+
<button class="cookie-drawer__button cookie-drawer__button--primary" data-action="accept-selection">
|
|
243
|
+
Save Preferences
|
|
244
|
+
</button>
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
` : ''}
|
|
248
|
+
</div>
|
|
249
|
+
` : ''}
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
`
|
|
254
|
+
|
|
255
|
+
this.attachEventHandlers()
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
attachEventHandlers() {
|
|
259
|
+
// Button handlers
|
|
260
|
+
this.querySelectorAll('[data-action]').forEach(button => {
|
|
261
|
+
button.addEventListener('click', (e) => {
|
|
262
|
+
const action = e.target.getAttribute('data-action')
|
|
263
|
+
switch (action) {
|
|
264
|
+
case 'accept-all':
|
|
265
|
+
this.handleAcceptAll()
|
|
266
|
+
break
|
|
267
|
+
case 'reject-all':
|
|
268
|
+
this.handleRejectAll()
|
|
269
|
+
break
|
|
270
|
+
case 'accept-selection':
|
|
271
|
+
this.handleAcceptSelection()
|
|
272
|
+
break
|
|
273
|
+
case 'open-settings':
|
|
274
|
+
this.showSettings()
|
|
275
|
+
break
|
|
276
|
+
}
|
|
277
|
+
})
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
// Close button
|
|
281
|
+
this.querySelector('.cookie-drawer__close')?.addEventListener('click', () => {
|
|
282
|
+
this.hideSettings()
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
// Backdrop click
|
|
286
|
+
this.querySelector('.cookie-drawer__backdrop')?.addEventListener('click', () => {
|
|
287
|
+
if (!this.isSettingsMode) {
|
|
288
|
+
this.hideSettings()
|
|
289
|
+
}
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
// Tab buttons
|
|
293
|
+
this.querySelectorAll('[data-tab]').forEach(button => {
|
|
294
|
+
button.addEventListener('click', (e) => {
|
|
295
|
+
const tabId = e.target.getAttribute('data-tab')
|
|
296
|
+
this.selectTab(tabId)
|
|
297
|
+
})
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
// Category toggles
|
|
301
|
+
this.querySelectorAll('[data-category]').forEach(checkbox => {
|
|
302
|
+
checkbox.addEventListener('change', (e) => {
|
|
303
|
+
const categoryId = e.target.getAttribute('data-category')
|
|
304
|
+
this.toggleCategory(categoryId)
|
|
305
|
+
})
|
|
306
|
+
})
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
getStyles() {
|
|
310
|
+
return `
|
|
311
|
+
:root {
|
|
312
|
+
--ck-accent: #0026aa;
|
|
313
|
+
--ck-accent-hover: #002699;
|
|
314
|
+
--ck-bg: #ffffff;
|
|
315
|
+
--ck-bg-muted: #f8f9fa;
|
|
316
|
+
--ck-text: rgba(13, 11, 61, 1);
|
|
317
|
+
--ck-text-muted: #666666;
|
|
318
|
+
--ck-border: #e0e0e0;
|
|
319
|
+
--ck-backdrop: rgba(0, 0, 0, 0.4);
|
|
320
|
+
--ck-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
|
321
|
+
--ck-link: var(--ck-accent);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
[data-cookie-kit-theme="dark"] {
|
|
325
|
+
--ck-accent: #4da3ff;
|
|
326
|
+
--ck-accent-hover: #2b8aff;
|
|
327
|
+
--ck-bg: #1e1e2e;
|
|
328
|
+
--ck-bg-muted: #2a2a3e;
|
|
329
|
+
--ck-text: #e0e0e0;
|
|
330
|
+
--ck-text-muted: #a0a0b0;
|
|
331
|
+
--ck-border: #3a3a4e;
|
|
332
|
+
--ck-backdrop: rgba(0, 0, 0, 0.6);
|
|
333
|
+
--ck-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
|
|
334
|
+
--ck-link: var(--ck-accent);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/* Animations */
|
|
338
|
+
.cookie-drawer__backdrop {
|
|
339
|
+
position: fixed;
|
|
340
|
+
top: 0;
|
|
341
|
+
left: 0;
|
|
342
|
+
right: 0;
|
|
343
|
+
bottom: 0;
|
|
344
|
+
background: var(--ck-backdrop);
|
|
345
|
+
z-index: 9998;
|
|
346
|
+
animation: fadeIn 0.3s ease;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.cookie-drawer__content-wrapper {
|
|
350
|
+
position: fixed;
|
|
351
|
+
top: 0;
|
|
352
|
+
bottom: 0;
|
|
353
|
+
left: 0;
|
|
354
|
+
right: 0;
|
|
355
|
+
z-index: 9999;
|
|
356
|
+
display: flex;
|
|
357
|
+
align-items: flex-end;
|
|
358
|
+
justify-content: center;
|
|
359
|
+
padding: 24px;
|
|
360
|
+
animation: slideUp 0.3s ease;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
@keyframes fadeIn {
|
|
364
|
+
from { opacity: 0; }
|
|
365
|
+
to { opacity: 1; }
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
@keyframes slideUp {
|
|
369
|
+
from { transform: translateY(100%); opacity: 0; }
|
|
370
|
+
to { transform: translateY(0); opacity: 1; }
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* Layout */
|
|
374
|
+
.cookie-drawer__content {
|
|
375
|
+
background: var(--ck-bg);
|
|
376
|
+
border-radius: 48px;
|
|
377
|
+
max-width: 900px;
|
|
378
|
+
width: 100%;
|
|
379
|
+
max-height: 100%;
|
|
380
|
+
overflow: hidden;
|
|
381
|
+
box-shadow: var(--ck-shadow);
|
|
382
|
+
display: flex;
|
|
383
|
+
flex-direction: column;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/* Header */
|
|
387
|
+
.cookie-drawer__header {
|
|
388
|
+
padding: 24px 24px 16px;
|
|
389
|
+
border-bottom: 1px solid var(--ck-border);
|
|
390
|
+
display: flex;
|
|
391
|
+
justify-content: space-between;
|
|
392
|
+
align-items: flex-start;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.cookie-drawer__title {
|
|
396
|
+
margin: 0;
|
|
397
|
+
font-size: 20px;
|
|
398
|
+
font-weight: 600;
|
|
399
|
+
color: var(--ck-text);
|
|
400
|
+
line-height: 1.4;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.cookie-drawer__message {
|
|
404
|
+
margin-top: 8px;
|
|
405
|
+
color: var(--ck-text-muted);
|
|
406
|
+
font-size: 14px;
|
|
407
|
+
line-height: 1.5;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.cookie-drawer__close {
|
|
411
|
+
background: none;
|
|
412
|
+
border: none;
|
|
413
|
+
padding: 4px;
|
|
414
|
+
cursor: pointer;
|
|
415
|
+
border-radius: 4px;
|
|
416
|
+
transition: background-color 0.2s;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.cookie-drawer__close:hover {
|
|
420
|
+
background-color: var(--ck-bg-muted);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/* Banner */
|
|
424
|
+
.cookie-drawer__banner {
|
|
425
|
+
padding: 24px;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.cookie-drawer__actions {
|
|
429
|
+
display: flex;
|
|
430
|
+
gap: 12px;
|
|
431
|
+
margin-top: 16px;
|
|
432
|
+
flex-wrap: wrap;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.cookie-drawer__button {
|
|
436
|
+
padding: 12px 24px;
|
|
437
|
+
border-radius: 8px;
|
|
438
|
+
font-size: 14px;
|
|
439
|
+
font-weight: 500;
|
|
440
|
+
cursor: pointer;
|
|
441
|
+
transition: all 0.2s;
|
|
442
|
+
border: none;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.cookie-drawer__button--primary {
|
|
446
|
+
background-color: var(--ck-accent);
|
|
447
|
+
color: white;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.cookie-drawer__button--primary:hover {
|
|
451
|
+
background-color: var(--ck-accent-hover);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.cookie-drawer__button--secondary {
|
|
455
|
+
background-color: var(--ck-bg-muted);
|
|
456
|
+
color: var(--ck-text);
|
|
457
|
+
border: 1px solid var(--ck-border);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.cookie-drawer__button--secondary:hover {
|
|
461
|
+
background-color: #e5e7eb;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.cookie-drawer__button--link {
|
|
465
|
+
background: none;
|
|
466
|
+
color: var(--ck-link);
|
|
467
|
+
padding: 8px 16px;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.cookie-drawer__button--link:hover {
|
|
471
|
+
text-decoration: underline;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/* Settings */
|
|
475
|
+
.cookie-drawer__settings {
|
|
476
|
+
padding: 0 24px 24px;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.cookie-drawer__tabs {
|
|
480
|
+
display: flex;
|
|
481
|
+
border-bottom: 1px solid var(--ck-border);
|
|
482
|
+
margin: 0 -24px;
|
|
483
|
+
padding: 0 24px;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.cookie-drawer__tab {
|
|
487
|
+
background: none;
|
|
488
|
+
border: none;
|
|
489
|
+
padding: 16px 20px;
|
|
490
|
+
cursor: pointer;
|
|
491
|
+
color: var(--ck-text-muted);
|
|
492
|
+
font-size: 14px;
|
|
493
|
+
font-weight: 500;
|
|
494
|
+
border-bottom: 2px solid transparent;
|
|
495
|
+
transition: all 0.2s;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.cookie-drawer__tab--active {
|
|
499
|
+
color: var(--ck-accent);
|
|
500
|
+
border-bottom-color: var(--ck-accent);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.cookie-drawer__tab:hover:not(.cookie-drawer__tab--active) {
|
|
504
|
+
color: var(--ck-text);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.cookie-drawer__tab-content {
|
|
508
|
+
padding: 24px 0;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.cookie-drawer__category-header {
|
|
512
|
+
display: flex;
|
|
513
|
+
justify-content: space-between;
|
|
514
|
+
align-items: center;
|
|
515
|
+
margin-bottom: 12px;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.cookie-drawer__category-header h4 {
|
|
519
|
+
margin: 0;
|
|
520
|
+
font-size: 16px;
|
|
521
|
+
font-weight: 600;
|
|
522
|
+
color: var(--ck-text);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.cookie-drawer__toggle {
|
|
526
|
+
position: relative;
|
|
527
|
+
display: inline-block;
|
|
528
|
+
width: 48px;
|
|
529
|
+
height: 24px;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
.cookie-drawer__toggle input {
|
|
533
|
+
opacity: 0;
|
|
534
|
+
width: 0;
|
|
535
|
+
height: 0;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.cookie-drawer__toggle-slider {
|
|
539
|
+
position: absolute;
|
|
540
|
+
cursor: pointer;
|
|
541
|
+
top: 0;
|
|
542
|
+
left: 0;
|
|
543
|
+
right: 0;
|
|
544
|
+
bottom: 0;
|
|
545
|
+
background-color: var(--ck-border);
|
|
546
|
+
transition: 0.3s;
|
|
547
|
+
border-radius: 24px;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.cookie-drawer__toggle-slider:before {
|
|
551
|
+
position: absolute;
|
|
552
|
+
content: "";
|
|
553
|
+
height: 18px;
|
|
554
|
+
width: 18px;
|
|
555
|
+
left: 3px;
|
|
556
|
+
bottom: 3px;
|
|
557
|
+
background-color: white;
|
|
558
|
+
transition: 0.3s;
|
|
559
|
+
border-radius: 50%;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.cookie-drawer__toggle input:checked + .cookie-drawer__toggle-slider {
|
|
563
|
+
background-color: var(--ck-accent);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
.cookie-drawer__toggle input:checked + .cookie-drawer__toggle-slider:before {
|
|
567
|
+
transform: translateX(24px);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.cookie-drawer__toggle input:disabled + .cookie-drawer__toggle-slider {
|
|
571
|
+
background-color: #9ca3af;
|
|
572
|
+
cursor: not-allowed;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
.cookie-drawer__category-description {
|
|
576
|
+
color: var(--ck-text-muted);
|
|
577
|
+
font-size: 14px;
|
|
578
|
+
line-height: 1.5;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
.cookie-drawer__settings-actions {
|
|
582
|
+
margin-top: 24px;
|
|
583
|
+
padding-top: 24px;
|
|
584
|
+
border-top: 1px solid var(--ck-border);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/* Responsive */
|
|
588
|
+
@media (max-width: 640px) {
|
|
589
|
+
.cookie-drawer__header {
|
|
590
|
+
padding: 20px 20px 16px;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
.cookie-drawer__banner {
|
|
594
|
+
padding: 20px;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.cookie-drawer__settings {
|
|
598
|
+
padding: 0 20px 20px;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.cookie-drawer__actions {
|
|
602
|
+
flex-direction: column;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
.cookie-drawer__button {
|
|
606
|
+
width: 100%;
|
|
607
|
+
text-align: center;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
`
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Export for manual registration
|
|
615
|
+
export { CookieConsent }
|
|
616
|
+
|
|
617
|
+
// Uncomment to enable automatic registration:
|
|
618
|
+
// customElements.define('cookie-consent', CookieConsent)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CookieConsent } from '../CookieConsent.js'
|
package/src/js/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { CookieKitCore, createCookieKit, DEFAULT_CONFIG } from '../core/index.js'
|
|
2
|
+
import { VERSION, getVersion, getVersionInfo, logVersion } from './version.js'
|
|
3
|
+
|
|
4
|
+
export { CookieKitCore, createCookieKit, DEFAULT_CONFIG }
|
|
5
|
+
export { VERSION, getVersion, getVersionInfo, logVersion }
|
|
6
|
+
|
|
7
|
+
export function mountCookieConsentGlobal(core, target = globalThis) {
|
|
8
|
+
if (!target) return null
|
|
9
|
+
|
|
10
|
+
target.CookieConsent = {
|
|
11
|
+
hasConsent: () => core.hasConsent(),
|
|
12
|
+
hasCategoryConsent: category => core.hasCategoryConsent(category),
|
|
13
|
+
getConsentData: () => core.getConsent(),
|
|
14
|
+
acceptAll: () => core.acceptAll('api'),
|
|
15
|
+
rejectAll: () => core.rejectAll('api'),
|
|
16
|
+
acceptSelected: categories => core.acceptSelected(categories, 'api'),
|
|
17
|
+
clearConsent: () => core.clearConsent(),
|
|
18
|
+
on: (event, cb) => core.on(event, cb),
|
|
19
|
+
off: (event, cb) => core.off(event, cb),
|
|
20
|
+
// Version helpers
|
|
21
|
+
getVersion: () => getVersion(),
|
|
22
|
+
getVersionInfo: () => getVersionInfo(),
|
|
23
|
+
logVersion: () => logVersion()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return target.CookieConsent
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function initCookieKit(config = {}, options = {}) {
|
|
30
|
+
const core = createCookieKit(config)
|
|
31
|
+
|
|
32
|
+
if (options.mountGlobal !== false) {
|
|
33
|
+
mountCookieConsentGlobal(core, options.target || globalThis)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return core
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function mountCookieConsent(config = {}, targetId = 'cookie-consent-root') {
|
|
40
|
+
const core = createCookieKit(config)
|
|
41
|
+
const target = document.getElementById(targetId)
|
|
42
|
+
|
|
43
|
+
if (target) {
|
|
44
|
+
// Import CookieConsent dynamically
|
|
45
|
+
import('./CookieConsent.js').then(({ CookieConsent }) => {
|
|
46
|
+
const element = new CookieConsent()
|
|
47
|
+
element.setAttribute('config', JSON.stringify(config))
|
|
48
|
+
target.appendChild(element)
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return core
|
|
53
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import test from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import { initCookieKit } from './index.js'
|
|
5
|
+
|
|
6
|
+
function createMemoryStorageAdapter() {
|
|
7
|
+
const memory = new Map()
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
getItem: key => memory.get(key) ?? null,
|
|
11
|
+
setItem: (key, value) => memory.set(key, value),
|
|
12
|
+
removeItem: key => memory.delete(key),
|
|
13
|
+
defaultKey: 'cookie_consent'
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
test('js adapter: mounts global API and performs consent actions', async () => {
|
|
18
|
+
const target = {}
|
|
19
|
+
|
|
20
|
+
initCookieKit({
|
|
21
|
+
storageAdapter: createMemoryStorageAdapter(),
|
|
22
|
+
categories: {
|
|
23
|
+
necessary: { required: true, enabled: true },
|
|
24
|
+
analytics: { required: false, enabled: true }
|
|
25
|
+
}
|
|
26
|
+
}, {
|
|
27
|
+
mountGlobal: true,
|
|
28
|
+
target
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
assert.ok(target.CookieConsent)
|
|
32
|
+
|
|
33
|
+
await target.CookieConsent.acceptSelected(['analytics'])
|
|
34
|
+
|
|
35
|
+
assert.equal(target.CookieConsent.hasConsent(), true)
|
|
36
|
+
assert.equal(target.CookieConsent.hasCategoryConsent('necessary'), true)
|
|
37
|
+
assert.equal(target.CookieConsent.hasCategoryConsent('analytics'), true)
|
|
38
|
+
|
|
39
|
+
target.CookieConsent.clearConsent()
|
|
40
|
+
|
|
41
|
+
assert.equal(target.CookieConsent.getConsentData(), null)
|
|
42
|
+
})
|