@el7ven/cookie-kit 0.2.19 → 0.2.21

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.
@@ -17,17 +17,17 @@
17
17
  <div ref="dialogRef" class="cookie-drawer__content" role="dialog" aria-modal="true" @click.stop>
18
18
  <!-- Header -->
19
19
  <div class="cookie-drawer__header">
20
- <h3 class="cookie-drawer__title">
20
+ <div class="cookie-drawer__title">
21
21
  {{ isSettingsMode
22
22
  ? (config.texts?.settings?.title || 'Cookie Settings')
23
23
  : (config.mode === 'essential'
24
24
  ? (config.texts?.essential?.title || 'Essential Cookies')
25
25
  : (config.texts?.gdpr?.title || 'Cookie Consent'))
26
26
  }}
27
- </h3>
28
- <!-- Message -->
27
+ </div>
28
+ <!-- Message -->
29
29
  <div v-if="!isSettingsMode && !isEssentialBanner" class="cookie-drawer__message">
30
- {{ config.texts?.gdpr?.message || 'We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies.' }}
30
+ {{ config.texts?.gdpr?.message || 'We use cookies to enhance your experience.' }}
31
31
  </div>
32
32
 
33
33
  <button
@@ -36,9 +36,9 @@
36
36
  class="cookie-drawer__close"
37
37
  aria-label="Close"
38
38
  >
39
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
40
- <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"/>
41
- </svg>
39
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
40
+ <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="currentColor"/>
41
+ </svg>
42
42
  </button>
43
43
  </div>
44
44
 
@@ -46,101 +46,191 @@
46
46
  <div v-if="!isSettingsMode && isEssentialBanner" class="cookie-drawer__banner">
47
47
  <div class="cookie-drawer__essential">
48
48
  <div class="cookie-drawer__message cookie-drawer__message--essential">
49
- {{ config.texts?.essential?.message || 'We use essential cookies to make our site work. By using our site, you accept our use of essential cookies.' }}
50
- </div>
51
- <div class="cookie-drawer__actions">
52
- <button @click="$emit('acceptAll')" class="cookie-drawer__button cookie-drawer__button--primary">
53
- {{ config.texts?.essential?.accept || 'Accept' }}
54
- </button>
49
+ {{ config.texts?.essential?.message || 'This site uses only essential cookies.' }}
55
50
  </div>
56
51
  </div>
57
52
  </div>
58
53
 
59
- <!-- GDPR Banner/Settings -->
60
- <div v-else class="cookie-drawer__body">
61
- <!-- Banner Mode -->
62
- <div v-if="!isSettingsMode" class="cookie-drawer__banner">
63
- <div class="cookie-drawer__message">
64
- {{ config.texts?.gdpr?.message || 'We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies.' }}
65
- </div>
66
- <div class="cookie-drawer__actions">
67
- <button @click="$emit('rejectAll')" class="cookie-drawer__button cookie-drawer__button--secondary">
68
- {{ config.texts?.gdpr?.reject || 'Reject All' }}
69
- </button>
70
- <button @click="$emit('acceptAll')" class="cookie-drawer__button cookie-drawer__button--primary">
71
- {{ config.texts?.gdpr?.accept || 'Accept All' }}
72
- </button>
73
- <button @click="$emit('openSettings')" class="cookie-drawer__button cookie-drawer__button--link">
74
- {{ config.texts?.gdpr?.settings || 'Customize' }}
75
- </button>
54
+ <!-- GDPR Banner -->
55
+ <div v-else-if="!isSettingsMode" class="cookie-drawer__banner">
56
+ <div class="cookie-drawer__gdpr">
57
+ <!-- Categories -->
58
+ <div class="cookie-drawer__categories">
59
+ <div
60
+ v-for="category in enabledCategories"
61
+ :key="category.id"
62
+ class="cookie-drawer__category"
63
+ >
64
+ <div class="cookie-drawer__category-header">
65
+ <span class="cookie-drawer__category-name">
66
+ {{ category.label }}
67
+ </span>
68
+ <div class="cookie-drawer__toggle">
69
+ <input
70
+ type="checkbox"
71
+ :id="`drawer-category-${category.id}`"
72
+ :checked="categories[category.id]"
73
+ @change="toggleCategory(category.id)"
74
+ :disabled="category.locked"
75
+ class="cookie-drawer__toggle-input"
76
+ />
77
+ <label
78
+ :for="`drawer-category-${category.id}`"
79
+ :class="[
80
+ 'cookie-drawer__toggle-label',
81
+ { 'cookie-drawer__toggle-label--disabled': category.locked }
82
+ ]"
83
+ ></label>
84
+ </div>
85
+ </div>
86
+ <div v-if="category.descriptionShow" class="cookie-drawer__category-description">
87
+ {{ category.description }}
88
+ </div>
89
+ </div>
76
90
  </div>
