@react-lgpd-consent/core 0.7.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -24
- package/README.md +5 -5
- package/dist/index.cjs +127 -108
- package/dist/index.d.cts +98 -7
- package/dist/index.d.ts +98 -7
- package/dist/index.js +127 -108
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,36 +1,80 @@
|
|
|
1
1
|
# Changelog - @react-lgpd-consent/core
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.9.0
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### Minor Changes
|
|
6
6
|
|
|
7
|
-
- [#
|
|
8
|
-
- 1d15920 fix: corrigir formatação da verificação de múltiplas versões do React
|
|
7
|
+
- [#145](https://github.com/lucianoedipo/react-lgpd-consent/pull/145) [`2d772bc`](https://github.com/lucianoedipo/react-lgpd-consent/commit/2d772bcf72d16ead7faace93f2e71d11c7bfec12) Thanks [@lucianoedipo](https://github.com/lucianoedipo)! - feat: adiciona posicionamento configurável do banner e aprimora textos de consentimento
|
|
9
8
|
|
|
10
|
-
###
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
9
|
+
### Melhorias de UX e Posicionamento
|
|
10
|
+
- **Posicionamento do banner**: novas props `position`, `anchor` e `offset` em `cookieBannerProps` permitem ajustar a posição do banner para evitar colisões com footers fixos, chat widgets e outros elementos flutuantes
|
|
11
|
+
- **Posicionamento do FAB**: prop `offset` em `floatingPreferencesButtonProps` possibilita afastar o botão flutuante de outros elementos da UI
|
|
12
|
+
- **Textos de consentimento**: aprimorados os textos padrão para comunicar claramente o uso de cookies necessários e categorias opcionais, melhorando a transparência LGPD/ANPD
|
|
13
|
+
|
|
14
|
+
### Melhorias Técnicas
|
|
15
|
+
- **Storybook**: removidas stories MDX e adicionada configuração Vite para avisos de tamanho de chunks
|
|
16
|
+
- **TypeDoc**: removida execução shell em `run-typedoc.mjs` para compatibilidade multiplataforma
|
|
17
|
+
- **Bundle**: ajustados limites de tamanho no `react-lgpd-consent/package.json`
|
|
18
|
+
- **MUI Patch**: aplicado patch em `@mui/icons-material@7.3.6` para resolver problemas de compatibilidade com exports
|
|
19
|
+
|
|
20
|
+
### Documentação
|
|
21
|
+
- Adicionada seção de posicionamento em `QUICKSTART.md` e `API.md`
|
|
22
|
+
- Atualizada `CONFORMIDADE.md` com ênfase na comunicação clara de categorias
|
|
23
|
+
- Aprimorada documentação de props em `DesignContext.tsx`
|
|
24
|
+
- Consolidados links entre pacotes em READMEs
|
|
25
|
+
|
|
26
|
+
### Limpeza e Refinamentos
|
|
27
|
+
- Ajustados testes de parsing de cookies legados em `cookieUtils.test.ts`
|
|
28
|
+
- Removidos comentários desnecessários em `cookieDiscovery.ts`
|
|
29
|
+
- Refinado guidance para desenvolvedores em `developerGuidance.ts`
|
|
30
|
+
|
|
31
|
+
## 0.8.0
|
|
32
|
+
|
|
33
|
+
### Minor Changes
|
|
34
|
+
|
|
35
|
+
- [#142](https://github.com/lucianoedipo/react-lgpd-consent/pull/142) [`29b4464`](https://github.com/lucianoedipo/react-lgpd-consent/commit/29b4464bd0ea878a21573a0752aca3adc31743d9) Thanks [@lucianoedipo](https://github.com/lucianoedipo)! - ### Correcoes
|
|
36
|
+
- 1d15920 fix: corrigir formatacao da verificacao de multiplas versoes do React
|
|
14
37
|
|
|
15
38
|
### Refactors e compatibilidade
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
- 3af2fcb
|
|
39
|
+
- ed5fa36 refactor: aprimorar documentacao e estrutura de validacao do ConsentProvider
|
|
40
|
+
- 709e977 refactor: melhorar validacao e sanitizacao das categorias no ConsentProvider
|
|
41
|
+
- 6ee4d03 feat: recalcular categorias no CategoriesContext ao adicionar novas entradas
|
|
42
|
+
- 6ee4d03 refactor: melhorar descoberta e validacao de cookies
|
|
43
|
+
- 6ee4d03 refactor: refinar helpers de integracao para maior clareza
|
|
44
|
+
- 6ee4d03 refactor: simplificar logica de sincronizacao de versoes no script sync-versions.mjs
|
|
45
|
+
- ef2968a refactor: trocar acessos diretos a window/document por globalThis em loaders, utils e testes
|
|
46
|
+
- 3af2fcb fix: ajustar path resolution no tsconfig para melhor import de modulos
|
|
24
47
|
|
|
25
|
-
###
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
48
|
+
### Funcionalidades
|
|
49
|
+
- 6ee4d03 feat: aprimorar acessibilidade e gerenciamento de consentimento
|
|
50
|
+
- 6ee4d03 feat: estender matchers Jest com jest-axe para acessibilidade
|
|
51
|
+
- 6ee4d03 feat: revisar textos de consentimento para mais clareza
|
|
52
|
+
- 6ee4d03 feat: introduzir modos de bloqueio no ConsentProvider
|
|
53
|
+
- 6ee4d03 feat: adicionar testes para hard blocking no ConsentProvider
|
|
54
|
+
- d641639 feat: adicionar gerenciamento de eventos para categorias obrigatorias no CategoriesProvider
|
|
29
55
|
|
|
30
|
-
###
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
56
|
+
### Testes
|
|
57
|
+
- b04c00b feat: adicionar testes para CookieBanner, FloatingPreferencesButton e PreferencesModal
|
|
58
|
+
- b04c00b testes: validar renderizacao do CookieBanner por consentimento e modo debug
|
|
59
|
+
- b04c00b testes: verificar textos localizados no FloatingPreferencesButton via props
|
|
60
|
+
- b04c00b testes: cobrir reset temporario, scripts ativos e textos customizados no PreferencesModal
|
|
61
|
+
- testes: cobrir fluxo SSR de leitura/remoção/escrita de cookie consent
|
|
62
|
+
|
|
63
|
+
### Ferramentas
|
|
64
|
+
- b04c00b feat: script interativo de changeset para versionamento em monorepos
|
|
65
|
+
- b04c00b refactor: coverage-check usando node imports
|
|
66
|
+
- b04c00b refactor: ajustar script do TypeDoc para compatibilidade ESM
|
|
67
|
+
|
|
68
|
+
### Documentacao
|
|
69
|
+
- 6ee4d03 docs: atualizar README e exemplos com novos recursos
|
|
70
|
+
- d430eef docs: atualizar instrucoes para agentes com comandos essenciais
|
|
71
|
+
- d430eef docs: refletir uso de globalThis na documentacao
|
|
72
|
+
- d430eef docs: atualizar API com novas integracoes e configuracoes de testes ESM/CJS
|
|
73
|
+
- docs: quickstart com comentarios e nota sobre injecao automatica de UI MUI
|
|
74
|
+
|
|
75
|
+
### A11y
|
|
76
|
+
- a11y: PreferencesModal com aria-describedby
|
|
77
|
+
- a11y: testes de teclado (Escape + retorno de foco)
|
|
34
78
|
|
|
35
79
|
## 0.7.1
|
|
36
80
|
|
package/README.md
CHANGED
|
@@ -100,13 +100,13 @@ import { ConsentProvider } from '@react-lgpd-consent/core'
|
|
|
100
100
|
### Presets ANPD
|
|
101
101
|
|
|
102
102
|
```tsx
|
|
103
|
-
import {
|
|
103
|
+
import { createAnpdCategoriesConfig, ANPD_CATEGORY_PRESETS } from '@react-lgpd-consent/core'
|
|
104
104
|
|
|
105
105
|
// Preset BÁSICO
|
|
106
|
-
const basic =
|
|
106
|
+
const basic = createAnpdCategoriesConfig({ include: ['analytics'] })
|
|
107
107
|
|
|
108
108
|
// Preset COMPLETO
|
|
109
|
-
const full =
|
|
109
|
+
const full = createAnpdCategoriesConfig({
|
|
110
110
|
include: ['analytics', 'marketing', 'functional', 'social', 'personalization']
|
|
111
111
|
})
|
|
112
112
|
```
|
|
@@ -133,8 +133,8 @@ Para documentação completa, exemplos e API reference:
|
|
|
133
133
|
|
|
134
134
|
## 🔗 Pacotes Relacionados
|
|
135
135
|
|
|
136
|
-
- [`@react-lgpd-consent/mui`](../mui) - Componentes prontos usando Material-UI
|
|
137
|
-
- [`react-lgpd-consent`](../react-lgpd-consent) - Pacote agregador (core + mui)
|
|
136
|
+
- [`@react-lgpd-consent/mui`](../mui/README.md) - Componentes prontos usando Material-UI
|
|
137
|
+
- [`react-lgpd-consent`](../react-lgpd-consent/README.md) - Pacote agregador (core + mui)
|
|
138
138
|
|
|
139
139
|
## 📄 Licença
|
|
140
140
|
|
package/dist/index.cjs
CHANGED
|
@@ -64,27 +64,27 @@ var EXPANDED_DEFAULT_TEXTS = {
|
|
|
64
64
|
categories: {
|
|
65
65
|
necessary: {
|
|
66
66
|
name: "Cookies Necess\xE1rios",
|
|
67
|
-
description: "Essenciais para o funcionamento b\xE1sico do site",
|
|
67
|
+
description: "Essenciais para o funcionamento b\xE1sico do site e n\xE3o podem ser desativados",
|
|
68
68
|
examples: "Sess\xE3o, seguran\xE7a, prefer\xEAncias de idioma"
|
|
69
69
|
},
|
|
70
70
|
analytics: {
|
|
71
71
|
name: "Cookies de Analytics",
|
|
72
|
-
description: "Ajudam a entender como os visitantes usam o site",
|
|
72
|
+
description: "Opcionais. Ajudam a entender como os visitantes usam o site",
|
|
73
73
|
examples: "Google Analytics, contadores de p\xE1gina"
|
|
74
74
|
},
|
|
75
75
|
marketing: {
|
|
76
76
|
name: "Cookies de Marketing",
|
|
77
|
-
description: "Usados para personalizar an\xFAncios e ofertas",
|
|
77
|
+
description: "Opcionais. Usados para personalizar an\xFAncios e ofertas",
|
|
78
78
|
examples: "Facebook Pixel, Google Ads, remarketing"
|
|
79
79
|
},
|
|
80
80
|
functional: {
|
|
81
81
|
name: "Cookies Funcionais",
|
|
82
|
-
description: "Melhoram a funcionalidade e personaliza\xE7\xE3o",
|
|
82
|
+
description: "Opcionais. Melhoram a funcionalidade e personaliza\xE7\xE3o",
|
|
83
83
|
examples: "Chat, mapas, v\xEDdeos embarcados"
|
|
84
84
|
},
|
|
85
85
|
performance: {
|
|
86
86
|
name: "Cookies de Performance",
|
|
87
|
-
description: "Coletam informa\xE7\xF5es sobre velocidade e estabilidade",
|
|
87
|
+
description: "Opcionais. Coletam informa\xE7\xF5es sobre velocidade e estabilidade",
|
|
88
88
|
examples: "Monitoramento de erro, otimiza\xE7\xE3o de velocidade"
|
|
89
89
|
}
|
|
90
90
|
},
|
|
@@ -118,7 +118,7 @@ var EXPANDED_DEFAULT_TEXTS = {
|
|
|
118
118
|
// Variações de tom
|
|
119
119
|
variants: {
|
|
120
120
|
formal: {
|
|
121
|
-
bannerMessage: "Este s\xEDtio eletr\xF4nico utiliza cookies para otimizar a experi\xEAncia de navega\xE7\xE3o.",
|
|
121
|
+
bannerMessage: "Este s\xEDtio eletr\xF4nico utiliza cookies necess\xE1rios e, mediante sua autoriza\xE7\xE3o, cookies opcionais para otimizar a experi\xEAncia de navega\xE7\xE3o.",
|
|
122
122
|
acceptAll: "Concordar com todos os cookies",
|
|
123
123
|
declineAll: "Recusar cookies opcionais",
|
|
124
124
|
modalTitle: "Configura\xE7\xE3o de Cookies"
|
|
@@ -136,7 +136,7 @@ var EXPANDED_DEFAULT_TEXTS = {
|
|
|
136
136
|
modalTitle: "Cookies"
|
|
137
137
|
},
|
|
138
138
|
detailed: {
|
|
139
|
-
bannerMessage: "Utilizamos cookies e tecnologias similares para melhorar sua experi\xEAncia de navega\xE7\xE3o, personalizar conte\xFAdo, analisar tr\xE1fego e oferecer funcionalidades de redes sociais.",
|
|
139
|
+
bannerMessage: "Utilizamos cookies e tecnologias similares para melhorar sua experi\xEAncia de navega\xE7\xE3o, personalizar conte\xFAdo, analisar tr\xE1fego e oferecer funcionalidades de redes sociais. Os cookies necess\xE1rios permanecem ativos e os opcionais dependem da sua autoriza\xE7\xE3o.",
|
|
140
140
|
acceptAll: "Aceitar todos os cookies e tecnologias",
|
|
141
141
|
declineAll: "Recusar todos os cookies opcionais",
|
|
142
142
|
modalTitle: "Centro de Prefer\xEAncias de Privacidade"
|
|
@@ -557,7 +557,6 @@ function buildConsentStorageKey(options) {
|
|
|
557
557
|
var DEFAULT_COOKIE_OPTS = {
|
|
558
558
|
name: "cookieConsent",
|
|
559
559
|
maxAge: DEFAULT_MAX_AGE_SECONDS,
|
|
560
|
-
maxAgeDays: 365,
|
|
561
560
|
sameSite: "Lax",
|
|
562
561
|
secure: false,
|
|
563
562
|
path: "/",
|
|
@@ -566,18 +565,23 @@ var DEFAULT_COOKIE_OPTS = {
|
|
|
566
565
|
function resolveCookieOptions(opts) {
|
|
567
566
|
const currentWindow = globalThis.window;
|
|
568
567
|
const currentLocation = globalThis.location;
|
|
569
|
-
const protocols = [currentWindow?.location?.protocol, currentLocation?.protocol].filter(
|
|
570
|
-
Boolean
|
|
571
|
-
);
|
|
568
|
+
const protocols = [currentWindow?.location?.protocol, currentLocation?.protocol].filter(Boolean);
|
|
572
569
|
const forceHttps = globalThis.__LGPD_FORCE_HTTPS__ === true;
|
|
573
570
|
const isHttps = forceHttps || protocols.includes("https:");
|
|
574
|
-
const
|
|
575
|
-
|
|
571
|
+
const maxAgeSeconds = typeof opts?.maxAge === "number" ? Math.max(0, opts.maxAge) : typeof opts?.maxAgeDays === "number" ? Math.max(0, opts.maxAgeDays) * 24 * 60 * 60 : DEFAULT_MAX_AGE_SECONDS;
|
|
572
|
+
let secure;
|
|
573
|
+
if (typeof opts?.secure === "boolean") {
|
|
574
|
+
secure = opts.secure;
|
|
575
|
+
} else if (isHttps) {
|
|
576
|
+
secure = true;
|
|
577
|
+
} else {
|
|
578
|
+
secure = DEFAULT_COOKIE_OPTS.secure;
|
|
579
|
+
}
|
|
576
580
|
return {
|
|
577
581
|
name: opts?.name ?? DEFAULT_COOKIE_OPTS.name,
|
|
578
582
|
maxAge: maxAgeSeconds,
|
|
579
583
|
sameSite: opts?.sameSite ?? DEFAULT_COOKIE_OPTS.sameSite ?? "Lax",
|
|
580
|
-
secure
|
|
584
|
+
secure,
|
|
581
585
|
path: opts?.path ?? DEFAULT_COOKIE_OPTS.path ?? "/",
|
|
582
586
|
domain: opts?.domain ?? DEFAULT_COOKIE_OPTS.domain ?? void 0
|
|
583
587
|
};
|
|
@@ -696,7 +700,7 @@ function removeConsentCookie(opts) {
|
|
|
696
700
|
}
|
|
697
701
|
|
|
698
702
|
// src/utils/dataLayerEvents.ts
|
|
699
|
-
var LIBRARY_VERSION = "0.
|
|
703
|
+
var LIBRARY_VERSION = "0.9.0";
|
|
700
704
|
function ensureDataLayer() {
|
|
701
705
|
const currentWindow = globalThis.window;
|
|
702
706
|
if (!currentWindow) return;
|
|
@@ -1732,14 +1736,88 @@ function runPeerDepsCheck() {
|
|
|
1732
1736
|
|
|
1733
1737
|
// src/utils/validation.ts
|
|
1734
1738
|
var isDev = () => typeof process !== "undefined" && process.env.NODE_ENV !== "production";
|
|
1739
|
+
var sanitizeCategories = (categories) => {
|
|
1740
|
+
const enabled = [...new Set(categories.enabledCategories ?? [])];
|
|
1741
|
+
const sanitizedEnabled = enabled.filter((c) => c !== "necessary");
|
|
1742
|
+
return {
|
|
1743
|
+
enabled,
|
|
1744
|
+
sanitizedEnabled,
|
|
1745
|
+
custom: categories.customCategories ?? []
|
|
1746
|
+
};
|
|
1747
|
+
};
|
|
1748
|
+
var collectZodIssues = (z, categories, issues) => {
|
|
1749
|
+
if (!z || !categories) return;
|
|
1750
|
+
const CustomCategorySchema = z.object({
|
|
1751
|
+
id: z.string().min(1, "customCategories[].id deve ser uma string n\xE3o vazia"),
|
|
1752
|
+
name: z.string().min(1, "customCategories[].name deve ser uma string n\xE3o vazia"),
|
|
1753
|
+
description: z.string().min(1, "customCategories[].description deve ser uma string n\xE3o vazia"),
|
|
1754
|
+
essential: z.boolean().optional(),
|
|
1755
|
+
cookies: z.array(z.string().min(1)).optional()
|
|
1756
|
+
});
|
|
1757
|
+
const ProjectCategoriesConfigSchema = z.object({
|
|
1758
|
+
enabledCategories: z.array(z.string().min(1)).optional(),
|
|
1759
|
+
customCategories: z.array(CustomCategorySchema).optional()
|
|
1760
|
+
}).strict();
|
|
1761
|
+
const res = ProjectCategoriesConfigSchema.safeParse(categories);
|
|
1762
|
+
if (!res.success) {
|
|
1763
|
+
res.error.issues.forEach(
|
|
1764
|
+
(issue) => issues.push({ path: `categories.${issue.path.join(".")}`, message: issue.message })
|
|
1765
|
+
);
|
|
1766
|
+
}
|
|
1767
|
+
const customParse = z.array(CustomCategorySchema).safeParse(categories.customCategories ?? []);
|
|
1768
|
+
if (!customParse.success) {
|
|
1769
|
+
customParse.error.issues.forEach(
|
|
1770
|
+
(issue) => issues.push({ path: `customCategories.${issue.path.join(".")}`, message: issue.message })
|
|
1771
|
+
);
|
|
1772
|
+
}
|
|
1773
|
+
};
|
|
1774
|
+
var collectCategoryWarnings = (input) => {
|
|
1775
|
+
const warnings = [];
|
|
1776
|
+
const { enabled, sanitizedEnabled, custom } = input;
|
|
1777
|
+
if (enabled.includes("necessary")) {
|
|
1778
|
+
warnings.push("'necessary' \xE9 sempre inclu\xEDda automaticamente \u2014 remova de enabledCategories.");
|
|
1779
|
+
}
|
|
1780
|
+
const invalidEnabled = sanitizedEnabled.filter((c) => typeof c !== "string" || c.trim() === "");
|
|
1781
|
+
if (invalidEnabled.length > 0) {
|
|
1782
|
+
warnings.push(
|
|
1783
|
+
`enabledCategories cont\xE9m valores inv\xE1lidos: ${invalidEnabled.map(String).join(", ")} \u2014 remova ou corrija os IDs de categoria`
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1787
|
+
const dupes = [];
|
|
1788
|
+
["necessary", ...sanitizedEnabled].forEach((id) => {
|
|
1789
|
+
if (ids.has(id)) dupes.push(id);
|
|
1790
|
+
ids.add(id);
|
|
1791
|
+
});
|
|
1792
|
+
custom?.forEach((c) => {
|
|
1793
|
+
if (ids.has(c.id)) dupes.push(c.id);
|
|
1794
|
+
ids.add(c.id);
|
|
1795
|
+
});
|
|
1796
|
+
if (dupes.length > 0) {
|
|
1797
|
+
warnings.push(
|
|
1798
|
+
`IDs de categoria duplicados detectados: ${Array.from(new Set(dupes)).join(
|
|
1799
|
+
", "
|
|
1800
|
+
)} \u2014 verifique 'enabledCategories' e 'customCategories'.`
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1803
|
+
return warnings;
|
|
1804
|
+
};
|
|
1805
|
+
var reportValidationMessages = (warnings, errors, issues) => {
|
|
1806
|
+
if (warnings.length > 0) {
|
|
1807
|
+
logger.warn("Valida\xE7\xE3o do ConsentProvider:", ...warnings);
|
|
1808
|
+
}
|
|
1809
|
+
if (errors.length > 0 || issues.length > 0) {
|
|
1810
|
+
issues.forEach((i) => errors.push(`Prop inv\xE1lida: ${i.path} \u2014 ${i.message}`));
|
|
1811
|
+
logger.error("Erros de configura\xE7\xE3o do ConsentProvider:", ...errors);
|
|
1812
|
+
}
|
|
1813
|
+
};
|
|
1735
1814
|
function validateConsentProviderProps(props) {
|
|
1736
1815
|
const warnings = [];
|
|
1737
1816
|
const errors = [];
|
|
1738
1817
|
const sanitized = {};
|
|
1739
1818
|
if (!isDev()) {
|
|
1740
1819
|
if (props.categories) {
|
|
1741
|
-
const
|
|
1742
|
-
const sanitizedEnabled = enabled.filter((c) => c !== "necessary");
|
|
1820
|
+
const { sanitizedEnabled } = sanitizeCategories(props.categories);
|
|
1743
1821
|
sanitized.categories = {
|
|
1744
1822
|
enabledCategories: sanitizedEnabled,
|
|
1745
1823
|
customCategories: props.categories.customCategories
|
|
@@ -1754,94 +1832,27 @@ function validateConsentProviderProps(props) {
|
|
|
1754
1832
|
z = void 0;
|
|
1755
1833
|
}
|
|
1756
1834
|
const issues = [];
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
description: z.string().min(1, "customCategories[].description deve ser uma string n\xE3o vazia"),
|
|
1762
|
-
essential: z.boolean().optional(),
|
|
1763
|
-
cookies: z.array(z.string().min(1)).optional()
|
|
1764
|
-
});
|
|
1765
|
-
const ProjectCategoriesConfigSchema = z.object({
|
|
1766
|
-
enabledCategories: z.array(z.string().min(1)).optional(),
|
|
1767
|
-
customCategories: z.array(CustomCategorySchema).optional()
|
|
1768
|
-
}).strict();
|
|
1769
|
-
const res = ProjectCategoriesConfigSchema.safeParse(props.categories);
|
|
1770
|
-
if (!res.success) {
|
|
1771
|
-
res.error.issues.forEach(
|
|
1772
|
-
(issue) => issues.push({ path: `categories.${issue.path.join(".")}`, message: issue.message })
|
|
1773
|
-
);
|
|
1774
|
-
}
|
|
1775
|
-
}
|
|
1776
|
-
if (!props.categories) {
|
|
1777
|
-
warnings.push(
|
|
1778
|
-
"Prop 'categories' n\xE3o fornecida \u2014 o ConsentProvider requer configura\xE7\xE3o de categorias."
|
|
1779
|
-
);
|
|
1780
|
-
} else {
|
|
1781
|
-
const cat = props.categories;
|
|
1782
|
-
const enabled = [...new Set(cat.enabledCategories ?? [])];
|
|
1783
|
-
if (enabled.includes("necessary")) {
|
|
1784
|
-
warnings.push("'necessary' \xE9 sempre inclu\xEDda automaticamente \u2014 remova de enabledCategories.");
|
|
1785
|
-
}
|
|
1786
|
-
const sanitizedEnabled = enabled.filter((c) => c !== "necessary");
|
|
1787
|
-
const invalidEnabled = sanitizedEnabled.filter((c) => typeof c !== "string" || c.trim() === "");
|
|
1788
|
-
if (invalidEnabled.length > 0) {
|
|
1789
|
-
warnings.push(
|
|
1790
|
-
`enabledCategories cont\xE9m valores inv\xE1lidos: ${invalidEnabled.map(String).join(", ")} \u2014 remova ou corrija os IDs de categoria`
|
|
1791
|
-
);
|
|
1792
|
-
}
|
|
1793
|
-
const custom = cat.customCategories ?? [];
|
|
1794
|
-
if (z) {
|
|
1795
|
-
const CustomCategorySchema = z.object({
|
|
1796
|
-
id: z.string().min(1),
|
|
1797
|
-
name: z.string().min(1),
|
|
1798
|
-
description: z.string().min(1),
|
|
1799
|
-
essential: z.boolean().optional(),
|
|
1800
|
-
cookies: z.array(z.string().min(1)).optional()
|
|
1801
|
-
});
|
|
1802
|
-
const customParse = z.array(CustomCategorySchema).safeParse(custom);
|
|
1803
|
-
if (!customParse.success) {
|
|
1804
|
-
customParse.error.issues.forEach(
|
|
1805
|
-
(issue) => issues.push({ path: `customCategories.${issue.path.join(".")}`, message: issue.message })
|
|
1806
|
-
);
|
|
1807
|
-
}
|
|
1808
|
-
}
|
|
1809
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1810
|
-
const dupes = [];
|
|
1811
|
-
["necessary", ...sanitizedEnabled].forEach((id) => {
|
|
1812
|
-
if (ids.has(id)) dupes.push(id);
|
|
1813
|
-
ids.add(id);
|
|
1814
|
-
});
|
|
1815
|
-
custom.forEach((c) => {
|
|
1816
|
-
if (ids.has(c.id)) dupes.push(c.id);
|
|
1817
|
-
ids.add(c.id);
|
|
1818
|
-
});
|
|
1819
|
-
if (dupes.length > 0) {
|
|
1820
|
-
warnings.push(
|
|
1821
|
-
`IDs de categoria duplicados detectados: ${Array.from(new Set(dupes)).join(
|
|
1822
|
-
", "
|
|
1823
|
-
)} \u2014 verifique 'enabledCategories' e 'customCategories'.`
|
|
1824
|
-
);
|
|
1825
|
-
}
|
|
1835
|
+
collectZodIssues(z, props.categories, issues);
|
|
1836
|
+
if (props.categories) {
|
|
1837
|
+
const { enabled, sanitizedEnabled, custom } = sanitizeCategories(props.categories);
|
|
1838
|
+
warnings.push(...collectCategoryWarnings({ enabled, sanitizedEnabled, custom }));
|
|
1826
1839
|
sanitized.categories = {
|
|
1827
1840
|
enabledCategories: sanitizedEnabled,
|
|
1828
1841
|
customCategories: custom
|
|
1829
1842
|
};
|
|
1843
|
+
} else {
|
|
1844
|
+
warnings.push(
|
|
1845
|
+
"Prop 'categories' n\xE3o fornecida \u2014 o ConsentProvider requer configura\xE7\xE3o de categorias."
|
|
1846
|
+
);
|
|
1830
1847
|
}
|
|
1831
|
-
|
|
1832
|
-
logger.warn("Valida\xE7\xE3o do ConsentProvider:", ...warnings);
|
|
1833
|
-
}
|
|
1834
|
-
if (errors.length > 0 || issues.length > 0) {
|
|
1835
|
-
issues.forEach((i) => errors.push(`Prop inv\xE1lida: ${i.path} \u2014 ${i.message}`));
|
|
1836
|
-
logger.error("Erros de configura\xE7\xE3o do ConsentProvider:", ...errors);
|
|
1837
|
-
}
|
|
1848
|
+
reportValidationMessages(warnings, errors, issues);
|
|
1838
1849
|
return { sanitized, warnings, errors };
|
|
1839
1850
|
}
|
|
1840
1851
|
|
|
1841
1852
|
// src/utils/cookieDiscovery.ts
|
|
1842
1853
|
function discoverRuntimeCookies() {
|
|
1843
1854
|
const currentDocument = globalThis.document;
|
|
1844
|
-
if (
|
|
1855
|
+
if (!currentDocument?.cookie) return [];
|
|
1845
1856
|
const names = Array.from(
|
|
1846
1857
|
new Set(
|
|
1847
1858
|
currentDocument.cookie.split(";").map((s) => s.trim()).filter(Boolean).map((s) => s.split("=")[0])
|
|
@@ -1873,7 +1884,7 @@ function isConsentJson(val) {
|
|
|
1873
1884
|
}
|
|
1874
1885
|
function detectConsentCookieName() {
|
|
1875
1886
|
const currentDocument = globalThis.document;
|
|
1876
|
-
if (
|
|
1887
|
+
if (!currentDocument?.cookie) return null;
|
|
1877
1888
|
try {
|
|
1878
1889
|
const pairs = currentDocument.cookie.split(";").map((s) => s.trim()).filter(Boolean);
|
|
1879
1890
|
for (const p of pairs) {
|
|
@@ -2002,10 +2013,7 @@ function useCategoryStatus(categoryId) {
|
|
|
2002
2013
|
};
|
|
2003
2014
|
}
|
|
2004
2015
|
var DesignContext = React4__namespace.createContext(void 0);
|
|
2005
|
-
function DesignProvider({
|
|
2006
|
-
tokens,
|
|
2007
|
-
children
|
|
2008
|
-
}) {
|
|
2016
|
+
function DesignProvider({ tokens, children }) {
|
|
2009
2017
|
return /* @__PURE__ */ jsxRuntime.jsx(DesignContext.Provider, { value: tokens, children });
|
|
2010
2018
|
}
|
|
2011
2019
|
function useDesignTokens() {
|
|
@@ -2027,19 +2035,19 @@ function createFullConsentState(consented, preferences, source, projectConfig, i
|
|
|
2027
2035
|
}
|
|
2028
2036
|
var BASE_TEXTS = {
|
|
2029
2037
|
// Textos básicos
|
|
2030
|
-
bannerMessage: "
|
|
2038
|
+
bannerMessage: "Usamos cookies necess\xE1rios para o funcionamento do site e, com sua autoriza\xE7\xE3o, cookies opcionais para melhorar sua experi\xEAncia. Voc\xEA pode aceitar todos, rejeitar os opcionais ou ajustar suas prefer\xEAncias.",
|
|
2031
2039
|
acceptAll: "Aceitar todos",
|
|
2032
|
-
declineAll: "
|
|
2040
|
+
declineAll: "Rejeitar opcionais",
|
|
2033
2041
|
preferences: "Prefer\xEAncias",
|
|
2034
|
-
policyLink: "
|
|
2035
|
-
modalTitle: "Prefer\xEAncias de
|
|
2036
|
-
modalIntro: "
|
|
2042
|
+
policyLink: "Pol\xEDtica de privacidade",
|
|
2043
|
+
modalTitle: "Prefer\xEAncias de cookies",
|
|
2044
|
+
modalIntro: "Cookies necess\xE1rios s\xE3o sempre ativos. As categorias opcionais s\xF3 ser\xE3o usadas com sua autoriza\xE7\xE3o e podem ser ativadas ou desativadas a qualquer momento.",
|
|
2037
2045
|
save: "Salvar prefer\xEAncias",
|
|
2038
2046
|
necessaryAlwaysOn: "Cookies necess\xE1rios (sempre ativos)",
|
|
2039
2047
|
// Textos adicionais para UI customizada
|
|
2040
|
-
preferencesButton: "
|
|
2041
|
-
preferencesTitle: "Gerenciar
|
|
2042
|
-
preferencesDescription: "Escolha quais
|
|
2048
|
+
preferencesButton: "Gerenciar cookies",
|
|
2049
|
+
preferencesTitle: "Gerenciar prefer\xEAncias de cookies",
|
|
2050
|
+
preferencesDescription: "Escolha quais categorias opcionais voc\xEA permite. Cookies necess\xE1rios permanecem sempre ativos e voc\xEA pode mudar sua escolha quando quiser.",
|
|
2043
2051
|
close: "Fechar",
|
|
2044
2052
|
accept: "Aceitar",
|
|
2045
2053
|
reject: "Rejeitar",
|
|
@@ -2160,6 +2168,7 @@ function ConsentProvider({
|
|
|
2160
2168
|
floatingPreferencesButtonProps = {},
|
|
2161
2169
|
disableFloatingPreferencesButton = false,
|
|
2162
2170
|
blocking = false,
|
|
2171
|
+
blockingMode = "soft",
|
|
2163
2172
|
blockingStrategy = "auto",
|
|
2164
2173
|
hideBranding: _hideBranding = false,
|
|
2165
2174
|
onConsentGiven,
|
|
@@ -2437,6 +2446,7 @@ function ConsentProvider({
|
|
|
2437
2446
|
hideBranding: incoming.hideBranding === void 0 ? _hideBranding : Boolean(incoming.hideBranding)
|
|
2438
2447
|
};
|
|
2439
2448
|
}, [cookieBannerProps, blocking, _hideBranding]);
|
|
2449
|
+
const hardBlockingActive = blocking && isHydrated && !state.consented && blockingMode === "hard";
|
|
2440
2450
|
const content = /* @__PURE__ */ jsxRuntime.jsx(StateCtx.Provider, { value: state, children: /* @__PURE__ */ jsxRuntime.jsx(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ jsxRuntime.jsx(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ jsxRuntime.jsx(HydrationCtx.Provider, { value: isHydrated, children: /* @__PURE__ */ jsxRuntime.jsx(DesignProvider, { tokens: designTokens, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2441
2451
|
CategoriesProvider,
|
|
2442
2452
|
{
|
|
@@ -2444,7 +2454,16 @@ function ConsentProvider({
|
|
|
2444
2454
|
disableDeveloperGuidance,
|
|
2445
2455
|
disableDiscoveryLog,
|
|
2446
2456
|
children: [
|
|
2447
|
-
|
|
2457
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2458
|
+
"div",
|
|
2459
|
+
{
|
|
2460
|
+
"data-testid": "lgpd-app-content",
|
|
2461
|
+
"aria-hidden": hardBlockingActive ? true : void 0,
|
|
2462
|
+
inert: hardBlockingActive,
|
|
2463
|
+
style: { display: "contents" },
|
|
2464
|
+
children
|
|
2465
|
+
}
|
|
2466
|
+
),
|
|
2448
2467
|
PreferencesModalComponent ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2449
2468
|
PreferencesModalComponent,
|
|
2450
2469
|
{
|
package/dist/index.d.cts
CHANGED
|
@@ -175,8 +175,7 @@ declare const GUIDANCE_PRESETS: {
|
|
|
175
175
|
* Tipo auxiliar para variações de texto.
|
|
176
176
|
*
|
|
177
177
|
* Define um subconjunto opcional dos textos principais do banner e modal,
|
|
178
|
-
* permitindo variações de
|
|
179
|
-
bannerMessage: 'Utilizamos cookies para mejorar su experiencia y mostrar contenido personalizado.', (formal, casual, etc.) sem sobrescrever todos os textos.
|
|
178
|
+
* permitindo variações de tom (formal, casual, etc.) sem sobrescrever todos os textos.
|
|
180
179
|
*
|
|
181
180
|
* @category Types
|
|
182
181
|
* @since 0.4.1
|
|
@@ -1174,6 +1173,19 @@ type BackdropConfig = boolean | string | {
|
|
|
1174
1173
|
* @since 0.1.3
|
|
1175
1174
|
* @remarks
|
|
1176
1175
|
* **Histórico**: v0.4.1 - Expandido substancialmente com novos tokens
|
|
1176
|
+
*
|
|
1177
|
+
* ### Mapa de tokens (top-level)
|
|
1178
|
+
* - `colors`: cores base, semânticas e por componente
|
|
1179
|
+
* - `typography`: fonte, tamanhos, pesos e hierarquia
|
|
1180
|
+
* - `spacing`: espaçamentos, padding/margin e radius
|
|
1181
|
+
* - `layout`: posição, largura, backdrop e z-index
|
|
1182
|
+
* - `effects`: sombras, transições e filtros
|
|
1183
|
+
* - `accessibility`: contraste, motion e foco
|
|
1184
|
+
* - `themes`: overrides para light/dark
|
|
1185
|
+
*
|
|
1186
|
+
* ### Overrides complementares (MUI)
|
|
1187
|
+
* Mesmo com tokens, você pode ajustar detalhes via `sx` e `ThemeProvider`.
|
|
1188
|
+
* Ex.: `cookieBannerProps.PaperProps.sx` e `preferencesModalProps.DialogProps.sx`.
|
|
1177
1189
|
* @public
|
|
1178
1190
|
*
|
|
1179
1191
|
* @example Configuração básica
|
|
@@ -1681,6 +1693,16 @@ interface ConsentProviderProps {
|
|
|
1681
1693
|
* - `true`: Banner bloqueia interação até decisão (compliance rigorosa)
|
|
1682
1694
|
*/
|
|
1683
1695
|
blocking?: boolean;
|
|
1696
|
+
/**
|
|
1697
|
+
* Intensidade do bloqueio quando `blocking` estiver habilitado.
|
|
1698
|
+
* - 'soft' (padrão): aplica apenas overlay visual (cliques bloqueados).
|
|
1699
|
+
* - 'hard': aplica overlay + torna o conteúdo da aplicação inerte (sem foco/teclado).
|
|
1700
|
+
*
|
|
1701
|
+
* @remarks
|
|
1702
|
+
* O modo `hard` utiliza o atributo `inert` para restringir navegação por teclado
|
|
1703
|
+
* ao banner/modal, atendendo contextos regulatórios mais estritos.
|
|
1704
|
+
*/
|
|
1705
|
+
blockingMode?: 'soft' | 'hard';
|
|
1684
1706
|
/**
|
|
1685
1707
|
* Estratégia de bloqueio quando `blocking` estiver habilitado.
|
|
1686
1708
|
* - 'auto' (padrão):
|
|
@@ -1826,6 +1848,20 @@ interface ConsentProviderProps {
|
|
|
1826
1848
|
* @since 0.3.1
|
|
1827
1849
|
* @public
|
|
1828
1850
|
* Fornece acesso ao estado de consentimento e ações necessárias para o banner.
|
|
1851
|
+
*
|
|
1852
|
+
* @example
|
|
1853
|
+
* ```tsx
|
|
1854
|
+
* function MyBanner({ acceptAll, rejectAll, openPreferences, texts }: CustomCookieBannerProps) {
|
|
1855
|
+
* return (
|
|
1856
|
+
* <div>
|
|
1857
|
+
* <p>{texts.bannerMessage}</p>
|
|
1858
|
+
* <button onClick={acceptAll}>{texts.acceptAll}</button>
|
|
1859
|
+
* <button onClick={rejectAll}>{texts.declineAll}</button>
|
|
1860
|
+
* <button onClick={openPreferences}>{texts.preferences}</button>
|
|
1861
|
+
* </div>
|
|
1862
|
+
* )
|
|
1863
|
+
* }
|
|
1864
|
+
* ```
|
|
1829
1865
|
*/
|
|
1830
1866
|
interface CustomCookieBannerProps {
|
|
1831
1867
|
consented: boolean;
|
|
@@ -1851,6 +1887,28 @@ interface CustomCookieBannerProps {
|
|
|
1851
1887
|
* Fornece acesso às preferências atuais do usuário, funções para atualizar e salvar preferências,
|
|
1852
1888
|
* fechar o modal e textos customizados da interface.
|
|
1853
1889
|
*
|
|
1890
|
+
* @example
|
|
1891
|
+
* ```tsx
|
|
1892
|
+
* function MyPreferencesModal({
|
|
1893
|
+
* preferences,
|
|
1894
|
+
* setPreferences,
|
|
1895
|
+
* closePreferences,
|
|
1896
|
+
* isModalOpen,
|
|
1897
|
+
* texts,
|
|
1898
|
+
* }: CustomPreferencesModalProps) {
|
|
1899
|
+
* if (!isModalOpen) return null
|
|
1900
|
+
* return (
|
|
1901
|
+
* <div role="dialog" aria-label={texts.accessibility?.modalLabel}>
|
|
1902
|
+
* <h2>{texts.modalTitle}</h2>
|
|
1903
|
+
* <button onClick={() => setPreferences({ ...preferences, analytics: true })}>
|
|
1904
|
+
* {texts.acceptAll}
|
|
1905
|
+
* </button>
|
|
1906
|
+
* <button onClick={closePreferences}>{texts.close ?? 'Fechar'}</button>
|
|
1907
|
+
* </div>
|
|
1908
|
+
* )
|
|
1909
|
+
* }
|
|
1910
|
+
* ```
|
|
1911
|
+
*
|
|
1854
1912
|
* @property preferences Preferências atuais de consentimento do usuário.
|
|
1855
1913
|
* @property setPreferences Função para atualizar e salvar as preferências.
|
|
1856
1914
|
* @property closePreferences Função para fechar o modal de preferências.
|
|
@@ -1870,6 +1928,14 @@ interface CustomPreferencesModalProps {
|
|
|
1870
1928
|
* @since 0.3.1
|
|
1871
1929
|
* @public
|
|
1872
1930
|
* Fornece acesso às ações de abertura do modal e ao estado de consentimento.
|
|
1931
|
+
*
|
|
1932
|
+
* @example
|
|
1933
|
+
* ```tsx
|
|
1934
|
+
* function MyFloatingButton({ openPreferences, consented }: CustomFloatingPreferencesButtonProps) {
|
|
1935
|
+
* if (!consented) return null
|
|
1936
|
+
* return <button onClick={openPreferences}>Gerenciar cookies</button>
|
|
1937
|
+
* }
|
|
1938
|
+
* ```
|
|
1873
1939
|
*/
|
|
1874
1940
|
interface CustomFloatingPreferencesButtonProps {
|
|
1875
1941
|
openPreferences: () => void;
|
|
@@ -2050,6 +2116,7 @@ type ConsentEvent = ConsentInitializedEvent | ConsentUpdatedEvent;
|
|
|
2050
2116
|
* @param {ProjectCategoriesConfig} props.categories - **Obrigatório**. Define as categorias de cookies que seu projeto utiliza, em conformidade com o princípio de minimização da LGPD.
|
|
2051
2117
|
* @param {Partial<AdvancedConsentTexts>} [props.texts] - Objeto para customizar todos os textos exibidos na UI.
|
|
2052
2118
|
* @param {boolean} [props.blocking=false] - Se `true`, exibe um overlay que impede a interação com o site até uma decisão do usuário.
|
|
2119
|
+
* @param {'soft' | 'hard'} [props.blockingMode='soft'] - Intensidade do bloqueio; use `hard` para tornar o conteúdo inerte e restringir navegação por teclado.
|
|
2053
2120
|
* @param {(state: ConsentState) => void} [props.onConsentGiven] - Callback executado na primeira vez que o usuário dá o consentimento.
|
|
2054
2121
|
* @param {(prefs: ConsentPreferences) => void} [props.onPreferencesSaved] - Callback executado sempre que o usuário salva novas preferências.
|
|
2055
2122
|
* @param {boolean} [props.disableDeveloperGuidance=false] - Desativa as mensagens de orientação no console em ambiente de desenvolvimento.
|
|
@@ -2083,7 +2150,7 @@ type ConsentEvent = ConsentInitializedEvent | ConsentUpdatedEvent;
|
|
|
2083
2150
|
* </ConsentProvider>
|
|
2084
2151
|
* ```
|
|
2085
2152
|
*/
|
|
2086
|
-
declare function ConsentProvider({ initialState, categories, texts: textsProp, language, textVariant, designTokens, PreferencesModalComponent, preferencesModalProps, CookieBannerComponent, cookieBannerProps, FloatingPreferencesButtonComponent, floatingPreferencesButtonProps, disableFloatingPreferencesButton, blocking, blockingStrategy, hideBranding: _hideBranding, onConsentGiven, onPreferencesSaved, cookie: cookieOpts, storage, onConsentVersionChange, disableDeveloperGuidance, guidanceConfig, children, disableDiscoveryLog, onConsentInit, onConsentChange, onAuditLog, }: Readonly<ConsentProviderProps>): react_jsx_runtime.JSX.Element;
|
|
2153
|
+
declare function ConsentProvider({ initialState, categories, texts: textsProp, language, textVariant, designTokens, PreferencesModalComponent, preferencesModalProps, CookieBannerComponent, cookieBannerProps, FloatingPreferencesButtonComponent, floatingPreferencesButtonProps, disableFloatingPreferencesButton, blocking, blockingMode, blockingStrategy, hideBranding: _hideBranding, onConsentGiven, onPreferencesSaved, cookie: cookieOpts, storage, onConsentVersionChange, disableDeveloperGuidance, guidanceConfig, children, disableDiscoveryLog, onConsentInit, onConsentChange, onAuditLog, }: Readonly<ConsentProviderProps>): react_jsx_runtime.JSX.Element;
|
|
2087
2154
|
declare const defaultTexts: AdvancedConsentTexts;
|
|
2088
2155
|
|
|
2089
2156
|
/**
|
|
@@ -2646,8 +2713,9 @@ declare function useCategoryStatus(categoryId: string): {
|
|
|
2646
2713
|
* precisam acessar tokens de design. Permite overrides globais de design sem alterar
|
|
2647
2714
|
* os componentes individuais, mantendo tree-shaking e performance.
|
|
2648
2715
|
*
|
|
2649
|
-
* @param
|
|
2650
|
-
* @param
|
|
2716
|
+
* @param props - Propriedades do DesignProvider.
|
|
2717
|
+
* @param props.tokens - Tokens de design opcionais para customização (cores, layouts, etc.)
|
|
2718
|
+
* @param props.children - Componentes filhos que terão acesso aos tokens via contexto
|
|
2651
2719
|
*
|
|
2652
2720
|
* @example Uso básico com tokens padrão
|
|
2653
2721
|
* ```tsx
|
|
@@ -2685,10 +2753,11 @@ declare function useCategoryStatus(categoryId: string): {
|
|
|
2685
2753
|
* @category Context
|
|
2686
2754
|
* @since 0.1.0
|
|
2687
2755
|
*/
|
|
2688
|
-
|
|
2756
|
+
interface DesignProviderProps {
|
|
2689
2757
|
tokens?: DesignTokens;
|
|
2690
2758
|
children: React$1.ReactNode;
|
|
2691
|
-
}
|
|
2759
|
+
}
|
|
2760
|
+
declare function DesignProvider({ tokens, children }: Readonly<DesignProviderProps>): react_jsx_runtime.JSX.Element;
|
|
2692
2761
|
/**
|
|
2693
2762
|
* Hook para acessar os tokens de design do contexto atual.
|
|
2694
2763
|
*
|
|
@@ -3678,6 +3747,20 @@ interface RegisteredScript {
|
|
|
3678
3747
|
* @returns Função de cleanup para remover o script da fila.
|
|
3679
3748
|
*/
|
|
3680
3749
|
declare function registerScript(def: RegisteredScript): () => void;
|
|
3750
|
+
/**
|
|
3751
|
+
* Props do ConsentScriptLoader.
|
|
3752
|
+
*
|
|
3753
|
+
* @category Types
|
|
3754
|
+
* @since 0.2.0
|
|
3755
|
+
*
|
|
3756
|
+
* @example
|
|
3757
|
+
* ```tsx
|
|
3758
|
+
* <ConsentScriptLoader
|
|
3759
|
+
* integrations={[COMMON_INTEGRATIONS.googleTagManager({ containerId: 'GTM-XXXX' })]}
|
|
3760
|
+
* reloadOnChange
|
|
3761
|
+
* />
|
|
3762
|
+
* ```
|
|
3763
|
+
*/
|
|
3681
3764
|
interface ConsentScriptLoaderProps {
|
|
3682
3765
|
/** Lista de integrações de scripts para carregar baseado no consentimento */
|
|
3683
3766
|
integrations: ScriptIntegration[];
|
|
@@ -3706,6 +3789,14 @@ interface ConsentScriptLoaderProps {
|
|
|
3706
3789
|
*
|
|
3707
3790
|
* <ConsentScriptLoader integrations={integrations} />
|
|
3708
3791
|
* ```
|
|
3792
|
+
*
|
|
3793
|
+
* @example
|
|
3794
|
+
* ```tsx
|
|
3795
|
+
* <ConsentScriptLoader
|
|
3796
|
+
* integrations={[COMMON_INTEGRATIONS.googleTagManager({ containerId: 'GTM-XXXX' })]}
|
|
3797
|
+
* nonce="csp-nonce"
|
|
3798
|
+
* />
|
|
3799
|
+
* ```
|
|
3709
3800
|
*/
|
|
3710
3801
|
declare function ConsentScriptLoader({ integrations, reloadOnChange, nonce, }: Readonly<ConsentScriptLoaderProps>): null;
|
|
3711
3802
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -175,8 +175,7 @@ declare const GUIDANCE_PRESETS: {
|
|
|
175
175
|
* Tipo auxiliar para variações de texto.
|
|
176
176
|
*
|
|
177
177
|
* Define um subconjunto opcional dos textos principais do banner e modal,
|
|
178
|
-
* permitindo variações de
|
|
179
|
-
bannerMessage: 'Utilizamos cookies para mejorar su experiencia y mostrar contenido personalizado.', (formal, casual, etc.) sem sobrescrever todos os textos.
|
|
178
|
+
* permitindo variações de tom (formal, casual, etc.) sem sobrescrever todos os textos.
|
|
180
179
|
*
|
|
181
180
|
* @category Types
|
|
182
181
|
* @since 0.4.1
|
|
@@ -1174,6 +1173,19 @@ type BackdropConfig = boolean | string | {
|
|
|
1174
1173
|
* @since 0.1.3
|
|
1175
1174
|
* @remarks
|
|
1176
1175
|
* **Histórico**: v0.4.1 - Expandido substancialmente com novos tokens
|
|
1176
|
+
*
|
|
1177
|
+
* ### Mapa de tokens (top-level)
|
|
1178
|
+
* - `colors`: cores base, semânticas e por componente
|
|
1179
|
+
* - `typography`: fonte, tamanhos, pesos e hierarquia
|
|
1180
|
+
* - `spacing`: espaçamentos, padding/margin e radius
|
|
1181
|
+
* - `layout`: posição, largura, backdrop e z-index
|
|
1182
|
+
* - `effects`: sombras, transições e filtros
|
|
1183
|
+
* - `accessibility`: contraste, motion e foco
|
|
1184
|
+
* - `themes`: overrides para light/dark
|
|
1185
|
+
*
|
|
1186
|
+
* ### Overrides complementares (MUI)
|
|
1187
|
+
* Mesmo com tokens, você pode ajustar detalhes via `sx` e `ThemeProvider`.
|
|
1188
|
+
* Ex.: `cookieBannerProps.PaperProps.sx` e `preferencesModalProps.DialogProps.sx`.
|
|
1177
1189
|
* @public
|
|
1178
1190
|
*
|
|
1179
1191
|
* @example Configuração básica
|
|
@@ -1681,6 +1693,16 @@ interface ConsentProviderProps {
|
|
|
1681
1693
|
* - `true`: Banner bloqueia interação até decisão (compliance rigorosa)
|
|
1682
1694
|
*/
|
|
1683
1695
|
blocking?: boolean;
|
|
1696
|
+
/**
|
|
1697
|
+
* Intensidade do bloqueio quando `blocking` estiver habilitado.
|
|
1698
|
+
* - 'soft' (padrão): aplica apenas overlay visual (cliques bloqueados).
|
|
1699
|
+
* - 'hard': aplica overlay + torna o conteúdo da aplicação inerte (sem foco/teclado).
|
|
1700
|
+
*
|
|
1701
|
+
* @remarks
|
|
1702
|
+
* O modo `hard` utiliza o atributo `inert` para restringir navegação por teclado
|
|
1703
|
+
* ao banner/modal, atendendo contextos regulatórios mais estritos.
|
|
1704
|
+
*/
|
|
1705
|
+
blockingMode?: 'soft' | 'hard';
|
|
1684
1706
|
/**
|
|
1685
1707
|
* Estratégia de bloqueio quando `blocking` estiver habilitado.
|
|
1686
1708
|
* - 'auto' (padrão):
|
|
@@ -1826,6 +1848,20 @@ interface ConsentProviderProps {
|
|
|
1826
1848
|
* @since 0.3.1
|
|
1827
1849
|
* @public
|
|
1828
1850
|
* Fornece acesso ao estado de consentimento e ações necessárias para o banner.
|
|
1851
|
+
*
|
|
1852
|
+
* @example
|
|
1853
|
+
* ```tsx
|
|
1854
|
+
* function MyBanner({ acceptAll, rejectAll, openPreferences, texts }: CustomCookieBannerProps) {
|
|
1855
|
+
* return (
|
|
1856
|
+
* <div>
|
|
1857
|
+
* <p>{texts.bannerMessage}</p>
|
|
1858
|
+
* <button onClick={acceptAll}>{texts.acceptAll}</button>
|
|
1859
|
+
* <button onClick={rejectAll}>{texts.declineAll}</button>
|
|
1860
|
+
* <button onClick={openPreferences}>{texts.preferences}</button>
|
|
1861
|
+
* </div>
|
|
1862
|
+
* )
|
|
1863
|
+
* }
|
|
1864
|
+
* ```
|
|
1829
1865
|
*/
|
|
1830
1866
|
interface CustomCookieBannerProps {
|
|
1831
1867
|
consented: boolean;
|
|
@@ -1851,6 +1887,28 @@ interface CustomCookieBannerProps {
|
|
|
1851
1887
|
* Fornece acesso às preferências atuais do usuário, funções para atualizar e salvar preferências,
|
|
1852
1888
|
* fechar o modal e textos customizados da interface.
|
|
1853
1889
|
*
|
|
1890
|
+
* @example
|
|
1891
|
+
* ```tsx
|
|
1892
|
+
* function MyPreferencesModal({
|
|
1893
|
+
* preferences,
|
|
1894
|
+
* setPreferences,
|
|
1895
|
+
* closePreferences,
|
|
1896
|
+
* isModalOpen,
|
|
1897
|
+
* texts,
|
|
1898
|
+
* }: CustomPreferencesModalProps) {
|
|
1899
|
+
* if (!isModalOpen) return null
|
|
1900
|
+
* return (
|
|
1901
|
+
* <div role="dialog" aria-label={texts.accessibility?.modalLabel}>
|
|
1902
|
+
* <h2>{texts.modalTitle}</h2>
|
|
1903
|
+
* <button onClick={() => setPreferences({ ...preferences, analytics: true })}>
|
|
1904
|
+
* {texts.acceptAll}
|
|
1905
|
+
* </button>
|
|
1906
|
+
* <button onClick={closePreferences}>{texts.close ?? 'Fechar'}</button>
|
|
1907
|
+
* </div>
|
|
1908
|
+
* )
|
|
1909
|
+
* }
|
|
1910
|
+
* ```
|
|
1911
|
+
*
|
|
1854
1912
|
* @property preferences Preferências atuais de consentimento do usuário.
|
|
1855
1913
|
* @property setPreferences Função para atualizar e salvar as preferências.
|
|
1856
1914
|
* @property closePreferences Função para fechar o modal de preferências.
|
|
@@ -1870,6 +1928,14 @@ interface CustomPreferencesModalProps {
|
|
|
1870
1928
|
* @since 0.3.1
|
|
1871
1929
|
* @public
|
|
1872
1930
|
* Fornece acesso às ações de abertura do modal e ao estado de consentimento.
|
|
1931
|
+
*
|
|
1932
|
+
* @example
|
|
1933
|
+
* ```tsx
|
|
1934
|
+
* function MyFloatingButton({ openPreferences, consented }: CustomFloatingPreferencesButtonProps) {
|
|
1935
|
+
* if (!consented) return null
|
|
1936
|
+
* return <button onClick={openPreferences}>Gerenciar cookies</button>
|
|
1937
|
+
* }
|
|
1938
|
+
* ```
|
|
1873
1939
|
*/
|
|
1874
1940
|
interface CustomFloatingPreferencesButtonProps {
|
|
1875
1941
|
openPreferences: () => void;
|
|
@@ -2050,6 +2116,7 @@ type ConsentEvent = ConsentInitializedEvent | ConsentUpdatedEvent;
|
|
|
2050
2116
|
* @param {ProjectCategoriesConfig} props.categories - **Obrigatório**. Define as categorias de cookies que seu projeto utiliza, em conformidade com o princípio de minimização da LGPD.
|
|
2051
2117
|
* @param {Partial<AdvancedConsentTexts>} [props.texts] - Objeto para customizar todos os textos exibidos na UI.
|
|
2052
2118
|
* @param {boolean} [props.blocking=false] - Se `true`, exibe um overlay que impede a interação com o site até uma decisão do usuário.
|
|
2119
|
+
* @param {'soft' | 'hard'} [props.blockingMode='soft'] - Intensidade do bloqueio; use `hard` para tornar o conteúdo inerte e restringir navegação por teclado.
|
|
2053
2120
|
* @param {(state: ConsentState) => void} [props.onConsentGiven] - Callback executado na primeira vez que o usuário dá o consentimento.
|
|
2054
2121
|
* @param {(prefs: ConsentPreferences) => void} [props.onPreferencesSaved] - Callback executado sempre que o usuário salva novas preferências.
|
|
2055
2122
|
* @param {boolean} [props.disableDeveloperGuidance=false] - Desativa as mensagens de orientação no console em ambiente de desenvolvimento.
|
|
@@ -2083,7 +2150,7 @@ type ConsentEvent = ConsentInitializedEvent | ConsentUpdatedEvent;
|
|
|
2083
2150
|
* </ConsentProvider>
|
|
2084
2151
|
* ```
|
|
2085
2152
|
*/
|
|
2086
|
-
declare function ConsentProvider({ initialState, categories, texts: textsProp, language, textVariant, designTokens, PreferencesModalComponent, preferencesModalProps, CookieBannerComponent, cookieBannerProps, FloatingPreferencesButtonComponent, floatingPreferencesButtonProps, disableFloatingPreferencesButton, blocking, blockingStrategy, hideBranding: _hideBranding, onConsentGiven, onPreferencesSaved, cookie: cookieOpts, storage, onConsentVersionChange, disableDeveloperGuidance, guidanceConfig, children, disableDiscoveryLog, onConsentInit, onConsentChange, onAuditLog, }: Readonly<ConsentProviderProps>): react_jsx_runtime.JSX.Element;
|
|
2153
|
+
declare function ConsentProvider({ initialState, categories, texts: textsProp, language, textVariant, designTokens, PreferencesModalComponent, preferencesModalProps, CookieBannerComponent, cookieBannerProps, FloatingPreferencesButtonComponent, floatingPreferencesButtonProps, disableFloatingPreferencesButton, blocking, blockingMode, blockingStrategy, hideBranding: _hideBranding, onConsentGiven, onPreferencesSaved, cookie: cookieOpts, storage, onConsentVersionChange, disableDeveloperGuidance, guidanceConfig, children, disableDiscoveryLog, onConsentInit, onConsentChange, onAuditLog, }: Readonly<ConsentProviderProps>): react_jsx_runtime.JSX.Element;
|
|
2087
2154
|
declare const defaultTexts: AdvancedConsentTexts;
|
|
2088
2155
|
|
|
2089
2156
|
/**
|
|
@@ -2646,8 +2713,9 @@ declare function useCategoryStatus(categoryId: string): {
|
|
|
2646
2713
|
* precisam acessar tokens de design. Permite overrides globais de design sem alterar
|
|
2647
2714
|
* os componentes individuais, mantendo tree-shaking e performance.
|
|
2648
2715
|
*
|
|
2649
|
-
* @param
|
|
2650
|
-
* @param
|
|
2716
|
+
* @param props - Propriedades do DesignProvider.
|
|
2717
|
+
* @param props.tokens - Tokens de design opcionais para customização (cores, layouts, etc.)
|
|
2718
|
+
* @param props.children - Componentes filhos que terão acesso aos tokens via contexto
|
|
2651
2719
|
*
|
|
2652
2720
|
* @example Uso básico com tokens padrão
|
|
2653
2721
|
* ```tsx
|
|
@@ -2685,10 +2753,11 @@ declare function useCategoryStatus(categoryId: string): {
|
|
|
2685
2753
|
* @category Context
|
|
2686
2754
|
* @since 0.1.0
|
|
2687
2755
|
*/
|
|
2688
|
-
|
|
2756
|
+
interface DesignProviderProps {
|
|
2689
2757
|
tokens?: DesignTokens;
|
|
2690
2758
|
children: React$1.ReactNode;
|
|
2691
|
-
}
|
|
2759
|
+
}
|
|
2760
|
+
declare function DesignProvider({ tokens, children }: Readonly<DesignProviderProps>): react_jsx_runtime.JSX.Element;
|
|
2692
2761
|
/**
|
|
2693
2762
|
* Hook para acessar os tokens de design do contexto atual.
|
|
2694
2763
|
*
|
|
@@ -3678,6 +3747,20 @@ interface RegisteredScript {
|
|
|
3678
3747
|
* @returns Função de cleanup para remover o script da fila.
|
|
3679
3748
|
*/
|
|
3680
3749
|
declare function registerScript(def: RegisteredScript): () => void;
|
|
3750
|
+
/**
|
|
3751
|
+
* Props do ConsentScriptLoader.
|
|
3752
|
+
*
|
|
3753
|
+
* @category Types
|
|
3754
|
+
* @since 0.2.0
|
|
3755
|
+
*
|
|
3756
|
+
* @example
|
|
3757
|
+
* ```tsx
|
|
3758
|
+
* <ConsentScriptLoader
|
|
3759
|
+
* integrations={[COMMON_INTEGRATIONS.googleTagManager({ containerId: 'GTM-XXXX' })]}
|
|
3760
|
+
* reloadOnChange
|
|
3761
|
+
* />
|
|
3762
|
+
* ```
|
|
3763
|
+
*/
|
|
3681
3764
|
interface ConsentScriptLoaderProps {
|
|
3682
3765
|
/** Lista de integrações de scripts para carregar baseado no consentimento */
|
|
3683
3766
|
integrations: ScriptIntegration[];
|
|
@@ -3706,6 +3789,14 @@ interface ConsentScriptLoaderProps {
|
|
|
3706
3789
|
*
|
|
3707
3790
|
* <ConsentScriptLoader integrations={integrations} />
|
|
3708
3791
|
* ```
|
|
3792
|
+
*
|
|
3793
|
+
* @example
|
|
3794
|
+
* ```tsx
|
|
3795
|
+
* <ConsentScriptLoader
|
|
3796
|
+
* integrations={[COMMON_INTEGRATIONS.googleTagManager({ containerId: 'GTM-XXXX' })]}
|
|
3797
|
+
* nonce="csp-nonce"
|
|
3798
|
+
* />
|
|
3799
|
+
* ```
|
|
3709
3800
|
*/
|
|
3710
3801
|
declare function ConsentScriptLoader({ integrations, reloadOnChange, nonce, }: Readonly<ConsentScriptLoaderProps>): null;
|
|
3711
3802
|
/**
|
package/dist/index.js
CHANGED
|
@@ -40,27 +40,27 @@ var EXPANDED_DEFAULT_TEXTS = {
|
|
|
40
40
|
categories: {
|
|
41
41
|
necessary: {
|
|
42
42
|
name: "Cookies Necess\xE1rios",
|
|
43
|
-
description: "Essenciais para o funcionamento b\xE1sico do site",
|
|
43
|
+
description: "Essenciais para o funcionamento b\xE1sico do site e n\xE3o podem ser desativados",
|
|
44
44
|
examples: "Sess\xE3o, seguran\xE7a, prefer\xEAncias de idioma"
|
|
45
45
|
},
|
|
46
46
|
analytics: {
|
|
47
47
|
name: "Cookies de Analytics",
|
|
48
|
-
description: "Ajudam a entender como os visitantes usam o site",
|
|
48
|
+
description: "Opcionais. Ajudam a entender como os visitantes usam o site",
|
|
49
49
|
examples: "Google Analytics, contadores de p\xE1gina"
|
|
50
50
|
},
|
|
51
51
|
marketing: {
|
|
52
52
|
name: "Cookies de Marketing",
|
|
53
|
-
description: "Usados para personalizar an\xFAncios e ofertas",
|
|
53
|
+
description: "Opcionais. Usados para personalizar an\xFAncios e ofertas",
|
|
54
54
|
examples: "Facebook Pixel, Google Ads, remarketing"
|
|
55
55
|
},
|
|
56
56
|
functional: {
|
|
57
57
|
name: "Cookies Funcionais",
|
|
58
|
-
description: "Melhoram a funcionalidade e personaliza\xE7\xE3o",
|
|
58
|
+
description: "Opcionais. Melhoram a funcionalidade e personaliza\xE7\xE3o",
|
|
59
59
|
examples: "Chat, mapas, v\xEDdeos embarcados"
|
|
60
60
|
},
|
|
61
61
|
performance: {
|
|
62
62
|
name: "Cookies de Performance",
|
|
63
|
-
description: "Coletam informa\xE7\xF5es sobre velocidade e estabilidade",
|
|
63
|
+
description: "Opcionais. Coletam informa\xE7\xF5es sobre velocidade e estabilidade",
|
|
64
64
|
examples: "Monitoramento de erro, otimiza\xE7\xE3o de velocidade"
|
|
65
65
|
}
|
|
66
66
|
},
|
|
@@ -94,7 +94,7 @@ var EXPANDED_DEFAULT_TEXTS = {
|
|
|
94
94
|
// Variações de tom
|
|
95
95
|
variants: {
|
|
96
96
|
formal: {
|
|
97
|
-
bannerMessage: "Este s\xEDtio eletr\xF4nico utiliza cookies para otimizar a experi\xEAncia de navega\xE7\xE3o.",
|
|
97
|
+
bannerMessage: "Este s\xEDtio eletr\xF4nico utiliza cookies necess\xE1rios e, mediante sua autoriza\xE7\xE3o, cookies opcionais para otimizar a experi\xEAncia de navega\xE7\xE3o.",
|
|
98
98
|
acceptAll: "Concordar com todos os cookies",
|
|
99
99
|
declineAll: "Recusar cookies opcionais",
|
|
100
100
|
modalTitle: "Configura\xE7\xE3o de Cookies"
|
|
@@ -112,7 +112,7 @@ var EXPANDED_DEFAULT_TEXTS = {
|
|
|
112
112
|
modalTitle: "Cookies"
|
|
113
113
|
},
|
|
114
114
|
detailed: {
|
|
115
|
-
bannerMessage: "Utilizamos cookies e tecnologias similares para melhorar sua experi\xEAncia de navega\xE7\xE3o, personalizar conte\xFAdo, analisar tr\xE1fego e oferecer funcionalidades de redes sociais.",
|
|
115
|
+
bannerMessage: "Utilizamos cookies e tecnologias similares para melhorar sua experi\xEAncia de navega\xE7\xE3o, personalizar conte\xFAdo, analisar tr\xE1fego e oferecer funcionalidades de redes sociais. Os cookies necess\xE1rios permanecem ativos e os opcionais dependem da sua autoriza\xE7\xE3o.",
|
|
116
116
|
acceptAll: "Aceitar todos os cookies e tecnologias",
|
|
117
117
|
declineAll: "Recusar todos os cookies opcionais",
|
|
118
118
|
modalTitle: "Centro de Prefer\xEAncias de Privacidade"
|
|
@@ -533,7 +533,6 @@ function buildConsentStorageKey(options) {
|
|
|
533
533
|
var DEFAULT_COOKIE_OPTS = {
|
|
534
534
|
name: "cookieConsent",
|
|
535
535
|
maxAge: DEFAULT_MAX_AGE_SECONDS,
|
|
536
|
-
maxAgeDays: 365,
|
|
537
536
|
sameSite: "Lax",
|
|
538
537
|
secure: false,
|
|
539
538
|
path: "/",
|
|
@@ -542,18 +541,23 @@ var DEFAULT_COOKIE_OPTS = {
|
|
|
542
541
|
function resolveCookieOptions(opts) {
|
|
543
542
|
const currentWindow = globalThis.window;
|
|
544
543
|
const currentLocation = globalThis.location;
|
|
545
|
-
const protocols = [currentWindow?.location?.protocol, currentLocation?.protocol].filter(
|
|
546
|
-
Boolean
|
|
547
|
-
);
|
|
544
|
+
const protocols = [currentWindow?.location?.protocol, currentLocation?.protocol].filter(Boolean);
|
|
548
545
|
const forceHttps = globalThis.__LGPD_FORCE_HTTPS__ === true;
|
|
549
546
|
const isHttps = forceHttps || protocols.includes("https:");
|
|
550
|
-
const
|
|
551
|
-
|
|
547
|
+
const maxAgeSeconds = typeof opts?.maxAge === "number" ? Math.max(0, opts.maxAge) : typeof opts?.maxAgeDays === "number" ? Math.max(0, opts.maxAgeDays) * 24 * 60 * 60 : DEFAULT_MAX_AGE_SECONDS;
|
|
548
|
+
let secure;
|
|
549
|
+
if (typeof opts?.secure === "boolean") {
|
|
550
|
+
secure = opts.secure;
|
|
551
|
+
} else if (isHttps) {
|
|
552
|
+
secure = true;
|
|
553
|
+
} else {
|
|
554
|
+
secure = DEFAULT_COOKIE_OPTS.secure;
|
|
555
|
+
}
|
|
552
556
|
return {
|
|
553
557
|
name: opts?.name ?? DEFAULT_COOKIE_OPTS.name,
|
|
554
558
|
maxAge: maxAgeSeconds,
|
|
555
559
|
sameSite: opts?.sameSite ?? DEFAULT_COOKIE_OPTS.sameSite ?? "Lax",
|
|
556
|
-
secure
|
|
560
|
+
secure,
|
|
557
561
|
path: opts?.path ?? DEFAULT_COOKIE_OPTS.path ?? "/",
|
|
558
562
|
domain: opts?.domain ?? DEFAULT_COOKIE_OPTS.domain ?? void 0
|
|
559
563
|
};
|
|
@@ -672,7 +676,7 @@ function removeConsentCookie(opts) {
|
|
|
672
676
|
}
|
|
673
677
|
|
|
674
678
|
// src/utils/dataLayerEvents.ts
|
|
675
|
-
var LIBRARY_VERSION = "0.
|
|
679
|
+
var LIBRARY_VERSION = "0.9.0";
|
|
676
680
|
function ensureDataLayer() {
|
|
677
681
|
const currentWindow = globalThis.window;
|
|
678
682
|
if (!currentWindow) return;
|
|
@@ -1708,14 +1712,88 @@ function runPeerDepsCheck() {
|
|
|
1708
1712
|
|
|
1709
1713
|
// src/utils/validation.ts
|
|
1710
1714
|
var isDev = () => typeof process !== "undefined" && process.env.NODE_ENV !== "production";
|
|
1715
|
+
var sanitizeCategories = (categories) => {
|
|
1716
|
+
const enabled = [...new Set(categories.enabledCategories ?? [])];
|
|
1717
|
+
const sanitizedEnabled = enabled.filter((c) => c !== "necessary");
|
|
1718
|
+
return {
|
|
1719
|
+
enabled,
|
|
1720
|
+
sanitizedEnabled,
|
|
1721
|
+
custom: categories.customCategories ?? []
|
|
1722
|
+
};
|
|
1723
|
+
};
|
|
1724
|
+
var collectZodIssues = (z, categories, issues) => {
|
|
1725
|
+
if (!z || !categories) return;
|
|
1726
|
+
const CustomCategorySchema = z.object({
|
|
1727
|
+
id: z.string().min(1, "customCategories[].id deve ser uma string n\xE3o vazia"),
|
|
1728
|
+
name: z.string().min(1, "customCategories[].name deve ser uma string n\xE3o vazia"),
|
|
1729
|
+
description: z.string().min(1, "customCategories[].description deve ser uma string n\xE3o vazia"),
|
|
1730
|
+
essential: z.boolean().optional(),
|
|
1731
|
+
cookies: z.array(z.string().min(1)).optional()
|
|
1732
|
+
});
|
|
1733
|
+
const ProjectCategoriesConfigSchema = z.object({
|
|
1734
|
+
enabledCategories: z.array(z.string().min(1)).optional(),
|
|
1735
|
+
customCategories: z.array(CustomCategorySchema).optional()
|
|
1736
|
+
}).strict();
|
|
1737
|
+
const res = ProjectCategoriesConfigSchema.safeParse(categories);
|
|
1738
|
+
if (!res.success) {
|
|
1739
|
+
res.error.issues.forEach(
|
|
1740
|
+
(issue) => issues.push({ path: `categories.${issue.path.join(".")}`, message: issue.message })
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
1743
|
+
const customParse = z.array(CustomCategorySchema).safeParse(categories.customCategories ?? []);
|
|
1744
|
+
if (!customParse.success) {
|
|
1745
|
+
customParse.error.issues.forEach(
|
|
1746
|
+
(issue) => issues.push({ path: `customCategories.${issue.path.join(".")}`, message: issue.message })
|
|
1747
|
+
);
|
|
1748
|
+
}
|
|
1749
|
+
};
|
|
1750
|
+
var collectCategoryWarnings = (input) => {
|
|
1751
|
+
const warnings = [];
|
|
1752
|
+
const { enabled, sanitizedEnabled, custom } = input;
|
|
1753
|
+
if (enabled.includes("necessary")) {
|
|
1754
|
+
warnings.push("'necessary' \xE9 sempre inclu\xEDda automaticamente \u2014 remova de enabledCategories.");
|
|
1755
|
+
}
|
|
1756
|
+
const invalidEnabled = sanitizedEnabled.filter((c) => typeof c !== "string" || c.trim() === "");
|
|
1757
|
+
if (invalidEnabled.length > 0) {
|
|
1758
|
+
warnings.push(
|
|
1759
|
+
`enabledCategories cont\xE9m valores inv\xE1lidos: ${invalidEnabled.map(String).join(", ")} \u2014 remova ou corrija os IDs de categoria`
|
|
1760
|
+
);
|
|
1761
|
+
}
|
|
1762
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1763
|
+
const dupes = [];
|
|
1764
|
+
["necessary", ...sanitizedEnabled].forEach((id) => {
|
|
1765
|
+
if (ids.has(id)) dupes.push(id);
|
|
1766
|
+
ids.add(id);
|
|
1767
|
+
});
|
|
1768
|
+
custom?.forEach((c) => {
|
|
1769
|
+
if (ids.has(c.id)) dupes.push(c.id);
|
|
1770
|
+
ids.add(c.id);
|
|
1771
|
+
});
|
|
1772
|
+
if (dupes.length > 0) {
|
|
1773
|
+
warnings.push(
|
|
1774
|
+
`IDs de categoria duplicados detectados: ${Array.from(new Set(dupes)).join(
|
|
1775
|
+
", "
|
|
1776
|
+
)} \u2014 verifique 'enabledCategories' e 'customCategories'.`
|
|
1777
|
+
);
|
|
1778
|
+
}
|
|
1779
|
+
return warnings;
|
|
1780
|
+
};
|
|
1781
|
+
var reportValidationMessages = (warnings, errors, issues) => {
|
|
1782
|
+
if (warnings.length > 0) {
|
|
1783
|
+
logger.warn("Valida\xE7\xE3o do ConsentProvider:", ...warnings);
|
|
1784
|
+
}
|
|
1785
|
+
if (errors.length > 0 || issues.length > 0) {
|
|
1786
|
+
issues.forEach((i) => errors.push(`Prop inv\xE1lida: ${i.path} \u2014 ${i.message}`));
|
|
1787
|
+
logger.error("Erros de configura\xE7\xE3o do ConsentProvider:", ...errors);
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1711
1790
|
function validateConsentProviderProps(props) {
|
|
1712
1791
|
const warnings = [];
|
|
1713
1792
|
const errors = [];
|
|
1714
1793
|
const sanitized = {};
|
|
1715
1794
|
if (!isDev()) {
|
|
1716
1795
|
if (props.categories) {
|
|
1717
|
-
const
|
|
1718
|
-
const sanitizedEnabled = enabled.filter((c) => c !== "necessary");
|
|
1796
|
+
const { sanitizedEnabled } = sanitizeCategories(props.categories);
|
|
1719
1797
|
sanitized.categories = {
|
|
1720
1798
|
enabledCategories: sanitizedEnabled,
|
|
1721
1799
|
customCategories: props.categories.customCategories
|
|
@@ -1730,94 +1808,27 @@ function validateConsentProviderProps(props) {
|
|
|
1730
1808
|
z = void 0;
|
|
1731
1809
|
}
|
|
1732
1810
|
const issues = [];
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
description: z.string().min(1, "customCategories[].description deve ser uma string n\xE3o vazia"),
|
|
1738
|
-
essential: z.boolean().optional(),
|
|
1739
|
-
cookies: z.array(z.string().min(1)).optional()
|
|
1740
|
-
});
|
|
1741
|
-
const ProjectCategoriesConfigSchema = z.object({
|
|
1742
|
-
enabledCategories: z.array(z.string().min(1)).optional(),
|
|
1743
|
-
customCategories: z.array(CustomCategorySchema).optional()
|
|
1744
|
-
}).strict();
|
|
1745
|
-
const res = ProjectCategoriesConfigSchema.safeParse(props.categories);
|
|
1746
|
-
if (!res.success) {
|
|
1747
|
-
res.error.issues.forEach(
|
|
1748
|
-
(issue) => issues.push({ path: `categories.${issue.path.join(".")}`, message: issue.message })
|
|
1749
|
-
);
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
if (!props.categories) {
|
|
1753
|
-
warnings.push(
|
|
1754
|
-
"Prop 'categories' n\xE3o fornecida \u2014 o ConsentProvider requer configura\xE7\xE3o de categorias."
|
|
1755
|
-
);
|
|
1756
|
-
} else {
|
|
1757
|
-
const cat = props.categories;
|
|
1758
|
-
const enabled = [...new Set(cat.enabledCategories ?? [])];
|
|
1759
|
-
if (enabled.includes("necessary")) {
|
|
1760
|
-
warnings.push("'necessary' \xE9 sempre inclu\xEDda automaticamente \u2014 remova de enabledCategories.");
|
|
1761
|
-
}
|
|
1762
|
-
const sanitizedEnabled = enabled.filter((c) => c !== "necessary");
|
|
1763
|
-
const invalidEnabled = sanitizedEnabled.filter((c) => typeof c !== "string" || c.trim() === "");
|
|
1764
|
-
if (invalidEnabled.length > 0) {
|
|
1765
|
-
warnings.push(
|
|
1766
|
-
`enabledCategories cont\xE9m valores inv\xE1lidos: ${invalidEnabled.map(String).join(", ")} \u2014 remova ou corrija os IDs de categoria`
|
|
1767
|
-
);
|
|
1768
|
-
}
|
|
1769
|
-
const custom = cat.customCategories ?? [];
|
|
1770
|
-
if (z) {
|
|
1771
|
-
const CustomCategorySchema = z.object({
|
|
1772
|
-
id: z.string().min(1),
|
|
1773
|
-
name: z.string().min(1),
|
|
1774
|
-
description: z.string().min(1),
|
|
1775
|
-
essential: z.boolean().optional(),
|
|
1776
|
-
cookies: z.array(z.string().min(1)).optional()
|
|
1777
|
-
});
|
|
1778
|
-
const customParse = z.array(CustomCategorySchema).safeParse(custom);
|
|
1779
|
-
if (!customParse.success) {
|
|
1780
|
-
customParse.error.issues.forEach(
|
|
1781
|
-
(issue) => issues.push({ path: `customCategories.${issue.path.join(".")}`, message: issue.message })
|
|
1782
|
-
);
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1786
|
-
const dupes = [];
|
|
1787
|
-
["necessary", ...sanitizedEnabled].forEach((id) => {
|
|
1788
|
-
if (ids.has(id)) dupes.push(id);
|
|
1789
|
-
ids.add(id);
|
|
1790
|
-
});
|
|
1791
|
-
custom.forEach((c) => {
|
|
1792
|
-
if (ids.has(c.id)) dupes.push(c.id);
|
|
1793
|
-
ids.add(c.id);
|
|
1794
|
-
});
|
|
1795
|
-
if (dupes.length > 0) {
|
|
1796
|
-
warnings.push(
|
|
1797
|
-
`IDs de categoria duplicados detectados: ${Array.from(new Set(dupes)).join(
|
|
1798
|
-
", "
|
|
1799
|
-
)} \u2014 verifique 'enabledCategories' e 'customCategories'.`
|
|
1800
|
-
);
|
|
1801
|
-
}
|
|
1811
|
+
collectZodIssues(z, props.categories, issues);
|
|
1812
|
+
if (props.categories) {
|
|
1813
|
+
const { enabled, sanitizedEnabled, custom } = sanitizeCategories(props.categories);
|
|
1814
|
+
warnings.push(...collectCategoryWarnings({ enabled, sanitizedEnabled, custom }));
|
|
1802
1815
|
sanitized.categories = {
|
|
1803
1816
|
enabledCategories: sanitizedEnabled,
|
|
1804
1817
|
customCategories: custom
|
|
1805
1818
|
};
|
|
1819
|
+
} else {
|
|
1820
|
+
warnings.push(
|
|
1821
|
+
"Prop 'categories' n\xE3o fornecida \u2014 o ConsentProvider requer configura\xE7\xE3o de categorias."
|
|
1822
|
+
);
|
|
1806
1823
|
}
|
|
1807
|
-
|
|
1808
|
-
logger.warn("Valida\xE7\xE3o do ConsentProvider:", ...warnings);
|
|
1809
|
-
}
|
|
1810
|
-
if (errors.length > 0 || issues.length > 0) {
|
|
1811
|
-
issues.forEach((i) => errors.push(`Prop inv\xE1lida: ${i.path} \u2014 ${i.message}`));
|
|
1812
|
-
logger.error("Erros de configura\xE7\xE3o do ConsentProvider:", ...errors);
|
|
1813
|
-
}
|
|
1824
|
+
reportValidationMessages(warnings, errors, issues);
|
|
1814
1825
|
return { sanitized, warnings, errors };
|
|
1815
1826
|
}
|
|
1816
1827
|
|
|
1817
1828
|
// src/utils/cookieDiscovery.ts
|
|
1818
1829
|
function discoverRuntimeCookies() {
|
|
1819
1830
|
const currentDocument = globalThis.document;
|
|
1820
|
-
if (
|
|
1831
|
+
if (!currentDocument?.cookie) return [];
|
|
1821
1832
|
const names = Array.from(
|
|
1822
1833
|
new Set(
|
|
1823
1834
|
currentDocument.cookie.split(";").map((s) => s.trim()).filter(Boolean).map((s) => s.split("=")[0])
|
|
@@ -1849,7 +1860,7 @@ function isConsentJson(val) {
|
|
|
1849
1860
|
}
|
|
1850
1861
|
function detectConsentCookieName() {
|
|
1851
1862
|
const currentDocument = globalThis.document;
|
|
1852
|
-
if (
|
|
1863
|
+
if (!currentDocument?.cookie) return null;
|
|
1853
1864
|
try {
|
|
1854
1865
|
const pairs = currentDocument.cookie.split(";").map((s) => s.trim()).filter(Boolean);
|
|
1855
1866
|
for (const p of pairs) {
|
|
@@ -1978,10 +1989,7 @@ function useCategoryStatus(categoryId) {
|
|
|
1978
1989
|
};
|
|
1979
1990
|
}
|
|
1980
1991
|
var DesignContext = React4.createContext(void 0);
|
|
1981
|
-
function DesignProvider({
|
|
1982
|
-
tokens,
|
|
1983
|
-
children
|
|
1984
|
-
}) {
|
|
1992
|
+
function DesignProvider({ tokens, children }) {
|
|
1985
1993
|
return /* @__PURE__ */ jsx(DesignContext.Provider, { value: tokens, children });
|
|
1986
1994
|
}
|
|
1987
1995
|
function useDesignTokens() {
|
|
@@ -2003,19 +2011,19 @@ function createFullConsentState(consented, preferences, source, projectConfig, i
|
|
|
2003
2011
|
}
|
|
2004
2012
|
var BASE_TEXTS = {
|
|
2005
2013
|
// Textos básicos
|
|
2006
|
-
bannerMessage: "
|
|
2014
|
+
bannerMessage: "Usamos cookies necess\xE1rios para o funcionamento do site e, com sua autoriza\xE7\xE3o, cookies opcionais para melhorar sua experi\xEAncia. Voc\xEA pode aceitar todos, rejeitar os opcionais ou ajustar suas prefer\xEAncias.",
|
|
2007
2015
|
acceptAll: "Aceitar todos",
|
|
2008
|
-
declineAll: "
|
|
2016
|
+
declineAll: "Rejeitar opcionais",
|
|
2009
2017
|
preferences: "Prefer\xEAncias",
|
|
2010
|
-
policyLink: "
|
|
2011
|
-
modalTitle: "Prefer\xEAncias de
|
|
2012
|
-
modalIntro: "
|
|
2018
|
+
policyLink: "Pol\xEDtica de privacidade",
|
|
2019
|
+
modalTitle: "Prefer\xEAncias de cookies",
|
|
2020
|
+
modalIntro: "Cookies necess\xE1rios s\xE3o sempre ativos. As categorias opcionais s\xF3 ser\xE3o usadas com sua autoriza\xE7\xE3o e podem ser ativadas ou desativadas a qualquer momento.",
|
|
2013
2021
|
save: "Salvar prefer\xEAncias",
|
|
2014
2022
|
necessaryAlwaysOn: "Cookies necess\xE1rios (sempre ativos)",
|
|
2015
2023
|
// Textos adicionais para UI customizada
|
|
2016
|
-
preferencesButton: "
|
|
2017
|
-
preferencesTitle: "Gerenciar
|
|
2018
|
-
preferencesDescription: "Escolha quais
|
|
2024
|
+
preferencesButton: "Gerenciar cookies",
|
|
2025
|
+
preferencesTitle: "Gerenciar prefer\xEAncias de cookies",
|
|
2026
|
+
preferencesDescription: "Escolha quais categorias opcionais voc\xEA permite. Cookies necess\xE1rios permanecem sempre ativos e voc\xEA pode mudar sua escolha quando quiser.",
|
|
2019
2027
|
close: "Fechar",
|
|
2020
2028
|
accept: "Aceitar",
|
|
2021
2029
|
reject: "Rejeitar",
|
|
@@ -2136,6 +2144,7 @@ function ConsentProvider({
|
|
|
2136
2144
|
floatingPreferencesButtonProps = {},
|
|
2137
2145
|
disableFloatingPreferencesButton = false,
|
|
2138
2146
|
blocking = false,
|
|
2147
|
+
blockingMode = "soft",
|
|
2139
2148
|
blockingStrategy = "auto",
|
|
2140
2149
|
hideBranding: _hideBranding = false,
|
|
2141
2150
|
onConsentGiven,
|
|
@@ -2413,6 +2422,7 @@ function ConsentProvider({
|
|
|
2413
2422
|
hideBranding: incoming.hideBranding === void 0 ? _hideBranding : Boolean(incoming.hideBranding)
|
|
2414
2423
|
};
|
|
2415
2424
|
}, [cookieBannerProps, blocking, _hideBranding]);
|
|
2425
|
+
const hardBlockingActive = blocking && isHydrated && !state.consented && blockingMode === "hard";
|
|
2416
2426
|
const content = /* @__PURE__ */ jsx(StateCtx.Provider, { value: state, children: /* @__PURE__ */ jsx(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ jsx(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ jsx(HydrationCtx.Provider, { value: isHydrated, children: /* @__PURE__ */ jsx(DesignProvider, { tokens: designTokens, children: /* @__PURE__ */ jsxs(
|
|
2417
2427
|
CategoriesProvider,
|
|
2418
2428
|
{
|
|
@@ -2420,7 +2430,16 @@ function ConsentProvider({
|
|
|
2420
2430
|
disableDeveloperGuidance,
|
|
2421
2431
|
disableDiscoveryLog,
|
|
2422
2432
|
children: [
|
|
2423
|
-
|
|
2433
|
+
/* @__PURE__ */ jsx(
|
|
2434
|
+
"div",
|
|
2435
|
+
{
|
|
2436
|
+
"data-testid": "lgpd-app-content",
|
|
2437
|
+
"aria-hidden": hardBlockingActive ? true : void 0,
|
|
2438
|
+
inert: hardBlockingActive,
|
|
2439
|
+
style: { display: "contents" },
|
|
2440
|
+
children
|
|
2441
|
+
}
|
|
2442
|
+
),
|
|
2424
2443
|
PreferencesModalComponent ? /* @__PURE__ */ jsx(
|
|
2425
2444
|
PreferencesModalComponent,
|
|
2426
2445
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-lgpd-consent/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Núcleo da biblioteca de consentimento LGPD para React - Estado, hooks e utilitários sem dependências de UI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lgpd",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"js-cookie": "^3.0.5",
|
|
56
|
-
"zod": "^4.
|
|
56
|
+
"zod": "^4.3.4"
|
|
57
57
|
},
|
|
58
58
|
"repository": {
|
|
59
59
|
"type": "git",
|