@tickboxhq/banner-default 0.0.14 → 0.0.16
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/README.md +19 -1
- package/dist/{chunk-FLFKIHIQ.js → chunk-DBGLNJWF.js} +172 -6
- package/dist/chunk-DBGLNJWF.js.map +1 -0
- package/dist/index-BYeQnxz5.d.ts +34 -0
- package/dist/react/index.d.ts +19 -6
- package/dist/react/index.js +4 -3
- package/dist/react/index.js.map +1 -1
- package/dist/vue/index.d.ts +28 -2
- package/dist/vue/index.js +14 -3
- package/dist/vue/index.js.map +1 -1
- package/package.json +6 -6
- package/dist/chunk-FLFKIHIQ.js.map +0 -1
- package/dist/copy-DA2csB2L.d.ts +0 -20
package/README.md
CHANGED
|
@@ -78,10 +78,28 @@ Both components accept the same shape:
|
|
|
78
78
|
|---|---|---|---|
|
|
79
79
|
| `policyUrl` | `string` | — | Privacy policy URL. Hidden if omitted. |
|
|
80
80
|
| `theme` | `'light' \| 'dark'` | follows `prefers-color-scheme` | Force a theme. |
|
|
81
|
-
| `
|
|
81
|
+
| `locale` | `string` | `'en'` | BCP-47 tag, or `'auto'`. See "Languages" below. |
|
|
82
|
+
| `copy` | `Partial<BannerCopy>` / `Partial<NoticeCopy>` | resolved from `locale` | Override individual labels. |
|
|
82
83
|
|
|
83
84
|
`<ConsentNoticeDefault>` also takes `optOutCategoryId` (default `'analytics'`) — the category to deny when the user clicks "Opt out".
|
|
84
85
|
|
|
86
|
+
## Languages
|
|
87
|
+
|
|
88
|
+
Built-in: `en`, `de`, `fr`, `es`, `it`, `nl`, `pt`, `pl`. Pass any BCP-47 tag — `'fr-CH'` resolves to `'fr'`, `'pt-BR'` to `'pt'`, unknown locales to English.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
<ConsentBannerDefault locale="de" />
|
|
92
|
+
<ConsentBannerDefault locale="auto" /> {/* reads navigator.language */}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`copy` layers on top of the resolved locale, so you can pick a language and tweak one label:
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
<ConsentBannerDefault locale="de" copy={{ acceptLabel: 'Klar, akzeptieren' }} />
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
If you need a language not in the built-in set, pass a full `copy` object. PRs adding more locales are welcome — files live in `src/shared/locales/`.
|
|
102
|
+
|
|
85
103
|
## Styling
|
|
86
104
|
|
|
87
105
|
The components inject a single `<style>` tag, once per page. Themes are CSS custom properties, so you can re-skin without forking:
|
|
@@ -1,5 +1,25 @@
|
|
|
1
|
-
// src/shared/
|
|
2
|
-
var
|
|
1
|
+
// src/shared/locales/de.ts
|
|
2
|
+
var banner = {
|
|
3
|
+
title: "Cookies und Tracking",
|
|
4
|
+
description: "Wir verwenden Cookies, damit diese Website funktioniert, und mit Ihrer Einwilligung, um die Nutzung zu messen. Sie k\xF6nnen selbst w\xE4hlen, was Sie zulassen.",
|
|
5
|
+
acceptLabel: "Alle akzeptieren",
|
|
6
|
+
rejectLabel: "Alle ablehnen",
|
|
7
|
+
customiseLabel: "Anpassen",
|
|
8
|
+
saveLabel: "Einstellungen speichern",
|
|
9
|
+
closeLabel: "Schlie\xDFen",
|
|
10
|
+
policyLinkLabel: "Datenschutz",
|
|
11
|
+
requiredBadge: "Erforderlich"
|
|
12
|
+
};
|
|
13
|
+
var notice = {
|
|
14
|
+
title: "Hinweis zur Analyse",
|
|
15
|
+
description: "Wir verwenden datenschutzfreundliche Analyse-Tools, um zu verstehen, wie diese Website genutzt wird. Es werden keine personenbezogenen Daten erhoben und keine Werbeprofile erstellt.",
|
|
16
|
+
acknowledgeLabel: "Verstanden",
|
|
17
|
+
optOutLabel: "Ablehnen",
|
|
18
|
+
policyLinkLabel: "Datenschutz"
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// src/shared/locales/en.ts
|
|
22
|
+
var banner2 = {
|
|
3
23
|
title: "Cookies and tracking",
|
|
4
24
|
description: "We use cookies to make this site work and, with your consent, to measure usage. You can choose what to allow.",
|
|
5
25
|
acceptLabel: "Accept all",
|
|
@@ -10,7 +30,7 @@ var DEFAULT_BANNER_COPY = {
|
|
|
10
30
|
policyLinkLabel: "Privacy policy",
|
|
11
31
|
requiredBadge: "Required"
|
|
12
32
|
};
|
|
13
|
-
var
|
|
33
|
+
var notice2 = {
|
|
14
34
|
title: "A note about analytics",
|
|
15
35
|
description: "We use privacy-friendly analytics to understand how this site is used. No personal data is collected and no advertising profiles are built.",
|
|
16
36
|
acknowledgeLabel: "Got it",
|
|
@@ -18,6 +38,152 @@ var DEFAULT_NOTICE_COPY = {
|
|
|
18
38
|
policyLinkLabel: "Privacy policy"
|
|
19
39
|
};
|
|
20
40
|
|
|
41
|
+
// src/shared/locales/es.ts
|
|
42
|
+
var banner3 = {
|
|
43
|
+
title: "Cookies y seguimiento",
|
|
44
|
+
description: "Utilizamos cookies para que este sitio funcione y, con tu consentimiento, para medir su uso. T\xFA eliges lo que permites.",
|
|
45
|
+
acceptLabel: "Aceptar todo",
|
|
46
|
+
rejectLabel: "Rechazar todo",
|
|
47
|
+
customiseLabel: "Personalizar",
|
|
48
|
+
saveLabel: "Guardar preferencias",
|
|
49
|
+
closeLabel: "Cerrar",
|
|
50
|
+
policyLinkLabel: "Pol\xEDtica de privacidad",
|
|
51
|
+
requiredBadge: "Obligatorio"
|
|
52
|
+
};
|
|
53
|
+
var notice3 = {
|
|
54
|
+
title: "Sobre la anal\xEDtica",
|
|
55
|
+
description: "Utilizamos anal\xEDtica respetuosa con la privacidad para entender c\xF3mo se usa este sitio. No recopilamos datos personales ni creamos perfiles publicitarios.",
|
|
56
|
+
acknowledgeLabel: "Entendido",
|
|
57
|
+
optOutLabel: "Rechazar",
|
|
58
|
+
policyLinkLabel: "Pol\xEDtica de privacidad"
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// src/shared/locales/fr.ts
|
|
62
|
+
var banner4 = {
|
|
63
|
+
title: "Cookies et suivi",
|
|
64
|
+
description: "Nous utilisons des cookies pour faire fonctionner ce site et, avec votre consentement, pour mesurer son utilisation. Vous choisissez ce que vous autorisez.",
|
|
65
|
+
acceptLabel: "Tout accepter",
|
|
66
|
+
rejectLabel: "Tout refuser",
|
|
67
|
+
customiseLabel: "Personnaliser",
|
|
68
|
+
saveLabel: "Enregistrer les pr\xE9f\xE9rences",
|
|
69
|
+
closeLabel: "Fermer",
|
|
70
|
+
policyLinkLabel: "Politique de confidentialit\xE9",
|
|
71
|
+
requiredBadge: "Requis"
|
|
72
|
+
};
|
|
73
|
+
var notice4 = {
|
|
74
|
+
title: "\xC0 propos de l'analyse",
|
|
75
|
+
description: "Nous utilisons une analyse respectueuse de la vie priv\xE9e pour comprendre comment ce site est utilis\xE9. Aucune donn\xE9e personnelle n'est collect\xE9e et aucun profil publicitaire n'est constitu\xE9.",
|
|
76
|
+
acknowledgeLabel: "Compris",
|
|
77
|
+
optOutLabel: "Refuser",
|
|
78
|
+
policyLinkLabel: "Politique de confidentialit\xE9"
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/shared/locales/it.ts
|
|
82
|
+
var banner5 = {
|
|
83
|
+
title: "Cookie e tracciamento",
|
|
84
|
+
description: "Utilizziamo i cookie per far funzionare il sito e, con il tuo consenso, per misurarne l'utilizzo. Puoi scegliere cosa consentire.",
|
|
85
|
+
acceptLabel: "Accetta tutto",
|
|
86
|
+
rejectLabel: "Rifiuta tutto",
|
|
87
|
+
customiseLabel: "Personalizza",
|
|
88
|
+
saveLabel: "Salva preferenze",
|
|
89
|
+
closeLabel: "Chiudi",
|
|
90
|
+
policyLinkLabel: "Informativa sulla privacy",
|
|
91
|
+
requiredBadge: "Obbligatorio"
|
|
92
|
+
};
|
|
93
|
+
var notice5 = {
|
|
94
|
+
title: "Nota sull'analisi",
|
|
95
|
+
description: "Utilizziamo strumenti di analisi rispettosi della privacy per capire come viene usato questo sito. Non raccogliamo dati personali n\xE9 creiamo profili pubblicitari.",
|
|
96
|
+
acknowledgeLabel: "Ho capito",
|
|
97
|
+
optOutLabel: "Rifiuta",
|
|
98
|
+
policyLinkLabel: "Informativa sulla privacy"
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/shared/locales/nl.ts
|
|
102
|
+
var banner6 = {
|
|
103
|
+
title: "Cookies en tracking",
|
|
104
|
+
description: "Wij gebruiken cookies om deze site te laten werken en, met uw toestemming, om het gebruik te meten. U kiest wat u toestaat.",
|
|
105
|
+
acceptLabel: "Alles accepteren",
|
|
106
|
+
rejectLabel: "Alles weigeren",
|
|
107
|
+
customiseLabel: "Aanpassen",
|
|
108
|
+
saveLabel: "Voorkeuren opslaan",
|
|
109
|
+
closeLabel: "Sluiten",
|
|
110
|
+
policyLinkLabel: "Privacybeleid",
|
|
111
|
+
requiredBadge: "Vereist"
|
|
112
|
+
};
|
|
113
|
+
var notice6 = {
|
|
114
|
+
title: "Over analytics",
|
|
115
|
+
description: "Wij gebruiken privacyvriendelijke analytics om te begrijpen hoe deze site wordt gebruikt. Er worden geen persoonsgegevens verzameld en er worden geen advertentieprofielen opgebouwd.",
|
|
116
|
+
acknowledgeLabel: "Begrepen",
|
|
117
|
+
optOutLabel: "Afmelden",
|
|
118
|
+
policyLinkLabel: "Privacybeleid"
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// src/shared/locales/pl.ts
|
|
122
|
+
var banner7 = {
|
|
123
|
+
title: "Pliki cookie i \u015Bledzenie",
|
|
124
|
+
description: "U\u017Cywamy plik\xF3w cookie, aby ta strona dzia\u0142a\u0142a, oraz \u2013 za Twoj\u0105 zgod\u0105 \u2013 aby mierzy\u0107 jej u\u017Cycie. To Ty decydujesz, na co pozwoli\u0107.",
|
|
125
|
+
acceptLabel: "Zaakceptuj wszystkie",
|
|
126
|
+
rejectLabel: "Odrzu\u0107 wszystkie",
|
|
127
|
+
customiseLabel: "Dostosuj",
|
|
128
|
+
saveLabel: "Zapisz preferencje",
|
|
129
|
+
closeLabel: "Zamknij",
|
|
130
|
+
policyLinkLabel: "Polityka prywatno\u015Bci",
|
|
131
|
+
requiredBadge: "Wymagane"
|
|
132
|
+
};
|
|
133
|
+
var notice7 = {
|
|
134
|
+
title: "O analityce",
|
|
135
|
+
description: "U\u017Cywamy analityki przyjaznej prywatno\u015Bci, aby zrozumie\u0107, jak korzysta si\u0119 z tej strony. Nie zbieramy danych osobowych ani nie tworzymy profili reklamowych.",
|
|
136
|
+
acknowledgeLabel: "Rozumiem",
|
|
137
|
+
optOutLabel: "Zrezygnuj",
|
|
138
|
+
policyLinkLabel: "Polityka prywatno\u015Bci"
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// src/shared/locales/pt.ts
|
|
142
|
+
var banner8 = {
|
|
143
|
+
title: "Cookies e rastreio",
|
|
144
|
+
description: "Utilizamos cookies para que este site funcione e, com o seu consentimento, para medir a sua utiliza\xE7\xE3o. Pode escolher o que permitir.",
|
|
145
|
+
acceptLabel: "Aceitar tudo",
|
|
146
|
+
rejectLabel: "Rejeitar tudo",
|
|
147
|
+
customiseLabel: "Personalizar",
|
|
148
|
+
saveLabel: "Guardar prefer\xEAncias",
|
|
149
|
+
closeLabel: "Fechar",
|
|
150
|
+
policyLinkLabel: "Pol\xEDtica de privacidade",
|
|
151
|
+
requiredBadge: "Obrigat\xF3rio"
|
|
152
|
+
};
|
|
153
|
+
var notice8 = {
|
|
154
|
+
title: "Sobre a an\xE1lise",
|
|
155
|
+
description: "Utilizamos an\xE1lises respeitadoras da privacidade para perceber como este site \xE9 utilizado. N\xE3o recolhemos dados pessoais nem criamos perfis publicit\xE1rios.",
|
|
156
|
+
acknowledgeLabel: "Entendi",
|
|
157
|
+
optOutLabel: "Recusar",
|
|
158
|
+
policyLinkLabel: "Pol\xEDtica de privacidade"
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// src/shared/locales/index.ts
|
|
162
|
+
var locales = {
|
|
163
|
+
en: { banner: banner2, notice: notice2 },
|
|
164
|
+
de: { banner, notice },
|
|
165
|
+
fr: { banner: banner4, notice: notice4 },
|
|
166
|
+
es: { banner: banner3, notice: notice3 },
|
|
167
|
+
it: { banner: banner5, notice: notice5 },
|
|
168
|
+
nl: { banner: banner6, notice: notice6 },
|
|
169
|
+
pt: { banner: banner8, notice: notice8 },
|
|
170
|
+
pl: { banner: banner7, notice: notice7 }
|
|
171
|
+
};
|
|
172
|
+
function resolveLocalePack(locale) {
|
|
173
|
+
if (!locale) return locales.en;
|
|
174
|
+
const tag = locale === "auto" ? readNavigatorLanguage() : locale;
|
|
175
|
+
if (!tag) return locales.en;
|
|
176
|
+
const lower = tag.toLowerCase();
|
|
177
|
+
if (locales[lower]) return locales[lower];
|
|
178
|
+
const prefix = lower.split("-")[0];
|
|
179
|
+
if (prefix && locales[prefix]) return locales[prefix];
|
|
180
|
+
return locales.en;
|
|
181
|
+
}
|
|
182
|
+
function readNavigatorLanguage() {
|
|
183
|
+
if (typeof navigator === "undefined") return void 0;
|
|
184
|
+
return navigator.language;
|
|
185
|
+
}
|
|
186
|
+
|
|
21
187
|
// src/shared/styles.ts
|
|
22
188
|
var TICKBOX_STYLES = `
|
|
23
189
|
:where(.tb-root) {
|
|
@@ -366,6 +532,6 @@ function injectStyles() {
|
|
|
366
532
|
injected = true;
|
|
367
533
|
}
|
|
368
534
|
|
|
369
|
-
export {
|
|
370
|
-
//# sourceMappingURL=chunk-
|
|
371
|
-
//# sourceMappingURL=chunk-
|
|
535
|
+
export { injectStyles, locales, resolveLocalePack };
|
|
536
|
+
//# sourceMappingURL=chunk-DBGLNJWF.js.map
|
|
537
|
+
//# sourceMappingURL=chunk-DBGLNJWF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/locales/de.ts","../src/shared/locales/en.ts","../src/shared/locales/es.ts","../src/shared/locales/fr.ts","../src/shared/locales/it.ts","../src/shared/locales/nl.ts","../src/shared/locales/pl.ts","../src/shared/locales/pt.ts","../src/shared/locales/index.ts","../src/shared/styles.ts"],"names":["banner","notice"],"mappings":"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","file":"chunk-DBGLNJWF.js","sourcesContent":["import type { BannerCopy, NoticeCopy } from '../copy.js'\n\nexport const banner: BannerCopy = {\n title: 'Cookies und Tracking',\n description:\n 'Wir verwenden Cookies, damit diese Website funktioniert, und mit Ihrer Einwilligung, um die Nutzung zu messen. Sie können selbst wählen, was Sie zulassen.',\n acceptLabel: 'Alle akzeptieren',\n rejectLabel: 'Alle ablehnen',\n customiseLabel: 'Anpassen',\n saveLabel: 'Einstellungen speichern',\n closeLabel: 'Schließen',\n policyLinkLabel: 'Datenschutz',\n requiredBadge: 'Erforderlich',\n}\n\nexport const notice: NoticeCopy = {\n title: 'Hinweis zur Analyse',\n description:\n 'Wir verwenden datenschutzfreundliche Analyse-Tools, um zu verstehen, wie diese Website genutzt wird. Es werden keine personenbezogenen Daten erhoben und keine Werbeprofile erstellt.',\n acknowledgeLabel: 'Verstanden',\n optOutLabel: 'Ablehnen',\n policyLinkLabel: 'Datenschutz',\n}\n","import type { BannerCopy, NoticeCopy } from '../copy.js'\n\nexport const banner: BannerCopy = {\n title: 'Cookies and tracking',\n description:\n 'We use cookies to make this site work and, with your consent, to measure usage. You can choose what to allow.',\n acceptLabel: 'Accept all',\n rejectLabel: 'Reject all',\n customiseLabel: 'Customise',\n saveLabel: 'Save preferences',\n closeLabel: 'Close',\n policyLinkLabel: 'Privacy policy',\n requiredBadge: 'Required',\n}\n\nexport const notice: NoticeCopy = {\n title: 'A note about analytics',\n description:\n 'We use privacy-friendly analytics to understand how this site is used. No personal data is collected and no advertising profiles are built.',\n acknowledgeLabel: 'Got it',\n optOutLabel: 'Opt out',\n policyLinkLabel: 'Privacy policy',\n}\n","import type { BannerCopy, NoticeCopy } from '../copy.js'\n\nexport const banner: BannerCopy = {\n title: 'Cookies y seguimiento',\n description:\n 'Utilizamos cookies para que este sitio funcione y, con tu consentimiento, para medir su uso. Tú eliges lo que permites.',\n acceptLabel: 'Aceptar todo',\n rejectLabel: 'Rechazar todo',\n customiseLabel: 'Personalizar',\n saveLabel: 'Guardar preferencias',\n closeLabel: 'Cerrar',\n policyLinkLabel: 'Política de privacidad',\n requiredBadge: 'Obligatorio',\n}\n\nexport const notice: NoticeCopy = {\n title: 'Sobre la analítica',\n description:\n 'Utilizamos analítica respetuosa con la privacidad para entender cómo se usa este sitio. No recopilamos datos personales ni creamos perfiles publicitarios.',\n acknowledgeLabel: 'Entendido',\n optOutLabel: 'Rechazar',\n policyLinkLabel: 'Política de privacidad',\n}\n","import type { BannerCopy, NoticeCopy } from '../copy.js'\n\nexport const banner: BannerCopy = {\n title: 'Cookies et suivi',\n description:\n 'Nous utilisons des cookies pour faire fonctionner ce site et, avec votre consentement, pour mesurer son utilisation. Vous choisissez ce que vous autorisez.',\n acceptLabel: 'Tout accepter',\n rejectLabel: 'Tout refuser',\n customiseLabel: 'Personnaliser',\n saveLabel: 'Enregistrer les préférences',\n closeLabel: 'Fermer',\n policyLinkLabel: 'Politique de confidentialité',\n requiredBadge: 'Requis',\n}\n\nexport const notice: NoticeCopy = {\n title: \"À propos de l'analyse\",\n description:\n \"Nous utilisons une analyse respectueuse de la vie privée pour comprendre comment ce site est utilisé. Aucune donnée personnelle n'est collectée et aucun profil publicitaire n'est constitué.\",\n acknowledgeLabel: 'Compris',\n optOutLabel: 'Refuser',\n policyLinkLabel: 'Politique de confidentialité',\n}\n","import type { BannerCopy, NoticeCopy } from '../copy.js'\n\nexport const banner: BannerCopy = {\n title: 'Cookie e tracciamento',\n description:\n \"Utilizziamo i cookie per far funzionare il sito e, con il tuo consenso, per misurarne l'utilizzo. Puoi scegliere cosa consentire.\",\n acceptLabel: 'Accetta tutto',\n rejectLabel: 'Rifiuta tutto',\n customiseLabel: 'Personalizza',\n saveLabel: 'Salva preferenze',\n closeLabel: 'Chiudi',\n policyLinkLabel: 'Informativa sulla privacy',\n requiredBadge: 'Obbligatorio',\n}\n\nexport const notice: NoticeCopy = {\n title: \"Nota sull'analisi\",\n description:\n 'Utilizziamo strumenti di analisi rispettosi della privacy per capire come viene usato questo sito. Non raccogliamo dati personali né creiamo profili pubblicitari.',\n acknowledgeLabel: 'Ho capito',\n optOutLabel: 'Rifiuta',\n policyLinkLabel: 'Informativa sulla privacy',\n}\n","import type { BannerCopy, NoticeCopy } from '../copy.js'\n\nexport const banner: BannerCopy = {\n title: 'Cookies en tracking',\n description:\n 'Wij gebruiken cookies om deze site te laten werken en, met uw toestemming, om het gebruik te meten. U kiest wat u toestaat.',\n acceptLabel: 'Alles accepteren',\n rejectLabel: 'Alles weigeren',\n customiseLabel: 'Aanpassen',\n saveLabel: 'Voorkeuren opslaan',\n closeLabel: 'Sluiten',\n policyLinkLabel: 'Privacybeleid',\n requiredBadge: 'Vereist',\n}\n\nexport const notice: NoticeCopy = {\n title: 'Over analytics',\n description:\n 'Wij gebruiken privacyvriendelijke analytics om te begrijpen hoe deze site wordt gebruikt. Er worden geen persoonsgegevens verzameld en er worden geen advertentieprofielen opgebouwd.',\n acknowledgeLabel: 'Begrepen',\n optOutLabel: 'Afmelden',\n policyLinkLabel: 'Privacybeleid',\n}\n","import type { BannerCopy, NoticeCopy } from '../copy.js'\n\nexport const banner: BannerCopy = {\n title: 'Pliki cookie i śledzenie',\n description:\n 'Używamy plików cookie, aby ta strona działała, oraz – za Twoją zgodą – aby mierzyć jej użycie. To Ty decydujesz, na co pozwolić.',\n acceptLabel: 'Zaakceptuj wszystkie',\n rejectLabel: 'Odrzuć wszystkie',\n customiseLabel: 'Dostosuj',\n saveLabel: 'Zapisz preferencje',\n closeLabel: 'Zamknij',\n policyLinkLabel: 'Polityka prywatności',\n requiredBadge: 'Wymagane',\n}\n\nexport const notice: NoticeCopy = {\n title: 'O analityce',\n description:\n 'Używamy analityki przyjaznej prywatności, aby zrozumieć, jak korzysta się z tej strony. Nie zbieramy danych osobowych ani nie tworzymy profili reklamowych.',\n acknowledgeLabel: 'Rozumiem',\n optOutLabel: 'Zrezygnuj',\n policyLinkLabel: 'Polityka prywatności',\n}\n","import type { BannerCopy, NoticeCopy } from '../copy.js'\n\nexport const banner: BannerCopy = {\n title: 'Cookies e rastreio',\n description:\n 'Utilizamos cookies para que este site funcione e, com o seu consentimento, para medir a sua utilização. Pode escolher o que permitir.',\n acceptLabel: 'Aceitar tudo',\n rejectLabel: 'Rejeitar tudo',\n customiseLabel: 'Personalizar',\n saveLabel: 'Guardar preferências',\n closeLabel: 'Fechar',\n policyLinkLabel: 'Política de privacidade',\n requiredBadge: 'Obrigatório',\n}\n\nexport const notice: NoticeCopy = {\n title: 'Sobre a análise',\n description:\n 'Utilizamos análises respeitadoras da privacidade para perceber como este site é utilizado. Não recolhemos dados pessoais nem criamos perfis publicitários.',\n acknowledgeLabel: 'Entendi',\n optOutLabel: 'Recusar',\n policyLinkLabel: 'Política de privacidade',\n}\n","import type { BannerCopy, NoticeCopy } from '../copy.js'\nimport * as de from './de.js'\nimport * as en from './en.js'\nimport * as es from './es.js'\nimport * as fr from './fr.js'\nimport * as it from './it.js'\nimport * as nl from './nl.js'\nimport * as pl from './pl.js'\nimport * as pt from './pt.js'\n\nexport type LocalePack = {\n banner: BannerCopy\n notice: NoticeCopy\n}\n\nexport const locales: Record<string, LocalePack> = {\n en: { banner: en.banner, notice: en.notice },\n de: { banner: de.banner, notice: de.notice },\n fr: { banner: fr.banner, notice: fr.notice },\n es: { banner: es.banner, notice: es.notice },\n it: { banner: it.banner, notice: it.notice },\n nl: { banner: nl.banner, notice: nl.notice },\n pt: { banner: pt.banner, notice: pt.notice },\n pl: { banner: pl.banner, notice: pl.notice },\n}\n\nexport type LocaleCode = keyof typeof locales\n\n/**\n * Resolve a BCP-47 locale tag to a built-in locale pack. Falls back from\n * the full tag (`en-GB`) to the language prefix (`en`), then to English.\n *\n * Pass `'auto'` to read `navigator.language` at call time. Anywhere that\n * `navigator` is missing (SSR, Node), `'auto'` falls back to English.\n */\nexport function resolveLocalePack(locale: string | undefined): LocalePack {\n if (!locale) return locales.en as LocalePack\n const tag = locale === 'auto' ? readNavigatorLanguage() : locale\n if (!tag) return locales.en as LocalePack\n const lower = tag.toLowerCase()\n if (locales[lower]) return locales[lower] as LocalePack\n const prefix = lower.split('-')[0]\n if (prefix && locales[prefix]) return locales[prefix] as LocalePack\n return locales.en as LocalePack\n}\n\nfunction readNavigatorLanguage(): string | undefined {\n if (typeof navigator === 'undefined') return undefined\n return navigator.language\n}\n","/**\n * Inline CSS for the default banner / notice / modal components.\n *\n * Uses CSS custom properties so users can re-theme without forking. Light\n * and dark themes are wired through `prefers-color-scheme` and the\n * `[data-tb-theme]` attribute.\n *\n * Visual style: GitHub-ish — system font, 6px corners, subtle border + soft\n * shadow, equal-prominence accept/reject buttons.\n */\nexport const TICKBOX_STYLES = `\n:where(.tb-root) {\n --tb-bg: #ffffff;\n --tb-fg: #1f2328;\n --tb-fg-muted: #59636e;\n --tb-border: #d1d9e0;\n --tb-shadow: 0 8px 24px rgba(140, 149, 159, 0.2);\n --tb-primary-bg: #1f2328;\n --tb-primary-fg: #ffffff;\n --tb-primary-bg-hover: #000000;\n --tb-secondary-bg: #ffffff;\n --tb-secondary-fg: #1f2328;\n --tb-secondary-bg-hover: #f6f8fa;\n --tb-link: #0969da;\n --tb-radius: 6px;\n --tb-z: 2147483000;\n font-family:\n -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica,\n Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\";\n color: var(--tb-fg);\n font-size: 14px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n}\n@media (prefers-color-scheme: dark) {\n :where(.tb-root:not([data-tb-theme=\"light\"])) {\n --tb-bg: #0d1117;\n --tb-fg: #f0f6fc;\n --tb-fg-muted: #9198a1;\n --tb-border: #30363d;\n --tb-shadow: 0 8px 24px rgba(1, 4, 9, 0.85);\n --tb-primary-bg: #f0f6fc;\n --tb-primary-fg: #0d1117;\n --tb-primary-bg-hover: #ffffff;\n --tb-secondary-bg: #15191f;\n --tb-secondary-fg: #f0f6fc;\n --tb-secondary-bg-hover: #1f2328;\n --tb-link: #4493f8;\n }\n}\n:where(.tb-root[data-tb-theme=\"dark\"]) {\n --tb-bg: #0d1117;\n --tb-fg: #f0f6fc;\n --tb-fg-muted: #9198a1;\n --tb-border: #30363d;\n --tb-shadow: 0 8px 24px rgba(1, 4, 9, 0.85);\n --tb-primary-bg: #f0f6fc;\n --tb-primary-fg: #0d1117;\n --tb-primary-bg-hover: #ffffff;\n --tb-secondary-bg: #15191f;\n --tb-secondary-fg: #f0f6fc;\n --tb-secondary-bg-hover: #1f2328;\n --tb-link: #4493f8;\n}\n\n.tb-banner {\n position: fixed;\n left: 16px;\n right: 16px;\n bottom: 16px;\n max-width: 1100px;\n margin-inline: auto;\n z-index: var(--tb-z);\n background: var(--tb-bg);\n color: var(--tb-fg);\n border: 1px solid var(--tb-border);\n border-radius: var(--tb-radius);\n box-shadow: var(--tb-shadow);\n padding: 16px 20px;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n animation: tb-fade-in 160ms ease-out;\n}\n.tb-banner-text {\n flex: 1 1 320px;\n min-width: 0;\n}\n.tb-banner-title {\n font-weight: 600;\n margin: 0 0 2px;\n font-size: 14px;\n}\n.tb-banner-desc {\n margin: 0;\n color: var(--tb-fg-muted);\n}\n.tb-banner-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.tb-notice {\n position: fixed;\n right: 16px;\n bottom: 16px;\n z-index: var(--tb-z);\n background: var(--tb-bg);\n color: var(--tb-fg);\n border: 1px solid var(--tb-border);\n border-radius: var(--tb-radius);\n box-shadow: var(--tb-shadow);\n padding: 14px 16px;\n max-width: 360px;\n animation: tb-fade-in 160ms ease-out;\n}\n.tb-notice-title {\n font-weight: 600;\n margin: 0 0 4px;\n font-size: 14px;\n}\n.tb-notice-desc {\n margin: 0 0 10px;\n color: var(--tb-fg-muted);\n font-size: 13px;\n}\n.tb-notice-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n justify-content: flex-end;\n flex-wrap: wrap;\n}\n\n.tb-link {\n color: var(--tb-link);\n text-decoration: none;\n font-size: 13px;\n margin-right: auto;\n}\n.tb-link:hover { text-decoration: underline; }\n\n.tb-btn {\n appearance: none;\n border: 1px solid transparent;\n border-radius: var(--tb-radius);\n padding: 6px 14px;\n font-size: 13px;\n font-weight: 500;\n font-family: inherit;\n cursor: pointer;\n line-height: 1.5;\n transition: background-color 80ms ease;\n white-space: nowrap;\n}\n.tb-btn:focus-visible {\n outline: 2px solid var(--tb-link);\n outline-offset: 2px;\n}\n.tb-btn-primary {\n background: var(--tb-primary-bg);\n color: var(--tb-primary-fg);\n}\n.tb-btn-primary:hover { background: var(--tb-primary-bg-hover); }\n.tb-btn-secondary {\n background: var(--tb-secondary-bg);\n color: var(--tb-secondary-fg);\n border-color: var(--tb-border);\n}\n.tb-btn-secondary:hover { background: var(--tb-secondary-bg-hover); }\n/*\n * Style for Accept All and Reject All on the first banner layer. They MUST\n * look identical — UK ICO and EU EDPB treat unequal visual weight on those\n * buttons as a dark pattern. Customisation should not break this symmetry;\n * if you need to apply brand colours, apply them here, not to one button.\n */\n.tb-btn-equal {\n background: var(--tb-secondary-bg);\n color: var(--tb-secondary-fg);\n border-color: var(--tb-border);\n}\n.tb-btn-equal:hover { background: var(--tb-secondary-bg-hover); }\n.tb-btn-ghost {\n background: transparent;\n color: var(--tb-fg-muted);\n padding: 6px 10px;\n}\n.tb-btn-ghost:hover { color: var(--tb-fg); }\n\n.tb-modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(15, 18, 24, 0.5);\n z-index: var(--tb-z);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 20px;\n animation: tb-fade-in 160ms ease-out;\n}\n.tb-modal {\n background: var(--tb-bg);\n color: var(--tb-fg);\n border: 1px solid var(--tb-border);\n border-radius: var(--tb-radius);\n box-shadow: var(--tb-shadow);\n width: 100%;\n max-width: 520px;\n max-height: 85vh;\n display: flex;\n flex-direction: column;\n}\n.tb-modal-head {\n padding: 14px 16px;\n border-bottom: 1px solid var(--tb-border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n.tb-modal-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n}\n.tb-modal-body {\n padding: 12px 16px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.tb-modal-foot {\n padding: 12px 16px;\n border-top: 1px solid var(--tb-border);\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n flex-wrap: wrap;\n}\n\n.tb-cat {\n border: 1px solid var(--tb-border);\n border-radius: var(--tb-radius);\n padding: 12px;\n display: flex;\n gap: 12px;\n align-items: flex-start;\n}\n.tb-cat-text { flex: 1; min-width: 0; }\n.tb-cat-name {\n font-weight: 600;\n margin: 0 0 2px;\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.tb-cat-desc {\n margin: 0;\n color: var(--tb-fg-muted);\n font-size: 13px;\n}\n.tb-badge {\n display: inline-block;\n font-size: 11px;\n font-weight: 500;\n color: var(--tb-fg-muted);\n background: var(--tb-secondary-bg-hover);\n border: 1px solid var(--tb-border);\n border-radius: 999px;\n padding: 1px 8px;\n}\n\n.tb-switch {\n position: relative;\n display: inline-block;\n width: 32px;\n height: 18px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n.tb-switch input {\n opacity: 0;\n width: 0;\n height: 0;\n position: absolute;\n}\n.tb-switch-track {\n position: absolute;\n inset: 0;\n background: var(--tb-border);\n border-radius: 999px;\n transition: background-color 100ms ease;\n cursor: pointer;\n}\n.tb-switch-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 14px;\n height: 14px;\n background: var(--tb-bg);\n border-radius: 50%;\n transition: transform 100ms ease;\n}\n.tb-switch input:checked + .tb-switch-track {\n background: var(--tb-primary-bg);\n}\n.tb-switch input:checked + .tb-switch-track .tb-switch-thumb {\n transform: translateX(14px);\n}\n.tb-switch input:disabled + .tb-switch-track {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.tb-switch input:focus-visible + .tb-switch-track {\n outline: 2px solid var(--tb-link);\n outline-offset: 2px;\n}\n\n@keyframes tb-fade-in {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@media (max-width: 640px) {\n .tb-banner {\n flex-direction: column;\n align-items: stretch;\n }\n .tb-banner-actions {\n flex-direction: column;\n }\n .tb-banner-actions .tb-btn { width: 100%; }\n}\n`\n\nconst STYLE_ID = 'tickbox-default-styles'\n\nlet injected = false\n\n/**\n * Insert the stylesheet into `<head>` exactly once per page. Safe to call\n * from every component mount — subsequent calls are no-ops. No-op on the\n * server (no `document`).\n */\nexport function injectStyles(): void {\n if (injected) return\n if (typeof document === 'undefined') return\n if (document.getElementById(STYLE_ID)) {\n injected = true\n return\n }\n const el = document.createElement('style')\n el.id = STYLE_ID\n el.textContent = TICKBOX_STYLES\n document.head.appendChild(el)\n injected = true\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type BannerCopy = {
|
|
2
|
+
title: string;
|
|
3
|
+
description: string;
|
|
4
|
+
acceptLabel: string;
|
|
5
|
+
rejectLabel: string;
|
|
6
|
+
customiseLabel: string;
|
|
7
|
+
saveLabel: string;
|
|
8
|
+
closeLabel: string;
|
|
9
|
+
policyLinkLabel: string;
|
|
10
|
+
requiredBadge: string;
|
|
11
|
+
};
|
|
12
|
+
type NoticeCopy = {
|
|
13
|
+
title: string;
|
|
14
|
+
description: string;
|
|
15
|
+
acknowledgeLabel: string;
|
|
16
|
+
optOutLabel: string;
|
|
17
|
+
policyLinkLabel: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type LocalePack = {
|
|
21
|
+
banner: BannerCopy;
|
|
22
|
+
notice: NoticeCopy;
|
|
23
|
+
};
|
|
24
|
+
declare const locales: Record<string, LocalePack>;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve a BCP-47 locale tag to a built-in locale pack. Falls back from
|
|
27
|
+
* the full tag (`en-GB`) to the language prefix (`en`), then to English.
|
|
28
|
+
*
|
|
29
|
+
* Pass `'auto'` to read `navigator.language` at call time. Anywhere that
|
|
30
|
+
* `navigator` is missing (SSR, Node), `'auto'` falls back to English.
|
|
31
|
+
*/
|
|
32
|
+
declare function resolveLocalePack(locale: string | undefined): LocalePack;
|
|
33
|
+
|
|
34
|
+
export { type BannerCopy as B, type LocalePack as L, type NoticeCopy as N, locales as l, resolveLocalePack as r };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { B as BannerCopy, N as NoticeCopy } from '../
|
|
2
|
+
import { B as BannerCopy, N as NoticeCopy } from '../index-BYeQnxz5.js';
|
|
3
|
+
export { L as LocalePack, l as locales, r as resolveLocalePack } from '../index-BYeQnxz5.js';
|
|
3
4
|
|
|
4
5
|
type ConsentBannerDefaultProps = {
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* BCP-47 language tag (`'en'`, `'de'`, `'fr-CH'`, ...) or `'auto'` to
|
|
8
|
+
* read from `navigator.language`. Falls back from the full tag to the
|
|
9
|
+
* language prefix, then to English. Built-in: en, de, fr, es, it, nl,
|
|
10
|
+
* pt, pl.
|
|
11
|
+
*/
|
|
12
|
+
locale?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Override individual labels and copy strings. Layered on top of
|
|
15
|
+
* whichever locale is selected, so you can ship in one language and
|
|
16
|
+
* tweak a single label.
|
|
8
17
|
*/
|
|
9
18
|
copy?: Partial<BannerCopy>;
|
|
10
19
|
/**
|
|
@@ -34,8 +43,12 @@ declare function ConsentBannerDefault(props: ConsentBannerDefaultProps): react_j
|
|
|
34
43
|
|
|
35
44
|
type ConsentNoticeDefaultProps = {
|
|
36
45
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
46
|
+
* BCP-47 language tag (`'en'`, `'de'`, ...) or `'auto'`. See
|
|
47
|
+
* `ConsentBannerDefault` for the built-in list.
|
|
48
|
+
*/
|
|
49
|
+
locale?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Override individual labels. Layered on top of the resolved locale.
|
|
39
52
|
*/
|
|
40
53
|
copy?: Partial<NoticeCopy>;
|
|
41
54
|
/** Privacy-policy URL. If omitted, the link is hidden. */
|
|
@@ -61,4 +74,4 @@ type ConsentNoticeDefaultProps = {
|
|
|
61
74
|
*/
|
|
62
75
|
declare function ConsentNoticeDefault(props: ConsentNoticeDefaultProps): react_jsx_runtime.JSX.Element;
|
|
63
76
|
|
|
64
|
-
export { ConsentBannerDefault, type ConsentBannerDefaultProps, ConsentNoticeDefault, type ConsentNoticeDefaultProps };
|
|
77
|
+
export { BannerCopy, ConsentBannerDefault, type ConsentBannerDefaultProps, ConsentNoticeDefault, type ConsentNoticeDefaultProps, NoticeCopy };
|
package/dist/react/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveLocalePack, injectStyles } from '../chunk-DBGLNJWF.js';
|
|
2
|
+
export { locales, resolveLocalePack } from '../chunk-DBGLNJWF.js';
|
|
2
3
|
import { ConsentBanner, ConsentNotice } from '@tickboxhq/react';
|
|
3
4
|
import { useState, useEffect, useId, useRef } from 'react';
|
|
4
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -10,7 +11,7 @@ function BannerInner({
|
|
|
10
11
|
api,
|
|
11
12
|
props
|
|
12
13
|
}) {
|
|
13
|
-
const copy = { ...
|
|
14
|
+
const copy = { ...resolveLocalePack(props.locale).banner, ...props.copy };
|
|
14
15
|
const [showModal, setShowModal] = useState(false);
|
|
15
16
|
useEffect(() => {
|
|
16
17
|
injectStyles();
|
|
@@ -160,7 +161,7 @@ function ConsentNoticeDefault(props) {
|
|
|
160
161
|
return /* @__PURE__ */ jsx(ConsentNotice, { children: (api) => /* @__PURE__ */ jsx(NoticeInner, { api, props }) });
|
|
161
162
|
}
|
|
162
163
|
function NoticeInner({ api, props }) {
|
|
163
|
-
const copy = { ...
|
|
164
|
+
const copy = { ...resolveLocalePack(props.locale).notice, ...props.copy };
|
|
164
165
|
const optOutId = props.optOutCategoryId ?? "analytics";
|
|
165
166
|
useEffect(() => {
|
|
166
167
|
injectStyles();
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/react/banner.tsx","../../src/react/notice.tsx"],"names":["jsx","useEffect","jsxs"],"mappings":"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","file":"index.js","sourcesContent":["import { type ConsentApi, ConsentBanner } from '@tickboxhq/react'\nimport { useEffect, useId, useRef, useState } from 'react'\nimport { type BannerCopy, DEFAULT_BANNER_COPY } from '../shared/copy.js'\nimport { injectStyles } from '../shared/styles.js'\n\nexport type ConsentBannerDefaultProps = {\n /**\n * Override individual labels and copy strings. Anything you don't pass\n * falls back to the English defaults.\n */\n copy?: Partial<BannerCopy>\n /**\n * URL of the privacy policy linked from the banner. If omitted, the link\n * is hidden. The Tickbox config's `policy.url` is the natural source —\n * pass it here.\n */\n policyUrl?: string | undefined\n /**\n * Force light or dark theme. By default the banner follows\n * `prefers-color-scheme`.\n */\n theme?: 'light' | 'dark'\n}\n\n/**\n * Drop-in styled consent banner. Mounts itself only when the headless\n * `<ConsentBanner>` says it should be open. Click \"Customise\" to expand\n * a per-category modal.\n *\n * @example\n * ```tsx\n * import config from './consent.config'\n * <ConsentBannerDefault policyUrl={config.policy?.url} />\n * ```\n */\nexport function ConsentBannerDefault(props: ConsentBannerDefaultProps) {\n return <ConsentBanner>{(api) => <BannerInner api={api} props={props} />}</ConsentBanner>\n}\n\nfunction BannerInner({\n api,\n props,\n}: {\n api: ConsentApi\n props: ConsentBannerDefaultProps\n}) {\n const copy: BannerCopy = { ...DEFAULT_BANNER_COPY, ...props.copy }\n const [showModal, setShowModal] = useState(false)\n\n useEffect(() => {\n injectStyles()\n }, [])\n\n const themeAttrs = props.theme ? { 'data-tb-theme': props.theme } : {}\n\n return (\n <>\n <div className=\"tb-root tb-banner\" role=\"region\" aria-label={copy.title} {...themeAttrs}>\n <div className=\"tb-banner-text\">\n <p className=\"tb-banner-title\">{copy.title}</p>\n <p className=\"tb-banner-desc\">{copy.description}</p>\n </div>\n <div className=\"tb-banner-actions\">\n {props.policyUrl && (\n <a className=\"tb-link\" href={props.policyUrl}>\n {copy.policyLinkLabel}\n </a>\n )}\n <button type=\"button\" className=\"tb-btn tb-btn-equal\" onClick={() => api.denyAll()}>\n {copy.rejectLabel}\n </button>\n <button type=\"button\" className=\"tb-btn tb-btn-ghost\" onClick={() => setShowModal(true)}>\n {copy.customiseLabel}\n </button>\n <button type=\"button\" className=\"tb-btn tb-btn-equal\" onClick={() => api.grantAll()}>\n {copy.acceptLabel}\n </button>\n </div>\n </div>\n {showModal && (\n <CustomiseModal\n api={api}\n copy={copy}\n theme={props.theme}\n onClose={() => setShowModal(false)}\n />\n )}\n </>\n )\n}\n\nfunction CustomiseModal({\n api,\n copy,\n theme,\n onClose,\n}: {\n api: ConsentApi\n copy: BannerCopy\n theme?: 'light' | 'dark'\n onClose: () => void\n}) {\n const titleId = useId()\n const containerRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape') onClose()\n if (e.key === 'Tab') trapFocus(e, containerRef.current)\n }\n document.addEventListener('keydown', onKey)\n const previouslyFocused = document.activeElement as HTMLElement | null\n const first = containerRef.current?.querySelector<HTMLElement>(\n 'button, [href], input, [tabindex]:not([tabindex=\"-1\"])',\n )\n first?.focus()\n return () => {\n document.removeEventListener('keydown', onKey)\n previouslyFocused?.focus?.()\n }\n }, [onClose])\n\n const themeAttrs = theme ? { 'data-tb-theme': theme } : {}\n\n return (\n <div\n className=\"tb-root tb-modal-backdrop\"\n onClick={onClose}\n onKeyDown={(e) => {\n if (e.key === 'Escape') onClose()\n }}\n role=\"presentation\"\n {...themeAttrs}\n >\n <div\n ref={containerRef}\n className=\"tb-modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n <div className=\"tb-modal-head\">\n <h2 id={titleId} className=\"tb-modal-title\">\n {copy.customiseLabel}\n </h2>\n <button\n type=\"button\"\n className=\"tb-btn tb-btn-ghost\"\n aria-label={copy.closeLabel}\n onClick={onClose}\n >\n ✕\n </button>\n </div>\n <div className=\"tb-modal-body\">\n {api.resolved.map((cat) => {\n const checked = api.decisions[cat.id] === true\n const id = `tb-cat-${cat.id}`\n return (\n <div key={cat.id} className=\"tb-cat\">\n <div className=\"tb-cat-text\">\n <p className=\"tb-cat-name\">\n <label htmlFor={id}>{cat.id}</label>\n {cat.required && <span className=\"tb-badge\">{copy.requiredBadge}</span>}\n </p>\n {cat.description && <p className=\"tb-cat-desc\">{cat.description}</p>}\n </div>\n <label className=\"tb-switch\">\n <input\n id={id}\n type=\"checkbox\"\n checked={checked}\n disabled={cat.required}\n onChange={(e) => {\n if (e.target.checked) api.grant(cat.id)\n else api.deny(cat.id)\n }}\n />\n <span className=\"tb-switch-track\">\n <span className=\"tb-switch-thumb\" />\n </span>\n </label>\n </div>\n )\n })}\n </div>\n <div className=\"tb-modal-foot\">\n <button type=\"button\" className=\"tb-btn tb-btn-equal\" onClick={() => api.denyAll()}>\n {copy.rejectLabel}\n </button>\n <button type=\"button\" className=\"tb-btn tb-btn-primary\" onClick={() => api.save()}>\n {copy.saveLabel}\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nfunction trapFocus(e: KeyboardEvent, container: HTMLDivElement | null) {\n if (!container) return\n const focusables = container.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), [href], input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n )\n if (focusables.length === 0) return\n const first = focusables[0]\n const last = focusables[focusables.length - 1]\n if (!first || !last) return\n const active = document.activeElement\n if (e.shiftKey && active === first) {\n e.preventDefault()\n last.focus()\n } else if (!e.shiftKey && active === last) {\n e.preventDefault()\n first.focus()\n }\n}\n","import { type ConsentApi, ConsentNotice } from '@tickboxhq/react'\nimport { useEffect } from 'react'\nimport { DEFAULT_NOTICE_COPY, type NoticeCopy } from '../shared/copy.js'\nimport { injectStyles } from '../shared/styles.js'\n\nexport type ConsentNoticeDefaultProps = {\n /**\n * Override individual labels and copy strings. Anything you don't pass\n * falls back to the English defaults.\n */\n copy?: Partial<NoticeCopy>\n /** Privacy-policy URL. If omitted, the link is hidden. */\n policyUrl?: string | undefined\n /**\n * Category ID to deny when the user clicks \"Opt out\". Defaults to\n * `'analytics'` since that's the most common notice-mode category.\n */\n optOutCategoryId?: string\n /** Force light or dark theme. */\n theme?: 'light' | 'dark'\n}\n\n/**\n * Drop-in styled notice card for sites that have only `notice`-mode\n * categories (typically UK DUAA-exempt analytics like Plausible or\n * GoatCounter). Bottom-right toast.\n *\n * @example\n * ```tsx\n * import config from './consent.config'\n * <ConsentNoticeDefault policyUrl={config.policy?.url} />\n * ```\n */\nexport function ConsentNoticeDefault(props: ConsentNoticeDefaultProps) {\n return <ConsentNotice>{(api) => <NoticeInner api={api} props={props} />}</ConsentNotice>\n}\n\nfunction NoticeInner({ api, props }: { api: ConsentApi; props: ConsentNoticeDefaultProps }) {\n const copy: NoticeCopy = { ...DEFAULT_NOTICE_COPY, ...props.copy }\n const optOutId = props.optOutCategoryId ?? 'analytics'\n\n useEffect(() => {\n injectStyles()\n }, [])\n\n const themeAttrs = props.theme ? { 'data-tb-theme': props.theme } : {}\n\n return (\n <div\n className=\"tb-root tb-notice\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label={copy.title}\n {...themeAttrs}\n >\n <p className=\"tb-notice-title\">{copy.title}</p>\n <p className=\"tb-notice-desc\">{copy.description}</p>\n <div className=\"tb-notice-actions\">\n {props.policyUrl && (\n <a className=\"tb-link\" href={props.policyUrl}>\n {copy.policyLinkLabel}\n </a>\n )}\n <button\n type=\"button\"\n className=\"tb-btn tb-btn-secondary\"\n onClick={() => {\n if (api.resolved.some((r) => r.id === optOutId)) {\n api.deny(optOutId)\n }\n api.save()\n }}\n >\n {copy.optOutLabel}\n </button>\n <button type=\"button\" className=\"tb-btn tb-btn-primary\" onClick={() => api.save()}>\n {copy.acknowledgeLabel}\n </button>\n </div>\n </div>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/react/banner.tsx","../../src/react/notice.tsx"],"names":["jsx","useEffect","jsxs"],"mappings":"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","file":"index.js","sourcesContent":["import { type ConsentApi, ConsentBanner } from '@tickboxhq/react'\nimport { useEffect, useId, useRef, useState } from 'react'\nimport type { BannerCopy } from '../shared/copy.js'\nimport { resolveLocalePack } from '../shared/locales/index.js'\nimport { injectStyles } from '../shared/styles.js'\n\nexport type ConsentBannerDefaultProps = {\n /**\n * BCP-47 language tag (`'en'`, `'de'`, `'fr-CH'`, ...) or `'auto'` to\n * read from `navigator.language`. Falls back from the full tag to the\n * language prefix, then to English. Built-in: en, de, fr, es, it, nl,\n * pt, pl.\n */\n locale?: string\n /**\n * Override individual labels and copy strings. Layered on top of\n * whichever locale is selected, so you can ship in one language and\n * tweak a single label.\n */\n copy?: Partial<BannerCopy>\n /**\n * URL of the privacy policy linked from the banner. If omitted, the link\n * is hidden. The Tickbox config's `policy.url` is the natural source —\n * pass it here.\n */\n policyUrl?: string | undefined\n /**\n * Force light or dark theme. By default the banner follows\n * `prefers-color-scheme`.\n */\n theme?: 'light' | 'dark'\n}\n\n/**\n * Drop-in styled consent banner. Mounts itself only when the headless\n * `<ConsentBanner>` says it should be open. Click \"Customise\" to expand\n * a per-category modal.\n *\n * @example\n * ```tsx\n * import config from './consent.config'\n * <ConsentBannerDefault policyUrl={config.policy?.url} />\n * ```\n */\nexport function ConsentBannerDefault(props: ConsentBannerDefaultProps) {\n return <ConsentBanner>{(api) => <BannerInner api={api} props={props} />}</ConsentBanner>\n}\n\nfunction BannerInner({\n api,\n props,\n}: {\n api: ConsentApi\n props: ConsentBannerDefaultProps\n}) {\n const copy: BannerCopy = { ...resolveLocalePack(props.locale).banner, ...props.copy }\n const [showModal, setShowModal] = useState(false)\n\n useEffect(() => {\n injectStyles()\n }, [])\n\n const themeAttrs = props.theme ? { 'data-tb-theme': props.theme } : {}\n\n return (\n <>\n <div className=\"tb-root tb-banner\" role=\"region\" aria-label={copy.title} {...themeAttrs}>\n <div className=\"tb-banner-text\">\n <p className=\"tb-banner-title\">{copy.title}</p>\n <p className=\"tb-banner-desc\">{copy.description}</p>\n </div>\n <div className=\"tb-banner-actions\">\n {props.policyUrl && (\n <a className=\"tb-link\" href={props.policyUrl}>\n {copy.policyLinkLabel}\n </a>\n )}\n <button type=\"button\" className=\"tb-btn tb-btn-equal\" onClick={() => api.denyAll()}>\n {copy.rejectLabel}\n </button>\n <button type=\"button\" className=\"tb-btn tb-btn-ghost\" onClick={() => setShowModal(true)}>\n {copy.customiseLabel}\n </button>\n <button type=\"button\" className=\"tb-btn tb-btn-equal\" onClick={() => api.grantAll()}>\n {copy.acceptLabel}\n </button>\n </div>\n </div>\n {showModal && (\n <CustomiseModal\n api={api}\n copy={copy}\n theme={props.theme}\n onClose={() => setShowModal(false)}\n />\n )}\n </>\n )\n}\n\nfunction CustomiseModal({\n api,\n copy,\n theme,\n onClose,\n}: {\n api: ConsentApi\n copy: BannerCopy\n theme?: 'light' | 'dark'\n onClose: () => void\n}) {\n const titleId = useId()\n const containerRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape') onClose()\n if (e.key === 'Tab') trapFocus(e, containerRef.current)\n }\n document.addEventListener('keydown', onKey)\n const previouslyFocused = document.activeElement as HTMLElement | null\n const first = containerRef.current?.querySelector<HTMLElement>(\n 'button, [href], input, [tabindex]:not([tabindex=\"-1\"])',\n )\n first?.focus()\n return () => {\n document.removeEventListener('keydown', onKey)\n previouslyFocused?.focus?.()\n }\n }, [onClose])\n\n const themeAttrs = theme ? { 'data-tb-theme': theme } : {}\n\n return (\n <div\n className=\"tb-root tb-modal-backdrop\"\n onClick={onClose}\n onKeyDown={(e) => {\n if (e.key === 'Escape') onClose()\n }}\n role=\"presentation\"\n {...themeAttrs}\n >\n <div\n ref={containerRef}\n className=\"tb-modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n <div className=\"tb-modal-head\">\n <h2 id={titleId} className=\"tb-modal-title\">\n {copy.customiseLabel}\n </h2>\n <button\n type=\"button\"\n className=\"tb-btn tb-btn-ghost\"\n aria-label={copy.closeLabel}\n onClick={onClose}\n >\n ✕\n </button>\n </div>\n <div className=\"tb-modal-body\">\n {api.resolved.map((cat) => {\n const checked = api.decisions[cat.id] === true\n const id = `tb-cat-${cat.id}`\n return (\n <div key={cat.id} className=\"tb-cat\">\n <div className=\"tb-cat-text\">\n <p className=\"tb-cat-name\">\n <label htmlFor={id}>{cat.id}</label>\n {cat.required && <span className=\"tb-badge\">{copy.requiredBadge}</span>}\n </p>\n {cat.description && <p className=\"tb-cat-desc\">{cat.description}</p>}\n </div>\n <label className=\"tb-switch\">\n <input\n id={id}\n type=\"checkbox\"\n checked={checked}\n disabled={cat.required}\n onChange={(e) => {\n if (e.target.checked) api.grant(cat.id)\n else api.deny(cat.id)\n }}\n />\n <span className=\"tb-switch-track\">\n <span className=\"tb-switch-thumb\" />\n </span>\n </label>\n </div>\n )\n })}\n </div>\n <div className=\"tb-modal-foot\">\n <button type=\"button\" className=\"tb-btn tb-btn-equal\" onClick={() => api.denyAll()}>\n {copy.rejectLabel}\n </button>\n <button type=\"button\" className=\"tb-btn tb-btn-primary\" onClick={() => api.save()}>\n {copy.saveLabel}\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nfunction trapFocus(e: KeyboardEvent, container: HTMLDivElement | null) {\n if (!container) return\n const focusables = container.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), [href], input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n )\n if (focusables.length === 0) return\n const first = focusables[0]\n const last = focusables[focusables.length - 1]\n if (!first || !last) return\n const active = document.activeElement\n if (e.shiftKey && active === first) {\n e.preventDefault()\n last.focus()\n } else if (!e.shiftKey && active === last) {\n e.preventDefault()\n first.focus()\n }\n}\n","import { type ConsentApi, ConsentNotice } from '@tickboxhq/react'\nimport { useEffect } from 'react'\nimport type { NoticeCopy } from '../shared/copy.js'\nimport { resolveLocalePack } from '../shared/locales/index.js'\nimport { injectStyles } from '../shared/styles.js'\n\nexport type ConsentNoticeDefaultProps = {\n /**\n * BCP-47 language tag (`'en'`, `'de'`, ...) or `'auto'`. See\n * `ConsentBannerDefault` for the built-in list.\n */\n locale?: string\n /**\n * Override individual labels. Layered on top of the resolved locale.\n */\n copy?: Partial<NoticeCopy>\n /** Privacy-policy URL. If omitted, the link is hidden. */\n policyUrl?: string | undefined\n /**\n * Category ID to deny when the user clicks \"Opt out\". Defaults to\n * `'analytics'` since that's the most common notice-mode category.\n */\n optOutCategoryId?: string\n /** Force light or dark theme. */\n theme?: 'light' | 'dark'\n}\n\n/**\n * Drop-in styled notice card for sites that have only `notice`-mode\n * categories (typically UK DUAA-exempt analytics like Plausible or\n * GoatCounter). Bottom-right toast.\n *\n * @example\n * ```tsx\n * import config from './consent.config'\n * <ConsentNoticeDefault policyUrl={config.policy?.url} />\n * ```\n */\nexport function ConsentNoticeDefault(props: ConsentNoticeDefaultProps) {\n return <ConsentNotice>{(api) => <NoticeInner api={api} props={props} />}</ConsentNotice>\n}\n\nfunction NoticeInner({ api, props }: { api: ConsentApi; props: ConsentNoticeDefaultProps }) {\n const copy: NoticeCopy = { ...resolveLocalePack(props.locale).notice, ...props.copy }\n const optOutId = props.optOutCategoryId ?? 'analytics'\n\n useEffect(() => {\n injectStyles()\n }, [])\n\n const themeAttrs = props.theme ? { 'data-tb-theme': props.theme } : {}\n\n return (\n <div\n className=\"tb-root tb-notice\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label={copy.title}\n {...themeAttrs}\n >\n <p className=\"tb-notice-title\">{copy.title}</p>\n <p className=\"tb-notice-desc\">{copy.description}</p>\n <div className=\"tb-notice-actions\">\n {props.policyUrl && (\n <a className=\"tb-link\" href={props.policyUrl}>\n {copy.policyLinkLabel}\n </a>\n )}\n <button\n type=\"button\"\n className=\"tb-btn tb-btn-secondary\"\n onClick={() => {\n if (api.resolved.some((r) => r.id === optOutId)) {\n api.deny(optOutId)\n }\n api.save()\n }}\n >\n {copy.optOutLabel}\n </button>\n <button type=\"button\" className=\"tb-btn tb-btn-primary\" onClick={() => api.save()}>\n {copy.acknowledgeLabel}\n </button>\n </div>\n </div>\n )\n}\n"]}
|
package/dist/vue/index.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import * as vue from 'vue';
|
|
2
2
|
import { PropType } from 'vue';
|
|
3
|
-
import { B as BannerCopy, N as NoticeCopy } from '../
|
|
3
|
+
import { B as BannerCopy, N as NoticeCopy } from '../index-BYeQnxz5.js';
|
|
4
|
+
export { L as LocalePack, l as locales, r as resolveLocalePack } from '../index-BYeQnxz5.js';
|
|
4
5
|
|
|
5
6
|
type ConsentBannerDefaultProps = {
|
|
7
|
+
/**
|
|
8
|
+
* BCP-47 language tag (`'en'`, `'de'`, `'fr-CH'`, ...) or `'auto'`.
|
|
9
|
+
* Built-in: en, de, fr, es, it, nl, pt, pl. Falls back from the full
|
|
10
|
+
* tag to the language prefix, then to English.
|
|
11
|
+
*/
|
|
12
|
+
locale?: string;
|
|
6
13
|
copy?: Partial<BannerCopy>;
|
|
7
14
|
policyUrl?: string;
|
|
8
15
|
theme?: 'light' | 'dark';
|
|
@@ -29,6 +36,10 @@ type ConsentBannerDefaultProps = {
|
|
|
29
36
|
* ```
|
|
30
37
|
*/
|
|
31
38
|
declare const ConsentBannerDefault: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
39
|
+
locale: {
|
|
40
|
+
type: PropType<string | undefined>;
|
|
41
|
+
default: undefined;
|
|
42
|
+
};
|
|
32
43
|
copy: {
|
|
33
44
|
type: PropType<Partial<BannerCopy>>;
|
|
34
45
|
default: () => {};
|
|
@@ -44,6 +55,10 @@ declare const ConsentBannerDefault: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
|
44
55
|
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
45
56
|
[key: string]: any;
|
|
46
57
|
}>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
58
|
+
locale: {
|
|
59
|
+
type: PropType<string | undefined>;
|
|
60
|
+
default: undefined;
|
|
61
|
+
};
|
|
47
62
|
copy: {
|
|
48
63
|
type: PropType<Partial<BannerCopy>>;
|
|
49
64
|
default: () => {};
|
|
@@ -57,12 +72,14 @@ declare const ConsentBannerDefault: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
|
57
72
|
default: undefined;
|
|
58
73
|
};
|
|
59
74
|
}>> & Readonly<{}>, {
|
|
75
|
+
locale: string | undefined;
|
|
60
76
|
copy: Partial<BannerCopy>;
|
|
61
77
|
policyUrl: string | undefined;
|
|
62
78
|
theme: "light" | "dark" | undefined;
|
|
63
79
|
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
64
80
|
|
|
65
81
|
type ConsentNoticeDefaultProps = {
|
|
82
|
+
locale?: string;
|
|
66
83
|
copy?: Partial<NoticeCopy>;
|
|
67
84
|
policyUrl?: string;
|
|
68
85
|
optOutCategoryId?: string;
|
|
@@ -74,6 +91,10 @@ type ConsentNoticeDefaultProps = {
|
|
|
74
91
|
* "Got it" / "Opt out" actions.
|
|
75
92
|
*/
|
|
76
93
|
declare const ConsentNoticeDefault: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
94
|
+
locale: {
|
|
95
|
+
type: PropType<string | undefined>;
|
|
96
|
+
default: undefined;
|
|
97
|
+
};
|
|
77
98
|
copy: {
|
|
78
99
|
type: PropType<Partial<NoticeCopy>>;
|
|
79
100
|
default: () => {};
|
|
@@ -93,6 +114,10 @@ declare const ConsentNoticeDefault: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
|
93
114
|
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
94
115
|
[key: string]: any;
|
|
95
116
|
}>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
117
|
+
locale: {
|
|
118
|
+
type: PropType<string | undefined>;
|
|
119
|
+
default: undefined;
|
|
120
|
+
};
|
|
96
121
|
copy: {
|
|
97
122
|
type: PropType<Partial<NoticeCopy>>;
|
|
98
123
|
default: () => {};
|
|
@@ -110,10 +135,11 @@ declare const ConsentNoticeDefault: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
|
110
135
|
default: undefined;
|
|
111
136
|
};
|
|
112
137
|
}>> & Readonly<{}>, {
|
|
138
|
+
locale: string | undefined;
|
|
113
139
|
copy: Partial<NoticeCopy>;
|
|
114
140
|
policyUrl: string | undefined;
|
|
115
141
|
theme: "light" | "dark" | undefined;
|
|
116
142
|
optOutCategoryId: string;
|
|
117
143
|
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
118
144
|
|
|
119
|
-
export { ConsentBannerDefault, type ConsentBannerDefaultProps, ConsentNoticeDefault, type ConsentNoticeDefaultProps };
|
|
145
|
+
export { BannerCopy, ConsentBannerDefault, type ConsentBannerDefaultProps, ConsentNoticeDefault, type ConsentNoticeDefaultProps, NoticeCopy };
|
package/dist/vue/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { injectStyles,
|
|
1
|
+
import { injectStyles, resolveLocalePack } from '../chunk-DBGLNJWF.js';
|
|
2
|
+
export { locales, resolveLocalePack } from '../chunk-DBGLNJWF.js';
|
|
2
3
|
import { ConsentBanner, ConsentNotice } from '@tickboxhq/vue';
|
|
3
4
|
import { defineComponent, onMounted, h, ref } from 'vue';
|
|
4
5
|
|
|
5
6
|
var ConsentBannerDefault = defineComponent({
|
|
6
7
|
name: "ConsentBannerDefault",
|
|
7
8
|
props: {
|
|
9
|
+
locale: { type: String, default: void 0 },
|
|
8
10
|
copy: { type: Object, default: () => ({}) },
|
|
9
11
|
policyUrl: { type: String, default: void 0 },
|
|
10
12
|
theme: { type: String, default: void 0 }
|
|
@@ -14,6 +16,7 @@ var ConsentBannerDefault = defineComponent({
|
|
|
14
16
|
return () => h(ConsentBanner, null, {
|
|
15
17
|
default: (api) => h(BannerInner, {
|
|
16
18
|
api,
|
|
19
|
+
locale: props.locale,
|
|
17
20
|
userCopy: props.copy ?? {},
|
|
18
21
|
policyUrl: props.policyUrl,
|
|
19
22
|
theme: props.theme
|
|
@@ -25,6 +28,7 @@ var BannerInner = defineComponent({
|
|
|
25
28
|
name: "ConsentBannerDefaultInner",
|
|
26
29
|
props: {
|
|
27
30
|
api: { type: Object, required: true },
|
|
31
|
+
locale: { type: String, default: void 0 },
|
|
28
32
|
userCopy: { type: Object, required: true },
|
|
29
33
|
policyUrl: { type: String, default: void 0 },
|
|
30
34
|
theme: { type: String, default: void 0 }
|
|
@@ -32,7 +36,10 @@ var BannerInner = defineComponent({
|
|
|
32
36
|
setup(props) {
|
|
33
37
|
const showModal = ref(false);
|
|
34
38
|
return () => {
|
|
35
|
-
const copy = {
|
|
39
|
+
const copy = {
|
|
40
|
+
...resolveLocalePack(props.locale).banner,
|
|
41
|
+
...props.userCopy
|
|
42
|
+
};
|
|
36
43
|
const themeAttrs = props.theme ? { "data-tb-theme": props.theme } : {};
|
|
37
44
|
return h("div", null, [
|
|
38
45
|
h(
|
|
@@ -188,6 +195,7 @@ function renderModal(api, copy, theme, onClose) {
|
|
|
188
195
|
var ConsentNoticeDefault = defineComponent({
|
|
189
196
|
name: "ConsentNoticeDefault",
|
|
190
197
|
props: {
|
|
198
|
+
locale: { type: String, default: void 0 },
|
|
191
199
|
copy: { type: Object, default: () => ({}) },
|
|
192
200
|
policyUrl: { type: String, default: void 0 },
|
|
193
201
|
optOutCategoryId: { type: String, default: "analytics" },
|
|
@@ -201,7 +209,10 @@ var ConsentNoticeDefault = defineComponent({
|
|
|
201
209
|
}
|
|
202
210
|
});
|
|
203
211
|
function renderNotice(api, props) {
|
|
204
|
-
const copy = {
|
|
212
|
+
const copy = {
|
|
213
|
+
...resolveLocalePack(props.locale).notice,
|
|
214
|
+
...props.copy ?? {}
|
|
215
|
+
};
|
|
205
216
|
const optOutId = props.optOutCategoryId ?? "analytics";
|
|
206
217
|
const themeAttrs = props.theme ? { "data-tb-theme": props.theme } : {};
|
|
207
218
|
return h(
|
package/dist/vue/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/vue/banner.ts","../../src/vue/notice.ts"],"names":["defineComponent","onMounted","h"],"mappings":"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","file":"index.js","sourcesContent":["import type { ConsentSlotApi } from '@tickboxhq/vue'\nimport { ConsentBanner } from '@tickboxhq/vue'\nimport { type PropType, defineComponent, h, onMounted, ref } from 'vue'\nimport { type BannerCopy, DEFAULT_BANNER_COPY } from '../shared/copy.js'\nimport { injectStyles } from '../shared/styles.js'\n\nexport type ConsentBannerDefaultProps = {\n copy?: Partial<BannerCopy>\n policyUrl?: string\n theme?: 'light' | 'dark'\n}\n\n/**\n * Drop-in styled consent banner for Vue. Mounts only when the headless\n * `<ConsentBanner>` says it should be open. \"Customise\" opens a modal\n * with per-category toggles.\n *\n * Equal-prominence design: Accept All and Reject All use identical button\n * styling. UK ICO and EU EDPB guidance treats unequal visual weight on\n * those buttons as a dark pattern. Customise is rendered as a ghost button\n * so the two consent paths stay symmetrical.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { ConsentBannerDefault } from '@tickboxhq/banner-default/vue'\n * import config from './consent.config'\n * </script>\n * <template>\n * <ConsentBannerDefault :policy-url=\"config.policy?.url\" />\n * </template>\n * ```\n */\nexport const ConsentBannerDefault = defineComponent({\n name: 'ConsentBannerDefault',\n props: {\n copy: { type: Object as PropType<Partial<BannerCopy>>, default: () => ({}) },\n policyUrl: { type: String as PropType<string | undefined>, default: undefined },\n theme: { type: String as PropType<'light' | 'dark' | undefined>, default: undefined },\n },\n setup(props) {\n onMounted(() => injectStyles())\n return () =>\n h(ConsentBanner, null, {\n default: (api: unknown) =>\n h(BannerInner, {\n api: api as ConsentSlotApi,\n userCopy: props.copy ?? {},\n policyUrl: props.policyUrl,\n theme: props.theme,\n }),\n })\n },\n})\n\n/**\n * Inner component that owns `showModal` state. Keeping it in the same\n * scope as the render guarantees Vue's reactivity wires up correctly\n * (slot-only render functions don't track refs from outer scopes).\n */\nconst BannerInner = defineComponent({\n name: 'ConsentBannerDefaultInner',\n props: {\n api: { type: Object as PropType<ConsentSlotApi>, required: true },\n userCopy: { type: Object as PropType<Partial<BannerCopy>>, required: true },\n policyUrl: { type: String as PropType<string | undefined>, default: undefined },\n theme: { type: String as PropType<'light' | 'dark' | undefined>, default: undefined },\n },\n setup(props) {\n const showModal = ref(false)\n\n return () => {\n const copy: BannerCopy = { ...DEFAULT_BANNER_COPY, ...props.userCopy }\n const themeAttrs = props.theme ? { 'data-tb-theme': props.theme } : {}\n\n return h('div', null, [\n h(\n 'div',\n {\n class: 'tb-root tb-banner',\n role: 'region',\n 'aria-label': copy.title,\n ...themeAttrs,\n },\n [\n h('div', { class: 'tb-banner-text' }, [\n h('p', { class: 'tb-banner-title' }, copy.title),\n h('p', { class: 'tb-banner-desc' }, copy.description),\n ]),\n h('div', { class: 'tb-banner-actions' }, [\n props.policyUrl\n ? h('a', { class: 'tb-link', href: props.policyUrl }, copy.policyLinkLabel)\n : null,\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-equal',\n onClick: () => props.api.denyAll(),\n },\n copy.rejectLabel,\n ),\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-ghost',\n onClick: () => {\n showModal.value = true\n },\n },\n copy.customiseLabel,\n ),\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-equal',\n onClick: () => props.api.grantAll(),\n },\n copy.acceptLabel,\n ),\n ]),\n ],\n ),\n showModal.value\n ? renderModal(props.api, copy, props.theme, () => {\n showModal.value = false\n })\n : null,\n ])\n }\n },\n})\n\nfunction renderModal(\n api: ConsentSlotApi,\n copy: BannerCopy,\n theme: 'light' | 'dark' | undefined,\n onClose: () => void,\n) {\n const themeAttrs = theme ? { 'data-tb-theme': theme } : {}\n\n return h(\n 'div',\n {\n class: 'tb-root tb-modal-backdrop',\n role: 'presentation',\n onClick: onClose,\n onKeydown: (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose()\n },\n ...themeAttrs,\n },\n [\n h(\n 'div',\n {\n class: 'tb-modal',\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-label': copy.customiseLabel,\n onClick: (e: MouseEvent) => e.stopPropagation(),\n onKeydown: (e: KeyboardEvent) => e.stopPropagation(),\n },\n [\n h('div', { class: 'tb-modal-head' }, [\n h('h2', { class: 'tb-modal-title' }, copy.customiseLabel),\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-ghost',\n 'aria-label': copy.closeLabel,\n onClick: onClose,\n },\n '✕',\n ),\n ]),\n h(\n 'div',\n { class: 'tb-modal-body' },\n api.resolved.map((cat) => {\n const checked = api.decisions[cat.id] === true\n const id = `tb-cat-${cat.id}`\n return h('div', { key: cat.id, class: 'tb-cat' }, [\n h('div', { class: 'tb-cat-text' }, [\n h('p', { class: 'tb-cat-name' }, [\n h('label', { for: id }, cat.id),\n cat.required ? h('span', { class: 'tb-badge' }, copy.requiredBadge) : null,\n ]),\n cat.description ? h('p', { class: 'tb-cat-desc' }, cat.description) : null,\n ]),\n h('label', { class: 'tb-switch' }, [\n h('input', {\n id,\n type: 'checkbox',\n checked,\n disabled: cat.required,\n onChange: (e: Event) => {\n const next = (e.target as HTMLInputElement).checked\n if (next) api.grant(cat.id)\n else api.deny(cat.id)\n },\n }),\n h('span', { class: 'tb-switch-track' }, [\n h('span', { class: 'tb-switch-thumb' }),\n ]),\n ]),\n ])\n }),\n ),\n h('div', { class: 'tb-modal-foot' }, [\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-equal',\n onClick: () => api.denyAll(),\n },\n copy.rejectLabel,\n ),\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-primary',\n onClick: () => api.save(),\n },\n copy.saveLabel,\n ),\n ]),\n ],\n ),\n ],\n )\n}\n","import type { ConsentSlotApi } from '@tickboxhq/vue'\nimport { ConsentNotice } from '@tickboxhq/vue'\nimport { type PropType, defineComponent, h, onMounted } from 'vue'\nimport { DEFAULT_NOTICE_COPY, type NoticeCopy } from '../shared/copy.js'\nimport { injectStyles } from '../shared/styles.js'\n\nexport type ConsentNoticeDefaultProps = {\n copy?: Partial<NoticeCopy>\n policyUrl?: string\n optOutCategoryId?: string\n theme?: 'light' | 'dark'\n}\n\n/**\n * Drop-in styled notice card for sites with only `notice`-mode categories\n * (typically UK DUAA-exempt analytics). Bottom-right toast with\n * \"Got it\" / \"Opt out\" actions.\n */\nexport const ConsentNoticeDefault = defineComponent({\n name: 'ConsentNoticeDefault',\n props: {\n copy: { type: Object as PropType<Partial<NoticeCopy>>, default: () => ({}) },\n policyUrl: { type: String as PropType<string | undefined>, default: undefined },\n optOutCategoryId: { type: String, default: 'analytics' },\n theme: { type: String as PropType<'light' | 'dark' | undefined>, default: undefined },\n },\n setup(props) {\n onMounted(() => injectStyles())\n return () =>\n h(ConsentNotice, null, {\n default: (api: unknown) => renderNotice(api as ConsentSlotApi, props),\n })\n },\n})\n\nfunction renderNotice(api: ConsentSlotApi, props: ConsentNoticeDefaultProps) {\n const copy: NoticeCopy = { ...DEFAULT_NOTICE_COPY, ...(props.copy ?? {}) }\n const optOutId = props.optOutCategoryId ?? 'analytics'\n\n const themeAttrs = props.theme ? { 'data-tb-theme': props.theme } : {}\n\n return h(\n 'div',\n {\n class: 'tb-root tb-notice',\n role: 'status',\n 'aria-live': 'polite',\n 'aria-label': copy.title,\n ...themeAttrs,\n },\n [\n h('p', { class: 'tb-notice-title' }, copy.title),\n h('p', { class: 'tb-notice-desc' }, copy.description),\n h('div', { class: 'tb-notice-actions' }, [\n props.policyUrl\n ? h('a', { class: 'tb-link', href: props.policyUrl }, copy.policyLinkLabel)\n : null,\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-secondary',\n onClick: () => {\n if (api.resolved.some((r) => r.id === optOutId)) {\n api.deny(optOutId)\n }\n api.save()\n },\n },\n copy.optOutLabel,\n ),\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-primary',\n onClick: () => api.save(),\n },\n copy.acknowledgeLabel,\n ),\n ]),\n ],\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/vue/banner.ts","../../src/vue/notice.ts"],"names":["defineComponent","onMounted","h"],"mappings":"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","file":"index.js","sourcesContent":["import type { ConsentSlotApi } from '@tickboxhq/vue'\nimport { ConsentBanner } from '@tickboxhq/vue'\nimport { type PropType, defineComponent, h, onMounted, ref } from 'vue'\nimport type { BannerCopy } from '../shared/copy.js'\nimport { resolveLocalePack } from '../shared/locales/index.js'\nimport { injectStyles } from '../shared/styles.js'\n\nexport type ConsentBannerDefaultProps = {\n /**\n * BCP-47 language tag (`'en'`, `'de'`, `'fr-CH'`, ...) or `'auto'`.\n * Built-in: en, de, fr, es, it, nl, pt, pl. Falls back from the full\n * tag to the language prefix, then to English.\n */\n locale?: string\n copy?: Partial<BannerCopy>\n policyUrl?: string\n theme?: 'light' | 'dark'\n}\n\n/**\n * Drop-in styled consent banner for Vue. Mounts only when the headless\n * `<ConsentBanner>` says it should be open. \"Customise\" opens a modal\n * with per-category toggles.\n *\n * Equal-prominence design: Accept All and Reject All use identical button\n * styling. UK ICO and EU EDPB guidance treats unequal visual weight on\n * those buttons as a dark pattern. Customise is rendered as a ghost button\n * so the two consent paths stay symmetrical.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { ConsentBannerDefault } from '@tickboxhq/banner-default/vue'\n * import config from './consent.config'\n * </script>\n * <template>\n * <ConsentBannerDefault :policy-url=\"config.policy?.url\" />\n * </template>\n * ```\n */\nexport const ConsentBannerDefault = defineComponent({\n name: 'ConsentBannerDefault',\n props: {\n locale: { type: String as PropType<string | undefined>, default: undefined },\n copy: { type: Object as PropType<Partial<BannerCopy>>, default: () => ({}) },\n policyUrl: { type: String as PropType<string | undefined>, default: undefined },\n theme: { type: String as PropType<'light' | 'dark' | undefined>, default: undefined },\n },\n setup(props) {\n onMounted(() => injectStyles())\n return () =>\n h(ConsentBanner, null, {\n default: (api: unknown) =>\n h(BannerInner, {\n api: api as ConsentSlotApi,\n locale: props.locale,\n userCopy: props.copy ?? {},\n policyUrl: props.policyUrl,\n theme: props.theme,\n }),\n })\n },\n})\n\n/**\n * Inner component that owns `showModal` state. Keeping it in the same\n * scope as the render guarantees Vue's reactivity wires up correctly\n * (slot-only render functions don't track refs from outer scopes).\n */\nconst BannerInner = defineComponent({\n name: 'ConsentBannerDefaultInner',\n props: {\n api: { type: Object as PropType<ConsentSlotApi>, required: true },\n locale: { type: String as PropType<string | undefined>, default: undefined },\n userCopy: { type: Object as PropType<Partial<BannerCopy>>, required: true },\n policyUrl: { type: String as PropType<string | undefined>, default: undefined },\n theme: { type: String as PropType<'light' | 'dark' | undefined>, default: undefined },\n },\n setup(props) {\n const showModal = ref(false)\n\n return () => {\n const copy: BannerCopy = {\n ...resolveLocalePack(props.locale).banner,\n ...props.userCopy,\n }\n const themeAttrs = props.theme ? { 'data-tb-theme': props.theme } : {}\n\n return h('div', null, [\n h(\n 'div',\n {\n class: 'tb-root tb-banner',\n role: 'region',\n 'aria-label': copy.title,\n ...themeAttrs,\n },\n [\n h('div', { class: 'tb-banner-text' }, [\n h('p', { class: 'tb-banner-title' }, copy.title),\n h('p', { class: 'tb-banner-desc' }, copy.description),\n ]),\n h('div', { class: 'tb-banner-actions' }, [\n props.policyUrl\n ? h('a', { class: 'tb-link', href: props.policyUrl }, copy.policyLinkLabel)\n : null,\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-equal',\n onClick: () => props.api.denyAll(),\n },\n copy.rejectLabel,\n ),\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-ghost',\n onClick: () => {\n showModal.value = true\n },\n },\n copy.customiseLabel,\n ),\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-equal',\n onClick: () => props.api.grantAll(),\n },\n copy.acceptLabel,\n ),\n ]),\n ],\n ),\n showModal.value\n ? renderModal(props.api, copy, props.theme, () => {\n showModal.value = false\n })\n : null,\n ])\n }\n },\n})\n\nfunction renderModal(\n api: ConsentSlotApi,\n copy: BannerCopy,\n theme: 'light' | 'dark' | undefined,\n onClose: () => void,\n) {\n const themeAttrs = theme ? { 'data-tb-theme': theme } : {}\n\n return h(\n 'div',\n {\n class: 'tb-root tb-modal-backdrop',\n role: 'presentation',\n onClick: onClose,\n onKeydown: (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose()\n },\n ...themeAttrs,\n },\n [\n h(\n 'div',\n {\n class: 'tb-modal',\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-label': copy.customiseLabel,\n onClick: (e: MouseEvent) => e.stopPropagation(),\n onKeydown: (e: KeyboardEvent) => e.stopPropagation(),\n },\n [\n h('div', { class: 'tb-modal-head' }, [\n h('h2', { class: 'tb-modal-title' }, copy.customiseLabel),\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-ghost',\n 'aria-label': copy.closeLabel,\n onClick: onClose,\n },\n '✕',\n ),\n ]),\n h(\n 'div',\n { class: 'tb-modal-body' },\n api.resolved.map((cat) => {\n const checked = api.decisions[cat.id] === true\n const id = `tb-cat-${cat.id}`\n return h('div', { key: cat.id, class: 'tb-cat' }, [\n h('div', { class: 'tb-cat-text' }, [\n h('p', { class: 'tb-cat-name' }, [\n h('label', { for: id }, cat.id),\n cat.required ? h('span', { class: 'tb-badge' }, copy.requiredBadge) : null,\n ]),\n cat.description ? h('p', { class: 'tb-cat-desc' }, cat.description) : null,\n ]),\n h('label', { class: 'tb-switch' }, [\n h('input', {\n id,\n type: 'checkbox',\n checked,\n disabled: cat.required,\n onChange: (e: Event) => {\n const next = (e.target as HTMLInputElement).checked\n if (next) api.grant(cat.id)\n else api.deny(cat.id)\n },\n }),\n h('span', { class: 'tb-switch-track' }, [\n h('span', { class: 'tb-switch-thumb' }),\n ]),\n ]),\n ])\n }),\n ),\n h('div', { class: 'tb-modal-foot' }, [\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-equal',\n onClick: () => api.denyAll(),\n },\n copy.rejectLabel,\n ),\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-primary',\n onClick: () => api.save(),\n },\n copy.saveLabel,\n ),\n ]),\n ],\n ),\n ],\n )\n}\n","import type { ConsentSlotApi } from '@tickboxhq/vue'\nimport { ConsentNotice } from '@tickboxhq/vue'\nimport { type PropType, defineComponent, h, onMounted } from 'vue'\nimport type { NoticeCopy } from '../shared/copy.js'\nimport { resolveLocalePack } from '../shared/locales/index.js'\nimport { injectStyles } from '../shared/styles.js'\n\nexport type ConsentNoticeDefaultProps = {\n locale?: string\n copy?: Partial<NoticeCopy>\n policyUrl?: string\n optOutCategoryId?: string\n theme?: 'light' | 'dark'\n}\n\n/**\n * Drop-in styled notice card for sites with only `notice`-mode categories\n * (typically UK DUAA-exempt analytics). Bottom-right toast with\n * \"Got it\" / \"Opt out\" actions.\n */\nexport const ConsentNoticeDefault = defineComponent({\n name: 'ConsentNoticeDefault',\n props: {\n locale: { type: String as PropType<string | undefined>, default: undefined },\n copy: { type: Object as PropType<Partial<NoticeCopy>>, default: () => ({}) },\n policyUrl: { type: String as PropType<string | undefined>, default: undefined },\n optOutCategoryId: { type: String, default: 'analytics' },\n theme: { type: String as PropType<'light' | 'dark' | undefined>, default: undefined },\n },\n setup(props) {\n onMounted(() => injectStyles())\n return () =>\n h(ConsentNotice, null, {\n default: (api: unknown) => renderNotice(api as ConsentSlotApi, props),\n })\n },\n})\n\nfunction renderNotice(api: ConsentSlotApi, props: ConsentNoticeDefaultProps) {\n const copy: NoticeCopy = {\n ...resolveLocalePack(props.locale).notice,\n ...(props.copy ?? {}),\n }\n const optOutId = props.optOutCategoryId ?? 'analytics'\n\n const themeAttrs = props.theme ? { 'data-tb-theme': props.theme } : {}\n\n return h(\n 'div',\n {\n class: 'tb-root tb-notice',\n role: 'status',\n 'aria-live': 'polite',\n 'aria-label': copy.title,\n ...themeAttrs,\n },\n [\n h('p', { class: 'tb-notice-title' }, copy.title),\n h('p', { class: 'tb-notice-desc' }, copy.description),\n h('div', { class: 'tb-notice-actions' }, [\n props.policyUrl\n ? h('a', { class: 'tb-link', href: props.policyUrl }, copy.policyLinkLabel)\n : null,\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-secondary',\n onClick: () => {\n if (api.resolved.some((r) => r.id === optOutId)) {\n api.deny(optOutId)\n }\n api.save()\n },\n },\n copy.optOutLabel,\n ),\n h(\n 'button',\n {\n type: 'button',\n class: 'tb-btn tb-btn-primary',\n onClick: () => api.save(),\n },\n copy.acknowledgeLabel,\n ),\n ]),\n ],\n )\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tickboxhq/banner-default",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "Drop-in styled consent banner and notice components for Tickbox",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://tickbox.dev",
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@tickboxhq/core": "0.0.
|
|
32
|
+
"@tickboxhq/core": "0.0.16"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"react": "^18.0.0 || ^19.0.0",
|
|
36
36
|
"vue": "^3.4.0",
|
|
37
|
-
"@tickboxhq/react": "0.0.
|
|
38
|
-
"@tickboxhq/vue": "0.0.
|
|
37
|
+
"@tickboxhq/react": "0.0.16",
|
|
38
|
+
"@tickboxhq/vue": "0.0.16"
|
|
39
39
|
},
|
|
40
40
|
"peerDependenciesMeta": {
|
|
41
41
|
"@tickboxhq/react": {
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
"typescript": "^5.7.2",
|
|
62
62
|
"vitest": "^2.1.8",
|
|
63
63
|
"vue": "^3.5.13",
|
|
64
|
-
"@tickboxhq/react": "0.0.
|
|
65
|
-
"@tickboxhq/vue": "0.0.
|
|
64
|
+
"@tickboxhq/react": "0.0.16",
|
|
65
|
+
"@tickboxhq/vue": "0.0.16"
|
|
66
66
|
},
|
|
67
67
|
"scripts": {
|
|
68
68
|
"build": "tsup",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/copy.ts","../src/shared/styles.ts"],"names":[],"mappings":"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","file":"chunk-FLFKIHIQ.js","sourcesContent":["export type BannerCopy = {\n title: string\n description: string\n acceptLabel: string\n rejectLabel: string\n customiseLabel: string\n saveLabel: string\n closeLabel: string\n policyLinkLabel: string\n requiredBadge: string\n}\n\nexport type NoticeCopy = {\n title: string\n description: string\n acknowledgeLabel: string\n optOutLabel: string\n policyLinkLabel: string\n}\n\nexport const DEFAULT_BANNER_COPY: BannerCopy = {\n title: 'Cookies and tracking',\n description:\n 'We use cookies to make this site work and, with your consent, to measure usage. You can choose what to allow.',\n acceptLabel: 'Accept all',\n rejectLabel: 'Reject all',\n customiseLabel: 'Customise',\n saveLabel: 'Save preferences',\n closeLabel: 'Close',\n policyLinkLabel: 'Privacy policy',\n requiredBadge: 'Required',\n}\n\nexport const DEFAULT_NOTICE_COPY: NoticeCopy = {\n title: 'A note about analytics',\n description:\n 'We use privacy-friendly analytics to understand how this site is used. No personal data is collected and no advertising profiles are built.',\n acknowledgeLabel: 'Got it',\n optOutLabel: 'Opt out',\n policyLinkLabel: 'Privacy policy',\n}\n","/**\n * Inline CSS for the default banner / notice / modal components.\n *\n * Uses CSS custom properties so users can re-theme without forking. Light\n * and dark themes are wired through `prefers-color-scheme` and the\n * `[data-tb-theme]` attribute.\n *\n * Visual style: GitHub-ish — system font, 6px corners, subtle border + soft\n * shadow, equal-prominence accept/reject buttons.\n */\nexport const TICKBOX_STYLES = `\n:where(.tb-root) {\n --tb-bg: #ffffff;\n --tb-fg: #1f2328;\n --tb-fg-muted: #59636e;\n --tb-border: #d1d9e0;\n --tb-shadow: 0 8px 24px rgba(140, 149, 159, 0.2);\n --tb-primary-bg: #1f2328;\n --tb-primary-fg: #ffffff;\n --tb-primary-bg-hover: #000000;\n --tb-secondary-bg: #ffffff;\n --tb-secondary-fg: #1f2328;\n --tb-secondary-bg-hover: #f6f8fa;\n --tb-link: #0969da;\n --tb-radius: 6px;\n --tb-z: 2147483000;\n font-family:\n -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica,\n Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\";\n color: var(--tb-fg);\n font-size: 14px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n}\n@media (prefers-color-scheme: dark) {\n :where(.tb-root:not([data-tb-theme=\"light\"])) {\n --tb-bg: #0d1117;\n --tb-fg: #f0f6fc;\n --tb-fg-muted: #9198a1;\n --tb-border: #30363d;\n --tb-shadow: 0 8px 24px rgba(1, 4, 9, 0.85);\n --tb-primary-bg: #f0f6fc;\n --tb-primary-fg: #0d1117;\n --tb-primary-bg-hover: #ffffff;\n --tb-secondary-bg: #15191f;\n --tb-secondary-fg: #f0f6fc;\n --tb-secondary-bg-hover: #1f2328;\n --tb-link: #4493f8;\n }\n}\n:where(.tb-root[data-tb-theme=\"dark\"]) {\n --tb-bg: #0d1117;\n --tb-fg: #f0f6fc;\n --tb-fg-muted: #9198a1;\n --tb-border: #30363d;\n --tb-shadow: 0 8px 24px rgba(1, 4, 9, 0.85);\n --tb-primary-bg: #f0f6fc;\n --tb-primary-fg: #0d1117;\n --tb-primary-bg-hover: #ffffff;\n --tb-secondary-bg: #15191f;\n --tb-secondary-fg: #f0f6fc;\n --tb-secondary-bg-hover: #1f2328;\n --tb-link: #4493f8;\n}\n\n.tb-banner {\n position: fixed;\n left: 16px;\n right: 16px;\n bottom: 16px;\n max-width: 1100px;\n margin-inline: auto;\n z-index: var(--tb-z);\n background: var(--tb-bg);\n color: var(--tb-fg);\n border: 1px solid var(--tb-border);\n border-radius: var(--tb-radius);\n box-shadow: var(--tb-shadow);\n padding: 16px 20px;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n animation: tb-fade-in 160ms ease-out;\n}\n.tb-banner-text {\n flex: 1 1 320px;\n min-width: 0;\n}\n.tb-banner-title {\n font-weight: 600;\n margin: 0 0 2px;\n font-size: 14px;\n}\n.tb-banner-desc {\n margin: 0;\n color: var(--tb-fg-muted);\n}\n.tb-banner-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.tb-notice {\n position: fixed;\n right: 16px;\n bottom: 16px;\n z-index: var(--tb-z);\n background: var(--tb-bg);\n color: var(--tb-fg);\n border: 1px solid var(--tb-border);\n border-radius: var(--tb-radius);\n box-shadow: var(--tb-shadow);\n padding: 14px 16px;\n max-width: 360px;\n animation: tb-fade-in 160ms ease-out;\n}\n.tb-notice-title {\n font-weight: 600;\n margin: 0 0 4px;\n font-size: 14px;\n}\n.tb-notice-desc {\n margin: 0 0 10px;\n color: var(--tb-fg-muted);\n font-size: 13px;\n}\n.tb-notice-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n justify-content: flex-end;\n flex-wrap: wrap;\n}\n\n.tb-link {\n color: var(--tb-link);\n text-decoration: none;\n font-size: 13px;\n margin-right: auto;\n}\n.tb-link:hover { text-decoration: underline; }\n\n.tb-btn {\n appearance: none;\n border: 1px solid transparent;\n border-radius: var(--tb-radius);\n padding: 6px 14px;\n font-size: 13px;\n font-weight: 500;\n font-family: inherit;\n cursor: pointer;\n line-height: 1.5;\n transition: background-color 80ms ease;\n white-space: nowrap;\n}\n.tb-btn:focus-visible {\n outline: 2px solid var(--tb-link);\n outline-offset: 2px;\n}\n.tb-btn-primary {\n background: var(--tb-primary-bg);\n color: var(--tb-primary-fg);\n}\n.tb-btn-primary:hover { background: var(--tb-primary-bg-hover); }\n.tb-btn-secondary {\n background: var(--tb-secondary-bg);\n color: var(--tb-secondary-fg);\n border-color: var(--tb-border);\n}\n.tb-btn-secondary:hover { background: var(--tb-secondary-bg-hover); }\n/*\n * Style for Accept All and Reject All on the first banner layer. They MUST\n * look identical — UK ICO and EU EDPB treat unequal visual weight on those\n * buttons as a dark pattern. Customisation should not break this symmetry;\n * if you need to apply brand colours, apply them here, not to one button.\n */\n.tb-btn-equal {\n background: var(--tb-secondary-bg);\n color: var(--tb-secondary-fg);\n border-color: var(--tb-border);\n}\n.tb-btn-equal:hover { background: var(--tb-secondary-bg-hover); }\n.tb-btn-ghost {\n background: transparent;\n color: var(--tb-fg-muted);\n padding: 6px 10px;\n}\n.tb-btn-ghost:hover { color: var(--tb-fg); }\n\n.tb-modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(15, 18, 24, 0.5);\n z-index: var(--tb-z);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 20px;\n animation: tb-fade-in 160ms ease-out;\n}\n.tb-modal {\n background: var(--tb-bg);\n color: var(--tb-fg);\n border: 1px solid var(--tb-border);\n border-radius: var(--tb-radius);\n box-shadow: var(--tb-shadow);\n width: 100%;\n max-width: 520px;\n max-height: 85vh;\n display: flex;\n flex-direction: column;\n}\n.tb-modal-head {\n padding: 14px 16px;\n border-bottom: 1px solid var(--tb-border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n.tb-modal-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n}\n.tb-modal-body {\n padding: 12px 16px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.tb-modal-foot {\n padding: 12px 16px;\n border-top: 1px solid var(--tb-border);\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n flex-wrap: wrap;\n}\n\n.tb-cat {\n border: 1px solid var(--tb-border);\n border-radius: var(--tb-radius);\n padding: 12px;\n display: flex;\n gap: 12px;\n align-items: flex-start;\n}\n.tb-cat-text { flex: 1; min-width: 0; }\n.tb-cat-name {\n font-weight: 600;\n margin: 0 0 2px;\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.tb-cat-desc {\n margin: 0;\n color: var(--tb-fg-muted);\n font-size: 13px;\n}\n.tb-badge {\n display: inline-block;\n font-size: 11px;\n font-weight: 500;\n color: var(--tb-fg-muted);\n background: var(--tb-secondary-bg-hover);\n border: 1px solid var(--tb-border);\n border-radius: 999px;\n padding: 1px 8px;\n}\n\n.tb-switch {\n position: relative;\n display: inline-block;\n width: 32px;\n height: 18px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n.tb-switch input {\n opacity: 0;\n width: 0;\n height: 0;\n position: absolute;\n}\n.tb-switch-track {\n position: absolute;\n inset: 0;\n background: var(--tb-border);\n border-radius: 999px;\n transition: background-color 100ms ease;\n cursor: pointer;\n}\n.tb-switch-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 14px;\n height: 14px;\n background: var(--tb-bg);\n border-radius: 50%;\n transition: transform 100ms ease;\n}\n.tb-switch input:checked + .tb-switch-track {\n background: var(--tb-primary-bg);\n}\n.tb-switch input:checked + .tb-switch-track .tb-switch-thumb {\n transform: translateX(14px);\n}\n.tb-switch input:disabled + .tb-switch-track {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.tb-switch input:focus-visible + .tb-switch-track {\n outline: 2px solid var(--tb-link);\n outline-offset: 2px;\n}\n\n@keyframes tb-fade-in {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@media (max-width: 640px) {\n .tb-banner {\n flex-direction: column;\n align-items: stretch;\n }\n .tb-banner-actions {\n flex-direction: column;\n }\n .tb-banner-actions .tb-btn { width: 100%; }\n}\n`\n\nconst STYLE_ID = 'tickbox-default-styles'\n\nlet injected = false\n\n/**\n * Insert the stylesheet into `<head>` exactly once per page. Safe to call\n * from every component mount — subsequent calls are no-ops. No-op on the\n * server (no `document`).\n */\nexport function injectStyles(): void {\n if (injected) return\n if (typeof document === 'undefined') return\n if (document.getElementById(STYLE_ID)) {\n injected = true\n return\n }\n const el = document.createElement('style')\n el.id = STYLE_ID\n el.textContent = TICKBOX_STYLES\n document.head.appendChild(el)\n injected = true\n}\n"]}
|
package/dist/copy-DA2csB2L.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
type BannerCopy = {
|
|
2
|
-
title: string;
|
|
3
|
-
description: string;
|
|
4
|
-
acceptLabel: string;
|
|
5
|
-
rejectLabel: string;
|
|
6
|
-
customiseLabel: string;
|
|
7
|
-
saveLabel: string;
|
|
8
|
-
closeLabel: string;
|
|
9
|
-
policyLinkLabel: string;
|
|
10
|
-
requiredBadge: string;
|
|
11
|
-
};
|
|
12
|
-
type NoticeCopy = {
|
|
13
|
-
title: string;
|
|
14
|
-
description: string;
|
|
15
|
-
acknowledgeLabel: string;
|
|
16
|
-
optOutLabel: string;
|
|
17
|
-
policyLinkLabel: string;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export type { BannerCopy as B, NoticeCopy as N };
|