77
- </div>
78
91
 
79
- <!-- Settings Mode -->
80
- <div v-else class="cookie-drawer__settings">
81
- <!-- Tabs -->
82
- <div v-if="enabledSettingsTabs.length > 1" class="cookie-drawer__tabs">
92
+ <!-- Settings Link -->
93
+ <div class="cookie-drawer__settings-link">
83
94
  <button
84
- v-for="tab in enabledSettingsTabs"
85
- :key="tab"
86
- :class="['cookie-drawer__tab', { 'cookie-drawer__tab--active': currentTab === tab }]"
87
- @click="$emit('selectTab', tab)"
95
+ @click="openSettings"
96
+ class="cookie-drawer__settings-button"
88
97
  >
89
- {{ getCategoryTitle(tab) }}
98
+ {{ config.texts?.buttons?.settings || config.texts?.gdpr?.buttons?.settings || 'Settings' }}
90
99
  </button>
91
100
  </div>
92
101
 
93
- <!-- Tab Content -->
94
- <div class="cookie-drawer__tab-content">
95
- <div v-if="currentTab === 'privacy'" class="cookie-drawer__privacy">
96
- <h4>{{ config.texts?.settings?.privacy?.title || 'Privacy Policy' }}</h4>
97
- <p>{{ config.texts?.settings?.privacy?.description || 'Learn about how we use cookies and protect your privacy.' }}</p>
98
- </div>
102
+ <!-- Capabilities -->
103
+ <div v-if="isV2" class="cookie-drawer__capabilities" aria-live="polite">
104
+ <span v-if="capabilities.gdpr" class="cookie-drawer__capability">GDPR</span>
105
+ <span v-if="capabilities.ccpa" class="cookie-drawer__capability">CCPA</span>
106
+ <span v-if="capabilities.pipeda" class="cookie-drawer__capability">PIPEDA</span>
107
+ <span v-if="capabilities.iabTcf22" class="cookie-drawer__capability">IAB TCF v2.2</span>
108
+ <span v-if="capabilities.googleConsentModeV2" class="cookie-drawer__capability">Google Consent Mode v2</span>
109
+ <span v-if="capabilities.scriptBlocking" class="cookie-drawer__capability">Script Blocking</span>
110
+ </div>
111
+ </div>
112
+ </div>
99
113
 
100
- <div v-else class="cookie-drawer__category">
101
- <div class="cookie-drawer__category-header">
102
- <h4>{{ getCategoryTitle(currentTab) }}</h4>
103
- <label class="cookie-drawer__toggle">
104
- <input
105
- type="checkbox"
106
- :checked="categories[currentTab]?.enabled"
107
- :disabled="categories[currentTab]?.required"
108
- @change="$emit('toggleCategory', currentTab)"
109
- />
110
- <span class="cookie-drawer__toggle-slider"></span>
111
- </label>
112
- </div>
113
- <div class="cookie-drawer__category-description">
114
- {{ getCategoryDescription(currentTab) }}
114
+ <!-- Settings Mode -->
115
+ <div v-else class="cookie-drawer__settings">
116
+ <!-- Tabs -->
117
+ <div class="cookie-drawer__tabs">
118
+ <button
119
+ v-for="tab in availableTabs"
120
+ :key="tab.id"
121
+ @click="selectTab(tab.id)"
122
+ :class="[
123
+ 'cookie-drawer__tab',
124
+ { 'cookie-drawer__tab--active': currentTab === tab.id }
125
+ ]"
126
+ >
127
+ {{ tab.label }}
128
+ </button>
129
+ </div>
130
+
131
+ <!-- Tab Content -->
132
+ <div class="cookie-drawer__tab-content">
133
+ <!-- Privacy Tab -->
134
+ <div v-if="currentTab === 'privacy'" class="cookie-drawer__privacy">
135
+ <div class="cookie-drawer__privacy-content">
136
+ <div class="cookie-drawer__text">
137
+ {{ config.texts?.settings?.privacy?.intro || 'We use cookies and similar technologies to ensure the site works properly.' }}
115
138
  </div>
