@el7ven/cookie-kit 0.2.20 → 0.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@el7ven/cookie-kit",
3
- "version": "0.2.20",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "module": "./src/index.js",
@@ -11,8 +11,10 @@
11
11
  "./dist/styles": "./dist/styles/index.css",
12
12
  "./react": "./src/react/index.js",
13
13
  "./vue": "./src/vue/index.js",
14
- "./src/composables/useCookieConsent": "./src/vue/composables/useCookieConsent.js",
14
+ "./analytics": "./src/core/analytics.js",
15
+ "./config": "./src/core/index.js",
15
16
  "./composables/useCookieConsent": "./src/vue/composables/useCookieConsent.js",
17
+ "./src/composables/useCookieConsent": "./src/vue/composables/useCookieConsent.js",
16
18
  "./package.json": "./package.json"
17
19
  },
18
20
  "files": [
@@ -0,0 +1,311 @@
1
+ /**
2
+ * @el7ven/cookie-kit - Analytics Integration Module
3
+ * Google Consent Mode v2, GTM, GA4, Meta Pixel, Yandex Metrica
4
+ */
5
+
6
+ /**
7
+ * Initialize Google Consent Mode v2 with default denied state
8
+ */
9
+ export function initGoogleConsentMode() {
10
+ if (typeof window === 'undefined') return
11
+
12
+ window.dataLayer = window.dataLayer || []
13
+ window.gtag = window.gtag || function gtag() { window.dataLayer.push(arguments) }
14
+
15
+ // Set default consent state - all denied until user consents
16
+ window.gtag('consent', 'default', {
17
+ ad_storage: 'denied',
18
+ ad_user_data: 'denied',
19
+ ad_personalization: 'denied',
20
+ analytics_storage: 'denied',
21
+ functionality_storage: 'denied',
22
+ personalization_storage: 'denied',
23
+ security_storage: 'granted' // Always granted for security
24
+ })
25
+ }
26
+
27
+ /**
28
+ * Update Google Consent Mode based on cookie consent categories
29
+ * @param {Object} categories - { analytics: true, marketing: false, preferences: true }
30
+ */
31
+ export function updateGoogleConsent(categories = {}) {
32
+ if (typeof window === 'undefined' || !window.gtag) return
33
+
34
+ const consentUpdate = {
35
+ analytics_storage: categories.analytics ? 'granted' : 'denied',
36
+ ad_storage: categories.marketing ? 'granted' : 'denied',
37
+ ad_user_data: categories.marketing ? 'granted' : 'denied',
38
+ ad_personalization: categories.marketing ? 'granted' : 'denied',
39
+ functionality_storage: categories.preferences ? 'granted' : 'denied',
40
+ personalization_storage: categories.preferences ? 'granted' : 'denied',
41
+ security_storage: 'granted'
42
+ }
43
+
44
+ window.gtag('consent', 'update', consentUpdate)
45
+ }
46
+
47
+ /**
48
+ * Load Google Tag Manager
49
+ * @param {string} gtmId - GTM container ID (e.g., 'GTM-XXXXX')
50
+ */
51
+ export function loadGTM(gtmId) {
52
+ if (!gtmId || typeof document === 'undefined') return
53
+
54
+ const script = document.createElement('script')
55
+ script.async = true
56
+ script.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`
57
+ document.head.appendChild(script)
58
+
59
+ window.dataLayer = window.dataLayer || []
60
+ window.dataLayer.push({
61
+ 'gtm.start': new Date().getTime(),
62
+ event: 'gtm.js'
63
+ })
64
+ }
65
+
66
+ /**
67
+ * Load Google Analytics 4
68
+ * @param {string} ga4Id - GA4 measurement ID (e.g., 'G-XXXXX')
69
+ */
70
+ export function loadGA4(ga4Id) {
71
+ if (!ga4Id || typeof document === 'undefined') return
72
+
73
+ const script = document.createElement('script')
74
+ script.async = true
75
+ script.src = `https://www.googletagmanager.com/gtag/js?id=${ga4Id}`
76
+ document.head.appendChild(script)
77
+
78
+ window.dataLayer = window.dataLayer || []
79
+ window.gtag = window.gtag || function gtag() { window.dataLayer.push(arguments) }
80
+ window.gtag('js', new Date())
81
+ window.gtag('config', ga4Id)
82
+ }
83
+
84
+ /**
85
+ * Load Meta (Facebook) Pixel
86
+ * @param {string} pixelId - Meta Pixel ID
87
+ */
88
+ export function loadMetaPixel(pixelId) {
89
+ if (!pixelId || typeof window === 'undefined') return
90
+
91
+ /* eslint-disable */
92
+ !function(f,b,e,v,n,t,s)
93
+ {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
94
+ n.callMethod.apply(n,arguments):n.queue.push(arguments)};
95
+ if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
96
+ n.queue=[];t=b.createElement(e);t.async=!0;
97
+ t.src=v;s=b.getElementsByTagName(e)[0];
98
+ s.parentNode.insertBefore(t,s)}(window, document,'script',
99
+ 'https://connect.facebook.net/en_US/fbevents.js');
100
+ /* eslint-enable */
101
+
102
+ window.fbq('init', pixelId)
103
+ window.fbq('track', 'PageView')
104
+ }
105
+
106
+ /**
107
+ * Load Yandex Metrica
108
+ * @param {string} counterId - Yandex Metrica counter ID
109
+ */
110
+ export function loadYandexMetrica(counterId) {
111
+ if (!counterId || typeof document === 'undefined') return
112
+
113
+ /* eslint-disable */
114
+ (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
115
+ m[i].l=1*new Date();
116
+ for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
117
+ k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
118
+ (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
119
+ /* eslint-enable */
120
+
121
+ window.ym(counterId, 'init', {
122
+ clickmap: true,
123
+ trackLinks: true,
124
+ accurateTrackBounce: true,
125
+ webvisor: true
126
+ })
127
+ }
128
+
129
+ /**
130
+ * Block all scripts with data-cookie-category BEFORE consent.
131
+ * Call this as early as possible (before DOMContentLoaded).
132
+ * Rewrites script type to text/plain so they don't execute.
133
+ *
134
+ * Usage in HTML:
135
+ * <script data-cookie-category="analytics" src="..."></script>
136
+ * <script data-cookie-category="marketing">inline code</script>
137
+ */
138
+ export function blockScriptsBeforeConsent() {
139
+ if (typeof document === 'undefined') return
140
+
141
+ // MutationObserver to catch dynamically added scripts
142
+ const observer = new MutationObserver((mutations) => {
143
+ for (const mutation of mutations) {
144
+ for (const node of mutation.addedNodes) {
145
+ if (node.tagName === 'SCRIPT' && node.getAttribute('data-cookie-category')) {
146
+ const category = node.getAttribute('data-cookie-category')
147
+ // Check if consent already given for this category
148
+ if (!_hasConsentFor(category)) {
149
+ node.type = 'text/plain'
150
+ if (node.src) {
151
+ node.dataset.originalSrc = node.src
152
+ node.removeAttribute('src')
153
+ }
154
+ }
155
+ }
156
+ }
157
+ }
158
+ })
159
+
160
+ observer.observe(document.documentElement, { childList: true, subtree: true })
161
+
162
+ // Also block any scripts already in the DOM
163
+ document.querySelectorAll('script[data-cookie-category]').forEach(script => {
164
+ const category = script.getAttribute('data-cookie-category')
165
+ if (!_hasConsentFor(category)) {
166
+ if (!script.dataset.blocked) {
167
+ script.dataset.blocked = 'true'
168
+ // Already executed scripts can't be un-executed,
169
+ // but we mark them so future loads respect consent
170
+ }
171
+ }
172
+ })
173
+
174
+ // Store observer reference for cleanup
175
+ if (typeof window !== 'undefined') {
176
+ window.__cookieKitScriptObserver = observer
177
+ }
178
+
179
+ return observer
180
+ }
181
+
182
+ /**
183
+ * Unblock and execute scripts for consented categories.
184
+ * @param {Object} categories - { analytics: true, marketing: false }
185
+ */
186
+ export function unblockConsentedScripts(categories = {}) {
187
+ if (typeof document === 'undefined') return
188
+
189
+ document.querySelectorAll('script[data-cookie-category][type="text/plain"]').forEach(script => {
190
+ const category = script.getAttribute('data-cookie-category')
191
+ if (categories[category]) {
192
+ const newScript = document.createElement('script')
193
+
194
+ // Copy attributes
195
+ for (const attr of script.attributes) {
196
+ if (attr.name !== 'type' && attr.name !== 'data-original-src') {
197
+ newScript.setAttribute(attr.name, attr.value)
198
+ }
199
+ }
200
+
201
+ // Restore src or inline content
202
+ if (script.dataset.originalSrc) {
203
+ newScript.src = script.dataset.originalSrc
204
+ newScript.async = true
205
+ } else if (script.textContent) {
206
+ newScript.textContent = script.textContent
207
+ }
208
+
209
+ newScript.type = 'text/javascript'
210
+ script.parentNode.replaceChild(newScript, script)
211
+ }
212
+ })
213
+ }
214
+
215
+ /**
216
+ * Check localStorage for existing consent for a category
217
+ * @private
218
+ */
219
+ function _hasConsentFor(category) {
220
+ if (typeof localStorage === 'undefined') return false
221
+ try {
222
+ const stored = localStorage.getItem('cookie_consent')
223
+ if (!stored) return false
224
+ const consent = JSON.parse(stored)
225
+ return consent?.categories?.[category] === true
226
+ } catch {
227
+ return false
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Legacy alias
233
+ * @param {Object} categories - { analytics: true, marketing: false }
234
+ */
235
+ export function manageScriptBlocking(categories = {}) {
236
+ unblockConsentedScripts(categories)
237
+ }
238
+
239
+ /**
240
+ * Create analytics manager that auto-integrates with cookie consent
241
+ * @param {Object} config - { ga4: 'G-XXX', gtm: 'GTM-XXX', metaPixel: 'XXX', yandexMetrica: 'XXX' }
242
+ * @returns {Object} Analytics manager instance
243
+ */
244
+ export function createAnalyticsManager(config = {}) {
245
+ let initialized = false
246
+
247
+ const init = () => {
248
+ if (initialized) return
249
+ initialized = true
250
+
251
+ // Block scripts before consent
252
+ blockScriptsBeforeConsent()
253
+
254
+ // Always init Google Consent Mode first (denied by default)
255
+ initGoogleConsentMode()
256
+
257
+ // Load GTM if configured (it respects consent mode)
258
+ if (config.gtm) loadGTM(config.gtm)
259
+ }
260
+
261
+ const onConsentUpdate = (categories = {}) => {
262
+ // Update Google Consent Mode
263
+ updateGoogleConsent(categories)
264
+
265
+ // Load analytics scripts based on consent
266
+ if (categories.analytics) {
267
+ if (config.ga4) loadGA4(config.ga4)
268
+ if (config.yandexMetrica) loadYandexMetrica(config.yandexMetrica)
269
+ }
270
+
271
+ if (categories.marketing) {
272
+ if (config.metaPixel) loadMetaPixel(config.metaPixel)
273
+ }
274
+
275
+ // Unblock scripts for consented categories
276
+ unblockConsentedScripts(categories)
277
+ }
278
+
279
+ const connectToCookieConsent = () => {
280
+ if (typeof window === 'undefined') return
281
+
282
+ // Wait for CookieConsent to be available
283
+ const checkInterval = setInterval(() => {
284
+ if (window.CookieConsent) {
285
+ clearInterval(checkInterval)
286
+
287
+ // Check if consent already given
288
+ const currentConsent = window.CookieConsent.getConsent()
289
+ if (currentConsent?.categories) {
290
+ onConsentUpdate(currentConsent.categories)
291
+ }
292
+
293
+ // Listen for future changes
294
+ window.CookieConsent.on('consentChanged', ({ consent }) => {
295
+ if (consent?.categories) {
296
+ onConsentUpdate(consent.categories)
297
+ }
298
+ })
299
+ }
300
+ }, 100)
301
+
302
+ // Stop checking after 10 seconds
303
+ setTimeout(() => clearInterval(checkInterval), 10000)
304
+ }
305
+
306
+ return {
307
+ init,
308
+ onConsentUpdate,
309
+ connectToCookieConsent
310
+ }
311
+ }
package/src/core/index.js CHANGED
@@ -32,7 +32,7 @@ const DEFAULT_CONFIG = {
32
32
  label: 'Necesare',
33
33
  description: 'Cookie-uri esențiale pentru funcționarea site-ului',
34
34
  required: true,
35
- locked: true,
35
+ disabled: true,
36
36
  enabled: true
37
37
  },
38
38
  analytics: {
@@ -40,24 +40,24 @@ const DEFAULT_CONFIG = {
40
40
  label: 'Analiză',
41
41
  description: 'Cookie-uri pentru analiza traficului și comportamentului utilizatorilor',
42
42
  required: false,
43
- locked: false,
44
- enabled: true
43
+ disabled: false,
44
+ enabled: false
45
45
  },
46
46
  marketing: {
47
47
  id: 'marketing',
48
48
  label: 'Marketing',
49
49
  description: 'Cookie-uri pentru publicitate personalizată',
50
50
  required: false,
51
- locked: false,
52
- enabled: true
51
+ disabled: false,
52
+ enabled: false
53
53
  },
54
54
  preferences: {
55
55
  id: 'preferences',
56
56
  label: 'Preferințe',
57
57
  description: 'Cookie-uri pentru salvarea preferințelor utilizatorului',
58
58
  required: false,
59
- locked: false,
60
- enabled: true
59
+ disabled: false,
60
+ enabled: false
61
61
  }
62
62
  },
63
63
 
package/src/index.js CHANGED
@@ -8,8 +8,12 @@
8
8
  // Core functionality
9
9
  export { createCookieKit, CookieKitCore, DEFAULT_CONFIG } from './core/index.js'
10
10
 
11
+ // Analytics integration
12
+ export { createAnalyticsManager, initGoogleConsentMode, updateGoogleConsent, loadGTM, loadGA4, loadMetaPixel, loadYandexMetrica, blockScriptsBeforeConsent, unblockConsentedScripts, manageScriptBlocking } from './core/analytics.js'
13
+
11
14
  // Import for default export
12
15
  import { createCookieKit, CookieKitCore, DEFAULT_CONFIG } from './core/index.js'
16
+ import { createAnalyticsManager } from './core/analytics.js'
13
17
  import { initCookieKit } from './js/index.js'
14
18
  import { VERSION } from './core/version.js'
15
19
 
@@ -62,6 +66,7 @@ export function autoCookieConsent(config = {}) {
62
66
  export default {
63
67
  createCookieKit,
64
68
  createCookieConsent,
69
+ createAnalyticsManager,
65
70
  autoCookieConsent,
66
71
  initCookieKit,
67
72
  CookieKitCore,
@@ -386,7 +386,6 @@ class CookieConsent extends HTMLElement {
386
386
  /* Header */
387
387
  .cookie-drawer__header {
388
388
  padding: 24px 24px 16px;
389
- border-bottom: 1px solid var(--ck-border);
390
389
  display: flex;
391
390
  justify-content: space-between;
392
391
  align-items: flex-start;