@consenti/ui 0.1.0 → 0.2.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/dist/vue.d.ts CHANGED
@@ -1,13 +1,56 @@
1
+ import * as vue from 'vue';
2
+
3
+ type NonEmptyArray<T> = [T, ...T[]];
4
+ type DeepPartial<T> = T extends Function ? T : T extends Array<infer InferredArrayType> ? Array<DeepPartial<InferredArrayType>> : T extends ReadonlyArray<infer InferredReadonlyArrayType> ? ReadonlyArray<DeepPartial<InferredReadonlyArrayType>> : T extends object ? {
5
+ [Key in keyof T]?: DeepPartial<T[Key]>;
6
+ } : T;
7
+
8
+ declare const COMPLIANCE_GROUP_IDS: readonly ["opt-in", "opt-out", "opt-out-strict", "opt-in-dpdpa", "opt-in-china", "opt-in-brazil", "general-privacy-consent", "notice-only"];
9
+
10
+ /**
11
+ * Compliance-related literal types, derived from the regulation/group ID data
12
+ * that lives in @consenti/utils (packages/utils/src/compliance.ts).
13
+ *
14
+ * This import is type-only and fully erased at compile time — @consenti/types
15
+ * has no runtime dependency on @consenti/utils. The actual data (COMPLIANCE_GROUPS,
16
+ * EMBEDDED_COMPLIANCE_MAP, COMPLIANCE_VALIDATION_RULES, GPC_OPTIONS, etc.) lives in
17
+ * @consenti/utils; import it from there.
18
+ *
19
+ * HOW TO ADD A NEW REGULATION OR COMPLIANCE GROUP: see the header comment in
20
+ * packages/utils/src/compliance.ts — these types auto-update from that data.
21
+ */
22
+
23
+ type ComplianceGroupId = typeof COMPLIANCE_GROUP_IDS[number];
24
+
25
+ interface ComplianceMapData {
26
+ version: string;
27
+ countries: Record<string, CountryComplianceEntry>;
28
+ }
29
+ interface CountryComplianceEntry {
30
+ complianceGroup: ComplianceGroupId;
31
+ default: ComplianceGroupId;
32
+ description: string;
33
+ overriddenRegions?: Record<string, {
34
+ complianceGroup: ComplianceGroupId;
35
+ description: string;
36
+ }>;
37
+ }
38
+
1
39
  type ConsentStatus = 'granted' | 'denied' | 'objected';
40
+ type ConsentAction = 'accept_all' | 'reject_all' | 'custom' | 'update';
2
41
  type ConsentValue = Record<string, ConsentStatus>;
3
42
  interface Cookie {
4
43
  id: string;
5
- type?: 'consent' | 'legitimate_interest';
44
+ legalBasis?: 'mandatory' | 'consent' | 'legitimate_interest';
45
+ /** @deprecated use legalBasis: 'mandatory' */
6
46
  mandatory?: boolean;
47
+ /** @deprecated use legalBasis */
48
+ type?: 'consent' | 'legitimate_interest';
7
49
  listenGpc?: boolean;
8
50
  expiry?: number;
9
51
  tcfVendorId?: number;
10
52
  tcfPurposes?: number[];
53
+ tcfSpecialFeatures?: number[];
11
54
  cpraCategory?: 'sale' | 'sharing' | 'sensitive';
12
55
  }
13
56
  type ButtonStyle = 'primary' | 'secondary' | 'text' | 'accent';
@@ -18,6 +61,7 @@ interface Button {
18
61
  action: ButtonAction;
19
62
  cookies?: string[] | '*' | '!';
20
63
  url?: string;
64
+ type?: string;
21
65
  }
22
66
  interface MainBanner {
23
67
  position: 'top' | 'bottom' | 'middle' | 'left-bottom' | 'right-bottom';
@@ -43,18 +87,13 @@ interface Category {
43
87
  };
44
88
  cookies: string[];
45
89
  }