139
+ <a :href="policyLinks.privacy || '#'" class="cookie-drawer__link">
140
+ {{ config.texts?.settings?.links?.moreInfo || 'More information' }}
141
+ </a>
116
142
  </div>
117
143
  </div>
118
144
 
119
- <!-- Settings Actions -->
120
- <div class="cookie-drawer__settings-actions">
121
- <button @click="$emit('acceptSelection')" class="cookie-drawer__button cookie-drawer__button--primary">
122
- {{ config.texts?.settings?.save || 'Save Preferences' }}
123
- </button>
145
+ <!-- Category Tabs -->
146
+ <div v-else class="cookie-drawer__category">
147
+ <div class="cookie-drawer__category-header">
148
+ <div class="cookie-drawer__category-title">
149
+ {{ currentCategoryData.label }}
150
+ </div>
151
+ <div class="cookie-drawer__toggle">
152
+ <input
153
+ type="checkbox"
154
+ :id="`settings-category-${currentTab}`"
155
+ :checked="categories[currentTab]"
156
+ @change="toggleCategory(currentTab)"
157
+ :disabled="currentCategoryData.locked"
158
+ class="cookie-drawer__toggle-input"
159
+ />
160
+ <label
161
+ :for="`settings-category-${currentTab}`"
162
+ :class="[
163
+ 'cookie-drawer__toggle-label',
164
+ { 'cookie-drawer__toggle-label--disabled': currentCategoryData.locked }
165
+ ]"
166
+ ></label>
167
+ </div>
168
+ </div>
169
+ <div class="cookie-drawer__category-description">
170
+ {{ currentCategoryData.description }}
171
+ </div>
172
+ <a :href="policyLinks.cookies || '#'" class="cookie-drawer__link">
173
+ {{ config.texts?.settings?.links?.cookieDetails || 'Cookie details' }}
174
+ </a>
124
175
  </div>
125
176
  </div>
126
177
  </div>
178
+
179
+ <!-- Actions: GDPR mode -->
180
+ <div v-if="!isEssentialBanner" class="cookie-drawer__actions">
181
+ <button
182
+ @click="handleAcceptSelection"
183
+ class="cookie-drawer__button cookie-drawer__button--outline"
184
+ >
185
+ {{ config.texts?.buttons?.acceptSelection || config.texts?.gdpr?.buttons?.acceptSelection || 'Accept Selection' }}
186
+ </button>
187
+ <button
188
+ @click="handleRejectAll"
189
+ class="cookie-drawer__button cookie-drawer__button--secondary"
190
+ >
191
+ {{ config.texts?.buttons?.rejectAll || config.texts?.gdpr?.buttons?.rejectAll || 'Reject All' }}
192
+ </button>
193
+ <button
194
+ @click="handleAcceptAll"
195
+ class="cookie-drawer__button cookie-drawer__button--primary"
196
+ >
197
+ {{ config.texts?.buttons?.acceptAll || config.texts?.gdpr?.buttons?.acceptAll || 'Accept All' }}
198
+ </button>
199
+ </div>
200
+ <!-- Actions: Essential mode -->
201
+ <div v-else class="cookie-drawer__actions cookie-drawer__actions_essential">
202
+ <button
203
+ @click="handleAcceptAll"
204
+ class="cookie-drawer__button cookie-drawer__button--primary cookie-drawer__button--essential"
205
+ >
206
+ {{ config.texts?.essential?.button || 'Accept' }}
207
+ </button>
208
+ </div>
209
+
127
210
  </div>
