refactor(consent-sdk): split ConsentManager + framework adapters under 500 LOC
Phase 4: extract config defaults, Google Consent Mode helper, and framework adapter internals into sibling files so every source file is under the hard cap. Public API surface preserved; all 135 tests green, tsup build + tsc typecheck clean. - core/ConsentManager 525 -> 467 LOC (extract config + google helpers) - react/index 511 LOC -> 199 LOC barrel + components/hooks/context - vue/index 511 LOC -> 32 LOC barrel + components/composables/context/plugin - angular/index 509 LOC -> 45 LOC barrel + interface/service/module/templates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* Vue consent components: ConsentProvider, ConsentGate, ConsentPlaceholder,
|
||||
* ConsentBanner.
|
||||
*
|
||||
* Phase 4: extracted from vue/index.ts.
|
||||
*/
|
||||
|
||||
import { computed, defineComponent, h, type PropType } from 'vue';
|
||||
import type { ConsentCategory, ConsentConfig } from '../types';
|
||||
import { provideConsent, useConsent } from './composables';
|
||||
|
||||
/**
|
||||
* ConsentProvider - Wrapper-Komponente.
|
||||
*/
|
||||
export const ConsentProvider = defineComponent({
|
||||
name: 'ConsentProvider',
|
||||
props: {
|
||||
config: {
|
||||
type: Object as PropType<ConsentConfig>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
provideConsent(props.config);
|
||||
return () => slots.default?.();
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* ConsentGate - Zeigt Inhalt nur bei Consent.
|
||||
*/
|
||||
export const ConsentGate = defineComponent({
|
||||
name: 'ConsentGate',
|
||||
props: {
|
||||
category: {
|
||||
type: String as PropType<ConsentCategory>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const { hasConsent, isLoading } = useConsent();
|
||||
|
||||
return () => {
|
||||
if (isLoading.value) {
|
||||
return slots.fallback?.() ?? null;
|
||||
}
|
||||
if (!hasConsent(props.category)) {
|
||||
return slots.placeholder?.() ?? null;
|
||||
}
|
||||
return slots.default?.();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* ConsentPlaceholder - Placeholder fuer blockierten Inhalt.
|
||||
*/
|
||||
export const ConsentPlaceholder = defineComponent({
|
||||
name: 'ConsentPlaceholder',
|
||||
props: {
|
||||
category: {
|
||||
type: String as PropType<ConsentCategory>,
|
||||
required: true,
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
buttonText: {
|
||||
type: String,
|
||||
default: 'Cookie-Einstellungen öffnen',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { showSettings } = useConsent();
|
||||
|
||||
const categoryNames: Record<ConsentCategory, string> = {
|
||||
essential: 'Essentielle Cookies',
|
||||
functional: 'Funktionale Cookies',
|
||||
analytics: 'Statistik-Cookies',
|
||||
marketing: 'Marketing-Cookies',
|
||||
social: 'Social Media-Cookies',
|
||||
};
|
||||
|
||||
const displayMessage = computed(() => {
|
||||
return (
|
||||
props.message ||
|
||||
`Dieser Inhalt erfordert ${categoryNames[props.category]}.`
|
||||
);
|
||||
});
|
||||
|
||||
return () =>
|
||||
h('div', { class: 'bp-consent-placeholder' }, [
|
||||
h('p', displayMessage.value),
|
||||
h(
|
||||
'button',
|
||||
{
|
||||
type: 'button',
|
||||
onClick: showSettings,
|
||||
},
|
||||
props.buttonText
|
||||
),
|
||||
]);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* ConsentBanner - Cookie-Banner Komponente (headless with default UI).
|
||||
*/
|
||||
export const ConsentBanner = defineComponent({
|
||||
name: 'ConsentBanner',
|
||||
setup(_, { slots }) {
|
||||
const {
|
||||
consent,
|
||||
isBannerVisible,
|
||||
needsConsent,
|
||||
acceptAll,
|
||||
rejectAll,
|
||||
saveSelection,
|
||||
showSettings,
|
||||
hideBanner,
|
||||
} = useConsent();
|
||||
|
||||
const slotProps = computed(() => ({
|
||||
isVisible: isBannerVisible.value,
|
||||
consent: consent.value,
|
||||
needsConsent: needsConsent.value,
|
||||
onAcceptAll: acceptAll,
|
||||
onRejectAll: rejectAll,
|
||||
onSaveSelection: saveSelection,
|
||||
onShowSettings: showSettings,
|
||||
onClose: hideBanner,
|
||||
}));
|
||||
|
||||
return () => {
|
||||
if (slots.default) {
|
||||
return slots.default(slotProps.value);
|
||||
}
|
||||
if (!isBannerVisible.value) {
|
||||
return null;
|
||||
}
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
class: 'bp-consent-banner',
|
||||
role: 'dialog',
|
||||
'aria-modal': 'true',
|
||||
'aria-label': 'Cookie-Einstellungen',
|
||||
},
|
||||
[
|
||||
h('div', { class: 'bp-consent-banner-content' }, [
|
||||
h('h2', 'Datenschutzeinstellungen'),
|
||||
h(
|
||||
'p',
|
||||
'Wir nutzen Cookies und ähnliche Technologien, um Ihnen ein optimales Nutzererlebnis zu bieten.'
|
||||
),
|
||||
h('div', { class: 'bp-consent-banner-actions' }, [
|
||||
h(
|
||||
'button',
|
||||
{
|
||||
type: 'button',
|
||||
class: 'bp-consent-btn bp-consent-btn-reject',
|
||||
onClick: rejectAll,
|
||||
},
|
||||
'Alle ablehnen'
|
||||
),
|
||||
h(
|
||||
'button',
|
||||
{
|
||||
type: 'button',
|
||||
class: 'bp-consent-btn bp-consent-btn-settings',
|
||||
onClick: showSettings,
|
||||
},
|
||||
'Einstellungen'
|
||||
),
|
||||
h(
|
||||
'button',
|
||||
{
|
||||
type: 'button',
|
||||
class: 'bp-consent-btn bp-consent-btn-accept',
|
||||
onClick: acceptAll,
|
||||
},
|
||||
'Alle akzeptieren'
|
||||
),
|
||||
]),
|
||||
]),
|
||||
]
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user