46
- interface PreferenceModal {
90
+ interface PreferenceModal extends Omit<MainBanner, "position"> {
47
91
  position?: 'left' | 'right' | 'center';
48
- overlayOpacity?: number;
49
- showClose?: boolean;
50
- showLocaleSwitcher?: boolean;
51
- heading?: string;
52
- headingTag?: string;
53
92
  subheading?: string;
54
- htmlText?: string;
55
- buttons: Button[];
56
93
  categories: Category[];
57
94
  persistent?: boolean;
95
+ /** Screen width in px below which the modal expands to full screen. Default: 576. Set to 0 to disable. */
96
+ mobileFullScreenBreakpoint?: number;
58
97
  }
59
98
  interface DpdpaConfig {
60
99
  dataFiduciary: string;
@@ -63,6 +102,7 @@ interface DpdpaConfig {
63
102
  }
64
103
  interface ResolvedProfile {
65
104
  id: number;
105
+ profileUuid?: string;
66
106
  version: number;
67
107
  defaultLocale: string;
68
108
  locales?: string[];
@@ -73,6 +113,26 @@ interface ResolvedProfile {
73
113
  cookieSigningKey?: string;
74
114
  dpdpa?: DpdpaConfig;
75
115
  darkMode?: boolean;
116
+ gpcMode?: 'ignore' | 'honor' | 'strict';
117
+ complianceGroup?: string;
118
+ complianceConfig?: Record<string, string>;
119
+ }
120
+ type WidgetCountryResolverFn = () => Promise<{
121
+ country: string | null;
122
+ region: string | null;
123
+ confidence: number;
124
+ }>;
125
+ interface AgeGateWidgetConfig {
126
+ enabled: boolean;
127
+ minimumAge: number;
128
+ requireParentalConsent?: boolean;
129
+ }
130
+ interface ComplianceWidgetConfig {
131
+ type?: 'auto' | ComplianceGroupId | string;
132
+ geoDataProvider?: 'default' | WidgetCountryResolverFn;
133
+ autoComplianceMap?: 'default' | ComplianceMapData | 'auto';
134
+ complianceMapUrl?: string;
135
+ ageGate?: AgeGateWidgetConfig;
76
136
  }
77
137
  interface GtmConfig {
78
138
  containerId?: string;
@@ -88,6 +148,9 @@ interface ApiConfig {
88
148
  enabled?: boolean;
89
149
  baseUrl?: string;
90
150
  authToken?: string;
151
+ tenantId?: string;
152
+ complianceGroup?: string;
153
+ trustDomain?: boolean;
91
154
  }
92
155
  interface ThemeConfig {
93
156
  bgColor?: string;
@@ -109,35 +172,52 @@ interface ThemeConfig {
109
172
  accentTextColor?: string;
110
173
  }
111
174
  interface CoreConfig {
112
- profileId?: number;
175
+ tenantId?: string;
113
176
  autoHonorGPC?: boolean | 'strict';
114
177
  locale?: string;
115
178
  disableCssTemplate?: boolean;
116
- signCookies?: boolean;
117
179
  cookieSigningKey?: string;
118
180
  allowReceipt?: boolean;
119
181
  cookieDomains?: string;
120
182
  storage?: 'cookie' | 'localStorage';
121
183
  theme?: ThemeConfig;
122
- privacyPolicyUrl?: string;
123
- regulation?: 'gdpr' | 'ccpa' | 'cpra' | 'dpdpa' | 'uk-gdpr' | 'lgpd' | 'pipeda' | 'popia' | 'pdpa-th' | 'appi' | 'kvkk';
124
184
  userId?: string;
185
+ usePrebuiltProfiles?: 'all' | NonEmptyArray<ComplianceGroupId>;
186
+ cacheResolvedProfiles?: boolean;
187
+ console?: Array<'info' | 'log' | 'warning' | 'error'>;
125
188
  }
126
189
  interface ConsentiConfig {
127
190
  core: CoreConfig;
191
+ compliance?: ComplianceWidgetConfig;
128
192
  rootEl?: string | HTMLElement;
129
193
  darkMode?: boolean;
130
194
  autoInit?: boolean;
131
195
  api?: ApiConfig;
132
196
  utils?: UtilsConfig;
133
197
  plugins?: ConsentiPlugin[];
134
- profileOverride?: Partial<ResolvedProfile>;
198
+ profileOverride?: DeepPartial<ResolvedProfile>;
199
+ /** When true, suppresses the "Powered by Consenti" footer link in the banner and modal. */
200
+ hidePoweredBy?: boolean;
135
201
  }
202
+ type ConsentiEventName = 'bannerInitialized' | 'consenti:bannerInitialized' | 'bannerVisibility' | 'consenti:bannerVisibility' | 'modalVisibility' | 'consenti:modalVisibility' | 'consentBeingSubmitted' | 'consenti:consentBeingSubmitted' | 'consentSubmitted' | 'consenti:consentSubmitted';
136
203
  interface ConsentiWidgetAPI {
137
204
  hasConsent(): boolean;
138
205
  getConsent(): ConsentValue | null;
139
206
  getConsentDate(): Date | false;
140
207
  getGTMConsent(): Record<string, string> | null;
208
+ isCookieGranted(cookieId: string, requestValue?: boolean): boolean | ConsentStatus;
209
+ isCategoryGranted(categoryId: string, requestValue?: boolean): boolean | {
210
+ [cookieId: string]: ConsentStatus;
211
+ }[];
212
+ grantAll(onlyMandatory?: boolean): Promise<void>;
213
+ denyAll(includingMandatory?: boolean): Promise<void>;
214
+ on(event: ConsentiEventName, handler: (data: ConsentEvent) => void): void;
215
+ off(event: ConsentiEventName, handler: (data: ConsentEvent) => void): void;
216
+ version(): {
217
+ package: string;
218
+ profileVersion: number | null;
219
+ consentVersion: number;
220
+ };
141
221
  bannerVisibility(): 'main' | 'gpc' | false;
142
222
  modalVisibility(): 'preference' | false;
143
223
  getProfile(): ResolvedProfile | null;
@@ -152,6 +232,10 @@ interface ConsentiWidgetAPI {
152
232
  getBannerElement(): HTMLElement | null;
153
233
  getModalElement(): HTMLElement | null;
154
234
  switchLocale(locale: string): void;
235
+ setDarkMode(enable?: boolean): void;
236
+ setTheme(theme: Partial<ThemeConfig>): void;
237
+ setConfig(config: DeepPartial<ConsentiConfig>): void;
238
+ setProfile(override: DeepPartial<ResolvedProfile>): void;
155
239
  init(): Promise<void>;
156
240
  onReady(callback: () => void): void;
157
241
  destroy(): void;
@@ -165,6 +249,19 @@ declare abstract class ConsentiPlugin {
165
249
  onModalShow?(): void | Promise<void>;
166
250
  onModalHide?(): void | Promise<void>;
167
251
  }
252
+ interface ConsentEvent {
253
+ profileId?: number;
254
+ consent?: ConsentValue;
255
+ hasExistingConsent?: boolean;
256
+ show?: boolean;
257
+ action?: boolean;
258
+ consentAction?: ConsentAction;
259
+ consentId?: string;
260
+ pageUrl?: string;
261
+ apiResponse?: unknown;
262
+ fromBroadcast?: boolean;
263
+ gpcDetected?: boolean;
264
+ }
168
265
 
169
266
  /**
170
267
  * Main entry point for the Consenti widget.
@@ -176,7 +273,7 @@ declare abstract class ConsentiPlugin {
176
273
  * @example
177
274
  * ```ts
178
275
  * const widget = new ConsentiSetup({
179
- * core: { profileId: 0 },
276
+ * compliance: { type: 'opt-in' },
180
277
  * })
181
278
  * await widget.ready
182
279
  * console.log(widget.hasConsent())
@@ -188,6 +285,7 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
188
285
  private initialized;
189
286
  private initializing;
190
287
  private profile;
288
+ private resolvedBase;
191
289
  private consentStore;
192
290
  private eventBus;
193
291
  private banner;
@@ -201,6 +299,8 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
201
299
  private lastSignature;
202
300
  /** Tracks which banner variant is currently visible, or null when hidden. */
203
301
  private _bannerVariant;
302
+ /** Maps original handler functions to their DOM-wrapped listeners for on/off bookkeeping. */
303
+ private _eventHandlers;
204
304
  /**
205
305
  * Creates and initialises the consent widget.
206
306
  *
@@ -233,6 +333,8 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
233
333
  * @param invoke - Function that calls the desired hook method on a single plugin.
234
334
  */
235
335
  private callPluginHook;
336
+ private _buildGrantAllConsent;
337
+ private _buildDenyAllConsent;
236
338
  private buildHandlers;
237
339
  /**
238
340
  * Classifies a consent submission as `accept_all`, `reject_all`, `custom`, or `update`.
@@ -381,6 +483,93 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
381
483
  * @param locale - BCP 47 locale code to switch to (e.g. `'fr'`, `'de-AT'`).
382
484
  */
383
485
  switchLocale(locale: string): void;
486
+ /**
487
+ * Returns `true` if the named cookie's consent is `'granted'`.
488
+ * When `requestValue` is `true`, returns the raw `ConsentStatus` string instead of a boolean,
489
+ * or `false` if the cookie is not in the consent map.
490
+ */
491
+ isCookieGranted(cookieId: string, requestValue?: boolean): boolean | 'granted' | 'denied' | 'objected';
492
+ /**
493
+ * Checks consent for all cookies belonging to the given category.
494
+ *
495
+ * With `requestValue = false` (default): returns `true` only when every cookie in the
496
+ * category is `'granted'`, `false` otherwise.
497
+ *
498
+ * With `requestValue = true`: returns an array of one-key records — one per cookie in the
499
+ * category — e.g. `[{ analytics: 'granted' }, { pixel: 'denied' }]`.
500
+ *
501
+ * Returns `false` / `[]` if the category is not found or the widget is not yet initialized.
502
+ */
503
+ isCategoryGranted(categoryId: string, requestValue?: boolean): boolean | {
504
+ [cookieId: string]: 'granted' | 'denied' | 'objected';
505
+ }[];
506
+ /**
507
+ * Programmatically accepts cookies and hides the banner.
508
+ *
509
+ * @param onlyMandatory - When `true`, only mandatory cookies are granted and all others
510
+ * are set to `'denied'`. Defaults to `false` (grant everything).
511
+ */
512
+ grantAll(onlyMandatory?: boolean): Promise<void>;
513
+ /**
514
+ * Programmatically denies cookies and hides the banner.
515
+ *
516
+ * @param includingMandatory - When `true`, mandatory cookies are also denied. Defaults to
517
+ * `false` (mandatory cookies remain `'granted'`). Passing `true`
518
+ * logs a warning — ensure this is intentional.
519
+ */
520
+ denyAll(includingMandatory?: boolean): Promise<void>;
521
+ /**
522
+ * Subscribes to a Consenti widget event. The `consenti:` prefix is optional —
523
+ * both `'consentSubmitted'` and `'consenti:consentSubmitted'` are accepted.
524
+ *
525
+ * The same handler reference must be passed to `off()` to unsubscribe.
526
+ *
527
+ * @example
528
+ * ```ts
529
+ * const handler = (data) => console.log(data)
530
+ * widget.on('consentSubmitted', handler)
531
+ * // later:
532
+ * widget.off('consentSubmitted', handler)
533
+ * ```
534
+ */
535
+ on(event: ConsentiEventName, handler: (data: ConsentEvent) => void): void;
536
+ /**
537
+ * Removes a previously registered event handler. The same function reference passed to
538
+ * `on()` must be used here.
539
+ */
540
+ off(event: ConsentiEventName, handler: (data: ConsentEvent) => void): void;
541
+ /**
542
+ * Returns the current version of the package and the active profile/consent versions.
543
+ * Useful for debugging and support diagnostics.
544
+ */
545
+ version(): {
546
+ package: string;
547
+ profileVersion: number | null;
548
+ consentVersion: number;
549
+ };
550
+ /**
551
+ * Toggles or sets dark mode at runtime without re-initialising the widget.
552
+ * When `enable` is omitted, the current dark mode state is toggled.
553
+ */
554
+ setDarkMode(enable?: boolean): void;
555
+ /**
556
+ * Applies partial theme token overrides at runtime, merging them into the current theme.
557
+ * CSS custom properties on the root element are updated immediately.
558
+ */
559
+ setTheme(theme: Partial<ThemeConfig>): void;
560
+ /**
561
+ * Deep-merges a partial config into the current widget config.
562
+ * Theme and dark mode side-effects are re-applied immediately.
563
+ * Changes to locale or profile require an explicit `switchLocale()` or `init()` call.
564
+ */
565
+ setConfig(config: DeepPartial<ConsentiConfig>): void;
566
+ /**
567
+ * Merges a partial profile override into the current profile and re-renders any visible UI.
568
+ * Does not make a network request — the resolved base profile from the last `init()` is reused.
569
+ *
570
+ * No-op before `init()` completes (while `resolvedBase` is null).
571
+ */
572
+ setProfile(override: DeepPartial<ResolvedProfile>): void;
384
573
  /**
385
574
  * Destroys the widget — removes all DOM elements, disconnects the BroadcastChannel,
386
575
  * and calls `destroy()` on all registered plugins.
@@ -390,34 +579,6 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
390
579
  destroy(): void;
391
580
  }
392
581
 
393
- /**
394
- * Vue 3 composable integration for `@consenti/ui`.
395
- *
396
- * Import from the `@consenti/ui/vue` subpath to keep this module
397
- * tree-shaken out of vanilla JS or React bundles.
398
- *
399
- * Intended for **Nuxt 3** and any Vue 3 project where you manage the `ConsentiSetup`
400
- * instance yourself (typically in a `.client.ts` plugin) and want `useConsent()`
401
- * to be reactive in components.
402
- *
403
- * @example
404
- * ```ts
405
- * // plugins/consenti.client.ts (Nuxt 3)
406
- * import { ConsentiSetup } from '@consenti/ui'
407
- * import { setConsentiWidget } from '@consenti/ui/vue'
408
- *
409
- * export default defineNuxtPlugin(() => {
410
- * const widget = new ConsentiSetup({ core: { profileId: 0 } })
411
- * setConsentiWidget(widget)
412
- * })
413
- *
414
- * // Any component
415
- * import { useConsent } from '@consenti/ui/vue'
416
- *
417
- * const { hasConsent, submitConsent } = useConsent()
418
- * ```
419
- */
420
-
421
582
  /**
422
583
  * Registers the active `ConsentiSetup` instance so `useConsent()` can read from it.
423
584
  * Call this once after creating your widget, typically in a `.client.ts` Nuxt plugin.
@@ -426,21 +587,51 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
426
587
  */
427
588
  declare function setConsentiWidget(widget: ConsentiSetup): void;
428
589
  /**
429
- * Vue 3 composable that exposes consent state and triggers reactivity on consent changes.
590
+ * Vue 3 composable that exposes consent state, banner/modal visibility, and widget actions.
430
591
  *
431
- * Listens to `consenti:consentSubmitted` on `window` via `onMounted` / `onUnmounted`
432
- * and increments a `ref(tick)` counter. Reactive getters read `tick.value` to register
433
- * a Vue dependency so components re-render when consent changes.
592
+ * State values (`hasConsent`, `consent`, `consentDate`, `bannerVisible`, `modalVisible`) are
593
+ * Vue `Ref`s — they are reactive in templates and `watch`/`computed` without calling `.value`
594
+ * in the template (Vue auto-unwraps top-level refs).
434
595
  *
435
- * Returns SSR-safe fallback values during Nuxt server render.
596
+ * Event listeners are registered in `onMounted` and removed in `onUnmounted`, so this
597
+ * composable is safe to call in components that render on the server (Nuxt SSR): the refs
598
+ * simply hold their initial values (`false` / `null`) during SSR and hydrate correctly.
436
599
  *
437
- * @returns An object with `hasConsent`, `getConsent`, `submitConsent`, and `getConsentDate`.
600
+ * @returns Reactive refs for consent state and plain functions for widget actions.
438
601
  */
439
602
  declare function useConsent(): {
440
- hasConsent: () => boolean;
441
- getConsent: () => ConsentValue | null;
442
- submitConsent: (_consent: Partial<ConsentValue>) => Promise<void>;
443
- getConsentDate: () => Date | false;
603
+ /** Reactive — `true` once the visitor has saved a valid consent record. */
604
+ hasConsent: vue.Ref<boolean, boolean>;
605
+ /** Reactive — the stored consent map (`Record<cookieId, status>`), or `null`. */
606
+ consent: vue.Ref<ConsentValue | null, ConsentValue | null>;
607
+ /** Reactive — `Date` of the last consent submission, or `false`. */
608
+ consentDate: vue.Ref<false | Date, false | Date>;
609
+ /** Reactive — `'main'`, `'gpc'`, or `false` (banner hidden). */
610
+ bannerVisible: vue.Ref<false | "main" | "gpc", false | "main" | "gpc">;
611
+ /** Reactive — `'preference'` or `false` (modal hidden). */
612
+ modalVisible: vue.Ref<false | "preference", false | "preference">;
613
+ /** Shows the consent banner. Pass `true` to force the GPC variant. */
614
+ showBanner: (gpc?: boolean) => void | undefined;
615
+ /** Hides the consent banner. */
616
+ hideBanner: () => void | undefined;
617
+ /** Opens the preference modal. */
618
+ showModal: () => void | undefined;
619
+ /** Closes the preference modal. */
620
+ hideModal: () => void | undefined;
621
+ /** Grants all non-mandatory cookies. Pass `true` to grant only mandatory ones and deny the rest. */
622
+ grantAll: (onlyMandatory?: boolean) => Promise<void>;
623
+ /** Denies all non-mandatory cookies. Pass `true` to deny mandatory ones too (use with care). */
624
+ denyAll: (includingMandatory?: boolean) => Promise<void>;
625
+ /** Saves the given partial consent map. */
626
+ submitConsent: (c: Partial<ConsentValue>) => Promise<void>;
627
+ /** Deletes the current consent record and re-shows the banner. */
628
+ reConsent: () => Promise<void>;
629
+ /** Returns `true` if the given cookie ID is `'granted'`. */
630
+ isCookieGranted: (id: string) => boolean;
631
+ /** Returns `true` if every cookie in the given category is `'granted'`. */
632
+ isCategoryGranted: (id: string) => boolean;
633
+ /** Switches the active locale and re-renders the banner and modal. */
634
+ switchLocale: (locale: string) => void | undefined;
444
635
  };
445
636
 
446
637
  export { setConsentiWidget, useConsent };
package/dist/vue.js CHANGED
@@ -1,73 +1,2 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/vue.ts
21
- var vue_exports = {};
22
- __export(vue_exports, {
23
- setConsentiWidget: () => setConsentiWidget,
24
- useConsent: () => useConsent
25
- });
26
- module.exports = __toCommonJS(vue_exports);
27
- var import_vue = require("vue");
28
- var _widget = null;
29
- function setConsentiWidget(widget) {
30
- _widget = widget;
31
- }
32
- function useConsent() {
33
- const isServer = typeof window === "undefined";
34
- const tick = (0, import_vue.ref)(0);
35
- const handler = () => {
36
- tick.value++;
37
- };
38
- (0, import_vue.onMounted)(() => {
39
- window.addEventListener("consenti:consentSubmitted", handler);
40
- });
41
- (0, import_vue.onUnmounted)(() => {
42
- window.removeEventListener("consenti:consentSubmitted", handler);
43
- });
44
- if (isServer) {
45
- return {
46
- hasConsent: () => false,
47
- getConsent: () => null,
48
- submitConsent: async (_consent) => {
49
- },
50
- getConsentDate: () => false
51
- };
52
- }
53
- return {
54
- /** Returns `true` if the visitor has saved consent. Reactive — re-evaluated on consent change. */
55
- hasConsent: () => {
56
- void tick.value;
57
- return _widget?.hasConsent() ?? false;
58
- },
59
- /** Returns the stored consent map, or `null`. Reactive. */
60
- getConsent: () => {
61
- void tick.value;
62
- return _widget?.getConsent() ?? null;
63
- },
64
- /** Saves the given partial consent map. Missing keys default to `'denied'`. */
65
- submitConsent: (consent) => _widget?.submitConsent(consent) ?? Promise.resolve(),
66
- /** Returns the `Date` of last consent submission, or `false`. Reactive. */
67
- getConsentDate: () => {
68
- void tick.value;
69
- return _widget?.getConsentDate() ?? false;
70
- }
71
- };
72
- }
1
+ "use strict";var r=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var w=(o,t)=>{for(var a in t)r(o,a,{get:t[a],enumerable:!0})},b=(o,t,a,l)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of C(t))!m.call(o,i)&&i!==a&&r(o,i,{get:()=>t[i],enumerable:!(l=f(t,i))||l.enumerable});return o};var v=o=>b(r({},"__esModule",{value:!0}),o);var g={};w(g,{setConsentiWidget:()=>p,useConsent:()=>y});module.exports=v(g);var s=require("vue"),e=null;function p(o){e=o}function y(){let o=(0,s.ref)(e?.hasConsent()??!1),t=(0,s.ref)(e?.getConsent()??null),a=(0,s.ref)(e?.getConsentDate()??!1),l=(0,s.ref)(!1),i=(0,s.ref)(!1),d=()=>{o.value=e?.hasConsent()??!1,t.value=e?.getConsent()??null,a.value=e?.getConsentDate()??!1},u=()=>{l.value=e?.bannerVisibility()??!1},c=()=>{i.value=e?.modalVisibility()??!1};return(0,s.onMounted)(()=>{typeof window>"u"||(window.addEventListener("consenti:consentSubmitted",d),window.addEventListener("consenti:bannerVisibility",u),window.addEventListener("consenti:modalVisibility",c))}),(0,s.onUnmounted)(()=>{typeof window>"u"||(window.removeEventListener("consenti:consentSubmitted",d),window.removeEventListener("consenti:bannerVisibility",u),window.removeEventListener("consenti:modalVisibility",c))}),{hasConsent:o,consent:t,consentDate:a,bannerVisible:l,modalVisible:i,showBanner:n=>e?.showBanner(n),hideBanner:()=>e?.hideBanner(),showModal:()=>e?.showModal(),hideModal:()=>e?.hideModal(),grantAll:n=>e?.grantAll(n)??Promise.resolve(),denyAll:n=>e?.denyAll(n)??Promise.resolve(),submitConsent:n=>e?.submitConsent(n)??Promise.resolve(),reConsent:()=>e?.reConsent()??Promise.resolve(),isCookieGranted:n=>e?.isCookieGranted(n)??!1,isCategoryGranted:n=>e?.isCategoryGranted(n)??!1,switchLocale:n=>e?.switchLocale(n)}}
73
2
  //# sourceMappingURL=vue.js.map
package/dist/vue.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/vue.ts"],"sourcesContent":["/**\n * Vue 3 composable integration for `@consenti/ui`.\n *\n * Import from the `@consenti/ui/vue` subpath to keep this module\n * tree-shaken out of vanilla JS or React bundles.\n *\n * Intended for **Nuxt 3** and any Vue 3 project where you manage the `ConsentiSetup`\n * instance yourself (typically in a `.client.ts` plugin) and want `useConsent()`\n * to be reactive in components.\n *\n * @example\n * ```ts\n * // plugins/consenti.client.ts (Nuxt 3)\n * import { ConsentiSetup } from '@consenti/ui'\n * import { setConsentiWidget } from '@consenti/ui/vue'\n *\n * export default defineNuxtPlugin(() => {\n * const widget = new ConsentiSetup({ core: { profileId: 0 } })\n * setConsentiWidget(widget)\n * })\n *\n * // Any component\n * import { useConsent } from '@consenti/ui/vue'\n *\n * const { hasConsent, submitConsent } = useConsent()\n * ```\n */\n\nimport { ref, onMounted, onUnmounted } from 'vue'\nimport type { ConsentValue } from './types'\nimport type { ConsentiSetup } from './core/consenti-setup'\n\n/**\n * Module-level singleton — the active `ConsentiSetup` instance.\n * Using a module-level variable (rather than `provide`/`inject`) keeps the integration\n * zero-configuration: no wrapper component is required.\n */\nlet _widget: ConsentiSetup | null = null\n\n/**\n * Registers the active `ConsentiSetup` instance so `useConsent()` can read from it.\n * Call this once after creating your widget, typically in a `.client.ts` Nuxt plugin.\n *\n * @param widget - The `ConsentiSetup` instance to register.\n */\nexport function setConsentiWidget(widget: ConsentiSetup): void {\n _widget = widget\n}\n\n/**\n * Vue 3 composable that exposes consent state and triggers reactivity on consent changes.\n *\n * Listens to `consenti:consentSubmitted` on `window` via `onMounted` / `onUnmounted`\n * and increments a `ref(tick)` counter. Reactive getters read `tick.value` to register\n * a Vue dependency so components re-render when consent changes.\n *\n * Returns SSR-safe fallback values during Nuxt server render.\n *\n * @returns An object with `hasConsent`, `getConsent`, `submitConsent`, and `getConsentDate`.\n */\nexport function useConsent() {\n const isServer = typeof window === 'undefined'\n\n const tick = ref(0)\n const handler = () => { tick.value++ }\n\n onMounted(() => {\n window.addEventListener('consenti:consentSubmitted', handler)\n })\n\n onUnmounted(() => {\n window.removeEventListener('consenti:consentSubmitted', handler)\n })\n\n if (isServer) {\n return {\n hasConsent: () => false as boolean,\n getConsent: () => null as ConsentValue | null,\n submitConsent: async (_consent: Partial<ConsentValue>) => {},\n getConsentDate: () => false as Date | false,\n }\n }\n\n return {\n /** Returns `true` if the visitor has saved consent. Reactive — re-evaluated on consent change. */\n hasConsent: () => {\n void tick.value // registers Vue dependency\n return _widget?.hasConsent() ?? false\n },\n /** Returns the stored consent map, or `null`. Reactive. */\n getConsent: () => {\n void tick.value\n return _widget?.getConsent() ?? null\n },\n /** Saves the given partial consent map. Missing keys default to `'denied'`. */\n submitConsent: (consent: Partial<ConsentValue>) =>\n _widget?.submitConsent(consent) ?? Promise.resolve(),\n /** Returns the `Date` of last consent submission, or `false`. Reactive. */\n getConsentDate: () => {\n void tick.value\n return _widget?.getConsentDate() ?? false\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BA,iBAA4C;AAS5C,IAAI,UAAgC;AAQ7B,SAAS,kBAAkB,QAA6B;AAC7D,YAAU;AACZ;AAaO,SAAS,aAAa;AAC3B,QAAM,WAAW,OAAO,WAAW;AAEnC,QAAM,WAAO,gBAAI,CAAC;AAClB,QAAM,UAAU,MAAM;AAAE,SAAK;AAAA,EAAQ;AAErC,4BAAU,MAAM;AACd,WAAO,iBAAiB,6BAA6B,OAAO;AAAA,EAC9D,CAAC;AAED,8BAAY,MAAM;AAChB,WAAO,oBAAoB,6BAA6B,OAAO;AAAA,EACjE,CAAC;AAED,MAAI,UAAU;AACZ,WAAO;AAAA,MACL,YAAY,MAAM;AAAA,MAClB,YAAY,MAAM;AAAA,MAClB,eAAe,OAAO,aAAoC;AAAA,MAAC;AAAA,MAC3D,gBAAgB,MAAM;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AAAA;AAAA,IAEL,YAAY,MAAM;AAChB,WAAK,KAAK;AACV,aAAO,SAAS,WAAW,KAAK;AAAA,IAClC;AAAA;AAAA,IAEA,YAAY,MAAM;AAChB,WAAK,KAAK;AACV,aAAO,SAAS,WAAW,KAAK;AAAA,IAClC;AAAA;AAAA,IAEA,eAAe,CAAC,YACd,SAAS,cAAc,OAAO,KAAK,QAAQ,QAAQ;AAAA;AAAA,IAErD,gBAAgB,MAAM;AACpB,WAAK,KAAK;AACV,aAAO,SAAS,eAAe,KAAK;AAAA,IACtC;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/vue.ts"],"sourcesContent":["/**\n * Vue 3 composable integration for `@consenti/ui`.\n *\n * Import from the `@consenti/ui/vue` subpath to keep this module\n * tree-shaken out of vanilla JS or React bundles.\n *\n * Intended for **Nuxt 3** and any Vue 3 project where you manage the `ConsentiSetup`\n * instance yourself (typically in a `.client.ts` plugin) and want `useConsent()`\n * to be reactive in components.\n *\n * @example\n * ```ts\n * // plugins/consenti.client.ts (Nuxt 3)\n * import { ConsentiSetup } from '@consenti/ui'\n * import { setConsentiWidget } from '@consenti/ui/vue'\n *\n * export default defineNuxtPlugin(() => {\n * const widget = new ConsentiSetup({\n * api: { enabled: true, baseUrl: useRuntimeConfig().public.apiUrl },\n * })\n * setConsentiWidget(widget)\n * })\n *\n * // Any component\n * import { useConsent } from '@consenti/ui/vue'\n *\n * const { hasConsent, consent, showModal } = useConsent()\n * // hasConsent, consent, bannerVisible, modalVisible are Refs — reactive in templates\n * ```\n */\n\nimport { ref, onMounted, onUnmounted } from 'vue'\nimport type { ConsentValue } from './types'\nimport type { ConsentiSetup } from './core/consenti-setup'\n\n/**\n * Module-level singleton — the active `ConsentiSetup` instance.\n * Using a module-level variable (rather than `provide`/`inject`) keeps the integration\n * zero-configuration: no wrapper component is required.\n */\nlet _widget: ConsentiSetup | null = null\n\n/**\n * Registers the active `ConsentiSetup` instance so `useConsent()` can read from it.\n * Call this once after creating your widget, typically in a `.client.ts` Nuxt plugin.\n *\n * @param widget - The `ConsentiSetup` instance to register.\n */\nexport function setConsentiWidget(widget: ConsentiSetup): void {\n _widget = widget\n}\n\n/**\n * Vue 3 composable that exposes consent state, banner/modal visibility, and widget actions.\n *\n * State values (`hasConsent`, `consent`, `consentDate`, `bannerVisible`, `modalVisible`) are\n * Vue `Ref`s — they are reactive in templates and `watch`/`computed` without calling `.value`\n * in the template (Vue auto-unwraps top-level refs).\n *\n * Event listeners are registered in `onMounted` and removed in `onUnmounted`, so this\n * composable is safe to call in components that render on the server (Nuxt SSR): the refs\n * simply hold their initial values (`false` / `null`) during SSR and hydrate correctly.\n *\n * @returns Reactive refs for consent state and plain functions for widget actions.\n */\nexport function useConsent() {\n const hasConsent = ref<boolean>(_widget?.hasConsent() ?? false)\n const consent = ref<ConsentValue | null>(_widget?.getConsent() ?? null)\n const consentDate = ref<Date | false>(_widget?.getConsentDate() ?? false)\n const bannerVisible = ref<'main' | 'gpc' | false>(false)\n const modalVisible = ref<'preference' | false>(false)\n\n const onConsent = () => {\n hasConsent.value = _widget?.hasConsent() ?? false\n consent.value = _widget?.getConsent() ?? null\n consentDate.value = _widget?.getConsentDate() ?? false\n }\n const onBanner = () => { bannerVisible.value = _widget?.bannerVisibility() ?? false }\n const onModal = () => { modalVisible.value = _widget?.modalVisibility() ?? false }\n\n onMounted(() => {\n if (typeof window === 'undefined') return\n window.addEventListener('consenti:consentSubmitted', onConsent)\n window.addEventListener('consenti:bannerVisibility', onBanner)\n window.addEventListener('consenti:modalVisibility', onModal)\n })\n\n onUnmounted(() => {\n if (typeof window === 'undefined') return\n window.removeEventListener('consenti:consentSubmitted', onConsent)\n window.removeEventListener('consenti:bannerVisibility', onBanner)\n window.removeEventListener('consenti:modalVisibility', onModal)\n })\n\n return {\n /** Reactive — `true` once the visitor has saved a valid consent record. */\n hasConsent,\n /** Reactive — the stored consent map (`Record<cookieId, status>`), or `null`. */\n consent,\n /** Reactive — `Date` of the last consent submission, or `false`. */\n consentDate,\n /** Reactive — `'main'`, `'gpc'`, or `false` (banner hidden). */\n bannerVisible,\n /** Reactive — `'preference'` or `false` (modal hidden). */\n modalVisible,\n\n /** Shows the consent banner. Pass `true` to force the GPC variant. */\n showBanner: (gpc?: boolean) => _widget?.showBanner(gpc),\n /** Hides the consent banner. */\n hideBanner: () => _widget?.hideBanner(),\n /** Opens the preference modal. */\n showModal: () => _widget?.showModal(),\n /** Closes the preference modal. */\n hideModal: () => _widget?.hideModal(),\n\n /** Grants all non-mandatory cookies. Pass `true` to grant only mandatory ones and deny the rest. */\n grantAll: (onlyMandatory?: boolean) => _widget?.grantAll(onlyMandatory) ?? Promise.resolve(),\n /** Denies all non-mandatory cookies. Pass `true` to deny mandatory ones too (use with care). */\n denyAll: (includingMandatory?: boolean) => _widget?.denyAll(includingMandatory) ?? Promise.resolve(),\n /** Saves the given partial consent map. */\n submitConsent: (c: Partial<ConsentValue>) => _widget?.submitConsent(c) ?? Promise.resolve(),\n /** Deletes the current consent record and re-shows the banner. */\n reConsent: () => _widget?.reConsent() ?? Promise.resolve(),\n\n /** Returns `true` if the given cookie ID is `'granted'`. */\n isCookieGranted: (id: string) => (_widget?.isCookieGranted(id) ?? false) as boolean,\n /** Returns `true` if every cookie in the given category is `'granted'`. */\n isCategoryGranted: (id: string) => (_widget?.isCategoryGranted(id) ?? false) as boolean,\n /** Switches the active locale and re-renders the banner and modal. */\n switchLocale: (locale: string) => _widget?.switchLocale(locale),\n }\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,uBAAAE,EAAA,eAAAC,IAAA,eAAAC,EAAAJ,GA+BA,IAAAK,EAA4C,eASxCC,EAAgC,KAQ7B,SAASJ,EAAkBK,EAA6B,CAC7DD,EAAUC,CACZ,CAeO,SAASJ,GAAa,CAC3B,IAAMK,KAAe,OAAaF,GAAS,WAAW,GAAK,EAAK,EAC1DG,KAAe,OAAyBH,GAAS,WAAW,GAAK,IAAI,EACrEI,KAAe,OAAkBJ,GAAS,eAAe,GAAK,EAAK,EACnEK,KAAgB,OAA4B,EAAK,EACjDC,KAAgB,OAA0B,EAAK,EAE/CC,EAAY,IAAM,CACtBL,EAAW,MAASF,GAAS,WAAW,GAAK,GAC7CG,EAAQ,MAAYH,GAAS,WAAW,GAAK,KAC7CI,EAAY,MAAQJ,GAAS,eAAe,GAAK,EACnD,EACMQ,EAAW,IAAM,CAAEH,EAAc,MAAQL,GAAS,iBAAiB,GAAK,EAAM,EAC9ES,EAAW,IAAM,CAAEH,EAAa,MAASN,GAAS,gBAAgB,GAAK,EAAM,EAEnF,sBAAU,IAAM,CACV,OAAO,OAAW,MACtB,OAAO,iBAAiB,4BAA6BO,CAAS,EAC9D,OAAO,iBAAiB,4BAA8BC,CAAQ,EAC9D,OAAO,iBAAiB,2BAA8BC,CAAO,EAC/D,CAAC,KAED,eAAY,IAAM,CACZ,OAAO,OAAW,MACtB,OAAO,oBAAoB,4BAA6BF,CAAS,EACjE,OAAO,oBAAoB,4BAA8BC,CAAQ,EACjE,OAAO,oBAAoB,2BAA8BC,CAAO,EAClE,CAAC,EAEM,CAEL,WAAAP,EAEA,QAAAC,EAEA,YAAAC,EAEA,cAAAC,EAEA,aAAAC,EAGA,WAAaI,GAAkBV,GAAS,WAAWU,CAAG,EAEtD,WAAY,IAAMV,GAAS,WAAW,EAEtC,UAAW,IAAMA,GAAS,UAAU,EAEpC,UAAW,IAAMA,GAAS,UAAU,EAGpC,SAAWW,GAA4BX,GAAS,SAASW,CAAa,GAAK,QAAQ,QAAQ,EAE3F,QAAUC,GAAiCZ,GAAS,QAAQY,CAAkB,GAAK,QAAQ,QAAQ,EAEnG,cAAgBC,GAA6Bb,GAAS,cAAca,CAAC,GAAK,QAAQ,QAAQ,EAE1F,UAAW,IAAMb,GAAS,UAAU,GAAK,QAAQ,QAAQ,EAGzD,gBAAkBc,GAAgBd,GAAS,gBAAgBc,CAAE,GAAK,GAElE,kBAAoBA,GAAgBd,GAAS,kBAAkBc,CAAE,GAAK,GAEtE,aAAeC,GAAmBf,GAAS,aAAae,CAAM,CAChE,CACF","names":["vue_exports","__export","setConsentiWidget","useConsent","__toCommonJS","import_vue","_widget","widget","hasConsent","consent","consentDate","bannerVisible","modalVisible","onConsent","onBanner","onModal","gpc","onlyMandatory","includingMandatory","c","id","locale"]}
package/dist/vue.mjs CHANGED
@@ -1,52 +1,2 @@
1
- // src/vue.ts
2
- import { ref, onMounted, onUnmounted } from "vue";
3
- var _widget = null;
4
- function setConsentiWidget(widget) {
5
- _widget = widget;
6
- }
7
- function useConsent() {
8
- const isServer = typeof window === "undefined";
9
- const tick = ref(0);
10
- const handler = () => {
11
- tick.value++;
12
- };
13
- onMounted(() => {
14
- window.addEventListener("consenti:consentSubmitted", handler);
15
- });
16
- onUnmounted(() => {
17
- window.removeEventListener("consenti:consentSubmitted", handler);
18
- });
19
- if (isServer) {
20
- return {
21
- hasConsent: () => false,
22
- getConsent: () => null,
23
- submitConsent: async (_consent) => {
24
- },
25
- getConsentDate: () => false
26
- };
27
- }
28
- return {
29
- /** Returns `true` if the visitor has saved consent. Reactive — re-evaluated on consent change. */
30
- hasConsent: () => {
31
- void tick.value;
32
- return _widget?.hasConsent() ?? false;
33
- },
34
- /** Returns the stored consent map, or `null`. Reactive. */
35
- getConsent: () => {
36
- void tick.value;
37
- return _widget?.getConsent() ?? null;
38
- },
39
- /** Saves the given partial consent map. Missing keys default to `'denied'`. */
40
- submitConsent: (consent) => _widget?.submitConsent(consent) ?? Promise.resolve(),
41
- /** Returns the `Date` of last consent submission, or `false`. Reactive. */
42
- getConsentDate: () => {
43
- void tick.value;
44
- return _widget?.getConsentDate() ?? false;
45
- }
46
- };
47
- }
48
- export {
49
- setConsentiWidget,
50
- useConsent
51
- };
1
+ import{ref as o,onMounted as c,onUnmounted as f}from"vue";var e=null;function m(t){e=t}function w(){let t=o(e?.hasConsent()??!1),s=o(e?.getConsent()??null),i=o(e?.getConsentDate()??!1),a=o(!1),l=o(!1),r=()=>{t.value=e?.hasConsent()??!1,s.value=e?.getConsent()??null,i.value=e?.getConsentDate()??!1},d=()=>{a.value=e?.bannerVisibility()??!1},u=()=>{l.value=e?.modalVisibility()??!1};return c(()=>{typeof window>"u"||(window.addEventListener("consenti:consentSubmitted",r),window.addEventListener("consenti:bannerVisibility",d),window.addEventListener("consenti:modalVisibility",u))}),f(()=>{typeof window>"u"||(window.removeEventListener("consenti:consentSubmitted",r),window.removeEventListener("consenti:bannerVisibility",d),window.removeEventListener("consenti:modalVisibility",u))}),{hasConsent:t,consent:s,consentDate:i,bannerVisible:a,modalVisible:l,showBanner:n=>e?.showBanner(n),hideBanner:()=>e?.hideBanner(),showModal:()=>e?.showModal(),hideModal:()=>e?.hideModal(),grantAll:n=>e?.grantAll(n)??Promise.resolve(),denyAll:n=>e?.denyAll(n)??Promise.resolve(),submitConsent:n=>e?.submitConsent(n)??Promise.resolve(),reConsent:()=>e?.reConsent()??Promise.resolve(),isCookieGranted:n=>e?.isCookieGranted(n)??!1,isCategoryGranted:n=>e?.isCategoryGranted(n)??!1,switchLocale:n=>e?.switchLocale(n)}}export{m as setConsentiWidget,w as useConsent};
52
2
  //# sourceMappingURL=vue.mjs.map