// src/vue/index.ts import { ref, computed, readonly, inject, provide, onMounted, onUnmounted, defineComponent, h } from "vue"; // src/core/ConsentStorage.ts var STORAGE_KEY = "bp_consent"; var STORAGE_VERSION = "1"; var ConsentStorage = class { constructor(config) { this.config = config; this.storageKey = `${STORAGE_KEY}_${config.siteId}`; } /** * Consent laden */ get() { if (typeof window === "undefined") { return null; } try { const raw = localStorage.getItem(this.storageKey); if (!raw) { return null; } const stored = JSON.parse(raw); if (stored.version !== STORAGE_VERSION) { this.log("Storage version mismatch, clearing"); this.clear(); return null; } if (!this.verifySignature(stored.consent, stored.signature)) { this.log("Invalid signature, clearing"); this.clear(); return null; } return stored.consent; } catch (error) { this.log("Failed to load consent:", error); return null; } } /** * Consent speichern */ set(consent) { if (typeof window === "undefined") { return; } try { const signature = this.generateSignature(consent); const stored = { version: STORAGE_VERSION, consent, signature }; localStorage.setItem(this.storageKey, JSON.stringify(stored)); this.setCookie(consent); this.log("Consent saved to storage"); } catch (error) { this.log("Failed to save consent:", error); } } /** * Consent loeschen */ clear() { if (typeof window === "undefined") { return; } try { localStorage.removeItem(this.storageKey); this.clearCookie(); this.log("Consent cleared from storage"); } catch (error) { this.log("Failed to clear consent:", error); } } /** * Pruefen ob Consent existiert */ exists() { return this.get() !== null; } // =========================================================================== // Cookie Management // =========================================================================== /** * Consent als Cookie setzen */ setCookie(consent) { const days = this.config.consent?.rememberDays ?? 365; const expires = /* @__PURE__ */ new Date(); expires.setDate(expires.getDate() + days); const cookieValue = JSON.stringify(consent.categories); const encoded = encodeURIComponent(cookieValue); document.cookie = [ `${this.storageKey}=${encoded}`, `expires=${expires.toUTCString()}`, "path=/", "SameSite=Lax", location.protocol === "https:" ? "Secure" : "" ].filter(Boolean).join("; "); } /** * Cookie loeschen */ clearCookie() { document.cookie = `${this.storageKey}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; } // =========================================================================== // Signature (Simple HMAC-like) // =========================================================================== /** * Signatur generieren */ generateSignature(consent) { const data = JSON.stringify(consent); const key = this.config.siteId; return this.simpleHash(data + key); } /** * Signatur verifizieren */ verifySignature(consent, signature) { const expected = this.generateSignature(consent); return expected === signature; } /** * Einfache Hash-Funktion (djb2) */ simpleHash(str) { let hash = 5381; for (let i = 0; i < str.length; i++) { hash = hash * 33 ^ str.charCodeAt(i); } return (hash >>> 0).toString(16); } /** * Debug-Logging */ log(...args) { if (this.config.debug) { console.log("[ConsentStorage]", ...args); } } }; // src/core/ScriptBlocker.ts var ScriptBlocker = class { constructor(config) { this.observer = null; this.enabledCategories = /* @__PURE__ */ new Set(["essential"]); this.processedElements = /* @__PURE__ */ new WeakSet(); this.config = config; } /** * Initialisieren und Observer starten */ init() { if (typeof window === "undefined") { return; } this.processExistingElements(); this.observer = new MutationObserver((mutations) => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (node.nodeType === Node.ELEMENT_NODE) { this.processElement(node); } } } }); this.observer.observe(document.documentElement, { childList: true, subtree: true }); this.log("ScriptBlocker initialized"); } /** * Kategorie aktivieren */ enableCategory(category) { if (this.enabledCategories.has(category)) { return; } this.enabledCategories.add(category); this.log("Category enabled:", category); this.activateCategory(category); } /** * Kategorie deaktivieren */ disableCategory(category) { if (category === "essential") { return; } this.enabledCategories.delete(category); this.log("Category disabled:", category); } /** * Alle Kategorien blockieren (ausser Essential) */ blockAll() { this.enabledCategories.clear(); this.enabledCategories.add("essential"); this.log("All categories blocked"); } /** * Pruefen ob Kategorie aktiviert */ isCategoryEnabled(category) { return this.enabledCategories.has(category); } /** * Observer stoppen */ destroy() { this.observer?.disconnect(); this.observer = null; this.log("ScriptBlocker destroyed"); } // =========================================================================== // Internal Methods // =========================================================================== /** * Bestehende Elemente verarbeiten */ processExistingElements() { const scripts = document.querySelectorAll( "script[data-consent]" ); scripts.forEach((script) => this.processScript(script)); const iframes = document.querySelectorAll( "iframe[data-consent]" ); iframes.forEach((iframe) => this.processIframe(iframe)); this.log(`Processed ${scripts.length} scripts, ${iframes.length} iframes`); } /** * Element verarbeiten */ processElement(element) { if (element.tagName === "SCRIPT") { this.processScript(element); } else if (element.tagName === "IFRAME") { this.processIframe(element); } element.querySelectorAll("script[data-consent]").forEach((script) => this.processScript(script)); element.querySelectorAll("iframe[data-consent]").forEach((iframe) => this.processIframe(iframe)); } /** * Script-Element verarbeiten */ processScript(script) { if (this.processedElements.has(script)) { return; } const category = script.dataset.consent; if (!category) { return; } this.processedElements.add(script); if (this.enabledCategories.has(category)) { this.activateScript(script); } else { this.log(`Script blocked (${category}):`, script.dataset.src || "inline"); } } /** * iFrame-Element verarbeiten */ processIframe(iframe) { if (this.processedElements.has(iframe)) { return; } const category = iframe.dataset.consent; if (!category) { return; } this.processedElements.add(iframe); if (this.enabledCategories.has(category)) { this.activateIframe(iframe); } else { this.log(`iFrame blocked (${category}):`, iframe.dataset.src); this.showPlaceholder(iframe, category); } } /** * Script aktivieren */ activateScript(script) { const src = script.dataset.src; if (src) { const newScript = document.createElement("script"); for (const attr of script.attributes) { if (attr.name !== "type" && attr.name !== "data-src") { newScript.setAttribute(attr.name, attr.value); } } newScript.src = src; newScript.removeAttribute("data-consent"); script.parentNode?.replaceChild(newScript, script); this.log("External script activated:", src); } else { const newScript = document.createElement("script"); for (const attr of script.attributes) { if (attr.name !== "type") { newScript.setAttribute(attr.name, attr.value); } } newScript.textContent = script.textContent; newScript.removeAttribute("data-consent"); script.parentNode?.replaceChild(newScript, script); this.log("Inline script activated"); } } /** * iFrame aktivieren */ activateIframe(iframe) { const src = iframe.dataset.src; if (!src) { return; } const placeholder = iframe.parentElement?.querySelector( ".bp-consent-placeholder" ); placeholder?.remove(); iframe.src = src; iframe.removeAttribute("data-src"); iframe.removeAttribute("data-consent"); iframe.style.display = ""; this.log("iFrame activated:", src); } /** * Placeholder fuer blockierten iFrame anzeigen */ showPlaceholder(iframe, category) { iframe.style.display = "none"; const placeholder = document.createElement("div"); placeholder.className = "bp-consent-placeholder"; placeholder.setAttribute("data-category", category); placeholder.innerHTML = ` `; const btn = placeholder.querySelector("button"); btn?.addEventListener("click", () => { window.dispatchEvent( new CustomEvent("bp-consent-request", { detail: { category } }) ); }); iframe.parentNode?.insertBefore(placeholder, iframe.nextSibling); } /** * Alle Elemente einer Kategorie aktivieren */ activateCategory(category) { const scripts = document.querySelectorAll( `script[data-consent="${category}"]` ); scripts.forEach((script) => this.activateScript(script)); const iframes = document.querySelectorAll( `iframe[data-consent="${category}"]` ); iframes.forEach((iframe) => this.activateIframe(iframe)); this.log( `Activated ${scripts.length} scripts, ${iframes.length} iframes for ${category}` ); } /** * Kategorie-Name fuer UI */ getCategoryName(category) { const names = { essential: "Essentielle Cookies", functional: "Funktionale Cookies", analytics: "Statistik-Cookies", marketing: "Marketing-Cookies", social: "Social Media-Cookies" }; return names[category] ?? category; } /** * Debug-Logging */ log(...args) { if (this.config.debug) { console.log("[ScriptBlocker]", ...args); } } }; // src/core/ConsentAPI.ts var ConsentAPI = class { constructor(config) { this.config = config; this.baseUrl = config.apiEndpoint.replace(/\/$/, ""); } /** * Consent speichern */ async saveConsent(request) { const payload = { ...request, metadata: { userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "", language: typeof navigator !== "undefined" ? navigator.language : "", screenResolution: typeof window !== "undefined" ? `${window.screen.width}x${window.screen.height}` : "", platform: "web", ...request.metadata } }; const response = await this.fetch("/consent", { method: "POST", body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`Failed to save consent: ${response.status}`); } return response.json(); } /** * Consent abrufen */ async getConsent(siteId, deviceFingerprint) { const params = new URLSearchParams({ siteId, deviceFingerprint }); const response = await this.fetch(`/consent?${params}`); if (response.status === 404) { return null; } if (!response.ok) { throw new Error(`Failed to get consent: ${response.status}`); } const data = await response.json(); return data.consent; } /** * Consent widerrufen */ async revokeConsent(consentId) { const response = await this.fetch(`/consent/${consentId}`, { method: "DELETE" }); if (!response.ok) { throw new Error(`Failed to revoke consent: ${response.status}`); } } /** * Site-Konfiguration abrufen */ async getSiteConfig(siteId) { const response = await this.fetch(`/config/${siteId}`); if (!response.ok) { throw new Error(`Failed to get site config: ${response.status}`); } return response.json(); } /** * Consent-Historie exportieren (DSGVO Art. 20) */ async exportConsent(userId) { const params = new URLSearchParams({ userId }); const response = await this.fetch(`/consent/export?${params}`); if (!response.ok) { throw new Error(`Failed to export consent: ${response.status}`); } return response.json(); } // =========================================================================== // Internal Methods // =========================================================================== /** * Fetch mit Standard-Headers */ async fetch(path, options = {}) { const url = `${this.baseUrl}${path}`; const headers = { "Content-Type": "application/json", Accept: "application/json", ...this.getSignatureHeaders(), ...options.headers || {} }; try { const response = await fetch(url, { ...options, headers, credentials: "include" }); this.log(`${options.method || "GET"} ${path}:`, response.status); return response; } catch (error) { this.log("Fetch error:", error); throw error; } } /** * Signatur-Headers generieren (HMAC) */ getSignatureHeaders() { const timestamp = Math.floor(Date.now() / 1e3).toString(); const signature = this.simpleHash(`${this.config.siteId}:${timestamp}`); return { "X-Consent-Timestamp": timestamp, "X-Consent-Signature": `sha256=${signature}` }; } /** * Einfache Hash-Funktion (djb2) */ simpleHash(str) { let hash = 5381; for (let i = 0; i < str.length; i++) { hash = hash * 33 ^ str.charCodeAt(i); } return (hash >>> 0).toString(16); } /** * Debug-Logging */ log(...args) { if (this.config.debug) { console.log("[ConsentAPI]", ...args); } } }; // src/utils/EventEmitter.ts var EventEmitter = class { constructor() { this.listeners = /* @__PURE__ */ new Map(); } /** * Event-Listener registrieren * @returns Unsubscribe-Funktion */ on(event, callback) { if (!this.listeners.has(event)) { this.listeners.set(event, /* @__PURE__ */ new Set()); } this.listeners.get(event).add(callback); return () => this.off(event, callback); } /** * Event-Listener entfernen */ off(event, callback) { this.listeners.get(event)?.delete(callback); } /** * Event emittieren */ emit(event, data) { this.listeners.get(event)?.forEach((callback) => { try { callback(data); } catch (error) { console.error(`Error in event handler for ${String(event)}:`, error); } }); } /** * Einmaligen Listener registrieren */ once(event, callback) { const wrapper = (data) => { this.off(event, wrapper); callback(data); }; return this.on(event, wrapper); } /** * Alle Listener entfernen */ clear() { this.listeners.clear(); } /** * Alle Listener fuer ein Event entfernen */ clearEvent(event) { this.listeners.delete(event); } /** * Anzahl Listener fuer ein Event */ listenerCount(event) { return this.listeners.get(event)?.size ?? 0; } }; // src/utils/fingerprint.ts function getComponents() { if (typeof window === "undefined") { return ["server"]; } const components = []; try { const ua = navigator.userAgent; if (ua.includes("Chrome")) components.push("chrome"); else if (ua.includes("Firefox")) components.push("firefox"); else if (ua.includes("Safari")) components.push("safari"); else if (ua.includes("Edge")) components.push("edge"); else components.push("other"); } catch { components.push("unknown-browser"); } try { components.push(navigator.language || "unknown-lang"); } catch { components.push("unknown-lang"); } try { const width = window.screen.width; if (width >= 2560) components.push("4k"); else if (width >= 1920) components.push("fhd"); else if (width >= 1366) components.push("hd"); else if (width >= 768) components.push("tablet"); else components.push("mobile"); } catch { components.push("unknown-screen"); } try { const depth = window.screen.colorDepth; if (depth >= 24) components.push("deep-color"); else components.push("standard-color"); } catch { components.push("unknown-color"); } try { const offset = (/* @__PURE__ */ new Date()).getTimezoneOffset(); const hours = Math.floor(Math.abs(offset) / 60); const sign = offset <= 0 ? "+" : "-"; components.push(`tz${sign}${hours}`); } catch { components.push("unknown-tz"); } try { const platform = navigator.platform?.toLowerCase() || ""; if (platform.includes("mac")) components.push("mac"); else if (platform.includes("win")) components.push("win"); else if (platform.includes("linux")) components.push("linux"); else if (platform.includes("iphone") || platform.includes("ipad")) components.push("ios"); else if (platform.includes("android")) components.push("android"); else components.push("other-platform"); } catch { components.push("unknown-platform"); } try { if ("ontouchstart" in window || navigator.maxTouchPoints > 0) { components.push("touch"); } else { components.push("no-touch"); } } catch { components.push("unknown-touch"); } try { if (navigator.doNotTrack === "1") { components.push("dnt"); } } catch { } return components; } async function sha256(message) { if (typeof window === "undefined" || !window.crypto?.subtle) { return simpleHash(message); } try { const encoder = new TextEncoder(); const data = encoder.encode(message); const hashBuffer = await crypto.subtle.digest("SHA-256", data); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map((b) => b.toString(16).padStart(2, "0")).join(""); } catch { return simpleHash(message); } } function simpleHash(str) { let hash = 5381; for (let i = 0; i < str.length; i++) { hash = hash * 33 ^ str.charCodeAt(i); } return (hash >>> 0).toString(16).padStart(8, "0"); } async function generateFingerprint() { const components = getComponents(); const combined = components.join("|"); const hash = await sha256(combined); return `fp_${hash.substring(0, 32)}`; } // src/version.ts var SDK_VERSION = "1.0.0"; // src/core/ConsentManager.ts var DEFAULT_CONFIG = { language: "de", fallbackLanguage: "en", ui: { position: "bottom", layout: "modal", theme: "auto", zIndex: 999999, blockScrollOnModal: true }, consent: { required: true, rejectAllVisible: true, acceptAllVisible: true, granularControl: true, vendorControl: false, rememberChoice: true, rememberDays: 365, geoTargeting: false, recheckAfterDays: 180 }, categories: ["essential", "functional", "analytics", "marketing", "social"], debug: false }; var DEFAULT_CONSENT = { essential: true, functional: false, analytics: false, marketing: false, social: false }; var ConsentManager = class { constructor(config) { this.currentConsent = null; this.initialized = false; this.bannerVisible = false; this.deviceFingerprint = ""; this.config = this.mergeConfig(config); this.storage = new ConsentStorage(this.config); this.scriptBlocker = new ScriptBlocker(this.config); this.api = new ConsentAPI(this.config); this.events = new EventEmitter(); this.log("ConsentManager created with config:", this.config); } /** * SDK initialisieren */ async init() { if (this.initialized) { this.log("Already initialized, skipping"); return; } try { this.log("Initializing ConsentManager..."); this.deviceFingerprint = await generateFingerprint(); this.currentConsent = this.storage.get(); if (this.currentConsent) { this.log("Loaded consent from storage:", this.currentConsent); if (this.isConsentExpired()) { this.log("Consent expired, clearing"); this.storage.clear(); this.currentConsent = null; } else { this.applyConsent(); } } this.scriptBlocker.init(); this.initialized = true; this.emit("init", this.currentConsent); if (this.needsConsent()) { this.showBanner(); } this.log("ConsentManager initialized successfully"); } catch (error) { this.handleError(error); throw error; } } // =========================================================================== // Public API // =========================================================================== /** * Pruefen ob Consent fuer Kategorie vorhanden */ hasConsent(category) { if (!this.currentConsent) { return category === "essential"; } return this.currentConsent.categories[category] ?? false; } /** * Pruefen ob Consent fuer Vendor vorhanden */ hasVendorConsent(vendorId) { if (!this.currentConsent) { return false; } return this.currentConsent.vendors[vendorId] ?? false; } /** * Aktuellen Consent-State abrufen */ getConsent() { return this.currentConsent ? { ...this.currentConsent } : null; } /** * Consent setzen */ async setConsent(input) { const categories = this.normalizeConsentInput(input); categories.essential = true; const newConsent = { categories, vendors: "vendors" in input && input.vendors ? input.vendors : {}, timestamp: (/* @__PURE__ */ new Date()).toISOString(), version: SDK_VERSION }; try { const response = await this.api.saveConsent({ siteId: this.config.siteId, deviceFingerprint: this.deviceFingerprint, consent: newConsent }); newConsent.consentId = response.consentId; newConsent.expiresAt = response.expiresAt; this.storage.set(newConsent); this.currentConsent = newConsent; this.applyConsent(); this.emit("change", newConsent); this.config.onConsentChange?.(newConsent); this.log("Consent saved:", newConsent); } catch (error) { this.log("API error, saving locally:", error); this.storage.set(newConsent); this.currentConsent = newConsent; this.applyConsent(); this.emit("change", newConsent); } } /** * Alle Kategorien akzeptieren */ async acceptAll() { const allCategories = { essential: true, functional: true, analytics: true, marketing: true, social: true }; await this.setConsent(allCategories); this.emit("accept_all", this.currentConsent); this.hideBanner(); } /** * Alle nicht-essentiellen Kategorien ablehnen */ async rejectAll() { const minimalCategories = { essential: true, functional: false, analytics: false, marketing: false, social: false }; await this.setConsent(minimalCategories); this.emit("reject_all", this.currentConsent); this.hideBanner(); } /** * Alle Einwilligungen widerrufen */ async revokeAll() { if (this.currentConsent?.consentId) { try { await this.api.revokeConsent(this.currentConsent.consentId); } catch (error) { this.log("Failed to revoke on server:", error); } } this.storage.clear(); this.currentConsent = null; this.scriptBlocker.blockAll(); this.log("All consents revoked"); } /** * Consent-Daten exportieren (DSGVO Art. 20) */ async exportConsent() { const exportData = { currentConsent: this.currentConsent, exportedAt: (/* @__PURE__ */ new Date()).toISOString(), siteId: this.config.siteId, deviceFingerprint: this.deviceFingerprint }; return JSON.stringify(exportData, null, 2); } // =========================================================================== // Banner Control // =========================================================================== /** * Pruefen ob Consent-Abfrage noetig */ needsConsent() { if (!this.currentConsent) { return true; } if (this.isConsentExpired()) { return true; } if (this.config.consent?.recheckAfterDays) { const consentDate = new Date(this.currentConsent.timestamp); const recheckDate = new Date(consentDate); recheckDate.setDate( recheckDate.getDate() + this.config.consent.recheckAfterDays ); if (/* @__PURE__ */ new Date() > recheckDate) { return true; } } return false; } /** * Banner anzeigen */ showBanner() { if (this.bannerVisible) { return; } this.bannerVisible = true; this.emit("banner_show", void 0); this.config.onBannerShow?.(); this.log("Banner shown"); } /** * Banner verstecken */ hideBanner() { if (!this.bannerVisible) { return; } this.bannerVisible = false; this.emit("banner_hide", void 0); this.config.onBannerHide?.(); this.log("Banner hidden"); } /** * Einstellungs-Modal oeffnen */ showSettings() { this.emit("settings_open", void 0); this.log("Settings opened"); } /** * Pruefen ob Banner sichtbar */ isBannerVisible() { return this.bannerVisible; } // =========================================================================== // Event Handling // =========================================================================== /** * Event-Listener registrieren */ on(event, callback) { return this.events.on(event, callback); } /** * Event-Listener entfernen */ off(event, callback) { this.events.off(event, callback); } // =========================================================================== // Internal Methods // =========================================================================== /** * Konfiguration zusammenfuehren */ mergeConfig(config) { return { ...DEFAULT_CONFIG, ...config, ui: { ...DEFAULT_CONFIG.ui, ...config.ui }, consent: { ...DEFAULT_CONFIG.consent, ...config.consent } }; } /** * Consent-Input normalisieren */ normalizeConsentInput(input) { if ("categories" in input && input.categories) { return { ...DEFAULT_CONSENT, ...input.categories }; } return { ...DEFAULT_CONSENT, ...input }; } /** * Consent anwenden (Skripte aktivieren/blockieren) */ applyConsent() { if (!this.currentConsent) { return; } for (const [category, allowed] of Object.entries( this.currentConsent.categories )) { if (allowed) { this.scriptBlocker.enableCategory(category); } else { this.scriptBlocker.disableCategory(category); } } this.updateGoogleConsentMode(); } /** * Google Consent Mode v2 aktualisieren */ updateGoogleConsentMode() { if (typeof window === "undefined" || !this.currentConsent) { return; } const gtag = window.gtag; if (typeof gtag !== "function") { return; } const { categories } = this.currentConsent; gtag("consent", "update", { ad_storage: categories.marketing ? "granted" : "denied", ad_user_data: categories.marketing ? "granted" : "denied", ad_personalization: categories.marketing ? "granted" : "denied", analytics_storage: categories.analytics ? "granted" : "denied", functionality_storage: categories.functional ? "granted" : "denied", personalization_storage: categories.functional ? "granted" : "denied", security_storage: "granted" }); this.log("Google Consent Mode updated"); } /** * Pruefen ob Consent abgelaufen */ isConsentExpired() { if (!this.currentConsent?.expiresAt) { if (this.currentConsent?.timestamp && this.config.consent?.rememberDays) { const consentDate = new Date(this.currentConsent.timestamp); const expiryDate = new Date(consentDate); expiryDate.setDate( expiryDate.getDate() + this.config.consent.rememberDays ); return /* @__PURE__ */ new Date() > expiryDate; } return false; } return /* @__PURE__ */ new Date() > new Date(this.currentConsent.expiresAt); } /** * Event emittieren */ emit(event, data) { this.events.emit(event, data); } /** * Fehler behandeln */ handleError(error) { this.log("Error:", error); this.emit("error", error); this.config.onError?.(error); } /** * Debug-Logging */ log(...args) { if (this.config.debug) { console.log("[ConsentSDK]", ...args); } } // =========================================================================== // Static Methods // =========================================================================== /** * SDK-Version abrufen */ static getVersion() { return SDK_VERSION; } }; // src/vue/index.ts var CONSENT_KEY = /* @__PURE__ */ Symbol("consent"); function useConsent() { const context = inject(CONSENT_KEY); if (!context) { throw new Error( "useConsent() must be used within a component that has called provideConsent() or is wrapped in ConsentProvider" ); } return context; } function provideConsent(config) { const manager = ref(null); const consent = ref(null); const isInitialized = ref(false); const isLoading = ref(true); const isBannerVisible = ref(false); const needsConsent = computed(() => { return manager.value?.needsConsent() ?? true; }); onMounted(async () => { const consentManager = new ConsentManager(config); manager.value = consentManager; const unsubChange = consentManager.on("change", (newConsent) => { consent.value = newConsent; }); const unsubBannerShow = consentManager.on("banner_show", () => { isBannerVisible.value = true; }); const unsubBannerHide = consentManager.on("banner_hide", () => { isBannerVisible.value = false; }); try { await consentManager.init(); consent.value = consentManager.getConsent(); isInitialized.value = true; isBannerVisible.value = consentManager.isBannerVisible(); } catch (error) { console.error("Failed to initialize ConsentManager:", error); } finally { isLoading.value = false; } onUnmounted(() => { unsubChange(); unsubBannerShow(); unsubBannerHide(); }); }); const hasConsent = (category) => { return manager.value?.hasConsent(category) ?? category === "essential"; }; const acceptAll = async () => { await manager.value?.acceptAll(); }; const rejectAll = async () => { await manager.value?.rejectAll(); }; const saveSelection = async (categories) => { await manager.value?.setConsent(categories); manager.value?.hideBanner(); }; const showBanner = () => { manager.value?.showBanner(); }; const hideBanner = () => { manager.value?.hideBanner(); }; const showSettings = () => { manager.value?.showSettings(); }; const context = { manager: readonly(manager), consent: readonly(consent), isInitialized: readonly(isInitialized), isLoading: readonly(isLoading), isBannerVisible: readonly(isBannerVisible), needsConsent, hasConsent, acceptAll, rejectAll, saveSelection, showBanner, hideBanner, showSettings }; provide(CONSENT_KEY, context); return context; } var ConsentProvider = defineComponent({ name: "ConsentProvider", props: { config: { type: Object, required: true } }, setup(props, { slots }) { provideConsent(props.config); return () => slots.default?.(); } }); var ConsentGate = defineComponent({ name: "ConsentGate", props: { category: { type: String, required: true } }, setup(props, { slots }) { const { hasConsent, isLoading } = useConsent(); return () => { if (isLoading.value) { return slots.fallback?.() ?? null; } if (!hasConsent(props.category)) { return slots.placeholder?.() ?? null; } return slots.default?.(); }; } }); var ConsentPlaceholder = defineComponent({ name: "ConsentPlaceholder", props: { category: { type: String, required: true }, message: { type: String, default: "" }, buttonText: { type: String, default: "Cookie-Einstellungen \xF6ffnen" } }, setup(props) { const { showSettings } = useConsent(); const categoryNames = { essential: "Essentielle Cookies", functional: "Funktionale Cookies", analytics: "Statistik-Cookies", marketing: "Marketing-Cookies", social: "Social Media-Cookies" }; const displayMessage = computed(() => { return props.message || `Dieser Inhalt erfordert ${categoryNames[props.category]}.`; }); return () => h("div", { class: "bp-consent-placeholder" }, [ h("p", displayMessage.value), h( "button", { type: "button", onClick: showSettings }, props.buttonText ) ]); } }); var ConsentBanner = defineComponent({ name: "ConsentBanner", setup(_, { slots }) { const { consent, isBannerVisible, needsConsent, acceptAll, rejectAll, saveSelection, showSettings, hideBanner } = useConsent(); const slotProps = computed(() => ({ isVisible: isBannerVisible.value, consent: consent.value, needsConsent: needsConsent.value, onAcceptAll: acceptAll, onRejectAll: rejectAll, onSaveSelection: saveSelection, onShowSettings: showSettings, onClose: hideBanner })); return () => { if (slots.default) { return slots.default(slotProps.value); } if (!isBannerVisible.value) { return null; } return h( "div", { class: "bp-consent-banner", role: "dialog", "aria-modal": "true", "aria-label": "Cookie-Einstellungen" }, [ h("div", { class: "bp-consent-banner-content" }, [ h("h2", "Datenschutzeinstellungen"), h( "p", "Wir nutzen Cookies und \xE4hnliche Technologien, um Ihnen ein optimales Nutzererlebnis zu bieten." ), h("div", { class: "bp-consent-banner-actions" }, [ h( "button", { type: "button", class: "bp-consent-btn bp-consent-btn-reject", onClick: rejectAll }, "Alle ablehnen" ), h( "button", { type: "button", class: "bp-consent-btn bp-consent-btn-settings", onClick: showSettings }, "Einstellungen" ), h( "button", { type: "button", class: "bp-consent-btn bp-consent-btn-accept", onClick: acceptAll }, "Alle akzeptieren" ) ]) ]) ] ); }; } }); var ConsentPlugin = { install(app, config) { const manager = new ConsentManager(config); const consent = ref(null); const isInitialized = ref(false); const isLoading = ref(true); const isBannerVisible = ref(false); manager.init().then(() => { consent.value = manager.getConsent(); isInitialized.value = true; isLoading.value = false; isBannerVisible.value = manager.isBannerVisible(); }); manager.on("change", (newConsent) => { consent.value = newConsent; }); manager.on("banner_show", () => { isBannerVisible.value = true; }); manager.on("banner_hide", () => { isBannerVisible.value = false; }); const context = { manager: ref(manager), consent, isInitialized, isLoading, isBannerVisible, needsConsent: computed(() => manager.needsConsent()), hasConsent: (category) => manager.hasConsent(category), acceptAll: () => manager.acceptAll(), rejectAll: () => manager.rejectAll(), saveSelection: async (categories) => { await manager.setConsent(categories); manager.hideBanner(); }, showBanner: () => manager.showBanner(), hideBanner: () => manager.hideBanner(), showSettings: () => manager.showSettings() }; app.provide(CONSENT_KEY, context); } }; export { CONSENT_KEY, ConsentBanner, ConsentGate, ConsentPlaceholder, ConsentPlugin, ConsentProvider, provideConsent, useConsent }; //# sourceMappingURL=index.mjs.map