128
211
  </div>
129
212
  </Transition>
130
213
  </template>
131
214
 
132
215
  <script setup>
133
- import { computed, ref } from 'vue'
216
+ import { computed, ref, watch, onMounted, onUnmounted } from 'vue'
134
217
 
135
218
  const props = defineProps({
136
- isVisible: Boolean,
137
- isSettingsMode: Boolean,
138
- currentTab: String,
139
- categories: Object,
140
- config: Object,
141
- consentVersion: String,
142
- capabilities: Object,
143
- isV2: Boolean
219
+ isVisible: { type: Boolean, required: true },
220
+ isSettingsMode: { type: Boolean, default: false },
221
+ currentTab: { type: String, required: true },
222
+ categories: { type: Object, required: true },
223
+ config: { type: Object, required: true },
224
+ consentVersion: { type: String, default: 'v1' },
225
+ capabilities: { type: Object, default: () => ({}) },
226
+ isV2: { type: Boolean, default: false }
227
+ })
228
+
229
+ const dialogRef = ref(null)
230
+ const windowWidth = ref(typeof window !== 'undefined' ? window.innerWidth : 1024)
231
+
232
+ defineExpose({
233
+ dialogElement: () => dialogRef.value
144
234
  })
145
235
 
146
236
  const emit = defineEmits([
@@ -153,51 +243,131 @@ const emit = defineEmits([
153
243
  'rejectAll'
154
244
  ])
155
245
 
156
- const dialogRef = ref(null)
246
+ // Computed properties
247
+ const enabledCategories = computed(() => {
248
+ if (!props.config.categories) return []
249
+ return Object.keys(props.config.categories)
250
+ .filter(catId => props.config.categories[catId].enabled)
251
+ .map(catId => props.config.categories[catId])
252
+ })
157
253
 
158
- const isEssentialBanner = computed(() => props.config.mode === 'essential')
254
+ const availableTabs = computed(() => {
255
+ const tabs = [
256
+ { id: 'privacy', label: props.config.texts?.settings?.tabs?.privacy || 'Privacy' }
257
+ ]
159
258
 
160
- const drawerClasses = computed(() => ({
161
- 'cookie-drawer__content-wrapper--settings': props.isSettingsMode,
162
- 'cookie-drawer__content-wrapper--banner': !props.isSettingsMode
163
- }))
259
+ if (props.config.categories) {
260
+ Object.keys(props.config.categories).forEach(categoryId => {
261
+ if (props.config.categories[categoryId].enabled) {
262
+ tabs.push({
263
+ id: categoryId,
264
+ label: props.config.categories[categoryId].label
265
+ })
266
+ }
267
+ })
268
+ }
164
269
 
165
- const rootClasses = computed(() => ({
166
- 'cookie-drawer__content-wrapper--bottom': true
167
- }))
270
+ return tabs
271
+ })
168
272
 
169
- const drawerAnimation = computed(() =>
170
- props.isSettingsMode ? 'drawer-slide-up' : 'banner-slide-up'
171
- )
273
+ const currentCategoryData = computed(() => {
274
+ return props.config.categories?.[props.currentTab] || {}
275
+ })
172
276
 
173
- const enabledSettingsTabs = computed(() => {
174
- return ['privacy', ...Object.keys(props.categories || {}).filter(id =>
175
- props.categories[id]?.enabled
176
- )]
277
+ const policyLinks = computed(() => {
278
+ return props.config.policies || {}
177
279
  })
178
280
 
179
- const getCategoryTitle = (categoryId) => {
180
- return props.categories[categoryId]?.name || categoryId
181
- }
281
+ const isEssentialBanner = computed(() => {
282
+ return props.config.mode === 'essential' && !props.isSettingsMode
283
+ })
182
284
 
183
- const getCategoryDescription = (categoryId) => {
184
- return props.categories[categoryId]?.description || `Description for ${categoryId} cookies.`
185
- }
285
+ // Reactive mobile detection
286
+ const isMobile = computed(() => {
287
+ return windowWidth.value <= 767
288
+ })
186
289
 
187
- const handleBackdropClick = () => {
188
- if (!props.isSettingsMode) {
189
- emit('close')
290
+ const handleResize = () => {
291
+ if (typeof window !== 'undefined') {
292
+ windowWidth.value = window.innerWidth
190
293
  }
191
294
  }
192
295
 
296
+ onMounted(() => {
297
+ if (typeof window !== 'undefined') {
298
+ window.addEventListener('resize', handleResize)
299
+ }
300
+ })
301
+
302
+ onUnmounted(() => {
303
+ if (typeof window !== 'undefined') {
304
+ window.removeEventListener('resize', handleResize)
305
+ }
306
+ })
307
+
308
+ // Root classes for essential mode
309
+ const rootClasses = computed(() => {
310
+ return {
311
+ 'cookie-drawer--essential-mode': isEssentialBanner.value
312
+ }
313
+ })
314
+
315
+ // Drawer classes and animations
316
+ const drawerClasses = computed(() => {
317
+ return {
318
+ 'cookie-drawer--mobile': isMobile.value && !isEssentialBanner.value
319
+ }
320
+ })
321
+
322
+ const drawerAnimation = computed(() => {
323
+ if (isEssentialBanner.value) return 'drawer-slide-up'
324
+ if (isMobile.value) return 'drawer-slide-up'
325
+ return 'drawer-slide-right'
326
+ })
327
+
328
+ // Event handlers
193
329
  const handleClose = () => {
194
330
  emit('close')
195
331
  }
196
332
 
197
- // Expose dialog element for focus trap
198
- defineExpose({
199
- dialogElement: () => dialogRef.value
200
- })
333
+ const handleBackdropClick = () => {
334
+ emit('close')
335
+ }
336
+
337
+ const openSettings = () => {
338
+ emit('openSettings')
339
+ }
340
+
341
+ const selectTab = (tabId) => {
342
+ emit('selectTab', tabId)
343
+ }
344
+
345
+ const toggleCategory = (categoryId) => {
346
+ emit('toggleCategory', categoryId)
347
+ }
348
+
349
+ const handleAcceptSelection = () => {
350
+ emit('acceptSelection')
351
+ }
352
+
353
+ const handleAcceptAll = () => {
354
+ emit('acceptAll')
355
+ }
356
+
357
+ const handleRejectAll = () => {
358
+ emit('rejectAll')
359
+ }
360
+
361
+ // Watch for drawer visibility to control body overflow
362
+ watch(
363
+ () => props.isVisible,
364
+ (newVal) => {
365
+ if (isEssentialBanner.value) return
366
+ if (typeof document === 'undefined') return
367
+ document.body.style.overflow = newVal ? 'hidden' : ''
368
+ },
369
+ { immediate: true }
370
+ )
201
371
  </script>
202
372
 
203
373
  <style src="@el7ven/cookie-kit/dist/styles"></style>
package/src/vue/index.js CHANGED
@@ -1,8 +1,13 @@
1
1
  import { computed, ref } from 'vue'
2
2
  import { createCookieKit, DEFAULT_CONFIG } from '../core/index.js'
3
3
  import { VERSION, getVersion, getVersionInfo, logVersion } from './version.js'
4
+ import { useCookieConsent } from './composables/useCookieConsent.js'
5
+ import { createAnalyticsManager } from '../core/analytics.js'
4
6
 
5
- export { createCookieKit, DEFAULT_CONFIG, VERSION, getVersion, getVersionInfo, logVersion }
7
+ export { createCookieKit, DEFAULT_CONFIG, VERSION, getVersion, getVersionInfo, logVersion, useCookieConsent, createAnalyticsManager }
8
+ export { default as CookieConsent } from './CookieConsent.vue'
9
+ export { default as CookieDrawer } from './CookieDrawer.vue'
10
+ export { default as CookieConsentDebug } from './CookieConsentDebug.vue'
6
11
 
7
12
  export function useCookieKitVue(userConfig = {}) {
8
13
  const core = createCookieKit(userConfig)