react-lgpd-consent 0.4.0 → 0.4.3

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/QUICKSTART.md CHANGED
@@ -62,9 +62,297 @@ export default App
62
62
 
63
63
  ````
64
64
 
65
+ ## ⚡ Quickstarts: Next.js (App Router) e Vite
66
+
67
+ Os exemplos a seguir integram GTM/GA4 com Consent Mode v2 e garantem que nenhum script de tracking rode antes do consentimento. Eles também mostram como usar `ConsentScriptLoader` e sincronizar os sinais do Consent Mode via `gtag('consent', ...)`.
68
+
69
+ - Exemplos completos: `examples/next-app-router/*`, `examples/vite/*`
70
+
71
+ ### Next.js 14/15 — App Router (SSR-safe)
72
+
73
+ 1) Criar app Next e instalar deps
74
+
75
+ ```bash
76
+ npm create next-app@latest my-app --ts --eslint --src-dir --app --no-tailwind --no-experimental-app
77
+ cd my-app
78
+ npm i react-lgpd-consent @mui/material @mui/icons-material @emotion/react @emotion/styled
79
+ ```
80
+
81
+ 2) Variáveis públicas no `.env.local`
82
+
83
+ ```
84
+ NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
85
+ NEXT_PUBLIC_GTM_ID=GTM-XXXXXXX
86
+ ```
87
+
88
+ 3) Copiar os arquivos do exemplo e ajustar imports
89
+
90
+ - De `examples/next-app-router/app/layout.tsx` → `app/layout.tsx`
91
+ - De `examples/next-app-router/app/page.tsx` → `app/page.tsx`
92
+ - De `examples/next-app-router/components/ClientConsent.tsx` → `app/components/ClientConsent.tsx`
93
+
94
+ Observação: nos arquivos copiados, troque imports relativos para `import { ConsentProvider, ConsentScriptLoader } from 'react-lgpd-consent'`.
95
+
96
+ 4) O que esse setup faz
97
+
98
+ - `ClientConsent` é um componente client-only (via `dynamic(..., { ssr: false })` no layout) que:
99
+ - Injeta um stub de `dataLayer/gtag` e define `consent default = denied` para todos os sinais (ad_storage, ad_user_data, ad_personalization, analytics_storage).
100
+ - Sincroniza as mudanças do consentimento com `gtag('consent','update', ...)` mapeando as categorias: `analytics → analytics_storage`, `marketing → ad_*`.
101
+ - Usa `ConsentScriptLoader` para carregar GTM/GA4 somente quando as categorias permitirem. Antes disso, nenhum script de tracking é carregado.
102
+
103
+ 5) Rodar
104
+
105
+ ```bash
106
+ npm run dev
107
+ ```
108
+
109
+ Validação rápida:
110
+ - Acesse em aba anônima: a rede não carrega `gtm.js`/`gtag/js` até aceitar preferências.
111
+ - Ao aceitar `analytics`, o GA4 é carregado; ao aceitar `marketing`, os sinais `ad_*` são atualizados como granted.
112
+
113
+ ### Vite (CSR)
114
+
115
+ 1) Criar app Vite e instalar deps
116
+
117
+ ```bash
118
+ npm create vite@latest my-app -- --template react-ts
119
+ cd my-app
120
+ npm i react-lgpd-consent @mui/material @mui/icons-material @emotion/react @emotion/styled
121
+ ```
122
+
123
+ 2) Variáveis no `.env`
124
+
125
+ ```
126
+ VITE_GA_ID=G-XXXXXXXXXX
127
+ VITE_GTM_ID=GTM-XXXXXXX
128
+ ```
129
+
130
+ 3) Copiar os arquivos do exemplo e ajustar imports
131
+
132
+ - De `examples/vite/index.html` → `index.html` (não adicione scripts do GA/GTM aqui)
133
+ - De `examples/vite/src/main.tsx` → `src/main.tsx`
134
+ - De `examples/vite/src/App.tsx` → `src/App.tsx`
135
+ - De `examples/vite/src/consent/GtagConsent.tsx` → `src/consent/GtagConsent.tsx`
136
+
137
+ Observação: nos arquivos copiados, troque imports relativos para `import { ... } from 'react-lgpd-consent'`.
138
+
139
+ 4) Rodar
140
+
141
+ ```bash
142
+ npm run dev
143
+ ```
144
+
145
+ Validação rápida:
146
+ - Ao abrir a app (em nova sessão), nenhum script de tracking é baixado até que o usuário consinta.
147
+ - Preferências atualizam `gtag('consent','update', ...)` corretamente por categoria.
148
+
65
149
  ## 🧩 Categorias customizadas (customCategories)
