@modernconsent/widget 0.0.1 → 1.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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../core/src/utils/store.ts","../../core/src/utils/uuid.ts","../../core/src/state.ts","../../core/src/resolver.ts","../../core/src/registry.ts","../../core/src/emitter.ts","../../core/src/consent.ts","../../core/src/layer.ts","../../core/src/index.ts","../src/index.ts","../src/cdn.ts"],"sourcesContent":["export type Subscriber<T> = (value: T) => void;\nexport type Unsubscriber = () => void;\n\nexport class Store<T> {\n private value: T;\n private subscribers: Set<Subscriber<T>> = new Set();\n\n constructor(initialValue: T) {\n this.value = initialValue;\n }\n\n get(): T {\n return this.value;\n }\n\n set(newValue: T): void {\n if (this.value !== newValue) {\n this.value = newValue;\n this.notify();\n }\n }\n\n update(updater: (value: T) => T): void {\n this.set(updater(this.value));\n }\n\n subscribe(callback: Subscriber<T>): Unsubscriber {\n this.subscribers.add(callback);\n callback(this.value); // Appel immédiat\n return () => this.subscribers.delete(callback);\n }\n\n private notify(): void {\n this.subscribers.forEach(cb => cb(this.value));\n }\n}\n","function manualUUIDv4(): string {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n // Set version 4 (0100) and variant 10xx bits per RFC 4122\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20),\n ].join('-');\n}\n\nexport const generateUUID = (): string =>\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : manualUUIDv4();\n","// core/src/state.ts\nimport { Store } from './utils/store';\nimport { generateUUID } from './utils/uuid';\n\nexport interface ConsentState {\n [serviceId: string]: boolean;\n}\n\nexport interface ServiceMetadata {\n id: string;\n name: string;\n description: string;\n category: string;\n /** Human-readable label for the purpose/category in 'purpose' displayMode. */\n purposeLabel?: string | Record<string, string>;\n /** Optional description for the purpose/category in 'purpose' displayMode. */\n purposeDescription?: string | Record<string, string>;\n loaded: boolean;\n requireConsent: boolean;\n}\n\ninterface StoredState {\n consent: ConsentState;\n answered: boolean;\n /** Unix timestamp (ms) of when consent was last given — for GDPR audit trail. */\n timestamp?: number;\n /** Version of the consent banner at the time of consent. */\n version?: string;\n /** Unique identifier per consent action — for GDPR audit trail. */\n consentId?: string;\n}\n\nconst DEFAULT_STORAGE_KEY = 'mc_consent_state';\n\ninterface CookieOptions {\n days?: number;\n path?: string;\n domain?: string;\n sameSite?: 'Lax' | 'Strict' | 'None';\n secure?: boolean;\n}\n\nfunction escapeCookieName(name: string): string {\n return name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nconst getCookie = (name: string): string | null => {\n if (typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(?:^|; )${escapeCookieName(name)}=([^;]*)`));\n return match ? decodeURIComponent(match[1]) : null;\n};\n\nconst setCookie = (name: string, value: string, options: CookieOptions = {}) => {\n if (typeof document === 'undefined') return;\n\n const { days = 365, path = '/', domain, sameSite = 'Lax', secure = false } = options;\n\n const expires = new Date();\n expires.setDate(expires.getDate() + days);\n\n let cookieString =\n `${name}=${encodeURIComponent(value)};` +\n `expires=${expires.toUTCString()};` +\n `path=${path};` +\n `SameSite=${sameSite}`;\n\n if (domain) {\n const hostname = typeof window !== 'undefined' ? window.location.hostname : '';\n if (hostname && !hostname.endsWith(domain.replace(/^\\./, ''))) {\n console.warn(\n `[modern-consent] cookieDomain \"${domain}\" does not match current hostname \"${hostname}\". ` +\n `The cookie will be silently rejected by the browser. ` +\n `Remove cookieDomain for local development.`,\n );\n }\n cookieString += `;domain=${domain}`;\n }\n if (secure || sameSite === 'None') cookieString += `;Secure`;\n\n document.cookie = cookieString;\n};\n\nexport const consentState = new Store<ConsentState>({});\nexport const hasAnswered = new Store<boolean>(false);\nexport const servicesList = new Store<ServiceMetadata[]>([]);\nexport const isPanelOpen = new Store<boolean>(false);\nexport const openPanel = () => isPanelOpen.set(true);\n\n// Tracked so that calling initState multiple times never stacks duplicate subscribers\nlet _cookieUnsubs: (() => void)[] = [];\n\nexport const initState = (config: any) => {\n const cookieName: string = config?.cookieName || DEFAULT_STORAGE_KEY;\n const cookieDomain: string | undefined = config?.cookieDomain;\n const consentVersion: string | undefined = config?.consentVersion;\n\n let initialData: StoredState = { consent: {}, answered: false };\n\n if (typeof window !== 'undefined') {\n const stored = getCookie(cookieName);\n if (stored) {\n try {\n initialData = JSON.parse(stored) as StoredState;\n } catch (e) {\n console.error('[modern-consent] Error parsing consent cookie', e);\n }\n }\n }\n\n consentState.set(initialData.consent || {});\n hasAnswered.set(initialData.answered || false);\n\n // Re-prompt when consentVersion changes (GDPR: policy update invalidates prior consent)\n if (initialData.answered && consentVersion && initialData.version !== consentVersion) {\n hasAnswered.set(false);\n isPanelOpen.set(true);\n }\n\n if (typeof window !== 'undefined') {\n // Clean up previous subscriptions before creating new ones\n _cookieUnsubs.forEach(fn => fn());\n _cookieUnsubs = [];\n\n const saveToCookie = () => {\n const state: StoredState = {\n consent: consentState.get(),\n answered: hasAnswered.get(),\n timestamp: Date.now(),\n version: consentVersion,\n consentId: generateUUID(),\n };\n setCookie(cookieName, JSON.stringify(state), {\n domain: cookieDomain,\n secure: window.location.protocol === 'https:',\n });\n };\n\n _cookieUnsubs.push(consentState.subscribe(saveToCookie));\n _cookieUnsubs.push(hasAnswered.subscribe(saveToCookie));\n }\n};\n","// core/src/resolver.ts\nimport type { VendorLoader } from './registry';\n\n/**\n * A resolver maps a vendor name to a loader function.\n * Return `undefined` to pass resolution to the next resolver in the chain.\n */\nexport type VendorResolver = (name: string) => VendorLoader | undefined;\n\nconst _resolvers: VendorResolver[] = [];\n\n/**\n * Register a vendor resolver. Resolvers are tried in LIFO order\n * (last registered = highest priority), following the convention\n * from Vite/Rollup where later plugins override earlier ones.\n *\n * @returns A cleanup function that removes this resolver from the chain.\n */\nexport function addResolver(resolver: VendorResolver): () => void {\n _resolvers.push(resolver);\n return () => {\n const idx = _resolvers.indexOf(resolver);\n if (idx !== -1) _resolvers.splice(idx, 1);\n };\n}\n\n/**\n * Resolve a vendor name to a loader by walking the resolver chain (LIFO).\n * Returns `undefined` if no resolver can handle the name.\n */\nexport function resolveVendor(name: string): VendorLoader | undefined {\n for (let i = _resolvers.length - 1; i >= 0; i--) {\n const result = _resolvers[i](name);\n if (result) return result;\n }\n return undefined;\n}\n\n/** @internal — test helper only */\nexport function __resetResolvers(): void {\n _resolvers.length = 0;\n}\n","import { consentState, hasAnswered, isPanelOpen, servicesList } from './state';\nimport { resolveVendor } from './resolver';\nimport type { McConfig } from './layer';\n\ndeclare global {\n interface Window {\n _modernConsentConfig: McConfig;\n }\n}\n\nexport type VendorConfig = unknown;\n\nexport interface Vendor<TConfig = void> {\n name: string;\n description: string;\n category: string;\n /**\n * Human-readable label for the purpose/category in 'purpose' displayMode.\n * Can be a string or a Record<lang, string> for i18n support.\n * @example purposeLabel: { fr: \"Mesure d'audience\", en: \"Audience measurement\" }\n */\n purposeLabel?: string | Record<string, string>;\n /**\n * Description for the purpose/category in 'purpose' displayMode.\n * Can be a string or a Record<lang, string> for i18n support.\n */\n purposeDescription?: string | Record<string, string>;\n setup?: (config: TConfig) => void;\n domSelector?: string;\n init?: (config: TConfig) => void;\n /** Cookie names set by this vendor — cleared when consent is revoked. */\n artifacts?: string[] | ((config: TConfig) => string[]);\n render?: (dataset: DOMStringMap) => string;\n requireConsent: boolean;\n event?: {\n name: string;\n callback: () => void;\n }[];\n link?: {\n vendor: string;\n /** Config passed to the linked vendor. Defaults to {} if omitted. */\n config?: VendorConfig;\n condition: (params: { vendorConfig: any; consentConfig: any }) => boolean;\n }[];\n}\n\nexport type VendorLoader = () => Promise<Vendor<any>>;\n\nconst loaders = new Map<string, VendorLoader>();\nconst loadedVendors = new Map<string, Vendor<VendorConfig>>();\nconst vendorsConfig = new Map<string, VendorConfig>();\n\n// Re-export resolveVendor from resolver.ts for backward compatibility\nexport { resolveVendor } from './resolver';\n\n/** @internal — test helper only */\nexport function __resetRegistry() {\n loaders.clear();\n loadedVendors.clear();\n vendorsConfig.clear();\n}\n\n/**\n * Clears all cookies declared in vendor.artifacts.\n * Called before reload or on denyAll to clean up vendor-set cookies.\n */\nexport function clearVendorArtifacts(id: string): void {\n const vendor = loadedVendors.get(id);\n if (!vendor?.artifacts) return;\n\n const config = vendorsConfig.get(id);\n const cookieNames =\n typeof vendor.artifacts === 'function' ? vendor.artifacts(config) : vendor.artifacts;\n\n const domain = window._modernConsentConfig?.cookieDomain;\n\n cookieNames.forEach(name => {\n document.cookie = `${name}=; max-age=0; path=/`;\n if (domain) {\n document.cookie = `${name}=; max-age=0; path=/; domain=${domain}`;\n }\n });\n}\n\nexport function registerService(args: {\n id: string;\n category: string;\n loader: VendorLoader;\n config: VendorConfig;\n}) {\n const { id, category, loader, config = {} } = args;\n\n // Prevent double-registration for the same service id\n if (loaders.has(id)) return;\n loaders.set(id, loader);\n\n loader()\n .then((module: any) => {\n const vendor: Vendor<any> = module.default || module;\n loadedVendors.set(id, vendor);\n if (config !== undefined) {\n vendorsConfig.set(id, config);\n }\n\n if (vendor?.setup) {\n vendor.setup(config);\n }\n\n if (vendor?.link && vendor.link.length > 0) {\n vendor.link.forEach(link => {\n if (\n link.condition &&\n !link.condition({ vendorConfig: config, consentConfig: window._modernConsentConfig })\n ) {\n return;\n }\n const linkedLoader = resolveVendor(link.vendor);\n if (linkedLoader) {\n registerService({\n id: link.vendor,\n category,\n config: link.config ?? {},\n loader: linkedLoader,\n });\n } else {\n console.warn(`[modern-consent] Dependency \"${link.vendor}\" not found for \"${id}\"`);\n }\n });\n }\n\n servicesList.update(list => {\n if (list.some(s => s.id === id)) return list;\n return [\n ...list,\n {\n id,\n name: vendor.name,\n description: vendor.description,\n category: vendor.category,\n purposeLabel: vendor.purposeLabel,\n purposeDescription: vendor.purposeDescription,\n loaded: false,\n requireConsent: vendor.requireConsent,\n },\n ];\n });\n\n checkAutoActivation(id);\n })\n .catch(err => {\n console.error(`[modern-consent] Failed to load vendor \"${id}\":`, err);\n });\n}\n\n/**\n * Vérifie si on doit activer le service ou ouvrir le panel (nouveau service détecté)\n */\nfunction checkAutoActivation(id: string) {\n const vendor = loadedVendors.get(id);\n\n // Services that don't require consent activate immediately\n if (vendor && !vendor.requireConsent) {\n activateService(id);\n return;\n }\n\n const currentConsent = consentState.get();\n const answered = hasAnswered.get();\n\n if (answered && currentConsent[id] === undefined) {\n isPanelOpen.set(true);\n }\n\n if (currentConsent[id]) {\n activateService(id);\n }\n}\n\n/**\n * Active le service (Script + DOM)\n */\nexport async function activateService(id: string) {\n if (typeof window === 'undefined') return;\n\n let vendor = loadedVendors.get(id);\n\n if (!vendor) {\n const loader = loaders.get(id);\n if (loader) {\n const module: any = await loader();\n vendor = module.default || module;\n if (vendor) loadedVendors.set(id, vendor);\n }\n }\n\n if (!vendor) return;\n\n const isSoft = window._modernConsentConfig?.consentOnly === true;\n const list = servicesList.get();\n const meta = list.find(s => s.id === id);\n\n if (!isSoft && vendor.init && meta && !meta.loaded) {\n vendor.init(vendorsConfig.get(id));\n servicesList.update(l => l.map(s => (s.id === id ? { ...s, loaded: true } : s)));\n\n // Trigger onAccept events after successful activation\n vendor.event?.forEach(ev => {\n if (ev.name === 'onAccept') {\n try {\n ev.callback();\n } catch {\n /* don't let event errors break activation */\n }\n }\n });\n }\n\n if (!isSoft && vendor.domSelector && vendor.render) {\n setTimeout(() => {\n document.querySelectorAll(vendor!.domSelector!).forEach(el => {\n const htmlElement = el as HTMLElement;\n if (htmlElement.dataset.loaded !== 'true' && vendor?.render) {\n htmlElement.innerHTML = vendor.render(htmlElement.dataset);\n htmlElement.dataset.loaded = 'true';\n htmlElement.classList.remove('mc-placeholder-pending');\n }\n });\n }, 50);\n }\n}\n","import type { ConsentState } from './state';\n\nexport type ConsentEventMap = {\n 'consent:update': { vendor: string; status: 'granted' | 'denied'; gcm?: Record<string, boolean> };\n 'consent:saved': {\n consentId: string;\n timestamp: number;\n version?: string;\n consent: ConsentState;\n };\n};\n\ntype Listener<T> = (data: T) => void;\n\nclass ConsentEmitter {\n private listeners = new Map<string, Set<Listener<any>>>();\n\n on<K extends keyof ConsentEventMap>(event: K, cb: Listener<ConsentEventMap[K]>): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n this.listeners.get(event)!.add(cb);\n return () => this.listeners.get(event)?.delete(cb);\n }\n\n off<K extends keyof ConsentEventMap>(event: K, cb: Listener<ConsentEventMap[K]>): void {\n this.listeners.get(event)?.delete(cb);\n }\n\n emit<K extends keyof ConsentEventMap>(event: K, data: ConsentEventMap[K]): void {\n this.listeners.get(event)?.forEach(cb => {\n try {\n cb(data);\n } catch {\n /* don't let listener errors break the core */\n }\n });\n }\n}\n\nexport const emitter = new ConsentEmitter();\n","import { servicesList, consentState, hasAnswered, isPanelOpen } from './state';\nimport type { ConsentState } from './state';\nimport { activateService, clearVendorArtifacts } from './registry';\nimport { emitter } from './emitter';\nimport { generateUUID } from './utils/uuid';\n\ndeclare global {\n interface Window {\n consentLayer: any[];\n dataLayer: any[];\n }\n}\n\n/**\n * Always pushes consent state to `window.consentLayer` (TMS-agnostic).\n * Optionally pushes to `window.dataLayer` when `pushDataLayer` is enabled (GTM convenience).\n */\nfunction pushConsentEvent(consent: ConsentState) {\n if (typeof window === 'undefined') return;\n\n const event = {\n event: 'consent_update',\n consent_state: consent,\n };\n\n // consentLayer — always active, TMS-agnostic\n window.consentLayer = window.consentLayer || [];\n window.consentLayer.push(event);\n\n // dataLayer — opt-in for GTM native triggers\n if (window._modernConsentConfig?.pushDataLayer) {\n window.dataLayer = window.dataLayer || [];\n window.dataLayer.push(event);\n }\n}\n\nfunction emitConsentSaved(consent: ConsentState) {\n emitter.emit('consent:saved', {\n consentId: generateUUID(),\n timestamp: Date.now(),\n version:\n typeof window !== 'undefined' ? window._modernConsentConfig?.consentVersion : undefined,\n consent,\n });\n}\n\nexport function setConsent(id: string, allowed: boolean) {\n // Check before updating state whether this service was actively running\n const wasPreviouslyLoaded = servicesList.get().find(s => s.id === id)?.loaded ?? false;\n\n consentState.update(s => ({ ...s, [id]: allowed }));\n hasAnswered.set(true);\n\n emitter.emit('consent:update', {\n vendor: id,\n status: allowed ? 'granted' : 'denied',\n });\n\n const updatedConsent = consentState.get();\n pushConsentEvent(updatedConsent);\n emitConsentSaved(updatedConsent);\n\n if (allowed) {\n activateService(id);\n return;\n }\n\n // Only clean up and reload if the service was actively running\n if (wasPreviouslyLoaded) {\n clearVendorArtifacts(id);\n const isConsentOnly =\n typeof window !== 'undefined' && window._modernConsentConfig?.consentOnly === true;\n if (!isConsentOnly && typeof window !== 'undefined') window.location.reload();\n }\n}\n\nexport function acceptAll() {\n const list = servicesList.get();\n const updates: Record<string, boolean> = {};\n\n list.forEach(s => {\n updates[s.id] = true;\n activateService(s.id);\n });\n\n consentState.set(updates);\n hasAnswered.set(true);\n isPanelOpen.set(false);\n\n list.forEach(s => {\n emitter.emit('consent:update', { vendor: s.id, status: 'granted' });\n });\n\n pushConsentEvent(updates);\n emitConsentSaved(updates);\n}\n\nexport function denyAll() {\n const list = servicesList.get();\n const updates: Record<string, boolean> = {};\n let needsReload = false;\n\n list.forEach(s => {\n updates[s.id] = false;\n clearVendorArtifacts(s.id);\n if (s.loaded) needsReload = true;\n });\n\n consentState.set(updates);\n hasAnswered.set(true);\n isPanelOpen.set(false);\n\n list.forEach(s => {\n emitter.emit('consent:update', { vendor: s.id, status: 'denied' });\n });\n\n pushConsentEvent(updates);\n emitConsentSaved(updates);\n\n // Reload only if at least one vendor was actively running —\n // clears vendor scripts from memory after cookie cleanup.\n const isConsentOnly =\n typeof window !== 'undefined' && window._modernConsentConfig?.consentOnly === true;\n if (needsReload && !isConsentOnly && typeof window !== 'undefined') {\n window.location.reload();\n }\n}\n","import { registerService } from './registry';\nimport { addResolver, resolveVendor } from './resolver';\nimport { consentState, initState, isPanelOpen } from './state';\nimport type { ConsentState } from './state';\nimport type { Vendor } from './registry';\nimport { emitter } from './emitter';\n\n/**\n * Command can add in config\n */\nconst validCommands = ['config', 'vendor'] as const;\n\nexport interface McConfig {\n cookieDomain?: string;\n cookieName?: string;\n consentMode?: boolean;\n /** Version string embedded in the stored consent — used for GDPR audit trails. */\n consentVersion?: string;\n /**\n * Base URL where vendor JS files are hosted.\n * Used by the CDN bundle to lazy-load vendors on demand.\n *\n * @example 'https://cdn.monsite.com/mc-vendors'\n * → window.modernConsent('vendor', { name: 'google-analytics' })\n * → fetches https://cdn.monsite.com/mc-vendors/google-analytics.js\n */\n cdnBase?: string;\n /**\n * In Consent-Only mode, the CMP only manages consent decisions + cookie storage.\n * Vendors are never initialized (no call to init()).\n * Use this to manage vendor scripts externally via a Tag Manager (GTM, TagCommander, etc.).\n *\n * Consent changes are always pushed to `window.consentLayer`.\n * Enable `pushDataLayer` to also push to `window.dataLayer` for native GTM triggers.\n */\n consentOnly?: boolean;\n /**\n * When true, consent changes are also pushed to `window.dataLayer` for native\n * GTM trigger support. Disabled by default — GTM users should enable this.\n */\n pushDataLayer?: boolean;\n /**\n * How the details panel displays consent controls:\n * - 'vendor' (default): individual toggle per vendor, grouped by category\n * - 'purpose': toggle per category/purpose, vendors listed as info below\n */\n displayMode?: 'vendor' | 'purpose';\n /**\n * Custom labels for each purpose/category in 'purpose' displayMode.\n * Keys must match the vendor `category` values.\n *\n * @example\n * purposes: {\n * analytics: { label: \"Analyse de session et mesure d'audience\" },\n * Publicité: { label: \"Ciblage Marketing\" },\n * }\n */\n purposes?: Record<\n string,\n {\n /** Human-readable label displayed as the purpose title. */\n label: string;\n /** Optional description shown below the purpose title. */\n description?: string;\n }\n >;\n /**\n * When true, displays a \"Functional / Site operation\" mandatory purpose block\n * at the top of the details panel. This is a visual-only block with no toggle —\n * it informs the user that essential cookies are always active.\n */\n functionalPurpose?: boolean;\n}\n\nexport interface McVendor {\n /**\n * Built-in vendor name (e.g. 'google-analytics') when using npm with\n * built-in loaders, OR a unique ID when providing an inline init().\n */\n name: string;\n /**\n * Category for this vendor (e.g. 'analytics', 'marketing').\n * Optional for built-in vendors — they define their own category.\n * Required for inline vendors (defaults to 'other' if omitted).\n */\n category?: string;\n config?: Record<string, any>;\n\n // --- Inline vendor definition (CDN users / custom vendors) ---\n /** Human-readable label shown in the consent UI. Defaults to `name`. */\n label?: string;\n /** Short description shown in the consent UI. */\n description?: string;\n /** Whether the user must explicitly consent before this vendor activates. @default true */\n requireConsent?: boolean;\n /** Called immediately at page load (e.g. set consent defaults). */\n setup?: (config?: Record<string, any>) => void;\n /** Called when consent is granted. Inject scripts, pixels, etc. here. */\n init?: (config?: Record<string, any>) => void;\n /** Cookie names written by this vendor — cleared when consent is revoked. */\n artifacts?: string[];\n}\n\nexport type ConfigCommand = ['config', McConfig];\nexport type VendorCommand = ['vendor', McVendor];\nexport type McCommand = ConfigCommand | VendorCommand;\n\ntype McAPI = {\n (...args: McCommand): void;\n openPanel: () => void;\n getConsent: () => ConsentState;\n on: typeof emitter.on;\n};\n\ndeclare global {\n interface Window {\n _modernConsentConfig: McConfig;\n mcLayer: McCommand[];\n modernConsent: McAPI;\n }\n}\n\nfunction handleVendor(event: McVendor) {\n const {\n name,\n label,\n description = '',\n category = 'other',\n config = {},\n requireConsent = true,\n setup,\n init,\n artifacts,\n } = event;\n\n let loader: import('./registry').VendorLoader;\n\n if (init ?? setup) {\n // Inline vendor — CDN users provide their own implementation.\n loader = async () => ({\n name: label ?? name,\n description,\n category,\n requireConsent,\n setup,\n init,\n artifacts,\n });\n } else {\n // Look up via the resolver chain (builtin, CDN, or user-registered resolvers).\n const resolved = resolveVendor(name);\n if (!resolved) {\n console.warn(\n `[modern-consent] Unknown vendor \"${name}\". ` +\n `Provide an init() function to define a custom vendor.`,\n );\n return;\n }\n loader = resolved;\n }\n\n registerService({ id: name, category, config, loader });\n}\n\n/**\n * Initialise window.mcLayer et traite la queue éventuelle.\n */\nexport function initMcLayer() {\n if (typeof window === 'undefined') return;\n\n const w = window;\n const existingQueue = Array.isArray(w.mcLayer) ? [...w.mcLayer] : [];\n\n w._modernConsentConfig = {};\n\n // CDN resolver — lowest priority (registered first = LIFO lowest).\n // Returns a loader for any name; cdnBase is checked lazily at activation time.\n addResolver(_name => {\n return async () => {\n const cdnBase = w._modernConsentConfig?.cdnBase;\n if (!cdnBase) {\n throw new Error(\n `[modern-consent] Vendor \"${_name}\" not found. ` +\n `Configure cdnBase to enable CDN loading, or provide an inline init().`,\n );\n }\n const url = `${cdnBase.replace(/\\/$/, '')}/${_name}.js`;\n const mod = await import(/* @vite-ignore */ url);\n return (mod.default ?? mod) as Vendor<any>;\n };\n });\n\n // Process the existing queue — config commands accumulate before vendors are registered\n existingQueue.forEach((args: McCommand) => {\n const [command, payload] = args;\n\n if (!validCommands.includes(command as any)) {\n console.warn(`[modern-consent] \"${command}\" is not a valid command`);\n return;\n }\n\n if (command === 'config') {\n w._modernConsentConfig = { ...w._modernConsentConfig, ...(payload as McConfig) };\n return;\n }\n\n handleVendor(payload as McVendor);\n });\n\n // State is initialised once after config is fully resolved from the queue\n initState(w._modernConsentConfig);\n\n // Live API\n const apiFn = (...args: McCommand) => {\n const [command, payload] = args;\n\n if (!validCommands.includes(command as any)) {\n console.warn(`[modern-consent] \"${command}\" is not a valid command`);\n return;\n }\n\n if (command === 'vendor') {\n handleVendor(payload as McVendor);\n } else if (command === 'config') {\n w._modernConsentConfig = { ...w._modernConsentConfig, ...(payload as McConfig) };\n }\n\n if (!Array.isArray(w.mcLayer)) w.mcLayer = [];\n w.mcLayer.push(args);\n };\n\n w.modernConsent = Object.assign(apiFn, {\n openPanel: () => isPanelOpen.set(true),\n getConsent: () => consentState.get(),\n on: emitter.on.bind(emitter),\n });\n}\n","export type { ConsentState, ServiceMetadata } from './state.ts';\n\nexport { Store } from './utils/store';\n\nexport { consentState, hasAnswered, servicesList, isPanelOpen, openPanel } from './state';\n\n// Vendor Resolution\nexport { addResolver, resolveVendor } from './resolver';\n\nexport {\n registerService,\n activateService,\n clearVendorArtifacts,\n type Vendor,\n type VendorLoader,\n type VendorConfig,\n} from './registry';\n\nexport { setConsent, acceptAll, denyAll } from './consent';\n\nexport type { McConfig, McVendor, McCommand, ConfigCommand, VendorCommand } from './layer';\n\nexport { emitter, type ConsentEventMap } from './emitter';\nexport { generateUUID } from './utils/uuid';\nexport { initMcLayer } from './layer';\n\nimport { initMcLayer } from './layer';\n\nif (typeof window !== 'undefined') {\n initMcLayer();\n}\n","import {\n consentState,\n servicesList,\n hasAnswered,\n isPanelOpen,\n openPanel,\n type ConsentState,\n type ServiceMetadata,\n} from '@modernconsent/core';\n\nimport { acceptAll, denyAll, setConsent } from '@modernconsent/core';\n\ntype WidgetMode = 'banner' | 'details';\n\n/**\n * Labels for UI chrome only — NOT for banner title/body content.\n * The integrator provides title and body via <slot name=\"title\"> and <slot name=\"body\">.\n */\ntype WidgetLabels = {\n bannerAcceptAll: string;\n bannerDenyAll: string;\n bannerCustomize: string;\n detailsTitle: string;\n detailsSubtitle: string;\n detailsBack: string;\n detailsAcceptAll: string;\n detailsDenyAll: string;\n serviceAccept: string;\n serviceDeny: string;\n statusAllowed: string;\n statusDenied: string;\n statusPending: string;\n statusAlwaysActive: string;\n categoryPending: string;\n close: string;\n purposeAccept: string;\n purposeDeny: string;\n purposeStatusAllowed: string;\n purposeStatusDenied: string;\n purposeStatusPending: string;\n functionalTitle: string;\n functionalDescription: string;\n};\n\nconst LABELS: Record<string, WidgetLabels> = {\n fr: {\n bannerAcceptAll: 'Tout accepter',\n bannerDenyAll: 'Continuer sans accepter',\n bannerCustomize: 'Personnaliser',\n detailsTitle: 'Personnaliser vos préférences',\n detailsSubtitle: 'Vous pouvez activer ou désactiver chaque service individuellement.',\n detailsBack: 'Retour',\n detailsAcceptAll: 'Tout accepter',\n detailsDenyAll: 'Tout refuser',\n serviceAccept: 'Accepter',\n serviceDeny: 'Refuser',\n statusAllowed: 'Autorisé',\n statusDenied: 'Refusé',\n statusPending: 'En attente',\n statusAlwaysActive: 'Obligatoire',\n categoryPending: 'Services en attente',\n close: 'Fermer',\n purposeAccept: 'Accepter',\n purposeDeny: 'Refuser',\n purposeStatusAllowed: 'Acceptée',\n purposeStatusDenied: 'Refusée',\n purposeStatusPending: 'En attente',\n functionalTitle: 'Fonctionnement du site',\n functionalDescription:\n \"Ces cookies et traceurs sont indispensables au fonctionnement du site, pour fournir nos services et nous assurer de leur bon fonctionnement, pour des raisons de sécurité et pour s'assurer du suivi de vos préférences.\",\n },\n en: {\n bannerAcceptAll: 'Accept all',\n bannerDenyAll: 'Continue without accepting',\n bannerCustomize: 'Customize',\n detailsTitle: 'Customize your preferences',\n detailsSubtitle: 'You can enable or disable each service individually.',\n detailsBack: 'Back',\n detailsAcceptAll: 'Accept all',\n detailsDenyAll: 'Deny all',\n serviceAccept: 'Accept',\n serviceDeny: 'Deny',\n statusAllowed: 'Allowed',\n statusDenied: 'Denied',\n statusPending: 'Pending',\n statusAlwaysActive: 'Always active',\n categoryPending: 'Pending services',\n close: 'Close',\n purposeAccept: 'Accept',\n purposeDeny: 'Deny',\n purposeStatusAllowed: 'Accepted',\n purposeStatusDenied: 'Denied',\n purposeStatusPending: 'Pending',\n functionalTitle: 'Site operation',\n functionalDescription:\n 'These cookies and trackers are essential for the site to function, to provide our services, ensure security, and remember your preferences.',\n },\n};\n\n/**\n * Resolve an i18n field: if it's a Record<lang, string>, pick the right language.\n * Falls back to 'fr', then first available value, then the fallback string.\n */\nfunction resolveI18n(\n value: string | Record<string, string> | undefined,\n lang: string,\n fallback: string,\n): string {\n if (!value) return fallback;\n if (typeof value === 'string') return value;\n return value[lang] ?? value['fr'] ?? Object.values(value)[0] ?? fallback;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\n/*\n * ─── Theming ──────────────────────────────────────────────────────────────────\n *\n * you can set these CSS custom properties on <mc-consent-widget>\n * or any ancestor:\n *\n * --mc-primary Primary button color (default: #111827)\n * --mc-primary-hover Primary button hover (default: derived)\n * --mc-radius Border radius scale (default: 12px)\n */\nconst STYLES = `\n :host {\n --_primary: var(--mc-primary, #111827);\n --_primary-hover: var(--mc-primary-hover, color-mix(in srgb, var(--_primary) 85%, black));\n --_primary-text: var(--mc-primary-text, #fff);\n --_radius: var(--mc-radius, 12px);\n --_font: var(--mc-font, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);\n\n position: fixed;\n inset: 0;\n z-index: 99999;\n font-family: var(--_font);\n pointer-events: none;\n display: none;\n }\n\n :host([open]) {\n pointer-events: auto;\n display: block;\n }\n\n *, *::before, *::after { box-sizing: border-box; }\n\n .backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n animation: mc-fade-in 0.2s ease;\n }\n\n @keyframes mc-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n\n @keyframes mc-slide-up {\n from { opacity: 0; transform: translateY(12px); }\n to { opacity: 1; transform: translateY(0); }\n }\n\n .modal {\n background: #ffffff;\n border-radius: var(--_radius);\n max-width: 640px;\n width: calc(100% - 32px);\n max-height: 90vh;\n box-shadow: 0 24px 48px -12px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.05);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: mc-slide-up 0.25s ease;\n }\n\n .header {\n padding: 20px 24px 16px;\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n }\n\n .title {\n font-size: 17px;\n font-weight: 700;\n margin: 0;\n color: #111827;\n letter-spacing: -0.01em;\n }\n\n .subtitle {\n font-size: 13px;\n color: #6b7280;\n margin: 6px 0 0;\n line-height: 1.5;\n }\n\n .close-btn {\n flex-shrink: 0;\n border: none;\n background: #f3f4f6;\n cursor: pointer;\n font-size: 16px;\n line-height: 1;\n padding: 6px 8px;\n color: #6b7280;\n border-radius: 8px;\n transition: background 0.15s;\n }\n .close-btn:hover { background: #e5e7eb; }\n\n .body {\n padding: 0 24px 16px;\n overflow: auto;\n font-size: 13px;\n color: #4b5563;\n line-height: 1.6;\n }\n\n .divider {\n height: 1px;\n background: #e5e7eb;\n margin: 0 24px;\n }\n\n .footer {\n padding: 16px 24px;\n border-top: 1px solid #f3f4f6;\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n justify-content: flex-end;\n }\n\n /* ─── Buttons ─────────────────────────────────────────── */\n\n .btn {\n appearance: none;\n border-radius: 999px;\n padding: 9px 18px;\n font-size: 13px;\n font-weight: 500;\n border: 1px solid transparent;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n letter-spacing: 0.01em;\n }\n\n .btn:active { transform: translateY(1px); }\n\n .btn-primary {\n background: var(--_primary);\n color: var(--_primary-text);\n border-color: var(--_primary);\n }\n .btn-primary:hover {\n background: var(--_primary-hover);\n border-color: var(--_primary-hover);\n }\n\n .btn-outline {\n background: #ffffff;\n border-color: #e5e7eb;\n color: #374151;\n }\n .btn-outline:hover { background: #f9fafb; border-color: #d1d5db; }\n\n .btn-allowed-active {\n background: #059669;\n border-color: #059669;\n color: #fff;\n }\n .btn-allowed-active:hover { background: #047857; border-color: #047857; }\n\n .btn-denied-active {\n background: #dc2626;\n border-color: #dc2626;\n color: #fff;\n }\n .btn-denied-active:hover { background: #b91c1c; border-color: #b91c1c; }\n\n .btn-ghost {\n background: transparent;\n color: #6b7280;\n }\n .btn-ghost:hover { background: #f9fafb; }\n\n /* ─── Categories & Services ───────────────────────────── */\n\n .categories {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .category {\n border-radius: calc(var(--_radius) - 2px);\n border: 1px solid #f3f4f6;\n background: #fafafa;\n padding: 14px;\n }\n\n .category-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 8px;\n }\n\n .category-title {\n font-size: 13px;\n font-weight: 600;\n color: #111827;\n }\n\n .services-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .service {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 8px 0 6px;\n border-top: 1px solid #f3f4f6;\n }\n\n .service-main { flex: 1; }\n\n .service-name {\n font-size: 13px;\n font-weight: 500;\n color: #111827;\n margin-bottom: 2px;\n }\n\n .service-description { font-size: 12px; color: #6b7280; line-height: 1.4; }\n\n .service-status { font-size: 11px; margin-top: 4px; font-weight: 500; }\n .service-status.allowed { color: #059669; }\n .service-status.denied { color: #dc2626; }\n .service-status.pending { color: #d97706; }\n\n .service-actions { display: flex; gap: 4px; flex-shrink: 0; }\n\n .chip {\n font-size: 11px;\n padding: 3px 10px;\n border-radius: 999px;\n border: 1px solid #e5e7eb;\n color: #6b7280;\n white-space: nowrap;\n font-weight: 500;\n }\n\n .chip-active {\n background: #ecfdf5;\n border-color: #a7f3d0;\n color: #059669;\n }\n\n /* ─── Purpose mode ────────────────────────────────────── */\n\n .category-info {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .category-status {\n font-size: 11px;\n font-weight: 500;\n }\n .category-status.allowed { color: #059669; }\n .category-status.denied { color: #dc2626; }\n .category-status.pending { color: #d97706; }\n\n .purpose-description {\n font-size: 12px;\n color: #6b7280;\n margin: 0 0 8px;\n line-height: 1.5;\n }\n\n .purpose-service-info {\n padding: 4px 0;\n border-top: none;\n }\n .purpose-service-info .service-name {\n font-size: 12px;\n color: #4b5563;\n font-weight: 400;\n }\n .purpose-service-info .service-description {\n font-size: 11px;\n color: #9ca3af;\n }\n`;\n\n// Shared across all instances — instantiated once, never GC'd\nlet _sharedStyleSheet: CSSStyleSheet | null = null;\n\nfunction getSharedStyleSheet(): CSSStyleSheet {\n if (!_sharedStyleSheet) {\n _sharedStyleSheet = new CSSStyleSheet();\n _sharedStyleSheet.replaceSync(STYLES);\n }\n return _sharedStyleSheet;\n}\n\nexport class McConsentWidget extends HTMLElement {\n static observedAttributes = ['lang'];\n\n private shadow: ShadowRoot;\n private mode: WidgetMode = 'banner';\n private _unsubscribers: (() => void)[] = [];\n private _renderScheduled = false;\n private _previouslyFocused: Element | null = null;\n private _keydownHandler: ((e: KeyboardEvent) => void) | null = null;\n\n private services: ServiceMetadata[] = [];\n private consent: ConsentState = {};\n private answered = false;\n private panelOpen = false;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n private get labels(): WidgetLabels {\n const lang = this.getAttribute('lang') ?? 'fr';\n return LABELS[lang] ?? LABELS['fr'];\n }\n\n private scheduleRender() {\n if (this._renderScheduled) return;\n this._renderScheduled = true;\n queueMicrotask(() => {\n this._renderScheduled = false;\n this.render();\n });\n }\n\n connectedCallback() {\n // Apply styles once — persists across renders since we're using adoptedStyleSheets\n this.shadow.adoptedStyleSheets = [getSharedStyleSheet()];\n\n // subscribe() fires immediately with current value.\n // ORDER MATTERS: consent + answered must sync BEFORE servicesList\n // because servicesList triggers ensurePanelOpenIfNeeded() which\n // reads this.consent and this.answered to decide whether to show.\n this._unsubscribers.push(\n consentState.subscribe(consent => {\n this.consent = consent;\n this.scheduleRender();\n }),\n hasAnswered.subscribe(answered => {\n this.answered = answered;\n this.scheduleRender();\n }),\n servicesList.subscribe(services => {\n this.services = services;\n this.ensurePanelOpenIfNeeded();\n this.scheduleRender();\n }),\n isPanelOpen.subscribe(open => {\n const previous = this.panelOpen;\n this.panelOpen = open;\n if (open && !previous && this.answered) {\n this.mode = 'details';\n }\n this.scheduleRender();\n }),\n );\n }\n\n disconnectedCallback() {\n this._unsubscribers.forEach(unsub => unsub());\n this._unsubscribers = [];\n this.teardownFocusTrap(false);\n }\n\n attributeChangedCallback() {\n this.scheduleRender();\n }\n\n private ensurePanelOpenIfNeeded() {\n if (this.getPendingServices().length > 0 && !this.answered && !this.panelOpen) {\n openPanel();\n }\n }\n\n private getPendingServices(): ServiceMetadata[] {\n return this.services.filter(s => s.requireConsent && this.consent[s.id] === undefined);\n }\n\n private shouldShowPopup(): boolean {\n return this.panelOpen && this.services.length > 0;\n }\n\n // ─── Focus trap ──────────────────────────────────────────────────────────────\n\n private setupFocusTrap() {\n const modal = this.shadow.querySelector<HTMLElement>('.modal');\n if (!modal) return;\n\n const focusable = [\n ...modal.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), [href], [tabindex]:not([tabindex=\"-1\"])',\n ),\n ];\n if (!focusable.length) return;\n\n // Capture the previously focused element so we can restore it on close\n if (!this._previouslyFocused) {\n this._previouslyFocused = document.activeElement;\n }\n\n // Move focus into the modal on the next frame (ensures paint is complete)\n requestAnimationFrame(() => focusable[0]?.focus());\n\n this._keydownHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n isPanelOpen.set(false);\n return;\n }\n\n if (e.key !== 'Tab') return;\n\n // shadow.activeElement gives the focused element within the shadow root\n const active = this.shadow.activeElement;\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey && active === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && active === last) {\n e.preventDefault();\n first.focus();\n }\n };\n\n document.addEventListener('keydown', this._keydownHandler);\n }\n\n private teardownFocusTrap(restoreFocus = true) {\n if (this._keydownHandler) {\n document.removeEventListener('keydown', this._keydownHandler);\n this._keydownHandler = null;\n }\n\n if (restoreFocus && this._previouslyFocused && 'focus' in this._previouslyFocused) {\n (this._previouslyFocused as HTMLElement).focus();\n this._previouslyFocused = null;\n }\n }\n\n // ─── Rendering ───────────────────────────────────────────────────────────────\n\n private render() {\n const shouldShow = this.shouldShowPopup();\n\n if (!shouldShow) {\n this.teardownFocusTrap(true);\n this.shadow.innerHTML = '';\n this.removeAttribute('open');\n return;\n }\n\n this.setAttribute('open', '');\n\n // Re-rendering while staying open: remove old keydown handler, keep previouslyFocused\n this.teardownFocusTrap(false);\n\n if (this.mode === 'banner') {\n this.renderBanner();\n } else {\n const displayMode =\n (typeof window !== 'undefined' ? window._modernConsentConfig?.displayMode : undefined) ??\n 'vendor';\n if (displayMode === 'purpose') {\n this.renderPurposeDetails();\n } else {\n this.renderDetails();\n }\n }\n\n this.setupFocusTrap();\n }\n\n private onAcceptAll = () => acceptAll();\n private onDenyAll = () => denyAll();\n\n private onCustomize = () => {\n this.mode = 'details';\n this.scheduleRender();\n };\n\n private onBackToBanner = () => {\n this.mode = 'banner';\n this.scheduleRender();\n };\n\n private onSetConsentForService(id: string, allowed: boolean) {\n setConsent(id, allowed);\n if (this.getPendingServices().filter(s => s.id !== id).length === 0) {\n isPanelOpen.set(false);\n }\n }\n\n private onSetConsentForCategory(category: string, allowed: boolean) {\n const servicesInCategory = this.services.filter(\n s => s.category === category && s.requireConsent,\n );\n servicesInCategory.forEach(s => setConsent(s.id, allowed));\n if (this.getPendingServices().length === 0) {\n isPanelOpen.set(false);\n }\n }\n\n private getCategoryStatus(services: ServiceMetadata[]): 'allowed' | 'denied' | 'pending' {\n const consentRequired = services.filter(s => s.requireConsent);\n if (consentRequired.length === 0) return 'allowed';\n const allAllowed = consentRequired.every(s => this.consent[s.id]);\n if (allAllowed) return 'allowed';\n const allDenied = consentRequired.every(s => !this.consent[s.id]);\n if (allDenied) return 'denied';\n return 'pending';\n }\n\n private groupServicesByCategory(): Record<string, ServiceMetadata[]> {\n const groups: Record<string, ServiceMetadata[]> = {};\n this.services.forEach(service => {\n const cat = service.category || 'Autres';\n if (!groups[cat]) groups[cat] = [];\n groups[cat].push(service);\n });\n return groups;\n }\n\n private renderFunctionalBlock(): string {\n const show =\n typeof window !== 'undefined' && window._modernConsentConfig?.functionalPurpose === true;\n if (!show) return '';\n const l = this.labels;\n return `\n <section class=\"category\">\n <div class=\"category-header\">\n <div class=\"category-info\">\n <span class=\"category-title\">${escapeHtml(l.functionalTitle)}</span>\n </div>\n <span class=\"chip chip-active\">${escapeHtml(l.statusAlwaysActive)}</span>\n </div>\n <div class=\"purpose-description\">${escapeHtml(l.functionalDescription)}</div>\n </section>\n `;\n }\n\n private renderBanner() {\n const l = this.labels;\n\n this.shadow.innerHTML = `\n <div class=\"backdrop\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"mc-title\">\n <div class=\"modal\">\n <div class=\"header\">\n <div>\n <h2 class=\"title\" id=\"mc-title\"><slot name=\"title\"></slot></h2>\n </div>\n <button class=\"close-btn\" type=\"button\" aria-label=\"${escapeHtml(l.close)}\" id=\"mc-close-btn\">✕</button>\n </div>\n <div class=\"body\">\n <slot name=\"body\"></slot>\n </div>\n <div class=\"footer\">\n <button class=\"btn btn-ghost\" type=\"button\" id=\"mc-deny-all-btn\">${escapeHtml(l.bannerDenyAll)}</button>\n <button class=\"btn btn-outline\" type=\"button\" id=\"mc-customize-btn\">${escapeHtml(l.bannerCustomize)}</button>\n <button class=\"btn btn-primary\" type=\"button\" id=\"mc-accept-all-btn\">${escapeHtml(l.bannerAcceptAll)}</button>\n </div>\n </div>\n </div>\n `;\n\n this.shadow.getElementById('mc-accept-all-btn')!.addEventListener('click', this.onAcceptAll);\n this.shadow.getElementById('mc-deny-all-btn')!.addEventListener('click', this.onDenyAll);\n this.shadow.getElementById('mc-customize-btn')!.addEventListener('click', this.onCustomize);\n this.shadow\n .getElementById('mc-close-btn')!\n .addEventListener('click', () => isPanelOpen.set(false));\n }\n\n private renderDetails() {\n const l = this.labels;\n const functionalHtml = this.renderFunctionalBlock();\n const groups = this.groupServicesByCategory();\n\n const bodyHtml = Object.keys(groups)\n .sort()\n .map(cat => {\n const services = groups[cat];\n const hasPending = services.some(s => s.requireConsent && this.consent[s.id] === undefined);\n\n const servicesHtml = services\n .map(s => {\n if (!s.requireConsent) {\n return `\n <div class=\"service\">\n <div class=\"service-main\">\n <div class=\"service-name\">${escapeHtml(s.name)}</div>\n <div class=\"service-description\">${escapeHtml(s.description)}</div>\n </div>\n <span class=\"chip chip-active\">${escapeHtml(l.statusAlwaysActive)}</span>\n </div>\n `;\n }\n\n const consent = this.consent[s.id];\n const statusLabel = consent\n ? l.statusAllowed\n : !consent\n ? l.statusDenied\n : l.statusPending;\n const statusClass = consent ? 'allowed' : !consent ? 'denied' : 'pending';\n\n return `\n <div class=\"service\">\n <div class=\"service-main\">\n <div class=\"service-name\">${escapeHtml(s.name)}</div>\n <div class=\"service-description\">${escapeHtml(s.description)}</div>\n <div class=\"service-status ${statusClass}\">${escapeHtml(statusLabel)}</div>\n </div>\n <div class=\"service-actions\">\n <button class=\"btn btn-outline ${statusClass === 'allowed' ? 'btn-allowed-active' : ''}\" type=\"button\" data-action=\"allow\" data-id=\"${escapeHtml(s.id)}\">\n ${escapeHtml(l.serviceAccept)}\n </button>\n <button class=\"btn btn-outline ${statusClass === 'denied' ? 'btn-denied-active' : ''}\" type=\"button\" data-action=\"deny\" data-id=\"${escapeHtml(s.id)}\">\n ${escapeHtml(l.serviceDeny)}\n </button>\n </div>\n </div>\n `;\n })\n .join('');\n\n return `\n <section class=\"category\">\n <div class=\"category-header\">\n <div class=\"category-title\">${escapeHtml(cat)}</div>\n ${hasPending ? `<span class=\"chip\">${escapeHtml(l.categoryPending)}</span>` : ''}\n </div>\n <div class=\"services-list\">${servicesHtml}</div>\n </section>\n `;\n })\n .join('');\n\n this.shadow.innerHTML = `\n <div class=\"backdrop\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"mc-details-title\">\n <div class=\"modal\">\n <div class=\"header\">\n <div>\n <h2 class=\"title\" id=\"mc-details-title\">${escapeHtml(l.detailsTitle)}</h2>\n <p class=\"subtitle\">${escapeHtml(l.detailsSubtitle)}</p>\n </div>\n <button class=\"close-btn\" type=\"button\" aria-label=\"${escapeHtml(l.close)}\" id=\"mc-close-btn\">✕</button>\n </div>\n <div class=\"body\">\n <div class=\"categories\">${functionalHtml}${bodyHtml}</div>\n </div>\n <div class=\"footer\">\n <button class=\"btn btn-ghost\" type=\"button\" id=\"mc-back-btn\">${escapeHtml(l.detailsBack)}</button>\n <button class=\"btn btn-outline\" type=\"button\" id=\"mc-deny-all-btn\">${escapeHtml(l.detailsDenyAll)}</button>\n <button class=\"btn btn-primary\" type=\"button\" id=\"mc-accept-all-btn\">${escapeHtml(l.detailsAcceptAll)}</button>\n </div>\n </div>\n </div>\n `;\n\n this.shadow.getElementById('mc-accept-all-btn')!.addEventListener('click', this.onAcceptAll);\n this.shadow.getElementById('mc-deny-all-btn')!.addEventListener('click', this.onDenyAll);\n this.shadow.getElementById('mc-back-btn')!.addEventListener('click', this.onBackToBanner);\n this.shadow\n .getElementById('mc-close-btn')!\n .addEventListener('click', () => isPanelOpen.set(false));\n\n this.shadow.querySelectorAll<HTMLButtonElement>('[data-action]').forEach(btn => {\n btn.addEventListener('click', () => {\n this.onSetConsentForService(btn.dataset.id!, btn.dataset.action === 'allow');\n });\n });\n }\n\n private renderPurposeDetails() {\n const l = this.labels;\n const lang = this.getAttribute('lang') ?? 'fr';\n const functionalHtml = this.renderFunctionalBlock();\n const groups = this.groupServicesByCategory();\n const configPurposes =\n typeof window !== 'undefined' ? window._modernConsentConfig?.purposes : undefined;\n\n const bodyHtml = Object.keys(groups)\n .sort()\n .map(cat => {\n const services = groups[cat];\n const allNonConsent = services.every(s => !s.requireConsent);\n const status = this.getCategoryStatus(services);\n\n // Resolve purpose label: vendor-level (i18n) > config-level > raw category name\n const vendorWithPurpose = services.find(s => s.purposeLabel);\n const purposeLabel = resolveI18n(\n vendorWithPurpose?.purposeLabel,\n lang,\n configPurposes?.[cat]?.label ?? cat,\n );\n const purposeDescription = resolveI18n(\n vendorWithPurpose?.purposeDescription,\n lang,\n configPurposes?.[cat]?.description ?? '',\n );\n\n const actionsHtml = allNonConsent\n ? `<span class=\"chip chip-active\">${escapeHtml(l.statusAlwaysActive)}</span>`\n : `\n <div class=\"service-actions\">\n <button class=\"btn btn-outline ${status === 'allowed' ? 'btn-allowed-active' : ''}\" type=\"button\" data-category=\"${escapeHtml(cat)}\" data-cat-action=\"allow\">\n ${escapeHtml(l.purposeAccept)}\n </button>\n <button class=\"btn btn-outline ${status === 'denied' ? 'btn-denied-active' : ''}\" type=\"button\" data-category=\"${escapeHtml(cat)}\" data-cat-action=\"deny\">\n ${escapeHtml(l.purposeDeny)}\n </button>\n </div>\n `;\n\n const vendorsHtml = services\n .map(\n s => `\n <div class=\"service purpose-service-info\">\n <div class=\"service-main\">\n <div class=\"service-name\">${escapeHtml(s.name)}</div>\n <div class=\"service-description\">${escapeHtml(s.description)}</div>\n </div>\n </div>\n `,\n )\n .join('');\n\n return `\n <section class=\"category\">\n <div class=\"category-header\">\n <div class=\"category-info\">\n <span class=\"category-title\">${escapeHtml(purposeLabel)}</span>\n </div>\n ${actionsHtml}\n </div>\n ${purposeDescription ? `<div class=\"purpose-description\">${escapeHtml(purposeDescription)}</div>` : ''}\n <div class=\"services-list\">${vendorsHtml}</div>\n </section>\n `;\n })\n .join('');\n\n this.shadow.innerHTML = `\n <div class=\"backdrop\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"mc-details-title\">\n <div class=\"modal\">\n <div class=\"header\">\n <div>\n <h2 class=\"title\" id=\"mc-details-title\">${escapeHtml(l.detailsTitle)}</h2>\n <p class=\"subtitle\">${escapeHtml(l.detailsSubtitle)}</p>\n </div>\n <button class=\"close-btn\" type=\"button\" aria-label=\"${escapeHtml(l.close)}\" id=\"mc-close-btn\">✕</button>\n </div>\n <div class=\"body\">\n <div class=\"categories\">${functionalHtml}${bodyHtml}</div>\n </div>\n <div class=\"footer\">\n <button class=\"btn btn-ghost\" type=\"button\" id=\"mc-back-btn\">${escapeHtml(l.detailsBack)}</button>\n <button class=\"btn btn-outline\" type=\"button\" id=\"mc-deny-all-btn\">${escapeHtml(l.detailsDenyAll)}</button>\n <button class=\"btn btn-primary\" type=\"button\" id=\"mc-accept-all-btn\">${escapeHtml(l.detailsAcceptAll)}</button>\n </div>\n </div>\n </div>\n `;\n\n this.shadow.getElementById('mc-accept-all-btn')!.addEventListener('click', this.onAcceptAll);\n this.shadow.getElementById('mc-deny-all-btn')!.addEventListener('click', this.onDenyAll);\n this.shadow.getElementById('mc-back-btn')!.addEventListener('click', this.onBackToBanner);\n this.shadow\n .getElementById('mc-close-btn')!\n .addEventListener('click', () => isPanelOpen.set(false));\n\n this.shadow.querySelectorAll<HTMLButtonElement>('[data-cat-action]').forEach(btn => {\n btn.addEventListener('click', () => {\n this.onSetConsentForCategory(btn.dataset.category!, btn.dataset.catAction === 'allow');\n });\n });\n }\n}\n\nif (typeof window !== 'undefined' && !customElements.get('mc-consent-widget')) {\n customElements.define('mc-consent-widget', McConsentWidget);\n}\n","/**\n * CDN / standalone bundle entry point.\n *\n * Registers <mc-consent-widget> and auto-mounts it into the page.\n * Users only need:\n *\n * <script src=\"mc-widget.js\" defer></script>\n */\nimport './index';\n\nfunction mount() {\n if (document.querySelector('mc-consent-widget')) return;\n\n const el = document.createElement('mc-consent-widget');\n\n // Inherit the page language for i18n (e.g. <html lang=\"en\"> → lang=\"en\")\n const pageLang = document.documentElement.lang?.split('-')[0];\n if (pageLang) el.setAttribute('lang', pageLang);\n\n document.body.appendChild(el);\n}\n\nif (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', mount);\n} else {\n mount();\n}\n"],"mappings":"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","names":["Store","initialValue","newValue","updater","callback","cb","manualUUIDv4","bytes","hex","b","generateUUID","DEFAULT_STORAGE_KEY","escapeCookieName","name","getCookie","match","setCookie","value","options","days","path","domain","sameSite","secure","expires","cookieString","hostname","consentState","Store","hasAnswered","servicesList","isPanelOpen","openPanel","_cookieUnsubs","initState","config","cookieName","cookieDomain","consentVersion","initialData","stored","e","fn","saveToCookie","state","generateUUID","_resolvers","addResolver","resolver","idx","resolveVendor","name","i","result","loaders","loadedVendors","vendorsConfig","clearVendorArtifacts","id","vendor","loadedVendors","config","vendorsConfig","cookieNames","domain","name","registerService","args","category","loader","loaders","module","link","linkedLoader","resolveVendor","servicesList","list","s","checkAutoActivation","err","activateService","currentConsent","consentState","hasAnswered","isPanelOpen","isSoft","meta","l","ev","el","htmlElement","ConsentEmitter","event","cb","data","emitter","pushConsentEvent","consent","event","emitConsentSaved","emitter","generateUUID","setConsent","id","allowed","wasPreviouslyLoaded","servicesList","s","consentState","hasAnswered","updatedConsent","activateService","clearVendorArtifacts","acceptAll","list","updates","isPanelOpen","denyAll","needsReload","isConsentOnly","validCommands","handleVendor","event","name","label","description","category","config","requireConsent","setup","init","artifacts","loader","resolved","resolveVendor","registerService","initMcLayer","w","existingQueue","addResolver","_name","cdnBase","mod","args","command","payload","initState","apiFn","isPanelOpen","consentState","emitter","initMcLayer","LABELS","resolveI18n","value","lang","fallback","escapeHtml","str","STYLES","_sharedStyleSheet","getSharedStyleSheet","McConsentWidget","consentState","consent","hasAnswered","answered","servicesList","services","isPanelOpen","open","previous","unsub","openPanel","s","modal","focusable","e","active","first","last","restoreFocus","acceptAll","denyAll","id","allowed","setConsent","category","consentRequired","groups","service","cat","l","functionalHtml","bodyHtml","hasPending","servicesHtml","statusLabel","statusClass","btn","configPurposes","allNonConsent","status","vendorWithPurpose","purposeLabel","purposeDescription","actionsHtml","vendorsHtml","mount","el","pageLang"]}