@c15t/svelte 3.0.0-alpha.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/AGENTS.md +88 -0
- package/README.md +136 -0
- package/SKILL.md +14 -0
- package/dist/actions/focus-trap.d.ts +8 -0
- package/dist/actions/focus-trap.js +23 -0
- package/dist/actions/portal.d.ts +8 -0
- package/dist/actions/portal.js +39 -0
- package/dist/actions/scroll-lock.d.ts +8 -0
- package/dist/actions/scroll-lock.js +23 -0
- package/dist/components/action-button.svelte +119 -0
- package/dist/components/action-button.svelte.d.ts +18 -0
- package/dist/components/branding.svelte +139 -0
- package/dist/components/branding.svelte.d.ts +13 -0
- package/dist/components/consent-dev-tools.svelte +58 -0
- package/dist/components/consent-dev-tools.svelte.d.ts +4 -0
- package/dist/components/frame.svelte +95 -0
- package/dist/components/frame.svelte.d.ts +12 -0
- package/dist/components/iab-panel.svelte +542 -0
- package/dist/components/iab-panel.svelte.d.ts +16 -0
- package/dist/components/iab-prompt.svelte +304 -0
- package/dist/components/iab-prompt.svelte.d.ts +14 -0
- package/dist/components/iab-purpose-item.svelte +511 -0
- package/dist/components/iab-purpose-item.svelte.d.ts +26 -0
- package/dist/components/iab-stack-item.svelte +146 -0
- package/dist/components/iab-stack-item.svelte.d.ts +19 -0
- package/dist/components/iab-vendor-list.svelte +900 -0
- package/dist/components/iab-vendor-list.svelte.d.ts +19 -0
- package/dist/components/icons/c15-t-icon-only.svelte +27 -0
- package/dist/components/icons/c15-t-icon-only.svelte.d.ts +9 -0
- package/dist/components/icons/chevron-down-icon.svelte +30 -0
- package/dist/components/icons/chevron-down-icon.svelte.d.ts +10 -0
- package/dist/components/icons/chevron-right-icon.svelte +36 -0
- package/dist/components/icons/chevron-right-icon.svelte.d.ts +12 -0
- package/dist/components/icons/close-icon.svelte +40 -0
- package/dist/components/icons/close-icon.svelte.d.ts +10 -0
- package/dist/components/icons/consent-icon-only.svelte +36 -0
- package/dist/components/icons/consent-icon-only.svelte.d.ts +9 -0
- package/dist/components/icons/external-link-icon.svelte +30 -0
- package/dist/components/icons/external-link-icon.svelte.d.ts +8 -0
- package/dist/components/icons/globe-icon.svelte +39 -0
- package/dist/components/icons/globe-icon.svelte.d.ts +9 -0
- package/dist/components/icons/info-icon.svelte +42 -0
- package/dist/components/icons/info-icon.svelte.d.ts +9 -0
- package/dist/components/icons/inth-logo.svelte +38 -0
- package/dist/components/icons/inth-logo.svelte.d.ts +9 -0
- package/dist/components/icons/layers-icon.svelte +25 -0
- package/dist/components/icons/layers-icon.svelte.d.ts +8 -0
- package/dist/components/icons/legitimate-interest-icon.svelte +29 -0
- package/dist/components/icons/legitimate-interest-icon.svelte.d.ts +10 -0
- package/dist/components/icons/lock-icon.svelte +31 -0
- package/dist/components/icons/lock-icon.svelte.d.ts +8 -0
- package/dist/components/icons/search-icon.svelte +33 -0
- package/dist/components/icons/search-icon.svelte.d.ts +8 -0
- package/dist/components/inline-legal-links.svelte +95 -0
- package/dist/components/inline-legal-links.svelte.d.ts +10 -0
- package/dist/components/manager-provider.svelte +459 -0
- package/dist/components/manager-provider.svelte.d.ts +27 -0
- package/dist/components/overlay.svelte +79 -0
- package/dist/components/overlay.svelte.d.ts +7 -0
- package/dist/components/panel-link.svelte +33 -0
- package/dist/components/panel-link.svelte.d.ts +10 -0
- package/dist/components/panel-trigger.svelte +237 -0
- package/dist/components/panel-trigger.svelte.d.ts +16 -0
- package/dist/components/panel.svelte +258 -0
- package/dist/components/panel.svelte.d.ts +22 -0
- package/dist/components/policy-actions-renderer.svelte +79 -0
- package/dist/components/policy-actions-renderer.svelte.d.ts +19 -0
- package/dist/components/preferences.svelte +320 -0
- package/dist/components/preferences.svelte.d.ts +8 -0
- package/dist/components/prompt.svelte +514 -0
- package/dist/components/prompt.svelte.d.ts +43 -0
- package/dist/context.svelte.d.ts +125 -0
- package/dist/context.svelte.js +354 -0
- package/dist/devtools-options.d.ts +7 -0
- package/dist/devtools-options.js +1 -0
- package/dist/devtools.d.ts +9 -0
- package/dist/devtools.js +7 -0
- package/dist/headless.d.ts +10 -0
- package/dist/headless.js +7 -0
- package/dist/iab/styles.css +11 -0
- package/dist/iab-loader.d.ts +30 -0
- package/dist/iab-loader.js +33 -0
- package/dist/iab-translations.d.ts +84 -0
- package/dist/iab-translations.js +45 -0
- package/dist/iab-types.d.ts +62 -0
- package/dist/iab-types.js +43 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +21 -0
- package/dist/kit/app.d.ts +35 -0
- package/dist/kit/handle.d.ts +34 -0
- package/dist/kit/handle.js +87 -0
- package/dist/kit/index.d.ts +30 -0
- package/dist/kit/index.js +5 -0
- package/dist/kit/load-consent.d.ts +57 -0
- package/dist/kit/load-consent.js +144 -0
- package/dist/kit/routes.d.ts +46 -0
- package/dist/kit/routes.js +203 -0
- package/dist/kit/types.d.ts +56 -0
- package/dist/kit/types.js +1 -0
- package/dist/primitives/accordion/accordion-item-content.svelte +35 -0
- package/dist/primitives/accordion/accordion-item-content.svelte.d.ts +9 -0
- package/dist/primitives/accordion/accordion-item-trigger.svelte +54 -0
- package/dist/primitives/accordion/accordion-item-trigger.svelte.d.ts +10 -0
- package/dist/primitives/accordion/accordion-item.svelte +61 -0
- package/dist/primitives/accordion/accordion-item.svelte.d.ts +11 -0
- package/dist/primitives/accordion/accordion-root.svelte +61 -0
- package/dist/primitives/accordion/accordion-root.svelte.d.ts +13 -0
- package/dist/primitives/accordion/context.d.ts +18 -0
- package/dist/primitives/accordion/context.js +23 -0
- package/dist/primitives/accordion/index.d.ts +29 -0
- package/dist/primitives/accordion/index.js +11 -0
- package/dist/primitives/collapsible/collapsible-content.svelte +36 -0
- package/dist/primitives/collapsible/collapsible-content.svelte.d.ts +9 -0
- package/dist/primitives/collapsible/collapsible-indicator.svelte +29 -0
- package/dist/primitives/collapsible/collapsible-indicator.svelte.d.ts +9 -0
- package/dist/primitives/collapsible/collapsible-root.svelte +70 -0
- package/dist/primitives/collapsible/collapsible-root.svelte.d.ts +11 -0
- package/dist/primitives/collapsible/collapsible-trigger.svelte +52 -0
- package/dist/primitives/collapsible/collapsible-trigger.svelte.d.ts +10 -0
- package/dist/primitives/collapsible/context.d.ts +10 -0
- package/dist/primitives/collapsible/context.js +12 -0
- package/dist/primitives/collapsible/index.d.ts +26 -0
- package/dist/primitives/collapsible/index.js +11 -0
- package/dist/primitives/dialog/context.d.ts +14 -0
- package/dist/primitives/dialog/context.js +12 -0
- package/dist/primitives/dialog/dialog-backdrop.svelte +39 -0
- package/dist/primitives/dialog/dialog-backdrop.svelte.d.ts +7 -0
- package/dist/primitives/dialog/dialog-close-trigger.svelte +48 -0
- package/dist/primitives/dialog/dialog-close-trigger.svelte.d.ts +11 -0
- package/dist/primitives/dialog/dialog-content.svelte +81 -0
- package/dist/primitives/dialog/dialog-content.svelte.d.ts +9 -0
- package/dist/primitives/dialog/dialog-description.svelte +28 -0
- package/dist/primitives/dialog/dialog-description.svelte.d.ts +9 -0
- package/dist/primitives/dialog/dialog-positioner.svelte +33 -0
- package/dist/primitives/dialog/dialog-positioner.svelte.d.ts +9 -0
- package/dist/primitives/dialog/dialog-root.svelte +117 -0
- package/dist/primitives/dialog/dialog-root.svelte.d.ts +14 -0
- package/dist/primitives/dialog/dialog-title.svelte +28 -0
- package/dist/primitives/dialog/dialog-title.svelte.d.ts +9 -0
- package/dist/primitives/dialog/index.d.ts +50 -0
- package/dist/primitives/dialog/index.js +19 -0
- package/dist/primitives/index.d.ts +7 -0
- package/dist/primitives/index.js +7 -0
- package/dist/primitives/portal/index.d.ts +4 -0
- package/dist/primitives/portal/index.js +2 -0
- package/dist/primitives/portal/portal.svelte +23 -0
- package/dist/primitives/portal/portal.svelte.d.ts +9 -0
- package/dist/primitives/preference-item/context.d.ts +11 -0
- package/dist/primitives/preference-item/context.js +12 -0
- package/dist/primitives/preference-item/index.d.ts +54 -0
- package/dist/primitives/preference-item/index.js +21 -0
- package/dist/primitives/preference-item/preference-item-auxiliary.svelte +33 -0
- package/dist/primitives/preference-item/preference-item-auxiliary.svelte.d.ts +9 -0
- package/dist/primitives/preference-item/preference-item-content.svelte +68 -0
- package/dist/primitives/preference-item/preference-item-content.svelte.d.ts +14 -0
- package/dist/primitives/preference-item/preference-item-control.svelte +33 -0
- package/dist/primitives/preference-item/preference-item-control.svelte.d.ts +9 -0
- package/dist/primitives/preference-item/preference-item-header.svelte +33 -0
- package/dist/primitives/preference-item/preference-item-header.svelte.d.ts +9 -0
- package/dist/primitives/preference-item/preference-item-leading.svelte +33 -0
- package/dist/primitives/preference-item/preference-item-leading.svelte.d.ts +9 -0
- package/dist/primitives/preference-item/preference-item-meta.svelte +33 -0
- package/dist/primitives/preference-item/preference-item-meta.svelte.d.ts +9 -0
- package/dist/primitives/preference-item/preference-item-root.svelte +82 -0
- package/dist/primitives/preference-item/preference-item-root.svelte.d.ts +12 -0
- package/dist/primitives/preference-item/preference-item-title.svelte +33 -0
- package/dist/primitives/preference-item/preference-item-title.svelte.d.ts +9 -0
- package/dist/primitives/preference-item/preference-item-trigger.svelte +62 -0
- package/dist/primitives/preference-item/preference-item-trigger.svelte.d.ts +10 -0
- package/dist/primitives/switch/context.d.ts +7 -0
- package/dist/primitives/switch/context.js +12 -0
- package/dist/primitives/switch/index.d.ts +25 -0
- package/dist/primitives/switch/index.js +11 -0
- package/dist/primitives/switch/switch-control.svelte +21 -0
- package/dist/primitives/switch/switch-control.svelte.d.ts +9 -0
- package/dist/primitives/switch/switch-hidden-input.svelte +31 -0
- package/dist/primitives/switch/switch-hidden-input.svelte.d.ts +8 -0
- package/dist/primitives/switch/switch-root.svelte +86 -0
- package/dist/primitives/switch/switch-root.svelte.d.ts +12 -0
- package/dist/primitives/switch/switch-thumb.svelte +14 -0
- package/dist/primitives/switch/switch-thumb.svelte.d.ts +7 -0
- package/dist/primitives/tabs/context.d.ts +11 -0
- package/dist/primitives/tabs/context.js +12 -0
- package/dist/primitives/tabs/index.d.ts +32 -0
- package/dist/primitives/tabs/index.js +11 -0
- package/dist/primitives/tabs/tabs-content.svelte +45 -0
- package/dist/primitives/tabs/tabs-content.svelte.d.ts +11 -0
- package/dist/primitives/tabs/tabs-list.svelte +38 -0
- package/dist/primitives/tabs/tabs-list.svelte.d.ts +10 -0
- package/dist/primitives/tabs/tabs-root.svelte +67 -0
- package/dist/primitives/tabs/tabs-root.svelte.d.ts +14 -0
- package/dist/primitives/tabs/tabs-trigger.svelte +108 -0
- package/dist/primitives/tabs/tabs-trigger.svelte.d.ts +11 -0
- package/dist/server/headers.d.ts +13 -0
- package/dist/server/headers.js +37 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.js +116 -0
- package/dist/server/normalize-url.d.ts +23 -0
- package/dist/server/normalize-url.js +46 -0
- package/dist/server/types.d.ts +25 -0
- package/dist/server/types.js +1 -0
- package/dist/styles.css +10 -0
- package/dist/transports/offline.d.ts +14 -0
- package/dist/transports/offline.js +22 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.js +1 -0
- package/dist/use-banner-visibility.svelte.d.ts +25 -0
- package/dist/use-banner-visibility.svelte.js +108 -0
- package/dist/utils.d.ts +25 -0
- package/dist/utils.js +32 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +2 -0
- package/docs/README.md +88 -0
- package/docs/assets/v3/brand-bar.png +0 -0
- package/docs/assets/v3/brand-card.png +0 -0
- package/docs/assets/v3/choice-wall.png +0 -0
- package/docs/assets/v3/mobile-card.png +0 -0
- package/docs/assets/v3/preferences.png +0 -0
- package/docs/customization/overview.md +45 -0
- package/docs/customization/recipes.md +79 -0
- package/docs/customization/slots.md +55 -0
- package/docs/customization/tokens.md +76 -0
- package/docs/customization/translations.md +49 -0
- package/docs/frameworks/svelte/quickstart.md +133 -0
- package/docs/frameworks/sveltekit/quickstart.md +144 -0
- package/docs/guides/consent-state.md +60 -0
- package/docs/guides/data-fetching.md +163 -0
- package/docs/guides/deployment-modes.md +63 -0
- package/docs/guides/troubleshooting.md +68 -0
- package/docs/guides/verify-consent.md +62 -0
- package/docs/integrations/adobe-analytics.md +294 -0
- package/docs/integrations/ahrefs-analytics.md +291 -0
- package/docs/integrations/amplitude.md +292 -0
- package/docs/integrations/building-integrations.md +47 -0
- package/docs/integrations/clearbit.md +291 -0
- package/docs/integrations/cloudflare-web-analytics.md +292 -0
- package/docs/integrations/crisp.md +294 -0
- package/docs/integrations/databuddy.md +311 -0
- package/docs/integrations/fathom-analytics.md +293 -0
- package/docs/integrations/google-maps.md +384 -0
- package/docs/integrations/google-tag-manager.md +306 -0
- package/docs/integrations/google-tag.md +305 -0
- package/docs/integrations/heap.md +292 -0
- package/docs/integrations/hightouch.md +293 -0
- package/docs/integrations/hotjar.md +292 -0
- package/docs/integrations/intercom.md +285 -0
- package/docs/integrations/linkedin-insights.md +291 -0
- package/docs/integrations/logrocket.md +293 -0
- package/docs/integrations/matomo-analytics.md +316 -0
- package/docs/integrations/meta-pixel.md +285 -0
- package/docs/integrations/microsoft-clarity.md +292 -0
- package/docs/integrations/microsoft-uet.md +291 -0
- package/docs/integrations/mixpanel-analytics.md +295 -0
- package/docs/integrations/openai-pixel.md +441 -0
- package/docs/integrations/overview.md +111 -0
- package/docs/integrations/pirsch.md +295 -0
- package/docs/integrations/plausible-analytics.md +295 -0
- package/docs/integrations/posthog.md +397 -0
- package/docs/integrations/promptwatch.md +291 -0
- package/docs/integrations/reddit-pixel.md +294 -0
- package/docs/integrations/rudderstack.md +328 -0
- package/docs/integrations/rybbit-analytics.md +296 -0
- package/docs/integrations/segment.md +292 -0
- package/docs/integrations/snapchat-pixel.md +293 -0
- package/docs/integrations/tiktok-pixel.md +291 -0
- package/docs/integrations/umami-analytics.md +295 -0
- package/docs/integrations/vercel-analytics.md +293 -0
- package/docs/integrations/x-pixel.md +291 -0
- package/docs/integrations/youtube.md +405 -0
- package/docs/upgrade-v3.md +334 -0
- package/iab/styles.css +1 -0
- package/package.json +153 -0
- package/readme.json +36 -0
- package/styles.css +1 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { LegalLinks as LegalLinksType } from '@c15t/core';
|
|
3
|
+
import { defaultTranslationConfig } from '@c15t/core';
|
|
4
|
+
import legalLinkStyles from '@c15t/ui/styles/components/legal-links';
|
|
5
|
+
import type { AllThemeKeys } from '@c15t/ui/theme';
|
|
6
|
+
import { resolveTranslations } from '@c15t/ui/utils';
|
|
7
|
+
|
|
8
|
+
import { getConsentContext, getThemeContext } from '../context.svelte';
|
|
9
|
+
import { resolveComponentStyles } from '../utils';
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
links,
|
|
13
|
+
themeKey = 'consentBannerDescription' as AllThemeKeys,
|
|
14
|
+
testIdPrefix,
|
|
15
|
+
}: {
|
|
16
|
+
links?: (keyof LegalLinksType)[] | null;
|
|
17
|
+
themeKey?: AllThemeKeys;
|
|
18
|
+
testIdPrefix?: string;
|
|
19
|
+
} = $props();
|
|
20
|
+
|
|
21
|
+
const consent = getConsentContext();
|
|
22
|
+
const theme = getThemeContext();
|
|
23
|
+
|
|
24
|
+
const noStyle = $derived(theme.noStyle ?? false);
|
|
25
|
+
|
|
26
|
+
const translations = $derived(
|
|
27
|
+
resolveTranslations(
|
|
28
|
+
consent.state.translationConfig,
|
|
29
|
+
defaultTranslationConfig
|
|
30
|
+
)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const filteredLinks = $derived.by(() => {
|
|
34
|
+
if (links === undefined || links === null) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const allLinks = consent.state.legalLinks;
|
|
38
|
+
if (!allLinks) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const entries = Object.entries(allLinks).filter(([key]) =>
|
|
42
|
+
links.includes(key as keyof LegalLinksType)
|
|
43
|
+
);
|
|
44
|
+
return entries.length > 0
|
|
45
|
+
? (Object.fromEntries(entries) as LegalLinksType)
|
|
46
|
+
: null;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const linkStyle = $derived(
|
|
50
|
+
resolveComponentStyles(
|
|
51
|
+
themeKey,
|
|
52
|
+
theme.theme,
|
|
53
|
+
{ baseClassName: legalLinkStyles.legalLink },
|
|
54
|
+
noStyle
|
|
55
|
+
)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const linkEntries = $derived(
|
|
59
|
+
filteredLinks
|
|
60
|
+
? (Object.entries(filteredLinks) as [
|
|
61
|
+
keyof LegalLinksType,
|
|
62
|
+
LegalLinksType[keyof LegalLinksType],
|
|
63
|
+
][])
|
|
64
|
+
: []
|
|
65
|
+
);
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
{#if linkEntries.length > 0}
|
|
69
|
+
<span>
|
|
70
|
+
|
|
71
|
+
{#each linkEntries as [type, link], index (type)}
|
|
72
|
+
{#if link}
|
|
73
|
+
<span>
|
|
74
|
+
<a
|
|
75
|
+
href={link.href}
|
|
76
|
+
target={link.target || '_blank'}
|
|
77
|
+
rel={link.rel ||
|
|
78
|
+
(link.target === '_blank' ? 'noopener noreferrer' : undefined)}
|
|
79
|
+
class={linkStyle.className || ''}
|
|
80
|
+
data-testid={testIdPrefix ? `${testIdPrefix}-${type}` : undefined}
|
|
81
|
+
>
|
|
82
|
+
{link.label ??
|
|
83
|
+
(translations.legalLinks as Record<string, string>)?.[
|
|
84
|
+
type as string
|
|
85
|
+
] ??
|
|
86
|
+
type}{index < linkEntries.length - 1 ? ',' : ''}
|
|
87
|
+
</a>
|
|
88
|
+
{#if index < linkEntries.length - 1}
|
|
89
|
+
|
|
90
|
+
{/if}
|
|
91
|
+
</span>
|
|
92
|
+
{/if}
|
|
93
|
+
{/each}
|
|
94
|
+
</span>
|
|
95
|
+
{/if}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LegalLinks as LegalLinksType } from '@c15t/core';
|
|
2
|
+
import type { AllThemeKeys } from '@c15t/ui/theme';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
links?: (keyof LegalLinksType)[] | null;
|
|
5
|
+
themeKey?: AllThemeKeys;
|
|
6
|
+
testIdPrefix?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const InlineLegalLinks: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type InlineLegalLinks = ReturnType<typeof InlineLegalLinks>;
|
|
10
|
+
export default InlineLegalLinks;
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type {
|
|
3
|
+
AllConsentNames,
|
|
4
|
+
ConsentSnapshot,
|
|
5
|
+
ConsentState,
|
|
6
|
+
KernelOverrides,
|
|
7
|
+
KernelUser,
|
|
8
|
+
} from '@c15t/core';
|
|
9
|
+
import {
|
|
10
|
+
createConsentRuntime,
|
|
11
|
+
normalizeKernelUser,
|
|
12
|
+
} from '@c15t/core/runtime';
|
|
13
|
+
import type { ConsentRuntime } from '@c15t/core/runtime';
|
|
14
|
+
import type { IABHandle } from '@c15t/iab';
|
|
15
|
+
import { generateThemeCSS } from '@c15t/ui/theme';
|
|
16
|
+
import { setupColorScheme } from '@c15t/ui/utils';
|
|
17
|
+
import type { Snippet } from 'svelte';
|
|
18
|
+
import { onDestroy, onMount, untrack } from 'svelte';
|
|
19
|
+
|
|
20
|
+
import { setConsentContext, setThemeContext } from '../context.svelte';
|
|
21
|
+
import type { ConsentDraftState, SvelteIABState } from '../context.svelte';
|
|
22
|
+
import { isIABConfigured, lazyCreateIAB } from '../iab-loader';
|
|
23
|
+
import type { ConsentManagerOptions } from '../types';
|
|
24
|
+
|
|
25
|
+
type ProviderOptionsInput = Omit<ConsentManagerOptions, 'mode'> & {
|
|
26
|
+
mode?: ConsentManagerOptions['mode'];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
interface ProviderRuntimeProps {
|
|
30
|
+
children?: Snippet;
|
|
31
|
+
/**
|
|
32
|
+
* An externally owned runtime to render instead of creating one.
|
|
33
|
+
*
|
|
34
|
+
* A SvelteKit root layout or an Astro page can create a single
|
|
35
|
+
* runtime with `createConsentRuntime()` and share it across
|
|
36
|
+
* component trees that cannot see each other's context. The
|
|
37
|
+
* provider neither starts nor disposes a runtime it did not
|
|
38
|
+
* create — the owner does both.
|
|
39
|
+
*/
|
|
40
|
+
runtime?: ConsentRuntime;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type ConsentManagerProviderProps =
|
|
44
|
+
| (ConsentManagerOptions &
|
|
45
|
+
ProviderRuntimeProps & {
|
|
46
|
+
options?: ProviderOptionsInput;
|
|
47
|
+
})
|
|
48
|
+
| (ProviderOptionsInput &
|
|
49
|
+
ProviderRuntimeProps & {
|
|
50
|
+
options: ConsentManagerOptions;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
let props: ConsentManagerProviderProps = $props();
|
|
54
|
+
|
|
55
|
+
const mergeDefinedOptions = function mergeDefinedOptions(
|
|
56
|
+
base: ProviderOptionsInput,
|
|
57
|
+
overrides: ProviderOptionsInput
|
|
58
|
+
): ProviderOptionsInput {
|
|
59
|
+
const merged = { ...base };
|
|
60
|
+
for (const [key, value] of Object.entries(overrides) as [
|
|
61
|
+
keyof ConsentManagerOptions,
|
|
62
|
+
ConsentManagerOptions[keyof ConsentManagerOptions],
|
|
63
|
+
][]) {
|
|
64
|
+
if (value !== undefined) {
|
|
65
|
+
merged[key] = value as never;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return merged;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const resolveProviderOptions = function resolveProviderOptions({
|
|
72
|
+
children: _children,
|
|
73
|
+
runtime: _runtime,
|
|
74
|
+
options: nestedOptions = {},
|
|
75
|
+
...topLevelOptions
|
|
76
|
+
}: ConsentManagerProviderProps): ProviderOptionsInput {
|
|
77
|
+
return mergeDefinedOptions(nestedOptions, topLevelOptions);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const children = $derived(props.children);
|
|
81
|
+
const options = $derived(resolveProviderOptions(props));
|
|
82
|
+
|
|
83
|
+
// The runtime owns the kernel and every side-effecting module. When one
|
|
84
|
+
// is handed in, its owner is also responsible for `start()`/`dispose()`.
|
|
85
|
+
const externalRuntime = untrack(() => props.runtime);
|
|
86
|
+
const ownsRuntime = externalRuntime === undefined;
|
|
87
|
+
const runtime: ConsentRuntime =
|
|
88
|
+
externalRuntime ??
|
|
89
|
+
untrack(() =>
|
|
90
|
+
createConsentRuntime({
|
|
91
|
+
...options,
|
|
92
|
+
// Only an app that configured IAB reaches for `@c15t/iab`, and
|
|
93
|
+
// even then the module arrives through a dynamic import.
|
|
94
|
+
createIAB: isIABConfigured(options.iab) ? lazyCreateIAB : undefined,
|
|
95
|
+
mode: options.mode as ConsentManagerOptions['mode'],
|
|
96
|
+
pkg: '@c15t/svelte',
|
|
97
|
+
})
|
|
98
|
+
);
|
|
99
|
+
const { kernel } = runtime;
|
|
100
|
+
|
|
101
|
+
let snapshot = $state<ConsentSnapshot>(kernel.getSnapshot());
|
|
102
|
+
let draftFingerprint = $state<string | null>(null);
|
|
103
|
+
let draftRevision = 0;
|
|
104
|
+
let draftSaveSequence = 0;
|
|
105
|
+
let draftValues = $state<Partial<ConsentState>>({});
|
|
106
|
+
let iabHandle = $state<IABHandle | null>(
|
|
107
|
+
untrack(() => runtime.iab as IABHandle | null)
|
|
108
|
+
);
|
|
109
|
+
let iabTab = $state<'purposes' | 'vendors'>('purposes');
|
|
110
|
+
let configuredCategories = $state<AllConsentNames[]>(
|
|
111
|
+
untrack(() => options.consentCategories ?? runtime.consentCategories)
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const draft: ConsentDraftState = {
|
|
115
|
+
get isStale() {
|
|
116
|
+
return (
|
|
117
|
+
draftFingerprint !== null &&
|
|
118
|
+
draftFingerprint !== snapshot.evaluationPolicy.choice.fingerprint
|
|
119
|
+
);
|
|
120
|
+
},
|
|
121
|
+
reset() {
|
|
122
|
+
draftRevision += 1;
|
|
123
|
+
draftValues = {};
|
|
124
|
+
draftFingerprint = null;
|
|
125
|
+
},
|
|
126
|
+
async save(categories) {
|
|
127
|
+
const revision = draftRevision;
|
|
128
|
+
draftSaveSequence += 1;
|
|
129
|
+
const sequence = draftSaveSequence;
|
|
130
|
+
const current = kernel.getSnapshot();
|
|
131
|
+
if (
|
|
132
|
+
draftFingerprint !== null &&
|
|
133
|
+
draftFingerprint !== current.evaluationPolicy.choice.fingerprint
|
|
134
|
+
) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
'The policy changed. Review your preferences before saving.'
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const { values } = draft;
|
|
140
|
+
const result = await kernel.commands.save(
|
|
141
|
+
Object.fromEntries(
|
|
142
|
+
current.policyRule.scope
|
|
143
|
+
.filter(
|
|
144
|
+
(name) =>
|
|
145
|
+
configuredCategories.length === 0 ||
|
|
146
|
+
configuredCategories.includes(name)
|
|
147
|
+
)
|
|
148
|
+
.filter(
|
|
149
|
+
(name) => categories === undefined || categories.includes(name)
|
|
150
|
+
)
|
|
151
|
+
.map((name) => [name, values[name]])
|
|
152
|
+
)
|
|
153
|
+
);
|
|
154
|
+
if (!result.ok) {
|
|
155
|
+
throw new Error('Unable to save preferences.');
|
|
156
|
+
}
|
|
157
|
+
if (revision === draftRevision && sequence === draftSaveSequence) {
|
|
158
|
+
draft.reset();
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
set(name, value) {
|
|
162
|
+
if (name === 'necessary') {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
draftRevision += 1;
|
|
166
|
+
draftFingerprint ??=
|
|
167
|
+
kernel.getSnapshot().evaluationPolicy.choice.fingerprint;
|
|
168
|
+
draftValues = { ...draftValues, [name]: value };
|
|
169
|
+
},
|
|
170
|
+
get values() {
|
|
171
|
+
return {
|
|
172
|
+
necessary: true,
|
|
173
|
+
...Object.fromEntries(
|
|
174
|
+
snapshot.policyRule.scope.map((name) => [
|
|
175
|
+
name,
|
|
176
|
+
draftValues[name] ??
|
|
177
|
+
snapshot.explicitChoice?.categories[name]?.value ??
|
|
178
|
+
options.presentation?.preferences?.defaults?.[name] ??
|
|
179
|
+
(snapshot.policyRule.model === 'opt-out' ||
|
|
180
|
+
snapshot.policyRule.preselectedCategories.includes(name)),
|
|
181
|
+
])
|
|
182
|
+
),
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const getIABState = function getIABState(): SvelteIABState | null {
|
|
188
|
+
const { iab } = snapshot;
|
|
189
|
+
if (!iab) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
// Rendering keys on the kernel state so a server-resolved GVL puts the
|
|
193
|
+
// IAB surfaces in the first HTML. Until `@c15t/iab` lands the lazy
|
|
194
|
+
// handle queues calls and replays them, so an early Accept still
|
|
195
|
+
// records consent; without any handle the actions are no-ops.
|
|
196
|
+
const readyHandle = iabHandle;
|
|
197
|
+
const noop = () => {
|
|
198
|
+
/* empty */
|
|
199
|
+
};
|
|
200
|
+
const noopAsync = async () => {
|
|
201
|
+
/* empty */
|
|
202
|
+
};
|
|
203
|
+
return {
|
|
204
|
+
...iab,
|
|
205
|
+
acceptAll: readyHandle?.acceptAll ?? noop,
|
|
206
|
+
config: {
|
|
207
|
+
cmpId: iab.cmpId,
|
|
208
|
+
enabled: iab.enabled,
|
|
209
|
+
},
|
|
210
|
+
isLoadingGVL: iab.enabled && !iab.gvl,
|
|
211
|
+
nonIABVendors: iab.customVendors,
|
|
212
|
+
preferenceCenterTab: iabTab,
|
|
213
|
+
rejectAll: readyHandle?.rejectAll ?? noop,
|
|
214
|
+
save: readyHandle?.save ?? noopAsync,
|
|
215
|
+
setPreferenceCenterTab(tab) {
|
|
216
|
+
iabTab = tab;
|
|
217
|
+
},
|
|
218
|
+
setPurposeConsent: readyHandle?.setPurposeConsent ?? noop,
|
|
219
|
+
setPurposeLegitimateInterest:
|
|
220
|
+
readyHandle?.setPurposeLegitimateInterest ?? noop,
|
|
221
|
+
setSpecialFeatureOptIn: readyHandle?.setSpecialFeatureOptIn ?? noop,
|
|
222
|
+
setVendorConsent: readyHandle?.setVendorConsent ?? noop,
|
|
223
|
+
setVendorLegitimateInterest:
|
|
224
|
+
readyHandle?.setVendorLegitimateInterest ?? noop,
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
setConsentContext(kernel, {
|
|
229
|
+
clearRecords: () => runtime.clearRecords(),
|
|
230
|
+
getConsentCategories: () => [
|
|
231
|
+
'necessary',
|
|
232
|
+
...snapshot.policyRule.scope.filter(
|
|
233
|
+
(name) =>
|
|
234
|
+
!configuredCategories.length || configuredCategories.includes(name)
|
|
235
|
+
),
|
|
236
|
+
],
|
|
237
|
+
getDraft: () => draft,
|
|
238
|
+
getIAB: getIABState,
|
|
239
|
+
getLegalLinks: () => options.legalLinks,
|
|
240
|
+
getPresentation: () => options.presentation,
|
|
241
|
+
getSnapshot: () => snapshot,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const unsubscribe = kernel.subscribe((next) => {
|
|
245
|
+
snapshot = next;
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// The lazy handle queues calls until `@c15t/iab` lands and replays them,
|
|
249
|
+
// so the surfaces render against it as soon as it exists.
|
|
250
|
+
const unsubscribeIAB = runtime.onIABChange((next) => {
|
|
251
|
+
iabHandle = next as IABHandle | null;
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
onMount(() => {
|
|
255
|
+
if (!ownsRuntime) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
runtime.start();
|
|
259
|
+
snapshot = kernel.getSnapshot();
|
|
260
|
+
return () => {
|
|
261
|
+
// Drop the IAB listener first: disposing the runtime emits a
|
|
262
|
+
// final `null` and this component is already tearing down.
|
|
263
|
+
unsubscribeIAB();
|
|
264
|
+
runtime.dispose();
|
|
265
|
+
};
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Each of the effects below reads one narrow value rather than the whole
|
|
269
|
+
// derived `options` object. Reading `options` would tie them to every
|
|
270
|
+
// prop — a new inline `options={{ theme }}` would re-run `identify()`
|
|
271
|
+
// and fire a second `init()` on a theme change.
|
|
272
|
+
const userOption = $derived(options.user);
|
|
273
|
+
const overridesOption = $derived(options.overrides);
|
|
274
|
+
const consentCategoriesOption = $derived(options.consentCategories);
|
|
275
|
+
const enabledOption = $derived(options.enabled ?? true);
|
|
276
|
+
|
|
277
|
+
// Every field `identify()` sends, in a fixed order. Keying on a subset
|
|
278
|
+
// would swallow an update: same `externalId`, new `properties`, no call.
|
|
279
|
+
const userKey = function userKey(
|
|
280
|
+
user: KernelUser | undefined
|
|
281
|
+
): string | null {
|
|
282
|
+
if (!user) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
return JSON.stringify([
|
|
286
|
+
user.externalId,
|
|
287
|
+
user.externalIdType,
|
|
288
|
+
user.identityProvider,
|
|
289
|
+
user.properties,
|
|
290
|
+
]);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// What the runtime carried before this provider pushed anything, so
|
|
294
|
+
// removing the prop restores that rather than leaving the last pushed
|
|
295
|
+
// list in place. Only restored if this provider did the pushing: a
|
|
296
|
+
// borrowed runtime's categories belong to whoever owns it.
|
|
297
|
+
const initialCategories = untrack(() => runtime.consentCategories);
|
|
298
|
+
let pushedCategories = false;
|
|
299
|
+
|
|
300
|
+
$effect(() => {
|
|
301
|
+
configuredCategories = consentCategoriesOption ?? initialCategories;
|
|
302
|
+
if (consentCategoriesOption) {
|
|
303
|
+
runtime.setConsentCategories(consentCategoriesOption);
|
|
304
|
+
pushedCategories = true;
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (pushedCategories) {
|
|
308
|
+
runtime.setConsentCategories(initialCategories);
|
|
309
|
+
pushedCategories = false;
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
let lastIdentifiedKey: string | null = null;
|
|
314
|
+
|
|
315
|
+
$effect(() => {
|
|
316
|
+
if (!ownsRuntime) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const nextUser = normalizeKernelUser(userOption);
|
|
320
|
+
const key = userKey(nextUser);
|
|
321
|
+
if (key === null || key === lastIdentifiedKey) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
lastIdentifiedKey = key;
|
|
325
|
+
void runtime.identify(nextUser);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
let lastOverridesKey: string | null = null;
|
|
329
|
+
let hasSkippedInitialOverridesInit = false;
|
|
330
|
+
|
|
331
|
+
$effect(() => {
|
|
332
|
+
if (!ownsRuntime) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const overrides: KernelOverrides = overridesOption ?? {};
|
|
336
|
+
const key = JSON.stringify(
|
|
337
|
+
Object.entries(overrides).sort(([left], [right]) =>
|
|
338
|
+
left.localeCompare(right)
|
|
339
|
+
)
|
|
340
|
+
);
|
|
341
|
+
if (key === lastOverridesKey) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
lastOverridesKey = key;
|
|
345
|
+
if (!hasSkippedInitialOverridesInit) {
|
|
346
|
+
hasSkippedInitialOverridesInit = true;
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
runtime.setOverrides(overrides);
|
|
350
|
+
if (enabledOption) {
|
|
351
|
+
void runtime.reinit();
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
$effect(() => {
|
|
356
|
+
if (!ownsRuntime || enabledOption) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
kernel.set.activeUI('none');
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
let prefersReducedMotion = $state(false);
|
|
363
|
+
|
|
364
|
+
onMount(() => {
|
|
365
|
+
if (typeof window === 'undefined' || !window.matchMedia) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
369
|
+
prefersReducedMotion = mediaQuery.matches;
|
|
370
|
+
|
|
371
|
+
const handler = (event: MediaQueryListEvent) => {
|
|
372
|
+
prefersReducedMotion = event.matches;
|
|
373
|
+
};
|
|
374
|
+
mediaQuery.addEventListener('change', handler);
|
|
375
|
+
return () => mediaQuery.removeEventListener('change', handler);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
const userTheme = $derived(options.theme);
|
|
379
|
+
|
|
380
|
+
setThemeContext({
|
|
381
|
+
get colorScheme() {
|
|
382
|
+
return options.colorScheme;
|
|
383
|
+
},
|
|
384
|
+
get disableAnimation() {
|
|
385
|
+
return options.disableAnimation ?? prefersReducedMotion;
|
|
386
|
+
},
|
|
387
|
+
get legalLinks() {
|
|
388
|
+
return options.legalLinks;
|
|
389
|
+
},
|
|
390
|
+
get noStyle() {
|
|
391
|
+
return options.noStyle;
|
|
392
|
+
},
|
|
393
|
+
get scrollLock() {
|
|
394
|
+
return options.scrollLock;
|
|
395
|
+
},
|
|
396
|
+
get theme() {
|
|
397
|
+
return userTheme;
|
|
398
|
+
},
|
|
399
|
+
get trapFocus() {
|
|
400
|
+
return options.trapFocus;
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const themeCSS = $derived(userTheme ? generateThemeCSS(userTheme) : '');
|
|
405
|
+
|
|
406
|
+
let themeStyleEl: HTMLStyleElement | null = null;
|
|
407
|
+
let ownedStyleEl = false;
|
|
408
|
+
|
|
409
|
+
$effect(() => {
|
|
410
|
+
if (typeof document === 'undefined') {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (!themeCSS) {
|
|
414
|
+
if (ownedStyleEl && themeStyleEl) {
|
|
415
|
+
themeStyleEl.remove();
|
|
416
|
+
themeStyleEl = null;
|
|
417
|
+
ownedStyleEl = false;
|
|
418
|
+
}
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
if (!themeStyleEl) {
|
|
422
|
+
themeStyleEl = document.getElementById(
|
|
423
|
+
'c15t-theme'
|
|
424
|
+
) as HTMLStyleElement | null;
|
|
425
|
+
if (!themeStyleEl) {
|
|
426
|
+
themeStyleEl = document.createElement('style');
|
|
427
|
+
themeStyleEl.id = 'c15t-theme';
|
|
428
|
+
document.head.appendChild(themeStyleEl);
|
|
429
|
+
ownedStyleEl = true;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// A nonce-based CSP rejects the injected block without it.
|
|
433
|
+
if (options.nonce) {
|
|
434
|
+
themeStyleEl.nonce = options.nonce;
|
|
435
|
+
}
|
|
436
|
+
themeStyleEl.textContent = themeCSS;
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
$effect(() => {
|
|
440
|
+
if (options.colorScheme === null || options.colorScheme === undefined) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
return setupColorScheme(options.colorScheme);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
onDestroy(() => {
|
|
447
|
+
unsubscribe();
|
|
448
|
+
unsubscribeIAB();
|
|
449
|
+
if (ownedStyleEl && themeStyleEl) {
|
|
450
|
+
themeStyleEl.remove();
|
|
451
|
+
themeStyleEl = null;
|
|
452
|
+
ownedStyleEl = false;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
</script>
|
|
456
|
+
|
|
457
|
+
{#if children}
|
|
458
|
+
{@render children()}
|
|
459
|
+
{/if}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ConsentRuntime } from '@c15t/core/runtime';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { ConsentManagerOptions } from '../types';
|
|
4
|
+
type ProviderOptionsInput = Omit<ConsentManagerOptions, 'mode'> & {
|
|
5
|
+
mode?: ConsentManagerOptions['mode'];
|
|
6
|
+
};
|
|
7
|
+
interface ProviderRuntimeProps {
|
|
8
|
+
children?: Snippet;
|
|
9
|
+
/**
|
|
10
|
+
* An externally owned runtime to render instead of creating one.
|
|
11
|
+
*
|
|
12
|
+
* A SvelteKit root layout or an Astro page can create a single
|
|
13
|
+
* runtime with `createConsentRuntime()` and share it across
|
|
14
|
+
* component trees that cannot see each other's context. The
|
|
15
|
+
* provider neither starts nor disposes a runtime it did not
|
|
16
|
+
* create — the owner does both.
|
|
17
|
+
*/
|
|
18
|
+
runtime?: ConsentRuntime;
|
|
19
|
+
}
|
|
20
|
+
type ConsentManagerProviderProps = (ConsentManagerOptions & ProviderRuntimeProps & {
|
|
21
|
+
options?: ProviderOptionsInput;
|
|
22
|
+
}) | (ProviderOptionsInput & ProviderRuntimeProps & {
|
|
23
|
+
options: ConsentManagerOptions;
|
|
24
|
+
});
|
|
25
|
+
declare const ManagerProvider: import("svelte").Component<ConsentManagerProviderProps, {}, "">;
|
|
26
|
+
type ManagerProvider = ReturnType<typeof ManagerProvider>;
|
|
27
|
+
export default ManagerProvider;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import bannerStyles from '@c15t/ui/styles/components/consent-banner';
|
|
3
|
+
import dialogStyles from '@c15t/ui/styles/components/consent-dialog';
|
|
4
|
+
import iabBannerStyles from '@c15t/ui/styles/components/iab-consent-banner';
|
|
5
|
+
import iabDialogStyles from '@c15t/ui/styles/components/iab-consent-dialog';
|
|
6
|
+
|
|
7
|
+
import { getThemeContext } from '../context.svelte';
|
|
8
|
+
import { resolveComponentStyles } from '../utils';
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
variant = 'banner',
|
|
12
|
+
visible = true,
|
|
13
|
+
}: {
|
|
14
|
+
variant?: 'banner' | 'dialog' | 'iab-banner' | 'iab-dialog';
|
|
15
|
+
visible?: boolean;
|
|
16
|
+
} = $props();
|
|
17
|
+
|
|
18
|
+
const theme = getThemeContext();
|
|
19
|
+
|
|
20
|
+
const styles = $derived.by(() => {
|
|
21
|
+
if (variant === 'dialog') {
|
|
22
|
+
return dialogStyles;
|
|
23
|
+
}
|
|
24
|
+
if (variant === 'iab-dialog') {
|
|
25
|
+
return iabDialogStyles;
|
|
26
|
+
}
|
|
27
|
+
return variant === 'iab-banner' ? iabBannerStyles : bannerStyles;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const themeKey = $derived.by(() => {
|
|
31
|
+
if (variant === 'dialog') {
|
|
32
|
+
return 'consentDialogOverlay' as const;
|
|
33
|
+
}
|
|
34
|
+
if (variant === 'iab-dialog') {
|
|
35
|
+
return 'iabConsentDialogOverlay' as const;
|
|
36
|
+
}
|
|
37
|
+
return variant === 'iab-banner'
|
|
38
|
+
? ('iabConsentBannerOverlay' as const)
|
|
39
|
+
: ('consentBannerOverlay' as const);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const testId = $derived.by(() => {
|
|
43
|
+
if (variant === 'dialog') {
|
|
44
|
+
return 'consent-dialog-overlay';
|
|
45
|
+
}
|
|
46
|
+
if (variant === 'iab-dialog') {
|
|
47
|
+
return 'iab-consent-dialog-overlay';
|
|
48
|
+
}
|
|
49
|
+
return variant === 'iab-banner'
|
|
50
|
+
? 'iab-consent-banner-overlay'
|
|
51
|
+
: 'consent-banner-overlay';
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const themeStyle = $derived(
|
|
55
|
+
resolveComponentStyles(
|
|
56
|
+
themeKey,
|
|
57
|
+
theme.theme,
|
|
58
|
+
{ baseClassName: styles.overlay },
|
|
59
|
+
theme.noStyle
|
|
60
|
+
)
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const className = $derived(
|
|
64
|
+
theme.noStyle
|
|
65
|
+
? themeStyle.className || ''
|
|
66
|
+
: `${themeStyle.className || ''} ${visible ? styles.overlayVisible : styles.overlayHidden}`
|
|
67
|
+
);
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<div
|
|
71
|
+
class={className}
|
|
72
|
+
style={themeStyle.style
|
|
73
|
+
? Object.entries(themeStyle.style)
|
|
74
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
75
|
+
.join(';')
|
|
76
|
+
: undefined}
|
|
77
|
+
data-testid={testId}
|
|
78
|
+
aria-hidden="true"
|
|
79
|
+
></div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
import { getConsentContext } from '../context.svelte';
|
|
5
|
+
import ConsentButton from './action-button.svelte';
|
|
6
|
+
|
|
7
|
+
const consent = getConsentContext();
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
children,
|
|
11
|
+
noStyle = true,
|
|
12
|
+
...restProps
|
|
13
|
+
}: {
|
|
14
|
+
children: Snippet;
|
|
15
|
+
noStyle?: boolean;
|
|
16
|
+
'data-testid'?: string;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
} = $props();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
{#if consent.state.hasConsentUi}
|
|
22
|
+
<ConsentButton
|
|
23
|
+
action="open-consent-dialog"
|
|
24
|
+
{noStyle}
|
|
25
|
+
data-testid="consent-dialog-link"
|
|
26
|
+
data-c15t-rights={consent.snapshot.policyRule.rights.join(' ')}
|
|
27
|
+
{...restProps}
|
|
28
|
+
>
|
|
29
|
+
{#if children}
|
|
30
|
+
{@render children()}
|
|
31
|
+
{/if}
|
|
32
|
+
</ConsentButton>
|
|
33
|
+
{/if}
|