66
150
  Disponível a partir da v0.4.0.
67
151
 
152
+ ## 🍪 Categorias: definição, uso e exemplos
153
+
154
+ Fonte única de verdade
155
+ - Defina as categorias do seu projeto SOMENTE na prop `categories` do `ConsentProvider`.
156
+ - A UI (Banner/Modal), os hooks (`useConsent`, `useCategories`) e as integrações (`ConsentScriptLoader`) leem a mesma definição. Não declare categorias em outros lugares.
157
+
158
+ O que é obrigatório?
159
+ - Apenas a categoria `necessary` é obrigatória (e já é sempre incluída automaticamente).
160
+ - Todas as demais (`analytics`, `marketing`, `functional`, etc.) são opcionais e dependem do seu caso de negócio. Se você não usa analytics/ads/chat, simplesmente não habilite essas categorias.
161
+
162
+ Como “esconder” categorias que não uso?
163
+ - Basta não incluí-las em `enabledCategories` e não declará-las em `customCategories`. A UI não exibirá toggles para categorias ausentes.
164
+
165
+ Exemplo A — Somente necessários (mínimo, comum para apps internos/governo sem tracking)
166
+ ```tsx
167
+ import { ConsentProvider } from 'react-lgpd-consent'
168
+
169
+ export default function App() {
170
+ return (
171
+ <ConsentProvider
172
+ categories={{ enabledCategories: [] }}
173
+ texts={{ bannerMessage: 'Usamos apenas cookies necessários para funcionamento.' }}
174
+ >
175
+ <YourApp />
176
+ </ConsentProvider>
177
+ )
178
+ }
179
+ ```
180
+
181
+ Exemplo B — Conjunto completo (site com analytics e marketing)
182
+ ```tsx
183
+ import { ConsentProvider } from 'react-lgpd-consent'
184
+
185
+ export default function App() {
186
+ return (
187
+ <ConsentProvider
188
+ categories={{ enabledCategories: ['analytics', 'marketing', 'functional'] }}
189
+ >
190
+ <YourApp />
191
+ </ConsentProvider>
192
+ )
193
+ }
194
+ ```
195
+
196
+ Boas práticas
197
+ - Sempre passe `categories` explicitamente. Em DEV, a biblioteca avisa quando `categories` não foi configurado para evitar ambiguidades.
198
+ - Não classifique scripts de analytics/ads como “necessary” — use `ConsentScriptLoader` e categorias adequadas.
199
+ - Em dúvidas, comece com “somente necessários” e evolua quando o negócio exigir outras categorias.
200
+
201
+ ### 🔎 Validação de configuração (DEV)
202
+
203
+ Em desenvolvimento, a biblioteca valida a configuração e mostra mensagens amigáveis no console. Nada disso impacta produção (onde só ocorre uma sanitização leve).
204
+
205
+ Avisos comuns e como corrigir:
206
+ - `Prop 'categories' não fornecida...` — defina `categories.enabledCategories` de forma explícita; exemplo mínimo: `categories={{ enabledCategories: [] }}`.
207
+ - `'necessary' é sempre incluída automaticamente` — remova `'necessary'` de `enabledCategories` (ela já é incluída por padrão).
208
+ - `IDs de categoria duplicados detectados` — revise `enabledCategories` e `customCategories` para garantir que não há IDs repetidos.
209
+ - `enabledCategories contém valores inválidos` — verifique se todos os itens são strings não vazias (IDs de categoria).
210
+ - `customCategories: ... — ... deve ser uma string não vazia` — preencha `id`, `name` e `description` das categorias customizadas.
211
+
212
+ Notas:
213
+ - Validação detalhada roda apenas em `NODE_ENV !== 'production'`.
214
+ - Em produção, a lib não carrega o validador; somente remove `'necessary'` se vier por engano, mantendo o comportamento seguro.
215
+
216
+ ## 🧱 SSR/Next.js (App Router) — Padrões seguros
217
+
218
+ Objetivo: evitar hydration mismatch, hooks em Server Components e vazamento de scripts.
219
+
220
+ Padrões recomendados
221
+ - Envolva o app com o `ConsentProvider` apenas no cliente.
222
+ - Use `dynamic(() => import('./ClientConsent'), { ssr: false })` no `RootLayout` (Server Component) e mova hooks e efeitos para o componente cliente.
223
+ - Nenhum acesso a `window`/`document` no topo de módulo; use apenas dentro de `useEffect`.
224
+ - Inicialize Consent Mode v2 com `gtag('consent','default', denied)` antes de carregar GTM/GA4; depois, atualize sinais na mudança de preferências.
225
+
226
+ Exemplo de RootLayout (Server) + Client wrapper
227
+
228
+ ```tsx
229
+ // app/layout.tsx (Server Component)
230
+ import dynamic from 'next/dynamic'
231
+
232
+ const ClientConsent = dynamic(() => import('./components/ClientConsent'), { ssr: false })
233
+
234
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
235
+ return (
236
+ <html lang="pt-BR">
237
+ <body>
238
+ <ClientConsent>{children}</ClientConsent>
239
+ </body>
240
+ </html>
241
+ )
242
+ }
243
+ ```
244
+
245
+ ```tsx
246
+ // app/components/ClientConsent.tsx (Client Component)
247
+ 'use client'
248
+ import React from 'react'
249
+ import { ConsentProvider, ConsentScriptLoader } from 'react-lgpd-consent'
250
+ import { COMMON_INTEGRATIONS } from 'react-lgpd-consent'
251
+ import { useConsent } from 'react-lgpd-consent'
252
+
253
+ function BootstrapConsentMode() {
254
+ React.useEffect(() => {
255
+ const w = window as any
256
+ w.dataLayer = w.dataLayer ?? []
257
+ w.gtag = w.gtag ?? ((...args: any[]) => w.dataLayer.push(args))
258
+ w.gtag('consent', 'default', {
259
+ ad_storage: 'denied',
260
+ ad_user_data: 'denied',
261
+ ad_personalization: 'denied',
262
+ analytics_storage: 'denied',
263
+ })
264
+ }, [])
265
+ return null
266
+ }
267
+
268
+ function SyncConsentMode() {
269
+ const { consented, preferences } = useConsent()
270
+ React.useEffect(() => {
271
+ if (!consented) return
272
+ const w = window as any
273
+ w.gtag?.('consent', 'update', {
274
+ analytics_storage: preferences.analytics ? 'granted' : 'denied',
275
+ ad_storage: preferences.marketing ? 'granted' : 'denied',
276
+ ad_user_data: preferences.marketing ? 'granted' : 'denied',
277
+ ad_personalization: preferences.marketing ? 'granted' : 'denied',
278
+ })
279
+ }, [consented, preferences])
280
+ return null
281
+ }
282
+
283
+ export default function ClientConsent({ children }: { children: React.ReactNode }) {
284
+ const GA = process.env.NEXT_PUBLIC_GA_ID!
285
+ const GTM = process.env.NEXT_PUBLIC_GTM_ID!
286
+ return (
287
+ <ConsentProvider categories={{ enabledCategories: ['analytics', 'marketing', 'functional'] }} blocking>
288
+ <BootstrapConsentMode />
289
+ <SyncConsentMode />
290
+ <ConsentScriptLoader
291
+ integrations={[
292
+ COMMON_INTEGRATIONS.googleAnalytics({ measurementId: GA }),
293
+ COMMON_INTEGRATIONS.googleTagManager({ containerId: GTM }),
294
+ ]}
295
+ />
296
+ {children}
297
+ </ConsentProvider>
298
+ )
299
+ }
300
+ ```
301
+
302
+ Ordem de provedores e estilos (MUI/Emotion)
303
+ - Preferência de ordem recomendada:
304
+ - `CacheProvider` (Emotion) ou `StyledEngineProvider` com `injectFirst`
305
+ - `ThemeProvider` (MUI)
306
+ - `CssBaseline`
307
+ - `ConsentProvider` (sem criar tema por padrão)
308
+ - Motivo: garante injeção de estilos do MUI antes de CSS da app e evita desalinhamento visual; os componentes da lib herdam o tema quando presente.
309
+
310
+ Z-index e Portals
311
+ - Componentes MUI usam o `zIndex` do tema; modals/portals padrão usam `zIndex.modal = 1300`.
312
+ - O overlay bloqueante do Provider usa `z-index: 1299`; o Modal/Banner usa camadas ≥ 1300.
313
+ - Em caso de conflito com headers fixos, ajuste o `theme.zIndex` (ex.: `appBar: 1200`, `modal: 1300+`) ou os `designTokens` conforme a necessidade.
314
+
315
+ Checklist SSR (evite hydration mismatch)
316
+ - [ ] Hooks somente em Client Components (`'use client'` no topo).
317
+ - [ ] Nada de `window`/`document`/`localStorage` no topo de módulo (apenas em `useEffect`).
318
+ - [ ] `dynamic(..., { ssr: false })` para wrappers que usam hooks e efeitos do consentimento.
319
+ - [ ] GTM/GA4 carregados apenas após consentimento (via `ConsentScriptLoader`).
320
+ - [ ] Sem `<script>` de GTM/GA4 em `head`/`body`; todo carregamento vem do loader.
321
+
322
+ ## 🎨 Dica de estilo: Backdrop sensível ao tema
323
+
324
+ No modo bloqueante, o banner usa um backdrop para focar a atenção do usuário. Você pode controlar via design tokens:
325
+
326
+ ```tsx
327
+ <ConsentProvider
328
+ categories={{ enabledCategories: ['analytics'] }}
329
+ designTokens={{
330
+ layout: {
331
+ // false: transparente | 'auto': ajusta ao tema | string: cor custom (ex.: '#00000088')
332
+ backdrop: 'auto',
333
+ },
334
+ colors: {
335
+ // Se omitido, usa o palette do tema MUI (background.paper, text.primary)
336
+ // background: '#1e1e1e',
337
+ // text: '#ffffff',
338
+ },
339
+ }}
340
+ >
341
+ <App />
342
+ </ConsentProvider>
343
+ ```
344
+
345
+ Se `colors.background` ou `colors.text` não forem fornecidos, a lib usa automaticamente `theme.palette.background.paper` e `theme.palette.text.primary` do MUI, garantindo compatibilidade com dark mode.
346
+
347
+ ## 🧑‍🏫 Guia do Dev (console)
348
+
349
+ Durante o desenvolvimento, o console exibe um guia com:
350
+ - Avisos quando a configuração padrão é usada; sugestões para explicitar categorias
351
+ - Lista de categorias ativas e quais exigem toggle
352
+ - Detecção de integrações que requerem categorias, com sugestão para habilitá-las
353
+ - Boas práticas LGPD (Brasil) e alertas de UX (categorias demais)
354
+ - Silenciado automaticamente em produção; SSR-safe
355
+
68
356
  Adicione categorias específicas do seu projeto (ex.: chat de suporte, players de vídeo, AB testing):
