cookie-app 2.0.0

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/index.js ADDED
@@ -0,0 +1,722 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ CONSENT_CHANGE_EVENT: () => CONSENT_CHANGE_EVENT,
25
+ CookieConsent: () => CookieConsent,
26
+ DEFAULT_BRAND_COLOR: () => DEFAULT_BRAND_COLOR,
27
+ DEFAULT_EXPIRY_DAYS: () => DEFAULT_EXPIRY_DAYS,
28
+ DEFAULT_TEXTS: () => DEFAULT_TEXTS,
29
+ DEFAULT_WAIT_FOR_UPDATE: () => DEFAULT_WAIT_FOR_UPDATE,
30
+ STORAGE_DATE_KEY: () => STORAGE_DATE_KEY,
31
+ STORAGE_KEY: () => STORAGE_KEY,
32
+ getConsentModeScript: () => getConsentModeScript,
33
+ useConsent: () => useConsent
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/CookieConsent.tsx
38
+ var import_react = require("react");
39
+
40
+ // src/defaults.ts
41
+ var STORAGE_KEY = "loi25-consent";
42
+ var STORAGE_DATE_KEY = "loi25-consent-date";
43
+ var CONSENT_CHANGE_EVENT = "loi25-consent-change";
44
+ var DEFAULT_BRAND_COLOR = "#1d4ed8";
45
+ var DEFAULT_EXPIRY_DAYS = 365;
46
+ var DEFAULT_WAIT_FOR_UPDATE = 500;
47
+ var DEFAULT_TEXTS = {
48
+ fr: {
49
+ title: "Respect de votre vie priv\xE9e",
50
+ message: "Ce site utilise des t\xE9moins (cookies) pour am\xE9liorer votre exp\xE9rience. Conform\xE9ment \xE0 la Loi 25 du Qu\xE9bec, nous demandons votre consentement.",
51
+ accept: "Tout accepter",
52
+ reject: "N\xE9cessaires seulement",
53
+ privacy: "Politique de confidentialit\xE9",
54
+ powered: "Propuls\xE9 par"
55
+ },
56
+ en: {
57
+ title: "Your Privacy Matters",
58
+ message: "This website uses cookies to improve your experience. In compliance with Quebec's Law 25, we ask for your consent.",
59
+ accept: "Accept All",
60
+ reject: "Necessary Only",
61
+ privacy: "Privacy Policy",
62
+ powered: "Powered by"
63
+ }
64
+ };
65
+
66
+ // src/CookieConsent.tsx
67
+ var import_jsx_runtime = require("react/jsx-runtime");
68
+ function detectLanguage() {
69
+ var _a;
70
+ if (typeof navigator === "undefined") return "fr";
71
+ const lang = (_a = navigator.language) == null ? void 0 : _a.substring(0, 2);
72
+ return lang === "en" ? "en" : "fr";
73
+ }
74
+ function isExpired(expiryDays) {
75
+ try {
76
+ const d = localStorage.getItem(STORAGE_DATE_KEY);
77
+ if (!d) return true;
78
+ const age = (Date.now() - parseInt(d, 10)) / (1e3 * 60 * 60 * 24);
79
+ return age > expiryDays;
80
+ } catch (e) {
81
+ return true;
82
+ }
83
+ }
84
+ function getStoredConsent(expiryDays) {
85
+ try {
86
+ const stored = localStorage.getItem(STORAGE_KEY);
87
+ if (stored && !isExpired(expiryDays)) return stored;
88
+ if (stored) {
89
+ localStorage.removeItem(STORAGE_KEY);
90
+ localStorage.removeItem(STORAGE_DATE_KEY);
91
+ }
92
+ return null;
93
+ } catch (e) {
94
+ return null;
95
+ }
96
+ }
97
+ function buildInjectCss(brandColor, glassmorphism, customCss) {
98
+ return `
99
+ #loi25-banner *{box-sizing:border-box;margin:0;padding:0;}
100
+ #loi25-banner button{cursor:pointer;transition:transform .15s,opacity .15s;}
101
+ #loi25-banner button:hover{transform:translateY(-1px);opacity:.9;}
102
+ #loi25-banner button:focus-visible,#loi25-banner a:focus-visible{outline:2px solid ${brandColor};outline-offset:2px;}
103
+ ${glassmorphism ? "#loi25-banner.loi25-glass{backdrop-filter:blur(16px) saturate(1.8);-webkit-backdrop-filter:blur(16px) saturate(1.8);}" : ""}
104
+ #loi25-reconsent{transition:transform .2s,opacity .3s;}
105
+ #loi25-reconsent:hover{transform:scale(1.1)!important;}
106
+ @media(max-width:600px){
107
+ #loi25-banner .loi25-inner{padding:16px!important;}
108
+ #loi25-banner .loi25-btns{flex-direction:column!important;}
109
+ #loi25-banner .loi25-btns button{width:100%!important;}
110
+ }
111
+ ${customCss}`.trim();
112
+ }
113
+ function getThemeColors(theme, glassmorphism) {
114
+ const dk = theme === "dark";
115
+ return {
116
+ bg: dk ? `rgba(24,24,27,${glassmorphism ? ".75" : "1"})` : `rgba(255,255,255,${glassmorphism ? ".8" : "1"})`,
117
+ text: dk ? "#e4e4e7" : "#1e293b",
118
+ muted: dk ? "#a1a1aa" : "#64748b",
119
+ border: dk ? "#3f3f46" : "#e2e8f0",
120
+ btnBg: dk ? "#27272a" : "#f1f5f9",
121
+ btnText: dk ? "#e4e4e7" : "#334155"
122
+ };
123
+ }
124
+ function CookieConsent({
125
+ lang = "fr",
126
+ position = "bottom",
127
+ theme = "light",
128
+ style = "bar",
129
+ glassmorphism = false,
130
+ privacyUrl = "/politique-de-confidentialite",
131
+ poweredBy = false,
132
+ brandColor = DEFAULT_BRAND_COLOR,
133
+ expiryDays = DEFAULT_EXPIRY_DAYS,
134
+ showReconsent = true,
135
+ animation = "slide",
136
+ showIcon = true,
137
+ customCss = "",
138
+ textsFr,
139
+ textsEn,
140
+ onConsent,
141
+ consentMode = false,
142
+ adsDataRedaction = false,
143
+ urlPassthrough = false,
144
+ consentModeRegion,
145
+ waitForUpdate = DEFAULT_WAIT_FOR_UPDATE,
146
+ scripts = "",
147
+ reloadOnConsent = false
148
+ }) {
149
+ const [mounted, setMounted] = (0, import_react.useState)(false);
150
+ const [showBanner, setShowBanner] = (0, import_react.useState)(false);
151
+ const [isVisible, setIsVisible] = (0, import_react.useState)(false);
152
+ const [consent, setConsentState] = (0, import_react.useState)(null);
153
+ const scriptsInjectedRef = (0, import_react.useRef)(false);
154
+ const consentModeInitRef = (0, import_react.useRef)(false);
155
+ const resolvedLang = lang === "auto" ? mounted ? detectLanguage() : "fr" : lang;
156
+ const defaults = DEFAULT_TEXTS[resolvedLang] || DEFAULT_TEXTS.fr;
157
+ const customTexts = resolvedLang === "fr" ? textsFr : textsEn;
158
+ const texts = {
159
+ title: (customTexts == null ? void 0 : customTexts.title) || defaults.title,
160
+ message: (customTexts == null ? void 0 : customTexts.message) || defaults.message,
161
+ accept: (customTexts == null ? void 0 : customTexts.accept) || defaults.accept,
162
+ reject: (customTexts == null ? void 0 : customTexts.reject) || defaults.reject,
163
+ privacy: (customTexts == null ? void 0 : customTexts.privacy) || defaults.privacy,
164
+ powered: (customTexts == null ? void 0 : customTexts.powered) || defaults.powered
165
+ };
166
+ const colors = getThemeColors(theme, glassmorphism);
167
+ (0, import_react.useEffect)(() => {
168
+ setMounted(true);
169
+ const stored = getStoredConsent(expiryDays);
170
+ setConsentState(stored);
171
+ if (!stored) {
172
+ setShowBanner(true);
173
+ }
174
+ }, [expiryDays]);
175
+ (0, import_react.useEffect)(() => {
176
+ if (!mounted) return;
177
+ const handler = () => {
178
+ const stored = getStoredConsent(expiryDays);
179
+ setConsentState(stored);
180
+ if (!stored && !showBanner) {
181
+ setIsVisible(false);
182
+ setShowBanner(true);
183
+ }
184
+ };
185
+ window.addEventListener(CONSENT_CHANGE_EVENT, handler);
186
+ window.addEventListener("storage", handler);
187
+ return () => {
188
+ window.removeEventListener(CONSENT_CHANGE_EVENT, handler);
189
+ window.removeEventListener("storage", handler);
190
+ };
191
+ }, [mounted, expiryDays, showBanner]);
192
+ (0, import_react.useEffect)(() => {
193
+ if (!showBanner || !mounted) return;
194
+ const raf1 = requestAnimationFrame(() => {
195
+ requestAnimationFrame(() => {
196
+ setIsVisible(true);
197
+ });
198
+ });
199
+ const timer = setTimeout(() => {
200
+ const btn = document.getElementById("loi25-yes");
201
+ if (btn) btn.focus();
202
+ }, 500);
203
+ return () => {
204
+ cancelAnimationFrame(raf1);
205
+ clearTimeout(timer);
206
+ };
207
+ }, [showBanner, mounted]);
208
+ (0, import_react.useEffect)(() => {
209
+ if (!consentMode || !mounted) return;
210
+ const w = window;
211
+ w.dataLayer = w.dataLayer || [];
212
+ if (!w.gtag) {
213
+ w.gtag = function gtag2() {
214
+ w.dataLayer.push(arguments);
215
+ };
216
+ }
217
+ const gtag = w.gtag;
218
+ if (!consentModeInitRef.current) {
219
+ consentModeInitRef.current = true;
220
+ const defaultConsent = {
221
+ ad_storage: "denied",
222
+ ad_user_data: "denied",
223
+ ad_personalization: "denied",
224
+ analytics_storage: "denied",
225
+ functionality_storage: "granted",
226
+ personalization_storage: "granted",
227
+ security_storage: "granted",
228
+ wait_for_update: waitForUpdate
229
+ };
230
+ if (consentModeRegion && consentModeRegion.length > 0) {
231
+ defaultConsent.region = consentModeRegion;
232
+ }
233
+ gtag("consent", "default", defaultConsent);
234
+ if (adsDataRedaction) {
235
+ gtag("set", "ads_data_redaction", true);
236
+ }
237
+ if (urlPassthrough) {
238
+ gtag("set", "url_passthrough", true);
239
+ }
240
+ if (consent === "all") {
241
+ gtag("consent", "update", {
242
+ ad_storage: "granted",
243
+ ad_user_data: "granted",
244
+ ad_personalization: "granted",
245
+ analytics_storage: "granted"
246
+ });
247
+ }
248
+ }
249
+ }, [consentMode, consent, mounted, waitForUpdate, consentModeRegion, adsDataRedaction, urlPassthrough]);
250
+ (0, import_react.useEffect)(() => {
251
+ if (!scripts || consent !== "all" || !mounted || scriptsInjectedRef.current) return;
252
+ scriptsInjectedRef.current = true;
253
+ const tmp = document.createElement("div");
254
+ tmp.innerHTML = scripts;
255
+ const els = tmp.querySelectorAll("script");
256
+ els.forEach((el) => {
257
+ const ns = document.createElement("script");
258
+ if (el.src) {
259
+ ns.src = el.src;
260
+ } else {
261
+ ns.textContent = el.text || el.textContent || "";
262
+ }
263
+ Array.from(el.attributes).forEach((attr) => {
264
+ if (attr.name !== "src") ns.setAttribute(attr.name, attr.value);
265
+ });
266
+ document.head.appendChild(ns);
267
+ });
268
+ }, [scripts, consent, mounted]);
269
+ (0, import_react.useEffect)(() => {
270
+ if (!showBanner) return;
271
+ const handler = (e) => {
272
+ if (e.key === "Escape") {
273
+ handleConsent("necessary");
274
+ }
275
+ };
276
+ document.addEventListener("keydown", handler);
277
+ return () => document.removeEventListener("keydown", handler);
278
+ }, [showBanner]);
279
+ const handleConsent = (0, import_react.useCallback)(
280
+ (level) => {
281
+ try {
282
+ localStorage.setItem(STORAGE_KEY, level);
283
+ localStorage.setItem(STORAGE_DATE_KEY, Date.now().toString());
284
+ } catch (e) {
285
+ }
286
+ setConsentState(level);
287
+ setIsVisible(false);
288
+ if (consentMode) {
289
+ const w = window;
290
+ const gtag = w.gtag;
291
+ if (gtag) {
292
+ const granted = level === "all";
293
+ gtag("consent", "update", {
294
+ ad_storage: granted ? "granted" : "denied",
295
+ ad_user_data: granted ? "granted" : "denied",
296
+ ad_personalization: granted ? "granted" : "denied",
297
+ analytics_storage: granted ? "granted" : "denied"
298
+ });
299
+ }
300
+ }
301
+ onConsent == null ? void 0 : onConsent(level);
302
+ window.dispatchEvent(new Event(CONSENT_CHANGE_EVENT));
303
+ setTimeout(() => {
304
+ setShowBanner(false);
305
+ if (reloadOnConsent && level === "all" && scripts) {
306
+ window.location.reload();
307
+ }
308
+ }, 400);
309
+ },
310
+ [consentMode, onConsent, reloadOnConsent, scripts]
311
+ );
312
+ const handleReconsent = (0, import_react.useCallback)(() => {
313
+ try {
314
+ localStorage.removeItem(STORAGE_KEY);
315
+ localStorage.removeItem(STORAGE_DATE_KEY);
316
+ } catch (e) {
317
+ }
318
+ setConsentState(null);
319
+ setIsVisible(false);
320
+ setShowBanner(true);
321
+ scriptsInjectedRef.current = false;
322
+ window.dispatchEvent(new Event(CONSENT_CHANGE_EVENT));
323
+ }, []);
324
+ if (!mounted) return null;
325
+ const getBannerStyle = () => {
326
+ const base = {
327
+ fontFamily: "-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,sans-serif",
328
+ lineHeight: 1.5,
329
+ boxSizing: "border-box",
330
+ zIndex: 999999
331
+ };
332
+ if (style === "bar") {
333
+ const borderSide = position === "top" ? "borderBottom" : "borderTop";
334
+ return {
335
+ ...base,
336
+ position: "fixed",
337
+ left: 0,
338
+ right: 0,
339
+ ...position === "top" ? { top: 0 } : { bottom: 0 },
340
+ background: colors.bg,
341
+ [borderSide]: `1px solid ${colors.border}`,
342
+ padding: 0,
343
+ color: colors.text,
344
+ boxShadow: `0 ${position === "top" ? "2" : "-2"}px 20px rgba(0,0,0,.1)`,
345
+ transition: animation === "slide" ? "transform .4s cubic-bezier(.4,0,.2,1), opacity .4s ease" : "opacity .5s ease",
346
+ transform: isVisible ? "translateY(0)" : animation === "slide" ? `translateY(${position === "bottom" ? "100%" : "-100%"})` : "none",
347
+ opacity: isVisible ? 1 : 0
348
+ };
349
+ }
350
+ if (style === "popup") {
351
+ return {
352
+ ...base,
353
+ position: "fixed",
354
+ top: "50%",
355
+ left: "50%",
356
+ maxWidth: 480,
357
+ width: "calc(100% - 40px)",
358
+ borderRadius: 16,
359
+ padding: 0,
360
+ background: colors.bg,
361
+ color: colors.text,
362
+ boxShadow: "0 25px 60px rgba(0,0,0,.2)",
363
+ transition: "transform .35s cubic-bezier(.4,0,.2,1), opacity .35s ease",
364
+ transform: isVisible ? "translate(-50%, -50%) scale(1)" : "translate(-50%, -50%) scale(.9)",
365
+ opacity: isVisible ? 1 : 0
366
+ };
367
+ }
368
+ return {
369
+ ...base,
370
+ position: "fixed",
371
+ ...position === "top" ? { top: 20 } : { bottom: 20 },
372
+ right: 20,
373
+ maxWidth: 380,
374
+ width: "calc(100% - 40px)",
375
+ borderRadius: 16,
376
+ padding: 0,
377
+ background: colors.bg,
378
+ color: colors.text,
379
+ boxShadow: "0 8px 30px rgba(0,0,0,.12)",
380
+ border: `1px solid ${colors.border}`,
381
+ transition: animation === "slide" ? "transform .4s cubic-bezier(.4,0,.2,1), opacity .4s ease" : "opacity .5s ease",
382
+ transform: isVisible ? "translateX(0)" : animation === "slide" ? "translateX(120%)" : "none",
383
+ opacity: isVisible ? 1 : 0
384
+ };
385
+ };
386
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
387
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
388
+ "style",
389
+ {
390
+ dangerouslySetInnerHTML: {
391
+ __html: buildInjectCss(brandColor, glassmorphism, customCss)
392
+ }
393
+ }
394
+ ),
395
+ showBanner && style === "popup" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
396
+ "div",
397
+ {
398
+ id: "loi25-overlay",
399
+ style: {
400
+ position: "fixed",
401
+ top: 0,
402
+ left: 0,
403
+ right: 0,
404
+ bottom: 0,
405
+ zIndex: 999998,
406
+ background: "rgba(0,0,0,.4)",
407
+ opacity: isVisible ? 1 : 0,
408
+ transition: "opacity .35s ease"
409
+ }
410
+ }
411
+ ),
412
+ showBanner && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
413
+ "div",
414
+ {
415
+ id: "loi25-banner",
416
+ role: "dialog",
417
+ "aria-label": resolvedLang === "fr" ? "Consentement aux cookies" : "Cookie consent",
418
+ "aria-modal": style === "popup" ? "true" : void 0,
419
+ className: glassmorphism ? "loi25-glass" : void 0,
420
+ style: getBannerStyle(),
421
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "loi25-inner", style: { padding: "24px 28px" }, children: [
422
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
423
+ "div",
424
+ {
425
+ style: {
426
+ fontWeight: 700,
427
+ fontSize: 17,
428
+ marginBottom: 10,
429
+ display: "flex",
430
+ alignItems: "center",
431
+ gap: 8
432
+ },
433
+ children: [
434
+ showIcon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 22 }, children: "\u{1F36A}" }),
435
+ texts.title
436
+ ]
437
+ }
438
+ ),
439
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
440
+ "p",
441
+ {
442
+ style: {
443
+ margin: "0 0 18px",
444
+ color: colors.muted,
445
+ fontSize: 14,
446
+ lineHeight: 1.6
447
+ },
448
+ children: texts.message
449
+ }
450
+ ),
451
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
452
+ "div",
453
+ {
454
+ className: "loi25-btns",
455
+ style: {
456
+ display: "flex",
457
+ flexWrap: "wrap",
458
+ gap: 10,
459
+ alignItems: "center"
460
+ },
461
+ children: [
462
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
463
+ "button",
464
+ {
465
+ id: "loi25-yes",
466
+ type: "button",
467
+ onClick: () => handleConsent("all"),
468
+ style: {
469
+ background: brandColor,
470
+ color: "#fff",
471
+ border: "none",
472
+ padding: "11px 24px",
473
+ borderRadius: 8,
474
+ fontWeight: 600,
475
+ fontSize: 14
476
+ },
477
+ children: texts.accept
478
+ }
479
+ ),
480
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
481
+ "button",
482
+ {
483
+ id: "loi25-no",
484
+ type: "button",
485
+ onClick: () => handleConsent("necessary"),
486
+ style: {
487
+ background: colors.btnBg,
488
+ color: colors.btnText,
489
+ border: `1px solid ${colors.border}`,
490
+ padding: "11px 24px",
491
+ borderRadius: 8,
492
+ fontWeight: 600,
493
+ fontSize: 14
494
+ },
495
+ children: texts.reject
496
+ }
497
+ )
498
+ ]
499
+ }
500
+ ),
501
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
502
+ "div",
503
+ {
504
+ style: {
505
+ marginTop: 14,
506
+ display: "flex",
507
+ flexWrap: "wrap",
508
+ gap: 12,
509
+ alignItems: "center"
510
+ },
511
+ children: [
512
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
513
+ "a",
514
+ {
515
+ href: privacyUrl,
516
+ style: {
517
+ color: colors.muted,
518
+ fontSize: 12,
519
+ textDecoration: "underline"
520
+ },
521
+ target: "_blank",
522
+ rel: "noopener noreferrer",
523
+ children: texts.privacy
524
+ }
525
+ ),
526
+ poweredBy && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
527
+ "a",
528
+ {
529
+ href: "https://rayelsconsulting.com",
530
+ target: "_blank",
531
+ rel: "noopener noreferrer",
532
+ style: {
533
+ color: colors.muted,
534
+ fontSize: 11,
535
+ marginLeft: "auto",
536
+ textDecoration: "none",
537
+ opacity: 0.6
538
+ },
539
+ children: [
540
+ texts.powered,
541
+ " Rayels"
542
+ ]
543
+ }
544
+ )
545
+ ]
546
+ }
547
+ )
548
+ ] })
549
+ }
550
+ ),
551
+ !showBanner && consent !== null && showReconsent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
552
+ "button",
553
+ {
554
+ id: "loi25-reconsent",
555
+ type: "button",
556
+ onClick: handleReconsent,
557
+ "aria-label": resolvedLang === "fr" ? "G\xE9rer les cookies" : "Manage cookies",
558
+ style: {
559
+ position: "fixed",
560
+ bottom: 20,
561
+ left: 20,
562
+ zIndex: 999998,
563
+ width: 44,
564
+ height: 44,
565
+ borderRadius: "50%",
566
+ border: "none",
567
+ background: brandColor,
568
+ color: "#fff",
569
+ fontSize: 20,
570
+ cursor: "pointer",
571
+ boxShadow: "0 4px 12px rgba(0,0,0,.15)",
572
+ display: "flex",
573
+ alignItems: "center",
574
+ justifyContent: "center"
575
+ },
576
+ children: showIcon ? "\u{1F36A}" : "\u2699\uFE0F"
577
+ }
578
+ )
579
+ ] });
580
+ }
581
+
582
+ // src/use-consent.ts
583
+ var import_react2 = require("react");
584
+ function subscribe(callback) {
585
+ window.addEventListener("storage", callback);
586
+ window.addEventListener(CONSENT_CHANGE_EVENT, callback);
587
+ return () => {
588
+ window.removeEventListener("storage", callback);
589
+ window.removeEventListener(CONSENT_CHANGE_EVENT, callback);
590
+ };
591
+ }
592
+ function getSnapshot() {
593
+ try {
594
+ return localStorage.getItem(STORAGE_KEY);
595
+ } catch (e) {
596
+ return null;
597
+ }
598
+ }
599
+ function getServerSnapshot() {
600
+ return null;
601
+ }
602
+ function isExpired2(expiryDays) {
603
+ try {
604
+ const d = localStorage.getItem(STORAGE_DATE_KEY);
605
+ if (!d) return true;
606
+ const age = (Date.now() - parseInt(d, 10)) / (1e3 * 60 * 60 * 24);
607
+ return age > expiryDays;
608
+ } catch (e) {
609
+ return true;
610
+ }
611
+ }
612
+ function useConsent(expiryDays = DEFAULT_EXPIRY_DAYS) {
613
+ const raw = (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
614
+ const isValid = (() => {
615
+ if (!raw) return false;
616
+ if (typeof window === "undefined") return false;
617
+ return !isExpired2(expiryDays);
618
+ })();
619
+ const consent = isValid ? raw : null;
620
+ const resetConsent = (0, import_react2.useCallback)(() => {
621
+ try {
622
+ localStorage.removeItem(STORAGE_KEY);
623
+ localStorage.removeItem(STORAGE_DATE_KEY);
624
+ } catch (e) {
625
+ }
626
+ window.dispatchEvent(new Event(CONSENT_CHANGE_EVENT));
627
+ }, []);
628
+ const setConsent = (0, import_react2.useCallback)((level) => {
629
+ try {
630
+ localStorage.setItem(STORAGE_KEY, level);
631
+ localStorage.setItem(STORAGE_DATE_KEY, Date.now().toString());
632
+ } catch (e) {
633
+ }
634
+ window.dispatchEvent(new Event(CONSENT_CHANGE_EVENT));
635
+ }, []);
636
+ return {
637
+ consent,
638
+ hasConsent: consent !== null,
639
+ resetConsent,
640
+ setConsent
641
+ };
642
+ }
643
+
644
+ // src/consent-mode.ts
645
+ function getConsentModeScript(options) {
646
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
647
+ const opts = options != null ? options : {};
648
+ const adStorage = (_a = opts.ad_storage) != null ? _a : "denied";
649
+ const adUserData = (_b = opts.ad_user_data) != null ? _b : "denied";
650
+ const adPersonalization = (_c = opts.ad_personalization) != null ? _c : "denied";
651
+ const analyticsStorage = (_d = opts.analytics_storage) != null ? _d : "denied";
652
+ const functionalityStorage = (_e = opts.functionality_storage) != null ? _e : "granted";
653
+ const personalizationStorage = (_f = opts.personalization_storage) != null ? _f : "granted";
654
+ const securityStorage = (_g = opts.security_storage) != null ? _g : "granted";
655
+ const waitForUpdate = (_h = opts.wait_for_update) != null ? _h : 500;
656
+ const region = opts.region;
657
+ const adsDataRedaction = (_i = opts.ads_data_redaction) != null ? _i : false;
658
+ const urlPassthrough = (_j = opts.url_passthrough) != null ? _j : false;
659
+ const expiryDays = (_k = opts.expiry_days) != null ? _k : DEFAULT_EXPIRY_DAYS;
660
+ const defaultObj = {
661
+ ad_storage: adStorage,
662
+ ad_user_data: adUserData,
663
+ ad_personalization: adPersonalization,
664
+ analytics_storage: analyticsStorage,
665
+ functionality_storage: functionalityStorage,
666
+ personalization_storage: personalizationStorage,
667
+ security_storage: securityStorage,
668
+ wait_for_update: waitForUpdate
669
+ };
670
+ if (region && region.length > 0) {
671
+ defaultObj.region = region;
672
+ }
673
+ const defaultJson = JSON.stringify(defaultObj);
674
+ const setCalls = [];
675
+ if (adsDataRedaction) {
676
+ setCalls.push("gtag('set','ads_data_redaction',true);");
677
+ }
678
+ if (urlPassthrough) {
679
+ setCalls.push("gtag('set','url_passthrough',true);");
680
+ }
681
+ return [
682
+ // Define dataLayer and gtag
683
+ `window.dataLayer=window.dataLayer||[];`,
684
+ `function gtag(){dataLayer.push(arguments);}`,
685
+ // Set consent defaults
686
+ `gtag('consent','default',${defaultJson});`,
687
+ // Optional set calls
688
+ ...setCalls,
689
+ // Check for returning user with stored consent
690
+ `(function(){`,
691
+ ` try{`,
692
+ ` var c=localStorage.getItem(${JSON.stringify(STORAGE_KEY)});`,
693
+ ` var d=localStorage.getItem(${JSON.stringify(STORAGE_DATE_KEY)});`,
694
+ ` if(c&&d){`,
695
+ ` var age=(Date.now()-parseInt(d,10))/(1000*60*60*24);`,
696
+ ` if(age<=${expiryDays}&&c==='all'){`,
697
+ ` gtag('consent','update',{`,
698
+ ` 'ad_storage':'granted',`,
699
+ ` 'ad_user_data':'granted',`,
700
+ ` 'ad_personalization':'granted',`,
701
+ ` 'analytics_storage':'granted'`,
702
+ ` });`,
703
+ ` }`,
704
+ ` }`,
705
+ ` }catch(e){}`,
706
+ `})();`
707
+ ].join("\n");
708
+ }
709
+ // Annotate the CommonJS export names for ESM import in node:
710
+ 0 && (module.exports = {
711
+ CONSENT_CHANGE_EVENT,
712
+ CookieConsent,
713
+ DEFAULT_BRAND_COLOR,
714
+ DEFAULT_EXPIRY_DAYS,
715
+ DEFAULT_TEXTS,
716
+ DEFAULT_WAIT_FOR_UPDATE,
717
+ STORAGE_DATE_KEY,
718
+ STORAGE_KEY,
719
+ getConsentModeScript,
720
+ useConsent
721
+ });
722
+ //# sourceMappingURL=index.js.map