@tickboxhq/vue 0.0.10 → 0.0.11

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/index.d.ts CHANGED
@@ -24,6 +24,30 @@ declare const ConsentBanner: vue.DefineComponent<{}, () => vue.VNode<vue.Rendere
24
24
 
25
25
  declare const ConsentStoreKey: InjectionKey<ConsentStore>;
26
26
 
27
+ /**
28
+ * Headless notice card. Renders nothing while the store is hydrating
29
+ * (`!ready`) or when there's nothing to notify about (`!noticeOpen`).
30
+ *
31
+ * Use this for sites that have only `notice`-mode categories (e.g. UK DUAA
32
+ * analytics like Plausible / GoatCounter). For sites with any `consent`-mode
33
+ * category, use `<ConsentBanner>` instead — the banner already covers
34
+ * notice-mode categories in its list, and `noticeOpen` will stay false.
35
+ *
36
+ * @example
37
+ * ```vue
38
+ * <ConsentNotice v-slot="{ save, deny }">
39
+ * <div class="toast">
40
+ * <p>We use privacy-friendly analytics.</p>
41
+ * <button @click="() => { deny('analytics'); save() }">Opt out</button>
42
+ * <button @click="save">Got it</button>
43
+ * </div>
44
+ * </ConsentNotice>
45
+ * ```
46
+ */
47
+ declare const ConsentNotice: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
48
+ [key: string]: any;
49
+ }>[] | null | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
50
+
27
51
  declare const ConsentProvider: vue.DefineComponent<vue.ExtractPropTypes<{
28
52
  config: {
29
53
  type: PropType<ConsentConfig>;
@@ -60,6 +84,7 @@ declare const ConsentProvider: vue.DefineComponent<vue.ExtractPropTypes<{
60
84
  type ConsentApi = {
61
85
  ready: ComputedRef<boolean>;
62
86
  isOpen: ComputedRef<boolean>;
87
+ noticeOpen: ComputedRef<boolean>;
63
88
  decisions: ComputedRef<Record<string, boolean>>;
64
89
  resolved: ComputedRef<ResolvedCategory[]>;
65
90
  storedAt: ComputedRef<number | null>;
@@ -71,6 +96,7 @@ type ConsentApi = {
71
96
  reset: () => void;
72
97
  open: () => void;
73
98
  close: () => void;
99
+ dismissNotice: () => void;
74
100
  isGranted: (id: string) => boolean;
75
101
  };
76
102
  type CategoryApi = {
@@ -83,4 +109,4 @@ type CategoryApi = {
83
109
  declare function useConsent(): ConsentApi;
84
110
  declare function useConsent(categoryId: string): CategoryApi;
85
111
 
86
- export { type CategoryApi, type ConsentApi, ConsentBanner, ConsentProvider, ConsentStoreKey, useConsent };
112
+ export { type CategoryApi, type ConsentApi, ConsentBanner, ConsentNotice, ConsentProvider, ConsentStoreKey, useConsent };
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ function useConsent(categoryId) {
33
33
  return {
34
34
  ready: computed(() => stateRef.value.ready),
35
35
  isOpen: computed(() => stateRef.value.isOpen),
36
+ noticeOpen: computed(() => stateRef.value.noticeOpen),
36
37
  decisions: computed(() => stateRef.value.decisions),
37
38
  resolved: computed(() => stateRef.value.resolved),
38
39
  storedAt: computed(() => stateRef.value.storedAt),
@@ -44,6 +45,7 @@ function useConsent(categoryId) {
44
45
  reset: () => store.reset(),
45
46
  open: () => store.open(),
46
47
  close: () => store.close(),
48
+ dismissNotice: () => store.dismissNotice(),
47
49
  isGranted: (id) => stateRef.value.decisions[id] === true
48
50
  };
49
51
  }
@@ -74,6 +76,33 @@ var ConsentBanner = defineComponent({
74
76
  };
75
77
  }
76
78
  });
79
+ var ConsentNotice = defineComponent({
80
+ name: "ConsentNotice",
81
+ setup(_, { slots }) {
82
+ const api = useConsent();
83
+ return () => {
84
+ if (!api.ready.value || !api.noticeOpen.value) return null;
85
+ return slots.default?.({
86
+ ready: api.ready.value,
87
+ isOpen: api.isOpen.value,
88
+ noticeOpen: api.noticeOpen.value,
89
+ decisions: api.decisions.value,
90
+ resolved: api.resolved.value,
91
+ storedAt: api.storedAt.value,
92
+ grant: api.grant,
93
+ deny: api.deny,
94
+ grantAll: api.grantAll,
95
+ denyAll: api.denyAll,
96
+ save: api.save,
97
+ reset: api.reset,
98
+ open: api.open,
99
+ close: api.close,
100
+ dismissNotice: api.dismissNotice,
101
+ isGranted: api.isGranted
102
+ });
103
+ };
104
+ }
105
+ });
77
106
  var ConsentProvider = defineComponent({
78
107
  name: "ConsentProvider",
79
108
  props: {
@@ -111,6 +140,6 @@ var ConsentProvider = defineComponent({
111
140
  }
112
141
  });
113
142
 
114
- export { ConsentBanner, ConsentProvider, ConsentStoreKey, useConsent };
143
+ export { ConsentBanner, ConsentNotice, ConsentProvider, ConsentStoreKey, useConsent };
115
144
  //# sourceMappingURL=index.js.map
116
145
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/keys.ts","../src/use-consent.ts","../src/banner.ts","../src/provider.ts"],"names":["defineComponent"],"mappings":"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","file":"index.js","sourcesContent":["import type { ConsentStore } from '@tickboxhq/core'\nimport type { InjectionKey } from 'vue'\n\nexport const ConsentStoreKey: InjectionKey<ConsentStore> = Symbol('TickboxConsentStore')\n","import type { ConsentMode, ConsentState, ResolvedCategory } from '@tickboxhq/core'\nimport { type ComputedRef, type Ref, computed, inject, onScopeDispose, shallowRef } from 'vue'\nimport { ConsentStoreKey } from './keys.js'\n\nexport type ConsentApi = {\n ready: ComputedRef<boolean>\n isOpen: ComputedRef<boolean>\n decisions: ComputedRef<Record<string, boolean>>\n resolved: ComputedRef<ResolvedCategory[]>\n storedAt: ComputedRef<number | null>\n grant: (id: string) => void\n deny: (id: string) => void\n grantAll: () => void\n denyAll: () => void\n save: () => void\n reset: () => void\n open: () => void\n close: () => void\n isGranted: (id: string) => boolean\n}\n\nexport type CategoryApi = {\n granted: ComputedRef<boolean>\n required: ComputedRef<boolean>\n mode: ComputedRef<ConsentMode>\n grant: () => void\n deny: () => void\n}\n\nexport function useConsent(): ConsentApi\nexport function useConsent(categoryId: string): CategoryApi\nexport function useConsent(categoryId?: string): ConsentApi | CategoryApi {\n const store = inject(ConsentStoreKey)\n if (!store) {\n throw new Error('[@tickboxhq/vue] useConsent must be called inside a <ConsentProvider>.')\n }\n\n const stateRef: Ref<ConsentState> = shallowRef(store.getState())\n const unsubscribe = store.subscribe((next) => {\n stateRef.value = next\n })\n onScopeDispose(unsubscribe)\n\n if (categoryId !== undefined) {\n return {\n granted: computed(() => stateRef.value.decisions[categoryId] === true),\n required: computed(\n () => stateRef.value.resolved.find((r) => r.id === categoryId)?.required ?? false,\n ),\n mode: computed(\n () => stateRef.value.resolved.find((r) => r.id === categoryId)?.mode ?? 'consent',\n ),\n grant: () => store.grant(categoryId),\n deny: () => store.deny(categoryId),\n }\n }\n\n return {\n ready: computed(() => stateRef.value.ready),\n isOpen: computed(() => stateRef.value.isOpen),\n decisions: computed(() => stateRef.value.decisions),\n resolved: computed(() => stateRef.value.resolved),\n storedAt: computed(() => stateRef.value.storedAt),\n grant: (id) => store.grant(id),\n deny: (id) => store.deny(id),\n grantAll: () => store.grantAll(),\n denyAll: () => store.denyAll(),\n save: () => store.save(),\n reset: () => store.reset(),\n open: () => store.open(),\n close: () => store.close(),\n isGranted: (id) => stateRef.value.decisions[id] === true,\n }\n}\n","import { defineComponent } from 'vue'\nimport { useConsent } from './use-consent.js'\n\n/**\n * Headless banner component. Renders nothing while the store is hydrating\n * (`!ready`) or when the banner is closed. Uses the default scoped slot to\n * pass the consent API down.\n *\n * @example\n * ```vue\n * <ConsentBanner v-slot=\"{ resolved, grantAll, denyAll, save }\">\n * <div class=\"banner\">\n * <CategoryRow v-for=\"c in resolved\" :key=\"c.id\" :category=\"c\" />\n * <button @click=\"denyAll\">Reject All</button>\n * <button @click=\"grantAll\">Accept All</button>\n * </div>\n * </ConsentBanner>\n * ```\n */\nexport const ConsentBanner = defineComponent({\n name: 'ConsentBanner',\n setup(_, { slots }) {\n const api = useConsent()\n return () => {\n if (!api.ready.value || !api.isOpen.value) return null\n return slots.default?.({\n ready: api.ready.value,\n isOpen: api.isOpen.value,\n decisions: api.decisions.value,\n resolved: api.resolved.value,\n storedAt: api.storedAt.value,\n grant: api.grant,\n deny: api.deny,\n grantAll: api.grantAll,\n denyAll: api.denyAll,\n save: api.save,\n reset: api.reset,\n open: api.open,\n close: api.close,\n isGranted: api.isGranted,\n })\n }\n },\n})\n\nexport default ConsentBanner\n","import { type ConsentConfig, ConsentStore, type Jurisdiction, applyConsent } from '@tickboxhq/core'\nimport { type PropType, defineComponent, onMounted, provide } from 'vue'\nimport { ConsentStoreKey } from './keys.js'\n\nexport const ConsentProvider = defineComponent({\n name: 'ConsentProvider',\n props: {\n config: {\n type: Object as PropType<ConsentConfig>,\n required: true,\n },\n jurisdiction: {\n type: Object as PropType<Jurisdiction>,\n default: undefined,\n },\n applyEffects: {\n type: Boolean,\n default: true,\n },\n },\n setup(props, { slots }) {\n const j =\n props.jurisdiction ??\n (typeof props.config.jurisdiction !== 'string' ? props.config.jurisdiction : undefined)\n if (!j) {\n throw new Error(\n '[@tickboxhq/vue] jurisdiction is \"auto\" but no `jurisdiction` prop was passed. ' +\n 'Resolve it (e.g. via resolveJurisdictionByCountry) and pass it explicitly.',\n )\n }\n\n const store = new ConsentStore(props.config, {\n jurisdiction: j,\n storage: props.config.storage,\n applyEffects: props.applyEffects,\n onApply: props.applyEffects\n ? (state) => applyConsent(state, { consentMode: props.config.consentMode })\n : undefined,\n })\n\n provide(ConsentStoreKey, store)\n\n onMounted(() => {\n store.hydrate()\n })\n\n return () => slots.default?.()\n },\n})\n\nexport default ConsentProvider\n"]}
1
+ {"version":3,"sources":["../src/keys.ts","../src/use-consent.ts","../src/banner.ts","../src/notice.ts","../src/provider.ts"],"names":["defineComponent"],"mappings":";;;;;;AAGO,IAAM,eAAA,0BAAqD,qBAAqB;;;AC8BhF,SAAS,WAAW,UAAA,EAA+C;AACxE,EAAA,MAAM,KAAA,GAAQ,OAAO,eAAe,CAAA;AACpC,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,MAAM,wEAAwE,CAAA;AAAA,EAC1F;AAEA,EAAA,MAAM,QAAA,GAA8B,UAAA,CAAW,KAAA,CAAM,QAAA,EAAU,CAAA;AAC/D,EAAA,MAAM,WAAA,GAAc,KAAA,CAAM,SAAA,CAAU,CAAC,IAAA,KAAS;AAC5C,IAAA,QAAA,CAAS,KAAA,GAAQ,IAAA;AAAA,EACnB,CAAC,CAAA;AACD,EAAA,cAAA,CAAe,WAAW,CAAA;AAE1B,EAAA,IAAI,eAAe,MAAA,EAAW;AAC5B,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,SAAS,MAAM,QAAA,CAAS,MAAM,SAAA,CAAU,UAAU,MAAM,IAAI,CAAA;AAAA,MACrE,QAAA,EAAU,QAAA;AAAA,QACR,MAAM,QAAA,CAAS,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,UAAU,CAAA,EAAG,QAAA,IAAY;AAAA,OAC9E;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,QACJ,MAAM,QAAA,CAAS,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,UAAU,CAAA,EAAG,IAAA,IAAQ;AAAA,OAC1E;AAAA,MACA,KAAA,EAAO,MAAM,KAAA,CAAM,KAAA,CAAM,UAAU,CAAA;AAAA,MACnC,IAAA,EAAM,MAAM,KAAA,CAAM,IAAA,CAAK,UAAU;AAAA,KACnC;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,QAAA,CAAS,MAAM,QAAA,CAAS,MAAM,KAAK,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA,CAAS,MAAM,QAAA,CAAS,MAAM,MAAM,CAAA;AAAA,IAC5C,UAAA,EAAY,QAAA,CAAS,MAAM,QAAA,CAAS,MAAM,UAAU,CAAA;AAAA,IACpD,SAAA,EAAW,QAAA,CAAS,MAAM,QAAA,CAAS,MAAM,SAAS,CAAA;AAAA,IAClD,QAAA,EAAU,QAAA,CAAS,MAAM,QAAA,CAAS,MAAM,QAAQ,CAAA;AAAA,IAChD,QAAA,EAAU,QAAA,CAAS,MAAM,QAAA,CAAS,MAAM,QAAQ,CAAA;AAAA,IAChD,KAAA,EAAO,CAAC,EAAA,KAAO,KAAA,CAAM,MAAM,EAAE,CAAA;AAAA,IAC7B,IAAA,EAAM,CAAC,EAAA,KAAO,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,IAC3B,QAAA,EAAU,MAAM,KAAA,CAAM,QAAA,EAAS;AAAA,IAC/B,OAAA,EAAS,MAAM,KAAA,CAAM,OAAA,EAAQ;AAAA,IAC7B,IAAA,EAAM,MAAM,KAAA,CAAM,IAAA,EAAK;AAAA,IACvB,KAAA,EAAO,MAAM,KAAA,CAAM,KAAA,EAAM;AAAA,IACzB,IAAA,EAAM,MAAM,KAAA,CAAM,IAAA,EAAK;AAAA,IACvB,KAAA,EAAO,MAAM,KAAA,CAAM,KAAA,EAAM;AAAA,IACzB,aAAA,EAAe,MAAM,KAAA,CAAM,aAAA,EAAc;AAAA,IACzC,WAAW,CAAC,EAAA,KAAO,SAAS,KAAA,CAAM,SAAA,CAAU,EAAE,CAAA,KAAM;AAAA,GACtD;AACF;;;AC1DO,IAAM,gBAAgB,eAAA,CAAgB;AAAA,EAC3C,IAAA,EAAM,eAAA;AAAA,EACN,KAAA,CAAM,CAAA,EAAG,EAAE,KAAA,EAAM,EAAG;AAClB,IAAA,MAAM,MAAM,UAAA,EAAW;AACvB,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,CAAC,IAAI,KAAA,CAAM,KAAA,IAAS,CAAC,GAAA,CAAI,MAAA,CAAO,OAAO,OAAO,IAAA;AAClD,MAAA,OAAO,MAAM,OAAA,GAAU;AAAA,QACrB,KAAA,EAAO,IAAI,KAAA,CAAM,KAAA;AAAA,QACjB,MAAA,EAAQ,IAAI,MAAA,CAAO,KAAA;AAAA,QACnB,SAAA,EAAW,IAAI,SAAA,CAAU,KAAA;AAAA,QACzB,QAAA,EAAU,IAAI,QAAA,CAAS,KAAA;AAAA,QACvB,QAAA,EAAU,IAAI,QAAA,CAAS,KAAA;AAAA,QACvB,OAAO,GAAA,CAAI,KAAA;AAAA,QACX,MAAM,GAAA,CAAI,IAAA;AAAA,QACV,UAAU,GAAA,CAAI,QAAA;AAAA,QACd,SAAS,GAAA,CAAI,OAAA;AAAA,QACb,MAAM,GAAA,CAAI,IAAA;AAAA,QACV,OAAO,GAAA,CAAI,KAAA;AAAA,QACX,MAAM,GAAA,CAAI,IAAA;AAAA,QACV,OAAO,GAAA,CAAI,KAAA;AAAA,QACX,WAAW,GAAA,CAAI;AAAA,OAChB,CAAA;AAAA,IACH,CAAA;AAAA,EACF;AACF,CAAC;ACpBM,IAAM,gBAAgBA,eAAAA,CAAgB;AAAA,EAC3C,IAAA,EAAM,eAAA;AAAA,EACN,KAAA,CAAM,CAAA,EAAG,EAAE,KAAA,EAAM,EAAG;AAClB,IAAA,MAAM,MAAM,UAAA,EAAW;AACvB,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,CAAC,IAAI,KAAA,CAAM,KAAA,IAAS,CAAC,GAAA,CAAI,UAAA,CAAW,OAAO,OAAO,IAAA;AACtD,MAAA,OAAO,MAAM,OAAA,GAAU;AAAA,QACrB,KAAA,EAAO,IAAI,KAAA,CAAM,KAAA;AAAA,QACjB,MAAA,EAAQ,IAAI,MAAA,CAAO,KAAA;AAAA,QACnB,UAAA,EAAY,IAAI,UAAA,CAAW,KAAA;AAAA,QAC3B,SAAA,EAAW,IAAI,SAAA,CAAU,KAAA;AAAA,QACzB,QAAA,EAAU,IAAI,QAAA,CAAS,KAAA;AAAA,QACvB,QAAA,EAAU,IAAI,QAAA,CAAS,KAAA;AAAA,QACvB,OAAO,GAAA,CAAI,KAAA;AAAA,QACX,MAAM,GAAA,CAAI,IAAA;AAAA,QACV,UAAU,GAAA,CAAI,QAAA;AAAA,QACd,SAAS,GAAA,CAAI,OAAA;AAAA,QACb,MAAM,GAAA,CAAI,IAAA;AAAA,QACV,OAAO,GAAA,CAAI,KAAA;AAAA,QACX,MAAM,GAAA,CAAI,IAAA;AAAA,QACV,OAAO,GAAA,CAAI,KAAA;AAAA,QACX,eAAe,GAAA,CAAI,aAAA;AAAA,QACnB,WAAW,GAAA,CAAI;AAAA,OAChB,CAAA;AAAA,IACH,CAAA;AAAA,EACF;AACF,CAAC;AC7CM,IAAM,kBAAkBA,eAAAA,CAAgB;AAAA,EAC7C,IAAA,EAAM,iBAAA;AAAA,EACN,KAAA,EAAO;AAAA,IACL,MAAA,EAAQ;AAAA,MACN,IAAA,EAAM,MAAA;AAAA,MACN,QAAA,EAAU;AAAA,KACZ;AAAA,IACA,YAAA,EAAc;AAAA,MACZ,IAAA,EAAM,MAAA;AAAA,MACN,OAAA,EAAS;AAAA,KACX;AAAA,IACA,YAAA,EAAc;AAAA,MACZ,IAAA,EAAM,OAAA;AAAA,MACN,OAAA,EAAS;AAAA;AACX,GACF;AAAA,EACA,KAAA,CAAM,KAAA,EAAO,EAAE,KAAA,EAAM,EAAG;AACtB,IAAA,MAAM,CAAA,GACJ,KAAA,CAAM,YAAA,KACL,OAAO,KAAA,CAAM,OAAO,YAAA,KAAiB,QAAA,GAAW,KAAA,CAAM,MAAA,CAAO,YAAA,GAAe,MAAA,CAAA;AAC/E,IAAA,IAAI,CAAC,CAAA,EAAG;AACN,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OAEF;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,IAAI,YAAA,CAAa,KAAA,CAAM,MAAA,EAAQ;AAAA,MAC3C,YAAA,EAAc,CAAA;AAAA,MACd,OAAA,EAAS,MAAM,MAAA,CAAO,OAAA;AAAA,MACtB,cAAc,KAAA,CAAM,YAAA;AAAA,MACpB,OAAA,EAAS,KAAA,CAAM,YAAA,GACX,CAAC,KAAA,KAAU,YAAA,CAAa,KAAA,EAAO,EAAE,WAAA,EAAa,KAAA,CAAM,MAAA,CAAO,WAAA,EAAa,CAAA,GACxE;AAAA,KACL,CAAA;AAED,IAAA,OAAA,CAAQ,iBAAiB,KAAK,CAAA;AAE9B,IAAA,SAAA,CAAU,MAAM;AACd,MAAA,KAAA,CAAM,OAAA,EAAQ;AAAA,IAChB,CAAC,CAAA;AAED,IAAA,OAAO,MAAM,MAAM,OAAA,IAAU;AAAA,EAC/B;AACF,CAAC","file":"index.js","sourcesContent":["import type { ConsentStore } from '@tickboxhq/core'\nimport type { InjectionKey } from 'vue'\n\nexport const ConsentStoreKey: InjectionKey<ConsentStore> = Symbol('TickboxConsentStore')\n","import type { ConsentMode, ConsentState, ResolvedCategory } from '@tickboxhq/core'\nimport { type ComputedRef, type Ref, computed, inject, onScopeDispose, shallowRef } from 'vue'\nimport { ConsentStoreKey } from './keys.js'\n\nexport type ConsentApi = {\n ready: ComputedRef<boolean>\n isOpen: ComputedRef<boolean>\n noticeOpen: ComputedRef<boolean>\n decisions: ComputedRef<Record<string, boolean>>\n resolved: ComputedRef<ResolvedCategory[]>\n storedAt: ComputedRef<number | null>\n grant: (id: string) => void\n deny: (id: string) => void\n grantAll: () => void\n denyAll: () => void\n save: () => void\n reset: () => void\n open: () => void\n close: () => void\n dismissNotice: () => void\n isGranted: (id: string) => boolean\n}\n\nexport type CategoryApi = {\n granted: ComputedRef<boolean>\n required: ComputedRef<boolean>\n mode: ComputedRef<ConsentMode>\n grant: () => void\n deny: () => void\n}\n\nexport function useConsent(): ConsentApi\nexport function useConsent(categoryId: string): CategoryApi\nexport function useConsent(categoryId?: string): ConsentApi | CategoryApi {\n const store = inject(ConsentStoreKey)\n if (!store) {\n throw new Error('[@tickboxhq/vue] useConsent must be called inside a <ConsentProvider>.')\n }\n\n const stateRef: Ref<ConsentState> = shallowRef(store.getState())\n const unsubscribe = store.subscribe((next) => {\n stateRef.value = next\n })\n onScopeDispose(unsubscribe)\n\n if (categoryId !== undefined) {\n return {\n granted: computed(() => stateRef.value.decisions[categoryId] === true),\n required: computed(\n () => stateRef.value.resolved.find((r) => r.id === categoryId)?.required ?? false,\n ),\n mode: computed(\n () => stateRef.value.resolved.find((r) => r.id === categoryId)?.mode ?? 'consent',\n ),\n grant: () => store.grant(categoryId),\n deny: () => store.deny(categoryId),\n }\n }\n\n return {\n ready: computed(() => stateRef.value.ready),\n isOpen: computed(() => stateRef.value.isOpen),\n noticeOpen: computed(() => stateRef.value.noticeOpen),\n decisions: computed(() => stateRef.value.decisions),\n resolved: computed(() => stateRef.value.resolved),\n storedAt: computed(() => stateRef.value.storedAt),\n grant: (id) => store.grant(id),\n deny: (id) => store.deny(id),\n grantAll: () => store.grantAll(),\n denyAll: () => store.denyAll(),\n save: () => store.save(),\n reset: () => store.reset(),\n open: () => store.open(),\n close: () => store.close(),\n dismissNotice: () => store.dismissNotice(),\n isGranted: (id) => stateRef.value.decisions[id] === true,\n }\n}\n","import { defineComponent } from 'vue'\nimport { useConsent } from './use-consent.js'\n\n/**\n * Headless banner component. Renders nothing while the store is hydrating\n * (`!ready`) or when the banner is closed. Uses the default scoped slot to\n * pass the consent API down.\n *\n * @example\n * ```vue\n * <ConsentBanner v-slot=\"{ resolved, grantAll, denyAll, save }\">\n * <div class=\"banner\">\n * <CategoryRow v-for=\"c in resolved\" :key=\"c.id\" :category=\"c\" />\n * <button @click=\"denyAll\">Reject All</button>\n * <button @click=\"grantAll\">Accept All</button>\n * </div>\n * </ConsentBanner>\n * ```\n */\nexport const ConsentBanner = defineComponent({\n name: 'ConsentBanner',\n setup(_, { slots }) {\n const api = useConsent()\n return () => {\n if (!api.ready.value || !api.isOpen.value) return null\n return slots.default?.({\n ready: api.ready.value,\n isOpen: api.isOpen.value,\n decisions: api.decisions.value,\n resolved: api.resolved.value,\n storedAt: api.storedAt.value,\n grant: api.grant,\n deny: api.deny,\n grantAll: api.grantAll,\n denyAll: api.denyAll,\n save: api.save,\n reset: api.reset,\n open: api.open,\n close: api.close,\n isGranted: api.isGranted,\n })\n }\n },\n})\n\nexport default ConsentBanner\n","import { defineComponent } from 'vue'\nimport { useConsent } from './use-consent.js'\n\n/**\n * Headless notice card. Renders nothing while the store is hydrating\n * (`!ready`) or when there's nothing to notify about (`!noticeOpen`).\n *\n * Use this for sites that have only `notice`-mode categories (e.g. UK DUAA\n * analytics like Plausible / GoatCounter). For sites with any `consent`-mode\n * category, use `<ConsentBanner>` instead — the banner already covers\n * notice-mode categories in its list, and `noticeOpen` will stay false.\n *\n * @example\n * ```vue\n * <ConsentNotice v-slot=\"{ save, deny }\">\n * <div class=\"toast\">\n * <p>We use privacy-friendly analytics.</p>\n * <button @click=\"() => { deny('analytics'); save() }\">Opt out</button>\n * <button @click=\"save\">Got it</button>\n * </div>\n * </ConsentNotice>\n * ```\n */\nexport const ConsentNotice = defineComponent({\n name: 'ConsentNotice',\n setup(_, { slots }) {\n const api = useConsent()\n return () => {\n if (!api.ready.value || !api.noticeOpen.value) return null\n return slots.default?.({\n ready: api.ready.value,\n isOpen: api.isOpen.value,\n noticeOpen: api.noticeOpen.value,\n decisions: api.decisions.value,\n resolved: api.resolved.value,\n storedAt: api.storedAt.value,\n grant: api.grant,\n deny: api.deny,\n grantAll: api.grantAll,\n denyAll: api.denyAll,\n save: api.save,\n reset: api.reset,\n open: api.open,\n close: api.close,\n dismissNotice: api.dismissNotice,\n isGranted: api.isGranted,\n })\n }\n },\n})\n\nexport default ConsentNotice\n","import { type ConsentConfig, ConsentStore, type Jurisdiction, applyConsent } from '@tickboxhq/core'\nimport { type PropType, defineComponent, onMounted, provide } from 'vue'\nimport { ConsentStoreKey } from './keys.js'\n\nexport const ConsentProvider = defineComponent({\n name: 'ConsentProvider',\n props: {\n config: {\n type: Object as PropType<ConsentConfig>,\n required: true,\n },\n jurisdiction: {\n type: Object as PropType<Jurisdiction>,\n default: undefined,\n },\n applyEffects: {\n type: Boolean,\n default: true,\n },\n },\n setup(props, { slots }) {\n const j =\n props.jurisdiction ??\n (typeof props.config.jurisdiction !== 'string' ? props.config.jurisdiction : undefined)\n if (!j) {\n throw new Error(\n '[@tickboxhq/vue] jurisdiction is \"auto\" but no `jurisdiction` prop was passed. ' +\n 'Resolve it (e.g. via resolveJurisdictionByCountry) and pass it explicitly.',\n )\n }\n\n const store = new ConsentStore(props.config, {\n jurisdiction: j,\n storage: props.config.storage,\n applyEffects: props.applyEffects,\n onApply: props.applyEffects\n ? (state) => applyConsent(state, { consentMode: props.config.consentMode })\n : undefined,\n })\n\n provide(ConsentStoreKey, store)\n\n onMounted(() => {\n store.hydrate()\n })\n\n return () => slots.default?.()\n },\n})\n\nexport default ConsentProvider\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tickboxhq/vue",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "description": "Vue 3 bindings for Tickbox consent management",
5
5
  "license": "MIT",
6
6
  "homepage": "https://tickbox.dev",
@@ -27,7 +27,7 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@tickboxhq/core": "0.0.10"
30
+ "@tickboxhq/core": "0.0.11"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "vue": "^3.4.0"