69
357
 
70
358
  ```tsx
@@ -193,7 +481,6 @@ A biblioteca `react-lgpd-consent` não injeta um `ThemeProvider` global por cont
193
481
 
194
482
  ```tsx
195
483
  import { ConsentProvider, createDefaultConsentTheme } from 'react-lgpd-consent'
196
-
197
484
  ;<ConsentProvider
198
485
  theme={createDefaultConsentTheme()}
199
486
  categories={{ enabledCategories: ['analytics'] }}
@@ -275,6 +562,280 @@ function App() {
275
562
  }
276
563
  ```
277
564
 
565
+ ### 🍪 Modal Personalizado com Detalhes dos Cookies
566
+
567
+ Para casos mais avançados onde você precisa exibir informações detalhadas sobre cada cookie (nome, finalidade, duração, provedor), use `getCookiesInfoForCategory` junto com `useCategories`:
568
+
569
+ ```tsx
570
+ import React from 'react'
571
+ import {
572
+ ConsentProvider,
573
+ useCategories,
574
+ getCookiesInfoForCategory,
575
+ type CustomPreferencesModalProps,
576
+ type CookieDescriptor,
577
+ } from 'react-lgpd-consent'
578
+
579
+ const ModalComDetalhesCookies: React.FC<CustomPreferencesModalProps> = ({
580
+ preferences,
581
+ setPreferences,
582
+ closePreferences,
583
+ isModalOpen,
584
+ texts,
585
+ }) => {
586
+ const { allCategories } = useCategories()
587
+
588
+ if (!isModalOpen) return null
589
+
590
+ // Simula integrações usadas no projeto (normalmente você teria isso em contexto)
591
+ const integracoesUsadas = ['google-analytics', 'google-tag-manager', 'mixpanel']
592
+
593
+ return (
594
+ <div
595
+ style={{
596
+ position: 'fixed',
597
+ top: 0,
598
+ left: 0,
599
+ width: '100vw',
600
+ height: '100vh',
601
+ backgroundColor: 'rgba(0, 0, 0, 0.7)',
602
+ display: 'flex',
603
+ justifyContent: 'center',
604
+ alignItems: 'center',
605
+ zIndex: 2000,
606
+ }}
607
+ >
608
+ <div
609
+ style={{
610
+ backgroundColor: 'white',
611
+ borderRadius: '12px',
612
+ padding: '2rem',
613
+ maxWidth: '800px',
614
+ maxHeight: '80vh',
615
+ overflow: 'auto',
616
+ boxShadow: '0 10px 25px rgba(0, 0, 0, 0.25)',
617
+ }}
618
+ >
619
+ <h2 style={{ marginBottom: '1rem', color: '#333' }}>{texts.modalTitle}</h2>
620
+ <p style={{ marginBottom: '2rem', color: '#666' }}>{texts.modalIntro}</p>
621
+
622
+ {/* Lista de categorias com detalhes dos cookies */}
623
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
624
+ {allCategories.map((categoria) => {
625
+ const cookiesDetalhados: CookieDescriptor[] = getCookiesInfoForCategory(
626
+ categoria.id as any,
627
+ integracoesUsadas,
628
+ )
629
+
630
+ return (
631
+ <div
632
+ key={categoria.id}
633
+ style={{
634
+ border: '1px solid #e0e0e0',
635
+ borderRadius: '8px',
636
+ padding: '1.5rem',
637
+ backgroundColor: '#fafafa',
638
+ }}
639
+ >
640
+ <div style={{ display: 'flex', alignItems: 'center', marginBottom: '1rem' }}>
641
+ <input
642
+ type="checkbox"
643
+ id={`categoria-${categoria.id}`}
644
+ checked={preferences[categoria.id] || false}
645
+ onChange={(e) =>
646
+ setPreferences({
647
+ ...preferences,
648
+ [categoria.id]: e.target.checked,
649
+ })
650
+ }
651
+ disabled={categoria.essential}
652
+ style={{ marginRight: '0.75rem', transform: 'scale(1.2)' }}
653
+ />
654
+ <label
655
+ htmlFor={`categoria-${categoria.id}`}
656
+ style={{ fontSize: '1.1rem', fontWeight: 'bold', color: '#333' }}
657
+ >
658
+ {categoria.name}
659
+ {categoria.essential && (
660
+ <span style={{ fontSize: '0.8rem', color: '#888', marginLeft: '0.5rem' }}>
661
+ (sempre ativo)
662
+ </span>
663
+ )}
664
+ </label>
665
+ </div>
666
+
667
+ <p style={{ marginBottom: '1rem', color: '#666', fontSize: '0.95rem' }}>
668
+ {categoria.description}
669
+ </p>
670
+
671
+ {/* Lista de cookies desta categoria */}
672
+ {cookiesDetalhados.length > 0 && (
673
+ <details style={{ marginTop: '1rem' }}>
674
+ <summary
675
+ style={{
676
+ cursor: 'pointer',
677
+ fontWeight: '500',
678
+ color: '#4f46e5',
679
+ marginBottom: '0.5rem',
680
+ }}
681
+ >
682
+ Ver cookies desta categoria ({cookiesDetalhados.length})
683
+ </summary>
684
+ <div style={{ marginTop: '0.75rem', paddingLeft: '1rem' }}>
685
+ {cookiesDetalhados.map((cookie, index) => (
686
+ <div
687
+ key={`${cookie.name}-${index}`}
688
+ style={{
689
+ backgroundColor: 'white',
690
+ border: '1px solid #e5e5e5',
691
+ borderRadius: '6px',
692
+ padding: '1rem',
693
+ marginBottom: '0.75rem',
694
+ }}
695
+ >
696
+ <h4
697
+ style={{ margin: '0 0 0.5rem 0', color: '#333', fontSize: '0.95rem' }}
698
+ >
699
+ <code
700
+ style={{
701
+ backgroundColor: '#f3f4f6',
702
+ padding: '2px 6px',
703
+ borderRadius: '4px',
704
+ fontFamily: 'monospace',
705
+ }}
706
+ >
707
+ {cookie.name}
708
+ </code>
709
+ </h4>
710
+ {cookie.purpose && (
711
+ <p style={{ margin: '0.25rem 0', fontSize: '0.9rem', color: '#555' }}>
712
+ <strong>Finalidade:</strong> {cookie.purpose}
713
+ </p>
714
+ )}
715
+ {cookie.duration && (
716
+ <p style={{ margin: '0.25rem 0', fontSize: '0.9rem', color: '#555' }}>
717
+ <strong>Duração:</strong> {cookie.duration}
718
+ </p>
719
+ )}
720
+ {cookie.provider && (
721
+ <p style={{ margin: '0.25rem 0', fontSize: '0.9rem', color: '#555' }}>
722
+ <strong>Provedor:</strong> {cookie.provider}
723
+ </p>
724
+ )}
725
+ </div>
726
+ ))}
727
+ </div>
728
+ </details>
729
+ )}
730
+
731
+ {/* Fallback para categorias sem cookies catalogados */}
732
+ {cookiesDetalhados.length === 0 &&
733
+ categoria.cookies &&
734
+ categoria.cookies.length > 0 && (
735
+ <div style={{ marginTop: '1rem', fontSize: '0.9rem', color: '#666' }}>
736
+ <strong>Padrões de cookies:</strong>{' '}
737
+ {categoria.cookies.map((pattern, i) => (
738
+ <code
739
+ key={i}
740
+ style={{
741
+ backgroundColor: '#f3f4f6',
742
+ padding: '2px 4px',
743
+ borderRadius: '3px',
744
+ marginRight: '0.5rem',
745
+ fontFamily: 'monospace',
746
+ fontSize: '0.8rem',
747
+ }}
748
+ >
749
+ {pattern}
750
+ </code>
751
+ ))}
752
+ </div>
753
+ )}
754
+ </div>
755
+ )
756
+ })}
757
+ </div>
758
+
759
+ {/* Botões de ação */}
760
+ <div
761
+ style={{
762
+ display: 'flex',
763
+ gap: '1rem',
764
+ justifyContent: 'flex-end',
765
+ marginTop: '2rem',
766
+ paddingTop: '1rem',
767
+ borderTop: '1px solid #e0e0e0',
768
+ }}
769
+ >
770
+ <button
771
+ onClick={closePreferences}
772
+ style={{
773
+ padding: '0.75rem 1.5rem',
774
+ backgroundColor: '#6b7280',
775
+ color: 'white',
776
+ border: 'none',
777
+ borderRadius: '6px',
778
+ cursor: 'pointer',
779
+ fontSize: '0.95rem',
780
+ }}
781
+ >
782
+ Cancelar
783
+ </button>
784
+ <button
785
+ onClick={closePreferences}
786
+ style={{
787
+ padding: '0.75rem 1.5rem',
788
+ backgroundColor: '#4f46e5',
789
+ color: 'white',
790
+ border: 'none',
791
+ borderRadius: '6px',
792
+ cursor: 'pointer',
793
+ fontSize: '0.95rem',
794
+ }}
795
+ >
796
+ {texts.save}
797
+ </button>
798
+ </div>
799
+ </div>
800
+ </div>
801
+ )
802
+ }
803
+
804
+ function AppComModalAvancado() {
805
+ return (
806
+ <ConsentProvider
807
+ categories={{
808
+ enabledCategories: ['analytics', 'marketing', 'functional'],
809
+ }}
810
+ PreferencesModalComponent={ModalComDetalhesCookies}
811
+ // Especifique as integrações para obter informações detalhadas dos cookies
812
+ scriptIntegrations={[
813
+ { id: 'google-analytics', config: { measurementId: 'GA_MEASUREMENT_ID' } },
814
+ { id: 'google-tag-manager', config: { containerId: 'GTM-XXXXXXX' } },
815
+ { id: 'mixpanel', config: { token: 'MIXPANEL_TOKEN' } },
816
+ ]}
817
+ >
818
+ <main>Minha App com Modal Avançado</main>
819
+ </ConsentProvider>
820
+ )
821
+ }
822
+ ```
823
+
824
+ #### 🔧 APIs Utilizadas no Exemplo Avançado
825
+
826
+ - **`useCategories()`**: Hook que retorna informações sobre todas as categorias ativas
827
+ - **`getCookiesInfoForCategory(categoryId, integrations)`**: Função que retorna detalhes completos dos cookies
828
+ - **`CookieDescriptor`**: Interface TypeScript com `name`, `purpose`, `duration`, `provider`
829
+
830
+ #### 💡 Principais Funcionalidades
831
+
832
+ 1. **Informações Detalhadas**: Cada cookie mostra nome, finalidade, duração e provedor
833
+ 2. **Organização por Categoria**: Cookies agrupados logicamente
834
+ 3. **Interface Expansível**: Detalhes dos cookies ficam em `<details>` expansível
835
+ 4. **Fallback Inteligente**: Mostra padrões básicos quando detalhes não estão disponíveis
836
+ 5. **Acessibilidade**: Labels apropriados e navegação por teclado
837
+ 6. **Design Responsivo**: Layout que se adapta a diferentes tamanhos de tela
838
+
278
839
  ## 🎮 Controle Programático
279
840
 
280
841
  ### Hook useOpenPreferencesModal (React)
package/README.en.md CHANGED
@@ -15,6 +15,12 @@
15
15
  <a href="https://nextjs.org/"><img src="https://img.shields.io/badge/Next.js-Compatible-000000?style=for-the-badge&logo=next.js&logoColor=white" alt="Next.js Compatible"></a>
16
16
  </div>
17
17
 
18
+ <div>
19
+ <a href="https://codecov.io/gh/lucianoedipo/react-lgpd-consent"><img src="https://img.shields.io/codecov/c/github/lucianoedipo/react-lgpd-consent?style=for-the-badge&logo=codecov&logoColor=white" alt="Coverage"></a>
20
+ <a href="https://bundlephobia.com/package/react-lgpd-consent"><img src="https://img.shields.io/bundlephobia/minzip/react-lgpd-consent?style=for-the-badge&logo=webpack&logoColor=white" alt="Bundle Size"></a>
21
+ <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/react-lgpd-consent?style=for-the-badge&logo=node.js&logoColor=white" alt="Node Version"></a>
22
+ </div>
23
+
18
24
  <br />
19
25
 
20
26
  <p>
@@ -64,6 +70,10 @@ export default function App() {
64
70
  -
65
71
  - **[QUICKSTART.en.md](./QUICKSTART.en.md)** (recommended)
66
72
  - New in v0.4.0: `customCategories` support — see the “Custom categories (customCategories)” section in the Quickstart.
73
+ - New in v0.4.1: native integrations for Facebook Pixel, Hotjar, Mixpanel, Clarity, Intercom, and Zendesk — see [INTEGRACOES.md](./INTEGRACOES.md).
74
+ - Tip: set `designTokens.layout.backdrop: 'auto'` for a theme-aware blocking banner backdrop.
75
+ - Auto-config of categories: the library detects required categories from integrations and surfaces toggles even if you forgot to enable them (initial value is always rejected). We still recommend explicitly listing them in `categories.enabledCategories` for clarity.
76
+ - Non-blocked Policy/Terms pages: if `policyLinkUrl` and/or `termsLinkUrl` point to the current page, the blocking overlay is not applied — ensuring readability of these pages.
67
77
  - **[Docs / API](./API.md)**
68
78
  - **[LGPD Compliance](./CONFORMIDADE.md)**
69
79
  - **[Integrations](./INTEGRACOES.md)**
@@ -73,6 +83,21 @@ export default function App() {
73
83
  - **[⚙️ TypeDoc - API Reference](https://lucianoedipo.github.io/react-lgpd-consent/docs/)**: Automatically generated complete API documentation.
74
84
  - **[🏠 Documentation Portal](https://lucianoedipo.github.io/react-lgpd-consent/)**: Home page that navigates between all docs sites.
75
85
 
86
+ ### 🧑‍🏫 Developer Guidance (dev-only)
87
+
88
+ In development, the library prints a guidance panel in the console to help you configure correctly:
89
+ - Warns when using default categories; suggests making them explicit
90
+ - Lists active categories and which ones require a UI toggle
91
+ - Detects integrations that require categories and suggests enabling them
92
+ - Flags excessive number of categories (UX)
93
+ - Highlights Brazilian LGPD best practices: opt-out by default, clear policy, consent logging, retention
94
+ - Silenced in production; SSR-safe
95
+
96
+ ### ⚠️ Breaking Changes v0.4.1
97
+ - **Custom categories support**: `setPreference` and `ScriptIntegration.category` now use `string` instead of `Category`
98
+ - **Minimal impact**: Code using literal strings continues working without changes
99
+ - **Migration guide**: See [CHANGELOG.md](./CHANGELOG.md) for complete details
100
+
76
101
  ---
77
102
 
78
103
  ## 🤝 Contributing
package/README.md CHANGED
@@ -15,6 +15,12 @@
15
15
  <a href="https://nextjs.org/"><img src="https://img.shields.io/badge/Next.js-Compatible-000000?style=for-the-badge&logo=next.js&logoColor=white" alt="Next.js Compatible"></a>
16
16
  </div>
17
17
 
18
+ <div>
19
+ <a href="https://codecov.io/gh/lucianoedipo/react-lgpd-consent"><img src="https://img.shields.io/codecov/c/github/lucianoedipo/react-lgpd-consent?style=for-the-badge&logo=codecov&logoColor=white" alt="Coverage"></a>
20
+ <a href="https://bundlephobia.com/package/react-lgpd-consent"><img src="https://img.shields.io/bundlephobia/minzip/react-lgpd-consent?style=for-the-badge&logo=webpack&logoColor=white" alt="Bundle Size"></a>
21
+ <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/react-lgpd-consent?style=for-the-badge&logo=node.js&logoColor=white" alt="Node Version"></a>
22
+ </div>
23
+
18
24
  <br />
19
25
 
20
26
  <p>
@@ -46,6 +52,32 @@ npm install react-lgpd-consent @mui/material @emotion/react @emotion/styled js-c
46
52
 
47
53
  ---
48
54
 
55
+ ## ✨ Novidades v0.4.1
56
+
57
+ ### 🎨 Design Tokens Expandidos
58
+ - **200+ pontos de customização** (cores, tipografia, espaçamento, layout)
59
+ - **Sistema responsivo** com breakpoints e variações
60
+ - **Acessibilidade nativa** com contrast ratios e focus states
61
+ - **Temas light/dark/auto** com transições suaves
62
+
63
+ ### 📝 Sistema Avançado de Textos
64
+ - **Templates pré-configurados** para ecommerce, SaaS e governo
65
+ - **Internacionalização completa** (pt, en, es)
66
+ - **Variações de tom** (formal, casual, técnico)
67
+ - **Resolução automática** baseada em contexto
68
+
69
+ ### 🔍 Descoberta de Cookies (Experimental)
70
+ - **Detecção automática** de cookies em runtime
71
+ - **Categorização inteligente** usando padrões LGPD
72
+ - **Integração nativa** com sistema de override
73
+
74
+ ### ⚠️ Breaking Changes
75
+ - **Suporte a categorias customizadas**: `setPreference` e `ScriptIntegration.category` agora usam `string` ao invés de `Category`
76
+ - **Impacto mínimo**: Código usando strings literais continua funcionando sem alterações
77
+ - **Consulte**: [CHANGELOG.md](./CHANGELOG.md) para guia de migração completo
78
+
79
+ ---
80
+
49
81
  ## 📖 Uso Básico
50
82
 
51
83
  Envolva sua aplicação com o `ConsentProvider` (exemplo mínimo):
@@ -87,7 +119,12 @@ Para mais detalhes sobre customização, hooks e funcionalidades, consulte os se
87
119
  ### 📋 Documentação Principal
88
120
 
89
121
  - **[📚 Guia de Início Rápido (`QUICKSTART.md`)](./QUICKSTART.md)**: Tutorial passo a passo com exemplos práticos, tabela completa de props, debugging e integrações.
122
+ - Seção recomendada: “SSR/Next.js (App Router) — Padrões seguros” com boas práticas de `'use client'`, `dynamic({ ssr: false })` e ordem dos provedores/estilos (MUI/Emotion) para evitar hydration mismatch.
90
123
  - Novo na v0.4.0: suporte a `customCategories` — veja a seção “Categorias customizadas (customCategories)” no Quickstart.
124
+ - Novo na v0.4.1: integrações nativas para Facebook Pixel, Hotjar, Mixpanel, Clarity, Intercom e Zendesk — veja o guia [INTEGRACOES.md](./INTEGRACOES.md).
125
+ - Dica: use `designTokens.layout.backdrop: 'auto'` para backdrop sensível ao tema no banner bloqueante.
126
+ - Auto-config de categorias: a biblioteca detecta categorias requeridas pelas integrações e exibe os toggles mesmo se você esquecer de habilitar (valor inicial sempre rejeitado). Recomendamos explicitar em `categories.enabledCategories` para clareza.
127
+ - Páginas de Política/Termos não bloqueadas: se `policyLinkUrl` e/ou `termsLinkUrl` apontarem para a página atual, o overlay bloqueante não é aplicado — garantindo legibilidade destas páginas.
91
128
  - **[Guia da API (`API.md`)](./API.md)**: Referência completa de todos os componentes, hooks e tipos.
92
129
  - **[Guia de Conformidade (`CONFORMIDADE.md`)](./CONFORMIDADE.md)**: Detalhes sobre as funcionalidades de conformidade com a LGPD.
93
130
  - **[Guia de Integrações (`INTEGRACOES.md`)](./INTEGRACOES.md)**: Como usar as integrações nativas e criar as suas.