non-spooky-react-cookie 0.1.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/CHANGELOG.md +1 -0
- package/LICENSE +21 -0
- package/README.md +577 -0
- package/dist/index.cjs +856 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +137 -0
- package/dist/index.d.ts +137 -0
- package/dist/index.js +837 -0
- package/dist/index.js.map +1 -0
- package/dist/resolve-texts-yAIbWOUX.d.cts +456 -0
- package/dist/resolve-texts-yAIbWOUX.d.ts +456 -0
- package/dist/server.cjs +26 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +28 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.js +23 -0
- package/dist/server.js.map +1 -0
- package/dist/storage-Cqed-yMR.cjs +373 -0
- package/dist/storage-Cqed-yMR.cjs.map +1 -0
- package/dist/storage-WH-kuxkg.js +296 -0
- package/dist/storage-WH-kuxkg.js.map +1 -0
- package/dist/styles.css +624 -0
- package/package.json +119 -0
- package/server/README.md +25 -0
- package/server/package.json +5 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["nav"],"sources":["../src/integrations/global-privacy-control.ts","../src/integrations/google-tracker.ts","../src/integrations/script-runtime.ts","../src/integrations/script-loader.ts","../src/CookieBannerConfigurationProvider.tsx","../src/hooks/usePreferences.ts","../src/ui.tsx","../src/CookieSettingsDialog.tsx","../src/CookieBanner.tsx","../src/CookieSettingsLink.tsx","../src/hooks/useConsentScript.ts"],"sourcesContent":["/**\n * Global Privacy Control (https://w3c.github.io/gpc/) is a browser-level\n * \"do not sell or share my data\" signal. When the visitor turns it on, the\n * browser sends `Sec-GPC: 1` with every request and exposes\n * `navigator.globalPrivacyControl === true` to scripts; when it is off the\n * header is absent and the property is `false` (or missing entirely in\n * browsers without native support, where extensions may define it).\n *\n * Returns `true` only for an active signal. Safe to call on the server.\n */\nexport function readGlobalPrivacyControl(): boolean {\n if (typeof navigator === \"undefined\") return false;\n\n // Not in TypeScript's DOM lib yet, hence the local widening.\n const nav = navigator as Navigator & { globalPrivacyControl?: unknown };\n return nav.globalPrivacyControl === true;\n}\n","import type { PreferenceCategory, PreferencesState } from \"../types\";\n\ntype ConsentValue = \"granted\" | \"denied\";\n\ndeclare global {\n interface Window {\n dataLayer?: unknown[];\n /**\n * Google tag manager stub. Declared with a permissive signature so\n * consumers can call any standard gtag command (`js`, `config`,\n * `event`, `consent`, …) — the real `gtag.js` replaces this at runtime.\n */\n gtag?: (...args: unknown[]) => void;\n }\n}\n\nfunction ensureGtag(): Window[\"gtag\"] | null {\n if (typeof window === \"undefined\") return null;\n\n window.dataLayer = window.dataLayer ?? [];\n window.gtag =\n window.gtag ??\n function gtag() {\n // Google's own snippet pushes the `arguments` object, not an array;\n // gtag.js relies on that exact shape when it replays the queue.\n // biome-ignore lint/complexity/noArguments: required by gtag.js\n window.dataLayer?.push(arguments);\n };\n\n return window.gtag;\n}\n\n/**\n * Initializes Google's consent mode with everything denied.\n * Call this before any Google tag loads.\n */\nexport function initGoogleTracker(): void {\n const gtag = ensureGtag();\n if (!gtag) return;\n\n gtag(\"consent\", \"default\", {\n ad_storage: \"denied\",\n ad_user_data: \"denied\",\n ad_personalization: \"denied\",\n analytics_storage: \"denied\",\n });\n}\n\n/**\n * Updates Google's consent mode based on the stored preferences.\n *\n * Without `categories`, the category ids `analytics` / `marketing` in the\n * accepted map drive the signals. With `categories`, a category grants its\n * signals when the category OR any of its fine-grained items is accepted,\n * so item-level consent (e.g. \"only Google Ads\") is respected.\n */\nexport function updateGoogleTracker(\n state: PreferencesState,\n categories?: PreferenceCategory[],\n): void {\n const gtag = ensureGtag();\n if (!gtag) return;\n\n const toValue = (id: string): ConsentValue => {\n const category = categories?.find((candidate) => candidate.id === id);\n const allowed =\n Boolean(state.accepted[id]) ||\n Boolean(category?.items?.some((item) => state.accepted[item.id]));\n return allowed ? \"granted\" : \"denied\";\n };\n\n const analytics = toValue(\"analytics\");\n const marketing = toValue(\"marketing\");\n\n gtag(\"consent\", \"update\", {\n analytics_storage: analytics,\n ad_storage: marketing,\n ad_user_data: marketing,\n ad_personalization: marketing,\n });\n}\n","/**\n * The reactive runtime store for per-script load status.\n *\n * This is the single source of truth for the 4-state lifecycle\n * (`blocked | loading | loaded | error`) of every managed script.\n * The provider drives this store (consent-gated) and `useConsentScript`\n * subscribes to it via `useSyncExternalStore`.\n *\n * The store is module-level (one per browser tab), keyed by script id.\n * It is intentionally framework-agnostic: no React imports here.\n */\n\nexport type ScriptStatus = \"blocked\" | \"loading\" | \"loaded\" | \"error\";\n\ntype RuntimeEntry = {\n status: ScriptStatus;\n error?: unknown;\n listeners: Set<() => void>;\n};\n\nconst runtimes = new Map<string, RuntimeEntry>();\n\nfunction getEntry(id: string): RuntimeEntry {\n let entry = runtimes.get(id);\n if (!entry) {\n entry = { status: \"blocked\", listeners: new Set() };\n runtimes.set(id, entry);\n }\n return entry;\n}\n\n/**\n * Subscribe a listener to status changes for `id`.\n * Returns an unsubscribe function. Safe to call on the server\n * (returns a no-op) so `useSyncExternalStore` never crashes during SSR.\n */\nexport function subscribeScript(id: string, notify: () => void): () => void {\n if (typeof window === \"undefined\") return () => {};\n getEntry(id).listeners.add(notify);\n return () => {\n getEntry(id).listeners.delete(notify);\n };\n}\n\n/** Primitive snapshot for `useSyncExternalStore` (must be stable). */\nexport function getScriptStatus(id: string): ScriptStatus {\n return getEntry(id).status;\n}\n\n/** The last error for `id`, if any. */\nexport function getScriptError(id: string): unknown {\n return getEntry(id).error;\n}\n\n/**\n * Sets the status (and error, if any) for `id` and notifies subscribers.\n * The error is always replaced, so a later `loaded` clears an old failure.\n */\nexport function setScriptStatus(id: string, status: ScriptStatus, error?: unknown): void {\n const entry = getEntry(id);\n entry.status = status;\n entry.error = error;\n entry.listeners.forEach((listener) => {\n try {\n listener();\n } catch {\n // A broken subscriber must never break consent enforcement.\n }\n });\n}\n","/**\n * Internal DOM + status primitives used by the provider to load and remove\n * consent-gated scripts. Not exported — the provider is the single place\n * that ever inserts a `<script>` element.\n */\nimport type { ConsentScript } from \"../types\";\nimport { getScriptStatus, setScriptStatus } from \"./script-runtime\";\n\n/** Runs a consumer callback; its errors must never break consent enforcement. */\nfunction safeCall(fn?: () => void): void {\n try {\n fn?.();\n } catch {\n // swallowed on purpose\n }\n}\n\nfunction findScriptElement(id: string): HTMLScriptElement | null {\n const element = document.getElementById(id);\n return element instanceof HTMLScriptElement ? element : null;\n}\n\nexport type LoadScriptOptions = {\n id: string;\n src?: string;\n attrs?: Record<string, string>;\n children?: string;\n /** Set `script.async`. Wins over `defer` when both are set. */\n async?: boolean;\n /** Set `script.defer`. Ignored when `async` is set. */\n defer?: boolean;\n onLoad?: () => void;\n onError?: () => void;\n};\n\nexport function loadScript({\n id,\n src,\n attrs,\n children,\n async: asyncFlag,\n defer,\n onLoad,\n onError,\n}: LoadScriptOptions): HTMLScriptElement | null {\n if (typeof document === \"undefined\") return null;\n\n const existing = findScriptElement(id);\n if (existing) return existing;\n\n const script = document.createElement(\"script\");\n script.id = id;\n\n // Setting both is invalid HTML, so async wins; the default is async.\n if (defer && !asyncFlag) {\n script.defer = true;\n } else {\n script.async = true;\n }\n\n if (src) script.src = src;\n if (children) script.text = children;\n if (onLoad) script.addEventListener(\"load\", onLoad);\n if (onError) script.addEventListener(\"error\", onError);\n\n Object.entries(attrs ?? {}).forEach(([key, value]) => {\n script.setAttribute(key, value);\n });\n\n document.head.appendChild(script);\n return script;\n}\n\n/**\n * Removes the script element with `id` and runs the optional\n * `cleanup` function.\n *\n * Caveat: this does NOT undo cookies or network requests the script\n * already made — use `cleanup` for integration-specific teardown.\n */\nexport function unloadScript(id: string, cleanup?: () => void): void {\n if (typeof document === \"undefined\") return;\n\n findScriptElement(id)?.remove();\n safeCall(cleanup);\n}\n\n/**\n * Ensures the script under `id` is loaded, driving the runtime store.\n *\n * - Already in the DOM → status `loaded` (dedup, `onLoad` not re-fired).\n * - Not in the DOM → status `loading`, then `loaded`/`error` when the\n * element settles. `def.onLoad` / `def.onError` run (wrapped so a throw\n * never breaks consent enforcement).\n */\nexport function ensureScript(id: string, def: ConsentScript): void {\n if (typeof document === \"undefined\") return;\n\n if (findScriptElement(id)) {\n setScriptStatus(id, \"loaded\");\n return;\n }\n\n const handleLoad = () => {\n setScriptStatus(id, \"loaded\");\n safeCall(def.onLoad);\n };\n\n setScriptStatus(id, \"loading\");\n\n const element = loadScript({\n id,\n src: def.src,\n attrs: def.attrs,\n children: def.children,\n async: def.async,\n defer: def.defer,\n onLoad: handleLoad,\n onError: () => {\n setScriptStatus(id, \"error\", new Error(`Script \"${id}\" failed to load.`));\n safeCall(def.onError);\n },\n });\n\n // Inline scripts (no `src`) execute synchronously on insertion and do NOT\n // fire the `load` event, so we settle the status immediately.\n if (element && !def.src) handleLoad();\n}\n\n/**\n * Removes the script under `id` from the DOM (running `cleanup`) and\n * resets its status back to `blocked`. A script that is already blocked\n * and not in the DOM is left alone, so `cleanup` runs only after a real load.\n */\nexport function removeScript(id: string, cleanup?: () => void): void {\n if (typeof document === \"undefined\") return;\n if (getScriptStatus(id) === \"blocked\" && !findScriptElement(id)) return;\n\n unloadScript(id, cleanup);\n setScriptStatus(id, \"blocked\");\n}\n","\"use client\";\n\nimport type * as React from \"react\";\nimport {\n createContext,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { readGlobalPrivacyControl } from \"./integrations/global-privacy-control\";\nimport { initGoogleTracker, updateGoogleTracker } from \"./integrations/google-tracker\";\nimport { ensureScript, removeScript } from \"./integrations/script-loader\";\nimport { resolveTexts } from \"./resolve-texts\";\nimport {\n DEFAULT_STORAGE_KEY,\n readPreferences,\n removePreferences,\n resolveStorage,\n writePreferences,\n} from \"./storage\";\nimport type {\n ConsentConfig,\n CookieBannerConfigurationProviderProps,\n CookieBannerContextValue,\n CookieStorageOptions,\n PreferenceCategory,\n PreferencesState,\n PreferencesUpdate,\n ThemePalette,\n} from \"./types\";\n\nconst DEFAULT_VERSION = \"1\";\n\nconst defaultCategories: PreferenceCategory[] = [\n { id: \"necessary\", required: true },\n { id: \"preferences\" },\n { id: \"analytics\" },\n { id: \"marketing\" },\n];\n\n/** Maps the object-map `config` prop to the internal category array. */\nfunction configToCategories(config: ConsentConfig): PreferenceCategory[] {\n return Object.entries(config.categories).map(([id, category]) => ({\n id,\n title: category.name,\n description: category.description,\n required: category.required,\n items: category.items\n ? Object.entries(category.items).map(([itemId, item]) => ({\n id: itemId,\n title: item.name,\n description: item.description,\n }))\n : undefined,\n }));\n}\n\nexport const CookieBannerContext = createContext<CookieBannerContextValue | null>(null);\n\n/**\n * Builds a complete state. Required categories are always on; optional\n * categories and every item follow `acceptOptional`.\n */\nfunction buildState(\n version: string,\n categories: PreferenceCategory[],\n acceptOptional: boolean,\n): PreferencesState {\n const accepted: Record<string, boolean> = {};\n\n categories.forEach((category) => {\n accepted[category.id] = Boolean(category.required) || acceptOptional;\n category.items?.forEach((item) => {\n accepted[item.id] = acceptOptional;\n });\n });\n\n return { version, updatedAt: new Date().toISOString(), accepted };\n}\n\nconst themeVariables: Record<keyof ThemePalette, string> = {\n primaryColor: \"--nsr-primary\",\n primaryTextColor: \"--nsr-primary-text\",\n primaryHoverColor: \"--nsr-primary-hover\",\n secondaryColor: \"--nsr-secondary\",\n secondaryTextColor: \"--nsr-secondary-text\",\n accentColor: \"--nsr-accent\",\n surfaceColor: \"--nsr-surface\",\n surfaceMutedColor: \"--nsr-surface-muted\",\n textColor: \"--nsr-text\",\n mutedTextColor: \"--nsr-muted\",\n borderColor: \"--nsr-border\",\n ringColor: \"--nsr-ring\",\n switchOffColor: \"--nsr-switch-off\",\n switchThumbColor: \"--nsr-switch-thumb\",\n backdropColor: \"--nsr-backdrop\",\n};\n\n/** The attribute that scopes a provider's theme rules to its elements. */\nexport const THEME_ATTRIBUTE = \"data-nsr-theme\";\n\n/**\n * Keeps a palette value safe to embed in a stylesheet: a value is a single\n * CSS color, so it never needs a declaration or block terminator.\n */\nfunction sanitizeCssValue(value: string): string {\n return value.replace(/[;{}<>]/g, \"\").trim();\n}\n\n/** `[--nsr-x, value]` pairs for the set entries of a palette. */\nfunction themeEntries(theme: ThemePalette): Array<[string, string]> {\n return Object.entries(themeVariables).flatMap(([key, variable]) => {\n const value = theme[key as keyof ThemePalette];\n return value ? [[variable, sanitizeCssValue(value)] as [string, string]] : [];\n });\n}\n\n/** Resolves the theme palette into CSS custom properties (set values only). */\nfunction themeToStyle(theme: ThemePalette): React.CSSProperties {\n return Object.fromEntries(themeEntries(theme)) as React.CSSProperties;\n}\n\n/**\n * Builds the scoped stylesheet for one provider. `theme` applies to every\n * element carrying the provider's theme attribute; `darkTheme` applies to the\n * same elements under a `.dark` / `[data-theme=\"dark\"]` ancestor. Returns an\n * empty string when neither palette sets anything, so nothing is rendered.\n */\nexport function buildThemeCss(\n id: string,\n theme: ThemePalette,\n darkTheme: ThemePalette,\n): string {\n const scope = `[${THEME_ATTRIBUTE}=\"${id.replace(/[\"\\\\]/g, \"\")}\"]`;\n const block = (entries: Array<[string, string]>) =>\n entries.map(([variable, value]) => ` ${variable}: ${value};`).join(\"\\n\");\n\n const light = themeEntries(theme);\n const dark = themeEntries(darkTheme);\n const rules: string[] = [];\n\n if (light.length > 0) rules.push(`${scope} {\\n${block(light)}\\n}`);\n if (dark.length > 0) {\n rules.push(`:is(.dark, [data-theme=\"dark\"]) ${scope} {\\n${block(dark)}\\n}`);\n }\n\n return rules.join(\"\\n\");\n}\n\nexport function CookieBannerConfigurationProvider({\n children,\n config,\n scripts,\n language = \"en\",\n texts: textOverrides,\n theme = {},\n darkTheme = {},\n components = {},\n storageKey = DEFAULT_STORAGE_KEY,\n storage = \"localStorage\",\n cookieOptions,\n initialPreferences,\n version = DEFAULT_VERSION,\n googleConsentMode = false,\n windowJustDont = true,\n respectGlobalPrivacyControl = true,\n onDecision,\n}: Readonly<CookieBannerConfigurationProviderProps>) {\n // Keyed on the serialized options so an inline `cookieOptions={{ ... }}`\n // does not create a new store (and re-run the hydration effect) per render.\n const cookieOptionsKey = JSON.stringify(cookieOptions ?? null);\n const store = useMemo(\n () =>\n resolveStorage(\n storage,\n (JSON.parse(cookieOptionsKey) as CookieStorageOptions | null) ?? undefined,\n ),\n [storage, cookieOptionsKey],\n );\n const categories = useMemo(\n () => (config ? configToCategories(config) : defaultCategories),\n [config],\n );\n const texts = useMemo(\n () => resolveTexts(language, textOverrides),\n [language, textOverrides],\n );\n\n // Theme rules live in a <style> scoped by this attribute (not inline\n // styles) so `darkTheme` can win under a `.dark` ancestor. Keyed on the\n // serialized palettes so an inline `theme={{ ... }}` literal is free.\n const themeId = useId();\n const themeKey = JSON.stringify(theme);\n const darkThemeKey = JSON.stringify(darkTheme);\n const themeStyle = useMemo(\n () => themeToStyle(JSON.parse(themeKey) as ThemePalette),\n [themeKey],\n );\n const themeCss = useMemo(\n () =>\n buildThemeCss(\n themeId,\n JSON.parse(themeKey) as ThemePalette,\n JSON.parse(darkThemeKey) as ThemePalette,\n ),\n [darkThemeKey, themeId, themeKey],\n );\n const themeAttributes = useMemo(() => ({ [THEME_ATTRIBUTE]: themeId }), [themeId]);\n\n // Which category owns each item (used to resolve item labels).\n const itemToCategory = useMemo(() => {\n const owners: Record<string, string> = {};\n categories.forEach((category) => {\n category.items?.forEach((item) => {\n owners[item.id] = category.id;\n });\n });\n return owners;\n }, [categories]);\n\n // A server-read decision (same version only) seeds the first render so it\n // matches the server markup; the effect below re-reads the client storage.\n const restoredInitial =\n initialPreferences?.version === version ? initialPreferences : null;\n\n const [loaded, setLoaded] = useState(initialPreferences !== undefined);\n const [hasDecision, setHasDecision] = useState(restoredInitial !== null);\n const [globalPrivacyControl, setGlobalPrivacyControl] = useState(false);\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [state, setState] = useState<PreferencesState>(\n () => restoredInitial ?? buildState(version, categories, false),\n );\n\n const syncGoogle = useCallback(\n (next: PreferencesState) => {\n if (googleConsentMode) updateGoogleTracker(next, categories);\n },\n [categories, googleConsentMode],\n );\n\n // The hydration effect reads `onDecision` through a ref so an inline\n // callback (new identity every render) never re-runs it.\n const onDecisionRef = useRef(onDecision);\n useEffect(() => {\n onDecisionRef.current = onDecision;\n }, [onDecision]);\n\n // Restore the stored decision (same version only) after hydration.\n useEffect(() => {\n if (googleConsentMode) initGoogleTracker();\n\n const stored = readPreferences(store, storageKey);\n const restored = stored?.version === version ? stored : null;\n const gpc = respectGlobalPrivacyControl && readGlobalPrivacyControl();\n const next = restored ?? buildState(version, categories, false);\n\n // An explicit answer on this site always wins. Without one, an active\n // Global Privacy Control signal counts as \"Reject all\" — `next` already\n // is that state — so the banner never shows. It is kept in memory only:\n // the signal is live, and turning it off should bring the banner back.\n const decidedByGpc = restored === null && gpc;\n\n setState(next);\n setHasDecision(restored !== null || decidedByGpc);\n setGlobalPrivacyControl(gpc);\n syncGoogle(next);\n setLoaded(true);\n if (decidedByGpc) onDecisionRef.current?.(next);\n }, [\n categories,\n googleConsentMode,\n respectGlobalPrivacyControl,\n storageKey,\n store,\n syncGoogle,\n version,\n ]);\n\n // On unmount (or a new `scripts` map) unload exactly the declared scripts.\n useEffect(() => {\n const entries = Object.entries(scripts ?? {});\n return () => {\n for (const [id, def] of entries) {\n removeScript(id, def.cleanup);\n }\n };\n }, [scripts]);\n\n // Central consent enforcement: a script loads when its own category or\n // item id is accepted (items are not gated by their parent category) and\n // is removed, with cleanup, when that consent is withdrawn.\n useEffect(() => {\n if (!loaded) return;\n\n Object.entries(scripts ?? {}).forEach(([id, def]) => {\n if (state.accepted[def.category]) {\n ensureScript(id, def);\n } else {\n removeScript(id, def.cleanup);\n }\n });\n }, [loaded, scripts, state.accepted]);\n\n const persist = useCallback(\n (next: PreferencesState) => {\n setState(next);\n setHasDecision(true);\n setSettingsOpen(false);\n writePreferences(store, storageKey, next);\n syncGoogle(next);\n onDecision?.(next);\n },\n [onDecision, storageKey, store, syncGoogle],\n );\n\n const acceptAll = useCallback(\n () => persist(buildState(version, categories, true)),\n [categories, persist, version],\n );\n\n const rejectAll = useCallback(\n () => persist(buildState(version, categories, false)),\n [categories, persist, version],\n );\n\n const savePreferences = useCallback(\n (partial: PreferencesUpdate) =>\n persist({\n version,\n updatedAt: new Date().toISOString(),\n accepted: { ...state.accepted, ...partial.accepted },\n }),\n [persist, state.accepted, version],\n );\n\n const resetPreferences = useCallback(() => {\n const initial = buildState(version, categories, false);\n removePreferences(store, storageKey);\n setState(initial);\n setHasDecision(false);\n setSettingsOpen(false);\n syncGoogle(initial);\n onDecision?.(initial);\n }, [categories, onDecision, storageKey, store, syncGoogle, version]);\n\n const openSettings = useCallback(() => setSettingsOpen(true), []);\n const closeSettings = useCallback(() => setSettingsOpen(false), []);\n\n const isAllowed = useCallback(\n (id: string) => Boolean(state.accepted[id]),\n [state.accepted],\n );\n\n /**\n * Resolves the display title/description for a category or item,\n * preferring the config values, then the texts, then the id.\n */\n const resolveLabel = useCallback(\n (\n id: string,\n config?: { title?: string; description?: string },\n ): { title: string; description: string } => {\n const parent = itemToCategory[id];\n const source = parent\n ? texts.categories[parent]?.items?.[id]\n : texts.categories[id];\n\n return {\n title: config?.title ?? source?.title ?? id,\n description: config?.description ?? source?.description ?? \"\",\n };\n },\n [itemToCategory, texts],\n );\n\n const value = useMemo<CookieBannerContextValue>(\n () => ({\n loaded,\n hasDecision,\n showBanner: loaded && !hasDecision,\n globalPrivacyControl,\n settingsOpen,\n preferences: state,\n texts,\n categories,\n scripts: scripts ?? {},\n theme,\n darkTheme,\n components,\n themeStyle,\n themeAttributes,\n acceptAll,\n rejectAll,\n savePreferences,\n resetPreferences,\n openSettings,\n closeSettings,\n isAllowed,\n resolveLabel,\n }),\n [\n acceptAll,\n categories,\n closeSettings,\n components,\n darkTheme,\n globalPrivacyControl,\n hasDecision,\n isAllowed,\n loaded,\n openSettings,\n rejectAll,\n resetPreferences,\n resolveLabel,\n savePreferences,\n scripts,\n settingsOpen,\n state,\n texts,\n theme,\n themeAttributes,\n themeStyle,\n ],\n );\n\n // One global function, `window.justDont()`, that rejects all optional\n // categories — aimed at console snippets and \"I don't care about\n // cookies\"-style browser extensions. No opt-in needed: it is registered\n // as soon as the provider mounts, and re-registered whenever `rejectAll`\n // changes so the global never holds a stale closure.\n useEffect(() => {\n if (!windowJustDont || typeof window === \"undefined\") return;\n\n const w = window as unknown as { justDont?: () => void };\n if (typeof w.justDont === \"function\") {\n console.warn(\n \"[non-spooky-react-cookie] window.justDont already exists; the \" +\n \"cookie banner will overwrite it.\",\n );\n }\n\n w.justDont = rejectAll;\n return () => {\n // Only clear the slot when we still own it, so an unmount never\n // removes a global a later-mounted provider registered.\n if (w.justDont === rejectAll) delete w.justDont;\n };\n }, [rejectAll, windowJustDont]);\n\n return (\n <CookieBannerContext.Provider value={value}>\n {themeCss ? <style data-nsr-theme-style={themeId}>{themeCss}</style> : null}\n {children}\n </CookieBannerContext.Provider>\n );\n}\n","\"use client\";\n\nimport { useContext } from \"react\";\nimport { CookieBannerContext } from \"../CookieBannerConfigurationProvider\";\n\n/**\n * Access the cookie banner state and actions from anywhere\n * inside a CookieBannerConfigurationProvider.\n */\nexport function usePreferences() {\n const context = useContext(CookieBannerContext);\n\n if (!context) {\n throw new Error(\n \"usePreferences must be used within a CookieBannerConfigurationProvider\",\n );\n }\n\n return context;\n}\n","\"use client\";\n\nimport { useId, useState } from \"react\";\nimport type { ButtonLikeProps, CollapsibleProps, SwitchLikeProps } from \"./types\";\n\nexport function cn(...classes: Array<string | false | null | undefined>) {\n return classes.filter(Boolean).join(\" \");\n}\n\n/**\n * Default Button.\n * Colors come from the `--nsr-*` variables: defaults in `styles.css`,\n * overrides from the provider's `theme` prop.\n */\nexport function Button({ className, variant = \"secondary\", ...props }: ButtonLikeProps) {\n return (\n <button\n className={cn(\"nsr-button\", `nsr-button--${variant}`, className)}\n {...props}\n />\n );\n}\n\n/**\n * Default Switch.\n * The \"on\" color follows the theme's primary color.\n */\nexport function Switch({\n checked,\n disabled,\n onCheckedChange,\n \"aria-label\": ariaLabel,\n}: Readonly<SwitchLikeProps>) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n aria-label={ariaLabel}\n disabled={disabled}\n onClick={() => onCheckedChange(!checked)}\n className=\"nsr-switch\"\n >\n <span className=\"nsr-switch__thumb\" />\n </button>\n );\n}\n\n/**\n * Default Collapsible.\n * A disclosure that hides its children until the trigger is pressed.\n * Works controlled (`open` + `onOpenChange`) or self-managed (`defaultOpen`).\n * The chevron follows the theme's primary color.\n */\nexport function Collapsible({\n children,\n count,\n label,\n open,\n onOpenChange,\n defaultOpen,\n className,\n contentClassName,\n}: Readonly<CollapsibleProps>) {\n const regionId = useId();\n const [internalOpen, setInternalOpen] = useState(defaultOpen ?? false);\n const isOpen = open ?? internalOpen;\n\n const toggle = () => {\n const next = !isOpen;\n if (open === undefined) setInternalOpen(next);\n onOpenChange?.(next);\n };\n\n return (\n <div className={cn(\"nsr-collapsible\", isOpen && \"nsr-collapsible--open\")}>\n <button\n type=\"button\"\n aria-controls={regionId}\n aria-expanded={isOpen}\n className={cn(\"nsr-collapsible__trigger\", className)}\n onClick={toggle}\n >\n <span className=\"nsr-collapsible__label\">\n {label} ({count})\n </span>\n <svg\n className=\"nsr-collapsible__chevron\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </button>\n {isOpen ? (\n <div className={cn(\"nsr-collapsible__content\", contentClassName)} id={regionId}>\n {children}\n </div>\n ) : null}\n </div>\n );\n}\n","\"use client\";\n\nimport type * as React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { usePreferences } from \"./hooks/usePreferences\";\nimport type { CookieSettingsDialogProps } from \"./types\";\nimport { Button, Collapsible, cn, Switch } from \"./ui\";\n\n/** Renders nothing while closed; the open dialog mounts fresh each time. */\nexport function CookieSettingsDialog(props: Readonly<CookieSettingsDialogProps>) {\n const { settingsOpen } = usePreferences();\n return settingsOpen ? <OpenSettingsDialog {...props} /> : null;\n}\n\nfunction OpenSettingsDialog({\n className,\n overlayClassName,\n contentClassName,\n headerClassName,\n bodyClassName,\n footerClassName,\n categoryCardClassName,\n itemClassName,\n buttonClassName,\n components: ownComponents,\n}: Readonly<CookieSettingsDialogProps>) {\n const {\n categories,\n closeSettings,\n components: providerComponents,\n preferences,\n resolveLabel,\n savePreferences,\n texts,\n themeAttributes,\n } = usePreferences();\n const dialogRef = useRef<HTMLDialogElement>(null);\n // Mounted only while open, so the initial value is the current decision.\n const [draft, setDraft] = useState(preferences.accepted);\n\n // showModal() gives us the top layer, focus trap, and Escape-to-close.\n useEffect(() => {\n const dialog = dialogRef.current;\n if (dialog && !dialog.open && typeof dialog.showModal === \"function\") {\n dialog.showModal();\n }\n }, []);\n\n const components = { ...providerComponents, ...ownComponents };\n const ButtonComponent = components.Button ?? Button;\n const SwitchComponent = components.Switch ?? Switch;\n const CollapsibleComponent = components.Collapsible ?? Collapsible;\n\n const setAccepted = (ids: string[], value: boolean) =>\n setDraft((current) => {\n const next = { ...current };\n for (const id of ids) {\n next[id] = value;\n }\n return next;\n });\n\n const handleCancel = (event: React.SyntheticEvent) => {\n // Escape (native cancel): prevent the native close and let the parent's\n // state change unmount the dialog instead, so state stays in sync.\n event.preventDefault();\n closeSettings();\n };\n\n return (\n <dialog\n aria-labelledby=\"nsr-settings-title\"\n className={cn(\"nsr-settings-dialog\", className)}\n onCancel={handleCancel}\n ref={dialogRef}\n {...themeAttributes}\n >\n {/*\n Click-to-close backdrop as a real (visually inert) button, sitting\n behind the content panel. Out of the tab order; mouse/touch only.\n */}\n <button\n aria-label={texts.dialog.close}\n className={cn(\"nsr-dialog__overlay\", overlayClassName)}\n onClick={closeSettings}\n tabIndex={-1}\n type=\"button\"\n />\n <div className={cn(\"nsr-dialog__panel\", contentClassName)}>\n <div className={cn(\"nsr-dialog__header\", headerClassName)}>\n <h2 id=\"nsr-settings-title\" className=\"nsr-dialog__title\">\n {texts.dialog.title}\n </h2>\n <p className=\"nsr-dialog__description\">{texts.dialog.description}</p>\n </div>\n\n <div className={cn(\"nsr-dialog__body\", bodyClassName)}>\n {categories.map((category) => {\n const { title, description } = resolveLabel(category.id, category);\n const required = Boolean(category.required);\n const items = category.items ?? [];\n\n return (\n <section\n className={cn(\n \"nsr-category\",\n required && \"nsr-category--required\",\n categoryCardClassName,\n )}\n key={category.id}\n >\n <div className=\"nsr-category__header\">\n <div>\n <h3 className=\"nsr-category__title\">{title}</h3>\n {description ? (\n <p className=\"nsr-category__description\">{description}</p>\n ) : null}\n </div>\n {/* Master switch: toggles the category and all of its items. */}\n <SwitchComponent\n aria-label={title}\n checked={Boolean(draft[category.id])}\n disabled={required}\n onCheckedChange={(value) =>\n setAccepted([category.id, ...items.map((item) => item.id)], value)\n }\n />\n </div>\n\n {items.length > 0 ? (\n <CollapsibleComponent\n count={items.length}\n label={texts.dialog.itemsLabel}\n contentClassName=\"nsr-category__items\"\n >\n {items.map((item) => {\n const itemLabel = resolveLabel(item.id, item);\n\n return (\n <div className={cn(\"nsr-item\", itemClassName)} key={item.id}>\n <div>\n <h4 className=\"nsr-item__title\">{itemLabel.title}</h4>\n {itemLabel.description ? (\n <p className=\"nsr-item__description\">\n {itemLabel.description}\n </p>\n ) : null}\n </div>\n <SwitchComponent\n aria-label={itemLabel.title}\n checked={Boolean(draft[item.id])}\n disabled={required}\n onCheckedChange={(value) => setAccepted([item.id], value)}\n />\n </div>\n );\n })}\n </CollapsibleComponent>\n ) : null}\n </section>\n );\n })}\n </div>\n\n <div className={cn(\"nsr-dialog__footer\", footerClassName)}>\n <ButtonComponent\n className={cn(\"nsr-dialog__button\", buttonClassName)}\n onClick={closeSettings}\n type=\"button\"\n variant=\"ghost\"\n >\n {texts.dialog.close}\n </ButtonComponent>\n <ButtonComponent\n className={cn(\"nsr-dialog__button\", buttonClassName)}\n onClick={() => savePreferences({ accepted: draft })}\n type=\"button\"\n variant=\"primary\"\n >\n {texts.dialog.save}\n </ButtonComponent>\n </div>\n </div>\n </dialog>\n );\n}\n","\"use client\";\n\nimport { CookieSettingsDialog } from \"./CookieSettingsDialog\";\nimport { usePreferences } from \"./hooks/usePreferences\";\nimport type { CookieBannerProps } from \"./types\";\nimport { Button, cn } from \"./ui\";\n\nexport function CookieBanner({\n policyUrl,\n className,\n contentClassName,\n titleClassName,\n descriptionClassName,\n actionsClassName,\n buttonClassName,\n components,\n dialogProps,\n}: Readonly<CookieBannerProps>) {\n const {\n acceptAll,\n components: providerComponents,\n openSettings,\n rejectAll,\n showBanner,\n texts,\n themeAttributes,\n } = usePreferences();\n\n const ButtonComponent = components?.Button ?? providerComponents.Button ?? Button;\n\n return (\n <>\n {showBanner ? (\n <section\n aria-label={texts.banner.title}\n className={cn(\"nsr-banner\", className)}\n {...themeAttributes}\n >\n <div className={cn(\"nsr-banner__card\", contentClassName)}>\n <div className=\"nsr-banner__text\">\n <h2 className={cn(\"nsr-banner__title\", titleClassName)}>\n {texts.banner.title}\n </h2>\n <p className={cn(\"nsr-banner__description\", descriptionClassName)}>\n {texts.banner.description}\n {policyUrl ? (\n <>\n {\" \"}\n <a className=\"nsr-banner__link\" href={policyUrl}>\n {texts.banner.policyLink}\n </a>\n </>\n ) : null}\n </p>\n </div>\n\n <div className={cn(\"nsr-banner__actions\", actionsClassName)}>\n <ButtonComponent\n className={buttonClassName}\n onClick={rejectAll}\n type=\"button\"\n variant=\"secondary\"\n >\n {texts.banner.rejectAll}\n </ButtonComponent>\n <ButtonComponent\n className={buttonClassName}\n onClick={openSettings}\n type=\"button\"\n variant=\"secondary\"\n >\n {texts.banner.settings}\n </ButtonComponent>\n <ButtonComponent\n className={buttonClassName}\n onClick={acceptAll}\n type=\"button\"\n variant=\"primary\"\n >\n {texts.banner.acceptAll}\n </ButtonComponent>\n </div>\n </div>\n </section>\n ) : null}\n <CookieSettingsDialog\n {...dialogProps}\n components={{ ...components, ...dialogProps?.components }}\n />\n </>\n );\n}\n","\"use client\";\n\nimport { usePreferences } from \"./hooks/usePreferences\";\nimport type { CookieSettingsLinkProps } from \"./types\";\nimport { cn } from \"./ui\";\n\n/**\n * A small link (e.g. in a footer) that opens the cookie settings dialog.\n * Renders your children, or the built-in \"Cookie settings\" text.\n */\nexport function CookieSettingsLink({\n children,\n className,\n type = \"button\",\n onClick,\n ...props\n}: Readonly<CookieSettingsLinkProps>) {\n const { openSettings, texts, themeAttributes } = usePreferences();\n\n return (\n <button\n className={cn(\"nsr-settings-link\", className)}\n {...themeAttributes}\n onClick={(event) => {\n // Open the dialog first, then let the consumer's handler run — the\n // spread below must not be able to silently override the built-in.\n openSettings();\n onClick?.(event);\n }}\n type={type}\n {...props}\n >\n {children ?? texts.footerLink}\n </button>\n );\n}\n","\"use client\";\n\nimport { useCallback, useContext, useSyncExternalStore } from \"react\";\nimport { CookieBannerContext } from \"../CookieBannerConfigurationProvider\";\nimport type { ScriptStatus } from \"../integrations/script-runtime\";\nimport {\n getScriptError,\n getScriptStatus,\n subscribeScript,\n} from \"../integrations/script-runtime\";\n\nexport type UseConsentScriptResult = {\n /**\n * - `blocked` — consent for the script's category is not granted.\n * - `loading` — consent granted, script is being fetched.\n * - `loaded` — the `<script>` is in the DOM and finished loading.\n * - `error` — the script failed to load, is not declared in the provider's\n * `scripts` map, or the hook is rendered outside a provider.\n */\n status: ScriptStatus;\n /** Present when `status === \"error\"`. */\n error?: unknown;\n};\n\n/**\n * Reactive, consent-gated load status for a script declared in the\n * provider's `scripts` map.\n *\n * The status is gated on the script's `category`: denied → `blocked`;\n * granted → the provider drives `loading` → `loaded`/`error`. The hook never\n * loads anything itself — the provider is the single enforcement point.\n *\n * Must be rendered inside a `CookieBannerConfigurationProvider`.\n */\nexport function useConsentScript(id: string): UseConsentScriptResult {\n const context = useContext(CookieBannerContext);\n const def = context?.scripts[id];\n\n // Two subscriptions on purpose: the store mutates entries in place, so a\n // single object snapshot would never look \"changed\" to React.\n const subscribe = useCallback(\n (notify: () => void) => subscribeScript(id, notify),\n [id],\n );\n const runtimeStatus = useSyncExternalStore<ScriptStatus>(\n subscribe,\n () => getScriptStatus(id),\n () => \"blocked\",\n );\n const runtimeError = useSyncExternalStore(\n subscribe,\n () => getScriptError(id),\n () => undefined,\n );\n\n if (!context) {\n return {\n status: \"error\",\n error: new Error(\n `useConsentScript(\"${id}\") must be used within a CookieBannerConfigurationProvider.`,\n ),\n };\n }\n\n if (!def) {\n return {\n status: \"error\",\n error: new Error(\n `useConsentScript(\"${id}\"): script is not declared in the provider's \\`scripts\\` map.`,\n ),\n };\n }\n\n if (!context.isAllowed(def.category)) {\n return { status: \"blocked\" };\n }\n\n // Consent granted. A not-yet-started script is presented as `loading` to\n // avoid a `blocked` flash before the provider's load effect runs.\n const status = runtimeStatus === \"blocked\" ? \"loading\" : runtimeStatus;\n return { status, error: status === \"error\" ? runtimeError : undefined };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
//#region src/types.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Makes every property of an object (and nested objects) optional.
|
|
5
|
+
* Used so users can override only the texts they care about.
|
|
6
|
+
*/
|
|
7
|
+
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; };
|
|
8
|
+
/**
|
|
9
|
+
* `DeepPartial` that also accepts `null` at every level. A CMS usually returns
|
|
10
|
+
* an empty field as `null` (Payload's generated types say `string | null`), and
|
|
11
|
+
* the merge treats `null` exactly like a missing key: the built-in text stays.
|
|
12
|
+
*/
|
|
13
|
+
type DeepPartialNullable<T> = { [K in keyof T]?: T[K] extends object ? DeepPartialNullable<T[K]> | null : T[K] | null; };
|
|
14
|
+
/** A single fine-grained entry inside a category, e.g. "Meta Pixel" inside Marketing. */
|
|
15
|
+
type PreferenceItem = {
|
|
16
|
+
/** Must be unique across all categories and items of the app. */
|
|
17
|
+
id: string;
|
|
18
|
+
/** Shown in the settings dialog. Can also come from `texts.categories[<categoryId>].items[<id>].title`. */
|
|
19
|
+
title?: string;
|
|
20
|
+
/** Shown under the item title. Can also come from `texts`. */
|
|
21
|
+
description?: string;
|
|
22
|
+
};
|
|
23
|
+
/** A group of optional technologies. May contain fine-grained `items`. */
|
|
24
|
+
type PreferenceCategory = {
|
|
25
|
+
/** Unique id, e.g. "necessary", "analytics", "marketing". */
|
|
26
|
+
id: string;
|
|
27
|
+
title?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
/** Always accepted and cannot be switched off (e.g. "necessary"). */
|
|
30
|
+
required?: boolean;
|
|
31
|
+
/** Optional fine-grained entries inside this category. */
|
|
32
|
+
items?: PreferenceItem[];
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* A single category inside `ConsentConfig.categories`.
|
|
36
|
+
* The key of the map is the category id (e.g. "analytics").
|
|
37
|
+
*/
|
|
38
|
+
type ConsentCategoryConfig = {
|
|
39
|
+
/** Always accepted and cannot be switched off (e.g. "necessary"). */
|
|
40
|
+
required?: boolean;
|
|
41
|
+
/** Display name, e.g. "Analytics". */
|
|
42
|
+
name?: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
/** Optional fine-grained entries, keyed by item id. */
|
|
45
|
+
items?: Record<string, ConsentItemConfig>;
|
|
46
|
+
};
|
|
47
|
+
type ConsentItemConfig = {
|
|
48
|
+
name?: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Declares the consent categories your site uses.
|
|
53
|
+
* Example:
|
|
54
|
+
* ```ts
|
|
55
|
+
* const consentConfig: ConsentConfig = {
|
|
56
|
+
* categories: {
|
|
57
|
+
* necessary: { required: true },
|
|
58
|
+
* analytics: { name: "Analytics" },
|
|
59
|
+
* marketing: { name: "Marketing" },
|
|
60
|
+
* },
|
|
61
|
+
* };
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
type ConsentConfig = {
|
|
65
|
+
categories: Record<string, ConsentCategoryConfig>;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* A third-party script managed by the provider.
|
|
69
|
+
* The script is loaded only when `category` (a category id or an item id)
|
|
70
|
+
* is accepted, and unloaded when consent is withdrawn.
|
|
71
|
+
*
|
|
72
|
+
* The script id is the key in the `scripts` map (not a field here) — it is
|
|
73
|
+
* used as the `<script>` element id and for deduplication.
|
|
74
|
+
*/
|
|
75
|
+
type ConsentScript = {
|
|
76
|
+
/** Category id (or item id) that must be accepted before the script loads. */
|
|
77
|
+
category: string;
|
|
78
|
+
/** URL of the script. Omit for inline scripts (`children`). */
|
|
79
|
+
src?: string;
|
|
80
|
+
/** Inline script body. */
|
|
81
|
+
children?: string;
|
|
82
|
+
/** Extra attributes, e.g. `{ "data-foo": "bar" }`. */
|
|
83
|
+
attrs?: Record<string, string>;
|
|
84
|
+
/** Set `script.async`. Wins over `defer` when both are set. */
|
|
85
|
+
async?: boolean;
|
|
86
|
+
/** Set `script.defer`. Ignored when `async` is set. */
|
|
87
|
+
defer?: boolean;
|
|
88
|
+
/** Called after the script finished loading. */
|
|
89
|
+
onLoad?: () => void;
|
|
90
|
+
/** Called when the script failed to load. */
|
|
91
|
+
onError?: () => void;
|
|
92
|
+
/**
|
|
93
|
+
* Runs when consent is withdrawn and the script is removed.
|
|
94
|
+
* Use it to undo side effects (e.g. `delete window.fbq`).
|
|
95
|
+
*/
|
|
96
|
+
cleanup?: () => void;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* The provider's `scripts` map: third-party scripts keyed by script id.
|
|
100
|
+
* Use this ready-made type instead of spelling out `Record<string, ConsentScript>`.
|
|
101
|
+
*/
|
|
102
|
+
type ConsentScripts = Record<string, ConsentScript>;
|
|
103
|
+
type ItemTexts = {
|
|
104
|
+
title?: string;
|
|
105
|
+
description?: string;
|
|
106
|
+
};
|
|
107
|
+
type CategoryTexts = {
|
|
108
|
+
title?: string;
|
|
109
|
+
description?: string;
|
|
110
|
+
items?: Record<string, ItemTexts>;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* All UI strings of the library. Every field is typed, so when you
|
|
114
|
+
* extend or override texts you get full autocomplete and type safety.
|
|
115
|
+
*/
|
|
116
|
+
type Texts = {
|
|
117
|
+
banner: {
|
|
118
|
+
title: string;
|
|
119
|
+
description: string;
|
|
120
|
+
acceptAll: string;
|
|
121
|
+
rejectAll: string;
|
|
122
|
+
settings: string;
|
|
123
|
+
policyLink: string;
|
|
124
|
+
};
|
|
125
|
+
dialog: {
|
|
126
|
+
title: string;
|
|
127
|
+
description: string;
|
|
128
|
+
save: string;
|
|
129
|
+
close: string;
|
|
130
|
+
/**
|
|
131
|
+
* Label of the collapsible trigger that reveals a category's items, e.g.
|
|
132
|
+
* "Show services". The item count follows in parentheses: "Show services (2)".
|
|
133
|
+
*/
|
|
134
|
+
itemsLabel: string;
|
|
135
|
+
};
|
|
136
|
+
footerLink: string;
|
|
137
|
+
/** Per-category and per-item texts, keyed by their ids. */
|
|
138
|
+
categories: Record<string, CategoryTexts>;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* The provider's `texts` prop: override any built-in string. Every field is
|
|
142
|
+
* optional, so you list only what you want to change, and `null` counts as
|
|
143
|
+
* not set. Every value is plain JSON, so it can come from a CMS or be passed
|
|
144
|
+
* from a React Server Component.
|
|
145
|
+
*/
|
|
146
|
+
type TextOverrides = DeepPartialNullable<Texts>;
|
|
147
|
+
/**
|
|
148
|
+
* Color palette. Provide any subset; everything else keeps the built-in look.
|
|
149
|
+
*
|
|
150
|
+
* Only five colors are true inputs: `primaryColor`, `primaryTextColor`,
|
|
151
|
+
* `accentColor`, `surfaceColor` and `textColor`. Every other color is derived
|
|
152
|
+
* from those with `color-mix()` unless you set it, so a dark surface with light
|
|
153
|
+
* text automatically gets matching muted text, borders, secondary buttons,
|
|
154
|
+
* hover states and switch tracks.
|
|
155
|
+
*/
|
|
156
|
+
type ThemePalette = {
|
|
157
|
+
/** Main action color (primary buttons, active switches). */
|
|
158
|
+
primaryColor?: string;
|
|
159
|
+
/** Text color on primary buttons. Also the switch thumb color when on. */
|
|
160
|
+
primaryTextColor?: string;
|
|
161
|
+
/** Primary button hover background. Derived from primary + primary text. */
|
|
162
|
+
primaryHoverColor?: string;
|
|
163
|
+
/** Secondary button background. Derived: same as `surfaceColor`. */
|
|
164
|
+
secondaryColor?: string;
|
|
165
|
+
/** Text color on secondary buttons. Derived: same as `textColor`. */
|
|
166
|
+
secondaryTextColor?: string;
|
|
167
|
+
/** Accent color (links, disclosure triggers). */
|
|
168
|
+
accentColor?: string;
|
|
169
|
+
/** Background of the banner and dialog. */
|
|
170
|
+
surfaceColor?: string;
|
|
171
|
+
/** Background of the required-category card and button hover states. Derived from surface + text. */
|
|
172
|
+
surfaceMutedColor?: string;
|
|
173
|
+
/** Main text color. */
|
|
174
|
+
textColor?: string;
|
|
175
|
+
/** Muted/secondary text color. Derived from text + surface. */
|
|
176
|
+
mutedTextColor?: string;
|
|
177
|
+
/** Border color. Derived from text + surface. */
|
|
178
|
+
borderColor?: string;
|
|
179
|
+
/** Focus ring color. Derived: same as `primaryColor`. */
|
|
180
|
+
ringColor?: string;
|
|
181
|
+
/** Switch track color when off. Derived from text + surface. */
|
|
182
|
+
switchOffColor?: string;
|
|
183
|
+
/** Switch thumb color for both states. Derived: `surfaceColor` when off, `primaryTextColor` when on. */
|
|
184
|
+
switchThumbColor?: string;
|
|
185
|
+
/** Dialog backdrop (dim layer behind the settings dialog). */
|
|
186
|
+
backdropColor?: string;
|
|
187
|
+
};
|
|
188
|
+
/** What is persisted (localStorage and/or cookie) and shared with `onDecision`. */
|
|
189
|
+
type PreferencesState = {
|
|
190
|
+
version: string;
|
|
191
|
+
updatedAt: string;
|
|
192
|
+
/** Flat map of accepted ids: categories and items. */
|
|
193
|
+
accepted: Record<string, boolean>;
|
|
194
|
+
};
|
|
195
|
+
/** Partial update of the accepted map. */
|
|
196
|
+
type PreferencesUpdate = {
|
|
197
|
+
accepted: Record<string, boolean>;
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* Built-in storage strategies:
|
|
201
|
+
* - `"localStorage"` (default) – per-origin, invisible to the server.
|
|
202
|
+
* - `"cookie"` – readable by the server (see `readPreferencesFromCookies`),
|
|
203
|
+
* can span subdomains via `cookieOptions.domain`.
|
|
204
|
+
* - `"both"` – writes to both; reads the cookie first, then localStorage.
|
|
205
|
+
*/
|
|
206
|
+
type StorageKind = "localStorage" | "cookie" | "both";
|
|
207
|
+
/**
|
|
208
|
+
* Storage strategy: a plain string store keyed by `storageKey`. The library
|
|
209
|
+
* handles JSON serialization and validation, so an adapter never sees the
|
|
210
|
+
* state shape. Pass your own to persist anywhere (sessionStorage, IndexedDB
|
|
211
|
+
* wrapper, in-memory for tests, ...).
|
|
212
|
+
*/
|
|
213
|
+
type PreferencesStorage = {
|
|
214
|
+
get(key: string): string | null;
|
|
215
|
+
set(key: string, value: string): void;
|
|
216
|
+
remove(key: string): void;
|
|
217
|
+
};
|
|
218
|
+
/** Cookie attributes used by the `"cookie"` and `"both"` strategies. */
|
|
219
|
+
type CookieStorageOptions = {
|
|
220
|
+
/** Lifetime in seconds. Default: 31536000 (365 days). */
|
|
221
|
+
maxAge?: number;
|
|
222
|
+
/** e.g. `".example.com"` to share the decision across subdomains. Default: current host. */
|
|
223
|
+
domain?: string;
|
|
224
|
+
/** Default: `"/"`. */
|
|
225
|
+
path?: string;
|
|
226
|
+
/** Default: `"lax"`. `"none"` forces `secure`. */
|
|
227
|
+
sameSite?: "lax" | "strict" | "none";
|
|
228
|
+
/** Default: `true` on https, `false` otherwise. */
|
|
229
|
+
secure?: boolean;
|
|
230
|
+
};
|
|
231
|
+
/** Button-like props shared by the default and custom Button components. */
|
|
232
|
+
type ButtonLikeProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
233
|
+
variant?: "primary" | "secondary" | "ghost";
|
|
234
|
+
};
|
|
235
|
+
/** Switch-like props shared by the default and custom Switch components. */
|
|
236
|
+
type SwitchLikeProps = {
|
|
237
|
+
checked: boolean;
|
|
238
|
+
disabled?: boolean;
|
|
239
|
+
onCheckedChange: (checked: boolean) => void;
|
|
240
|
+
"aria-label": string;
|
|
241
|
+
};
|
|
242
|
+
/** Props of the default Collapsible (a controlled or self-managed disclosure). */
|
|
243
|
+
type CollapsibleProps = {
|
|
244
|
+
children: React.ReactNode;
|
|
245
|
+
/** Number of entries inside, shown after the label, e.g. "(2)". */
|
|
246
|
+
count: number;
|
|
247
|
+
/** Localized trigger label, e.g. "Show services" / "Dienste anzeigen". */
|
|
248
|
+
label: string;
|
|
249
|
+
/** Controlled open state. Omit to let the component manage its own state. */
|
|
250
|
+
open?: boolean;
|
|
251
|
+
/** Fired when the disclosure is toggled (controlled mode). */
|
|
252
|
+
onOpenChange?: (open: boolean) => void;
|
|
253
|
+
/** Initial open state when uncontrolled. Default: `false`. */
|
|
254
|
+
defaultOpen?: boolean;
|
|
255
|
+
/** Extra classes for the trigger button. */
|
|
256
|
+
className?: string;
|
|
257
|
+
/** Extra classes for the revealed content region. */
|
|
258
|
+
contentClassName?: string;
|
|
259
|
+
};
|
|
260
|
+
/** Escape hatch: swap the default Button/Switch/Collapsible for your own components. */
|
|
261
|
+
type PreferenceComponents = {
|
|
262
|
+
Button?: React.ComponentType<ButtonLikeProps>;
|
|
263
|
+
Switch?: React.ComponentType<SwitchLikeProps>;
|
|
264
|
+
Collapsible?: React.ComponentType<CollapsibleProps>;
|
|
265
|
+
};
|
|
266
|
+
type CookieBannerConfigurationProviderProps = {
|
|
267
|
+
children: React.ReactNode;
|
|
268
|
+
/**
|
|
269
|
+
* Consent category configuration (object map, keyed by category id).
|
|
270
|
+
* Defaults to necessary/preferences/analytics/marketing.
|
|
271
|
+
*/
|
|
272
|
+
config?: ConsentConfig;
|
|
273
|
+
/**
|
|
274
|
+
* Third-party scripts managed by the provider, keyed by script id.
|
|
275
|
+
* Each loads only when its `category` is accepted and is removed (with
|
|
276
|
+
* `cleanup`) when consent is withdrawn.
|
|
277
|
+
*/
|
|
278
|
+
scripts?: ConsentScripts;
|
|
279
|
+
/**
|
|
280
|
+
* Language of the built-in texts: "en" (default), "de", or "pl". Region
|
|
281
|
+
* codes resolve to their base language ("pl-PL" -> "pl"); anything else
|
|
282
|
+
* falls back to English.
|
|
283
|
+
*/
|
|
284
|
+
language?: string;
|
|
285
|
+
/** Override or extend any built-in text. Fully typed. */
|
|
286
|
+
texts?: TextOverrides;
|
|
287
|
+
/**
|
|
288
|
+
* Color palette override. Applied to the banner, the dialog and the
|
|
289
|
+
* settings link in both light and dark mode (unless `darkTheme` overrides
|
|
290
|
+
* a color for dark mode).
|
|
291
|
+
*/
|
|
292
|
+
theme?: ThemePalette;
|
|
293
|
+
/**
|
|
294
|
+
* Colors that apply only under a `.dark` or `[data-theme="dark"]`
|
|
295
|
+
* ancestor. Any color not set here falls back to `theme`, then to the
|
|
296
|
+
* built-in dark palette.
|
|
297
|
+
*/
|
|
298
|
+
darkTheme?: ThemePalette;
|
|
299
|
+
/** Swap the default Button/Switch/Collapsible for your own components. */
|
|
300
|
+
components?: PreferenceComponents;
|
|
301
|
+
/** Storage key: the localStorage key and/or cookie name. Default: "non-spooky-react-cookie". */
|
|
302
|
+
storageKey?: string;
|
|
303
|
+
/**
|
|
304
|
+
* Where the decision is persisted: `"localStorage"` (default), `"cookie"`,
|
|
305
|
+
* `"both"`, or a custom `PreferencesStorage` adapter. A custom adapter must
|
|
306
|
+
* be a stable reference (module-level const or `useMemo`), not an inline
|
|
307
|
+
* object literal.
|
|
308
|
+
*/
|
|
309
|
+
storage?: StorageKind | PreferencesStorage;
|
|
310
|
+
/** Cookie attributes, used when `storage` is `"cookie"` or `"both"`. */
|
|
311
|
+
cookieOptions?: CookieStorageOptions;
|
|
312
|
+
/**
|
|
313
|
+
* Decision read on the server (see `readPreferencesFromCookies`). When
|
|
314
|
+
* given — even as `null` — the first render is already `loaded`, so server
|
|
315
|
+
* and client markup match and the banner does not flash. After mount the
|
|
316
|
+
* client storage is re-read and wins.
|
|
317
|
+
*/
|
|
318
|
+
initialPreferences?: PreferencesState | null;
|
|
319
|
+
/** Bump this to ask visitors again. Default: "1". */
|
|
320
|
+
version?: string;
|
|
321
|
+
/**
|
|
322
|
+
* Keep Google consent mode (`gtag("consent", ...)`) in sync with the
|
|
323
|
+
* `analytics` / `marketing` categories. Creates the `window.gtag` stub,
|
|
324
|
+
* so enable it only when you load Google tags. Default: `false`.
|
|
325
|
+
*/
|
|
326
|
+
googleConsentMode?: boolean;
|
|
327
|
+
/**
|
|
328
|
+
* Register `window.justDont()`: a global that rejects all optional
|
|
329
|
+
* categories (required ones stay on, the banner closes, managed scripts
|
|
330
|
+
* unload) — handy for console snippets and "I don't care about cookies"-
|
|
331
|
+
* style browser extensions. Client-only. Enabled by default; pass
|
|
332
|
+
* `false` to opt out. The last mounted provider owns the global.
|
|
333
|
+
*/
|
|
334
|
+
windowJustDont?: boolean;
|
|
335
|
+
/**
|
|
336
|
+
* Honor the browser's Global Privacy Control signal
|
|
337
|
+
* (`navigator.globalPrivacyControl === true`, sent as `Sec-GPC: 1`). When
|
|
338
|
+
* a visitor with the signal on has no stored decision for the current
|
|
339
|
+
* `version`, the provider behaves as if they clicked "Reject all": required
|
|
340
|
+
* categories stay on, optional ones stay off, the banner never shows and
|
|
341
|
+
* `onDecision` fires. The decision is not persisted, because the signal is
|
|
342
|
+
* live: turning it off brings the banner back. A decision the visitor
|
|
343
|
+
* already made on this site always wins over the signal, and they can
|
|
344
|
+
* still opt in through the settings dialog. Enabled by default; pass
|
|
345
|
+
* `false` to opt out.
|
|
346
|
+
*/
|
|
347
|
+
respectGlobalPrivacyControl?: boolean;
|
|
348
|
+
/** Called whenever the visitor makes or changes their choice. */
|
|
349
|
+
onDecision?: (state: PreferencesState) => void;
|
|
350
|
+
};
|
|
351
|
+
type CookieBannerContextValue = {
|
|
352
|
+
loaded: boolean;
|
|
353
|
+
hasDecision: boolean;
|
|
354
|
+
showBanner: boolean;
|
|
355
|
+
/**
|
|
356
|
+
* `true` when `respectGlobalPrivacyControl` is on and the browser sent an
|
|
357
|
+
* active Global Privacy Control signal for this page load. Use it to tell
|
|
358
|
+
* the visitor their browser setting was honored.
|
|
359
|
+
*/
|
|
360
|
+
globalPrivacyControl: boolean;
|
|
361
|
+
settingsOpen: boolean;
|
|
362
|
+
preferences: PreferencesState;
|
|
363
|
+
texts: Texts;
|
|
364
|
+
categories: PreferenceCategory[];
|
|
365
|
+
/** The `scripts` map the provider was given, keyed by script id. */
|
|
366
|
+
scripts: ConsentScripts;
|
|
367
|
+
theme: ThemePalette;
|
|
368
|
+
darkTheme: ThemePalette;
|
|
369
|
+
components: PreferenceComponents;
|
|
370
|
+
/**
|
|
371
|
+
* `theme` as inline CSS custom properties. Kept for custom elements that
|
|
372
|
+
* only need the light palette; prefer spreading `themeAttributes` so the
|
|
373
|
+
* element also picks up `darkTheme`.
|
|
374
|
+
*/
|
|
375
|
+
themeStyle: React.CSSProperties;
|
|
376
|
+
/**
|
|
377
|
+
* Marker attribute that scopes the provider's theme rules to an element.
|
|
378
|
+
* Spread it onto any element of your own that uses `--nsr-*` variables.
|
|
379
|
+
*/
|
|
380
|
+
themeAttributes: Record<`data-${string}`, string>;
|
|
381
|
+
acceptAll: () => void;
|
|
382
|
+
rejectAll: () => void;
|
|
383
|
+
savePreferences: (partial: PreferencesUpdate) => void;
|
|
384
|
+
resetPreferences: () => void;
|
|
385
|
+
openSettings: () => void;
|
|
386
|
+
closeSettings: () => void;
|
|
387
|
+
/** True when the category or item id is accepted. Items are independent of their parent category. */
|
|
388
|
+
isAllowed: (id: string) => boolean;
|
|
389
|
+
/** Resolves the display title/description for a category or item id. */
|
|
390
|
+
resolveLabel: (id: string, config?: {
|
|
391
|
+
title?: string;
|
|
392
|
+
description?: string;
|
|
393
|
+
}) => {
|
|
394
|
+
title: string;
|
|
395
|
+
description: string;
|
|
396
|
+
};
|
|
397
|
+
};
|
|
398
|
+
type CookieBannerProps = {
|
|
399
|
+
/** URL of your privacy policy page. */
|
|
400
|
+
policyUrl?: string;
|
|
401
|
+
/** Root element classes. */
|
|
402
|
+
className?: string;
|
|
403
|
+
/** Inner card classes. */
|
|
404
|
+
contentClassName?: string;
|
|
405
|
+
/** Title classes. */
|
|
406
|
+
titleClassName?: string;
|
|
407
|
+
/** Description classes. */
|
|
408
|
+
descriptionClassName?: string;
|
|
409
|
+
/** Button group classes. */
|
|
410
|
+
actionsClassName?: string;
|
|
411
|
+
/** Extra classes applied to every button. */
|
|
412
|
+
buttonClassName?: string;
|
|
413
|
+
/**
|
|
414
|
+
* Swap the default components for the banner and the dialog it renders.
|
|
415
|
+
* Wins over the provider's `components`; `dialogProps.components` wins
|
|
416
|
+
* over this for the dialog only.
|
|
417
|
+
*/
|
|
418
|
+
components?: PreferenceComponents;
|
|
419
|
+
/**
|
|
420
|
+
* Props forwarded to the settings dialog that `CookieBanner` renders for
|
|
421
|
+
* you (class names for its parts). Use this instead of rendering a second
|
|
422
|
+
* `CookieSettingsDialog`.
|
|
423
|
+
*/
|
|
424
|
+
dialogProps?: CookieSettingsDialogProps;
|
|
425
|
+
};
|
|
426
|
+
type CookieSettingsDialogProps = {
|
|
427
|
+
className?: string;
|
|
428
|
+
overlayClassName?: string;
|
|
429
|
+
contentClassName?: string;
|
|
430
|
+
headerClassName?: string;
|
|
431
|
+
bodyClassName?: string;
|
|
432
|
+
footerClassName?: string;
|
|
433
|
+
categoryCardClassName?: string;
|
|
434
|
+
itemClassName?: string;
|
|
435
|
+
buttonClassName?: string;
|
|
436
|
+
/** Swap the default components for this dialog. Wins over the provider's `components`. */
|
|
437
|
+
components?: PreferenceComponents;
|
|
438
|
+
};
|
|
439
|
+
type CookieSettingsLinkProps = React.ButtonHTMLAttributes<HTMLButtonElement>;
|
|
440
|
+
//#endregion
|
|
441
|
+
//#region src/resolve-texts.d.ts
|
|
442
|
+
/** The languages that ship with built-in texts. Anything else gets English. */
|
|
443
|
+
declare const BUILT_IN_LANGUAGES: readonly ["en", "de", "pl"];
|
|
444
|
+
type BuiltInLanguage = (typeof BUILT_IN_LANGUAGES)[number];
|
|
445
|
+
/**
|
|
446
|
+
* The built-in texts for a language code. Matching ignores case, and a
|
|
447
|
+
* region or script suffix falls back to the base language ("pl-PL" and
|
|
448
|
+
* "de_AT" resolve to "pl" and "de"). Unknown languages get English.
|
|
449
|
+
*
|
|
450
|
+
* The result is plain JSON, so it is safe to use on the server, e.g. as the
|
|
451
|
+
* default values of CMS fields.
|
|
452
|
+
*/
|
|
453
|
+
declare function getBuiltInTexts(language?: string): Texts;
|
|
454
|
+
//#endregion
|
|
455
|
+
export { Texts as A, PreferenceItem as C, StorageKind as D, PreferencesUpdate as E, SwitchLikeProps as O, PreferenceComponents as S, PreferencesStorage as T, CookieStorageOptions as _, CategoryTexts as a, ItemTexts as b, ConsentConfig as c, ConsentScripts as d, CookieBannerConfigurationProviderProps as f, CookieSettingsLinkProps as g, CookieSettingsDialogProps as h, ButtonLikeProps as i, ThemePalette as j, TextOverrides as k, ConsentItemConfig as l, CookieBannerProps as m, BuiltInLanguage as n, CollapsibleProps as o, CookieBannerContextValue as p, getBuiltInTexts as r, ConsentCategoryConfig as s, BUILT_IN_LANGUAGES as t, ConsentScript as u, DeepPartial as v, PreferencesState as w, PreferenceCategory as x, DeepPartialNullable as y };
|
|
456
|
+
//# sourceMappingURL=resolve-texts-yAIbWOUX.d.cts.map
|