@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 CHANGED
@@ -1,36 +1,80 @@
1
1
  # Changelog - @react-lgpd-consent/core
2
2
 
3
- ## 0.7.2
3
+ ## 0.9.0
4
4
 
5
- ### Patch Changes
5
+ ### Minor Changes
6
6
 
7
- - [#134](https://github.com/lucianoedipo/react-lgpd-consent/pull/134) [`44b885b`](https://github.com/lucianoedipo/react-lgpd-consent/commit/44b885b7c81f1cb5822e2dcfde2975e69e8d4893) Thanks [@github-actions](https://github.com/apps/github-actions)! - ### Correções
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
- ### Funcionalidades
11
- - d641639 feat: adicionar gerenciamento de eventos para categorias obrigatórias no CategoriesProvider
12
- - b04c00b feat: add tests for CookieBanner, FloatingPreferencesButton, and PreferencesModal components
13
- - b04c00b Introduce interactive changeset script for easier versioning in monorepos.
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
- - ef2968a refactor: replace direct document and window references with globalThis for better compatibility
17
- - ef2968a Updated scriptLoader, cookieDiscovery, cookieUtils, dataLayerEvents, developerGuidance, peerDepsCheck, scriptIntegrations, and scriptLoader files to use globalThis.document and globalThis.window.
18
- - ef2968a Improved cookie handling functions to check for document and window availability using globalThis.
19
- - ef2968a Enhanced tests to reference globalThis for consistency.
20
- - ef2968a Cleaned up code formatting and comments for clarity.
21
- - b04c00b Refactor coverage check script to use node imports.
22
- - b04c00b Adjust TypeDoc script for ESM compatibility.
23
- - 3af2fcb Fix path resolution in tsconfig for better module imports.
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
- ### Testes
26
- - b04c00b Implement tests for CookieBanner to verify rendering based on consent and debug mode.
27
- - b04c00b Enhance FloatingPreferencesButton tests to check for localized text via props.
28
- - b04c00b Extend PreferencesModal tests to cover temporary preference resets, active scripts rendering, and custom text application.
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
- ### Documentação
31
- - d430eef docs: atualizar instruções para agentes com visão geral do projeto e comandos essenciais
32
- - d430eef Updated documentation to reflect changes in globalThis usage.
33
- - d430eef Update API documentation to include new integration functions and ESM/CJS testing configurations.
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 { createAnpdCategories, ANPD_CATEGORY_PRESETS } from '@react-lgpd-consent/core'
103
+ import { createAnpdCategoriesConfig, ANPD_CATEGORY_PRESETS } from '@react-lgpd-consent/core'
104
104
 
105
105
  // Preset BÁSICO
106
- const basic = createAnpdCategories({ include: ['analytics'] })
106
+ const basic = createAnpdCategoriesConfig({ include: ['analytics'] })
107
107
 
108
108
  // Preset COMPLETO
109
- const full = createAnpdCategories({
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 maxAgeSecondsFromDays = typeof opts?.maxAgeDays === "number" ? Math.max(0, opts.maxAgeDays * 24 * 60 * 60) : null;
575
- const maxAgeSeconds = typeof opts?.maxAge === "number" ? Math.max(0, opts.maxAge) : maxAgeSecondsFromDays ?? DEFAULT_MAX_AGE_SECONDS;
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: typeof opts?.secure === "boolean" ? opts.secure : isHttps ? true : DEFAULT_COOKIE_OPTS.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.7.2";
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 enabled = [...new Set(props.categories.enabledCategories ?? [])];
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
- if (z) {
1758
- const CustomCategorySchema = z.object({
1759
- id: z.string().min(1, "customCategories[].id deve ser uma string n\xE3o vazia"),
1760
- name: z.string().min(1, "customCategories[].name deve ser uma string n\xE3o vazia"),
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
- if (warnings.length > 0) {
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 (currentDocument === void 0 || !currentDocument.cookie) return [];
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 (currentDocument === void 0 || !currentDocument.cookie) return null;
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: "Utilizamos cookies para melhorar sua experi\xEAncia.",
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: "Recusar",
2040
+ declineAll: "Rejeitar opcionais",
2033
2041
  preferences: "Prefer\xEAncias",
2034
- policyLink: "Saiba mais",
2035
- modalTitle: "Prefer\xEAncias de Cookies",
2036
- modalIntro: "Ajuste as categorias de cookies. Cookies necess\xE1rios s\xE3o sempre utilizados para funcionalidades b\xE1sicas.",
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: "Configurar Cookies",
2041
- preferencesTitle: "Gerenciar Prefer\xEAncias de Cookies",
2042
- preferencesDescription: "Escolha quais tipos de cookies voc\xEA permite que sejam utilizados.",
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
- children,
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 t es: {
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 tokens - Tokens de design opcionais para customização (cores, layouts, etc.)
2650
- * @param children - Componentes filhos que terão acesso aos tokens via contexto
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
- declare function DesignProvider({ tokens, children, }: Readonly<{
2756
+ interface DesignProviderProps {
2689
2757
  tokens?: DesignTokens;
2690
2758
  children: React$1.ReactNode;
2691
- }>): react_jsx_runtime.JSX.Element;
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 t es: {
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 tokens - Tokens de design opcionais para customização (cores, layouts, etc.)
2650
- * @param children - Componentes filhos que terão acesso aos tokens via contexto
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
- declare function DesignProvider({ tokens, children, }: Readonly<{
2756
+ interface DesignProviderProps {
2689
2757
  tokens?: DesignTokens;
2690
2758
  children: React$1.ReactNode;
2691
- }>): react_jsx_runtime.JSX.Element;
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 maxAgeSecondsFromDays = typeof opts?.maxAgeDays === "number" ? Math.max(0, opts.maxAgeDays * 24 * 60 * 60) : null;
551
- const maxAgeSeconds = typeof opts?.maxAge === "number" ? Math.max(0, opts.maxAge) : maxAgeSecondsFromDays ?? DEFAULT_MAX_AGE_SECONDS;
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: typeof opts?.secure === "boolean" ? opts.secure : isHttps ? true : DEFAULT_COOKIE_OPTS.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.7.2";
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 enabled = [...new Set(props.categories.enabledCategories ?? [])];
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
- if (z) {
1734
- const CustomCategorySchema = z.object({
1735
- id: z.string().min(1, "customCategories[].id deve ser uma string n\xE3o vazia"),
1736
- name: z.string().min(1, "customCategories[].name deve ser uma string n\xE3o vazia"),
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
- if (warnings.length > 0) {
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 (currentDocument === void 0 || !currentDocument.cookie) return [];
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 (currentDocument === void 0 || !currentDocument.cookie) return null;
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: "Utilizamos cookies para melhorar sua experi\xEAncia.",
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: "Recusar",
2016
+ declineAll: "Rejeitar opcionais",
2009
2017
  preferences: "Prefer\xEAncias",
2010
- policyLink: "Saiba mais",
2011
- modalTitle: "Prefer\xEAncias de Cookies",
2012
- modalIntro: "Ajuste as categorias de cookies. Cookies necess\xE1rios s\xE3o sempre utilizados para funcionalidades b\xE1sicas.",
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: "Configurar Cookies",
2017
- preferencesTitle: "Gerenciar Prefer\xEAncias de Cookies",
2018
- preferencesDescription: "Escolha quais tipos de cookies voc\xEA permite que sejam utilizados.",
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
- children,
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.7.2",
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.2.1"
56
+ "zod": "^4.3.4"
57
57
  },
58
58
  "repository": {
59
59
  "type": "git",