react-lgpd-consent 0.3.2 → 0.3.4
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 +59 -2
- package/QUICKSTART.en.md +245 -0
- package/QUICKSTART.md +596 -0
- package/README.en.md +86 -0
- package/README.md +30 -88
- package/dist/{PreferencesModal-7RSEEVUK.js → PreferencesModal-XYBFROAB.js} +1 -1
- package/dist/{chunk-JUZQJHQW.js → chunk-7D2F6JFW.js} +70 -11
- package/dist/index.cjs +72 -10
- package/dist/index.d.cts +26 -4
- package/dist/index.d.ts +26 -4
- package/dist/index.js +1 -1
- package/package.json +34 -18
package/README.md
CHANGED
|
@@ -4,42 +4,35 @@
|
|
|
4
4
|
|
|
5
5
|
<div>
|
|
6
6
|
<a href="https://www.npmjs.com/package/react-lgpd-consent"><img src="https://img.shields.io/npm/v/react-lgpd-consent?style=for-the-badge&logo=npm&color=cb3837&logoColor=white" alt="NPM Version"></a>
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
<a href="https://www.npmjs.com/package/react-lgpd-consent"><img src="https://img.shields.io/npm/dm/react-lgpd-consent?style=for-the-badge&logo=npm&color=ff6b35&logoColor=white" alt="Downloads"></a>
|
|
8
|
+
<a href="https://github.com/lucianoedipo/react-lgpd-consent/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/react-lgpd-consent?style=for-the-badge&color=green&logoColor=white" alt="License"></a>
|
|
9
|
+
<a href="https://lucianoedipo.github.io/react-lgpd-consent/storybook/"><img src="https://img.shields.io/badge/Storybook-Playground-ff4785?style=for-the-badge&logo=storybook&logoColor=white" alt="Storybook"></a>
|
|
9
10
|
</div>
|
|
10
|
-
|
|
11
|
+
|
|
11
12
|
<div>
|
|
12
13
|
<a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-Ready-3178c6?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript Ready"></a>
|
|
13
14
|
<a href="https://reactjs.org/"><img src="https://img.shields.io/badge/React-18+-61dafb?style=for-the-badge&logo=react&logoColor=white" alt="React 18+"></a>
|
|
14
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>
|
|
15
16
|
</div>
|
|
16
17
|
|
|
17
|
-
<br
|
|
18
|
+
<br />
|
|
18
19
|
|
|
19
20
|
<p>
|
|
20
21
|
<a href="#-instalação"><strong>Instalação</strong></a> •
|
|
21
22
|
<a href="#-uso-básico"><strong>Uso Básico</strong></a> •
|
|
22
|
-
|
|
23
|
+
<a href="./QUICKSTART.md"><strong>📚 Guia de Início Rápido</strong></a> •
|
|
24
|
+
<a href="#-documentação-completa"><strong>Documentação</strong></a> •
|
|
25
|
+
<a href="./README.en.md">🇺🇸 🇬🇧 English</a> •
|
|
23
26
|
<a href="#-como-contribuir"><strong>Contribuir</strong></a>
|
|
24
27
|
</p>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## 🎯 Por que usar `react-lgpd-consent`?
|
|
30
|
-
|
|
31
|
-
Esta biblioteca oferece uma solução robusta e flexível para gerenciar o consentimento de cookies em aplicações React, com foco total na **Lei Geral de Proteção de Dados (LGPD)** do Brasil.
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
<!-- Quickstart callout (mantido) -->
|
|
30
|
+
<p align="center">
|
|
31
|
+
<a href="./QUICKSTART.md"><img src="https://img.shields.io/badge/Quickstart-Iniciar%20R%C3%A1pido-blue?style=for-the-badge&logo=book" alt="Quickstart"></a>
|
|
32
|
+
</p>
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
| 🇧🇷 **Foco na LGPD** | Implementação baseada nas diretrizes da ANPD, com textos e categorias alinhados à lei brasileira. |
|
|
38
|
-
| 🎨 **UI Automática e Customizável** | Componentes de UI (Banner e Modal) prontos para uso, baseados em Material-UI, e totalmente substituíveis. |
|
|
39
|
-
| ⚙️ **Configuração Consciente** | A prop `categories` força a declaração explícita dos cookies utilizados, seguindo o princípio da minimização. |
|
|
40
|
-
| 🧠 **Guia para Desenvolvedores** | Sistema que exibe avisos e sugestões no console (em ambiente de dev) para garantir a correta implementação. |
|
|
41
|
-
| 🚀 **Integrações Nativas** | Carregamento automático de scripts como Google Analytics e GTM, condicionado ao consentimento do usuário. |
|
|
42
|
-
| 🔒 **Auditoria e Transparência** | O cookie de consentimento armazena metadados como data, origem e versão para fins de auditoria. |
|
|
34
|
+
<p align="center"><strong>Comece por aqui:</strong> siga o <a href="./QUICKSTART.md">Guia de Início Rápido (QUICKSTART.md)</a> para um tutorial passo-a-passo, exemplos TypeScript, tabela de props e integração com MUI — recomendado para usuários novos.</p>
|
|
35
|
+
</div>
|
|
43
36
|
|
|
44
37
|
---
|
|
45
38
|
|
|
@@ -49,98 +42,47 @@ Esta biblioteca oferece uma solução robusta e flexível para gerenciar o conse
|
|
|
49
42
|
npm install react-lgpd-consent @mui/material @emotion/react @emotion/styled js-cookie
|
|
50
43
|
```
|
|
51
44
|
|
|
52
|
-
**Dependências
|
|
53
|
-
|
|
54
|
-
A biblioteca requer `react`, `react-dom`, `@mui/material` e `js-cookie` como dependências peer.
|
|
45
|
+
**Dependências peer:** `react`, `react-dom`, `@mui/material` e `js-cookie`.
|
|
55
46
|
|
|
56
47
|
---
|
|
57
48
|
|
|
58
49
|
## 📖 Uso Básico
|
|
59
50
|
|
|
60
|
-
Envolva sua aplicação com o `ConsentProvider`
|
|
51
|
+
Envolva sua aplicação com o `ConsentProvider` (exemplo mínimo):
|
|
61
52
|
|
|
62
53
|
```tsx
|
|
63
|
-
|
|
64
|
-
import { ConsentProvider } from 'react-lgpd-consent';
|
|
54
|
+
import { ConsentProvider } from 'react-lgpd-consent'
|
|
65
55
|
|
|
66
|
-
function App() {
|
|
56
|
+
export default function App() {
|
|
67
57
|
return (
|
|
68
|
-
<ConsentProvider
|
|
69
|
-
|
|
70
|
-
// É obrigatório especificar as categorias que seu site usa.
|
|
71
|
-
// A categoria 'necessary' é sempre incluída.
|
|
72
|
-
enabledCategories: ['analytics', 'marketing'],
|
|
73
|
-
}}
|
|
74
|
-
>
|
|
75
|
-
{/* O banner e o botão de preferências aparecerão automaticamente */}
|
|
76
|
-
<SuaAplicacao />
|
|
58
|
+
<ConsentProvider categories={{ enabledCategories: ['analytics'] }}>
|
|
59
|
+
<YourApp />
|
|
77
60
|
</ConsentProvider>
|
|
78
|
-
)
|
|
61
|
+
)
|
|
79
62
|
}
|
|
80
63
|
```
|
|
81
64
|
|
|
82
|
-
### Exemplo com Integração e Textos Customizados
|
|
83
|
-
|
|
84
|
-
```tsx
|
|
85
|
-
import {
|
|
86
|
-
ConsentProvider,
|
|
87
|
-
ConsentScriptLoader,
|
|
88
|
-
createGoogleAnalyticsIntegration,
|
|
89
|
-
} from 'react-lgpd-consent';
|
|
90
|
-
|
|
91
|
-
// 1. Crie as integrações que você precisa
|
|
92
|
-
const integrations = [
|
|
93
|
-
createGoogleAnalyticsIntegration({
|
|
94
|
-
measurementId: 'G-XXXXXXXXXX', // Substitua pelo seu ID
|
|
95
|
-
}),
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
function App() {
|
|
99
|
-
return (
|
|
100
|
-
<ConsentProvider
|
|
101
|
-
categories={{ enabledCategories: ['analytics'] }}
|
|
102
|
-
texts={{
|
|
103
|
-
bannerMessage: 'Nós usamos cookies para analisar o tráfego e melhorar a sua experiência.',
|
|
104
|
-
acceptAll: 'Aceitar',
|
|
105
|
-
declineAll: 'Recusar',
|
|
106
|
-
// Para conformidade com a ANPD, preencha os campos abaixo
|
|
107
|
-
controllerInfo: 'Controlado por: Sua Empresa LTDA (CNPJ: XX.XXX.XXX/XXXX-XX)',
|
|
108
|
-
contactInfo: 'Contato do DPO: dpo@suaempresa.com',
|
|
109
|
-
}}
|
|
110
|
-
onConsentGiven={(state) => {
|
|
111
|
-
console.log('O usuário deu o primeiro consentimento!', state.preferences);
|
|
112
|
-
}}
|
|
113
|
-
>
|
|
114
|
-
{/* 2. Adicione o loader de scripts para carregá-los após o consentimento */}
|
|
115
|
-
<ConsentScriptLoader integrations={integrations} />
|
|
116
|
-
|
|
117
|
-
<SuaAplicacao />
|
|
118
|
-
</ConsentProvider>
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
65
|
## 📚 Documentação Completa
|
|
126
66
|
|
|
127
67
|
Para mais detalhes sobre customização, hooks e funcionalidades, consulte os seguintes guias:
|
|
128
68
|
|
|
69
|
+
### 📋 Documentação Principal
|
|
70
|
+
- **[📚 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.
|
|
129
71
|
- **[Guia da API (`API.md`)](./API.md)**: Referência completa de todos os componentes, hooks e tipos.
|
|
130
72
|
- **[Guia de Conformidade (`CONFORMIDADE.md`)](./CONFORMIDADE.md)**: Detalhes sobre as funcionalidades de conformidade com a LGPD.
|
|
131
73
|
- **[Guia de Integrações (`INTEGRACOES.md`)](./INTEGRACOES.md)**: Como usar as integrações nativas e criar as suas.
|
|
132
74
|
|
|
75
|
+
### 🎨 Documentação Interativa (GitHub Pages)
|
|
76
|
+
- **[📖 Storybook - Playground Interativo](https://lucianoedipo.github.io/react-lgpd-consent/storybook/)**: Explore e teste todos os componentes em tempo real com controles interativos.
|
|
77
|
+
- **[⚙️ TypeDoc - Referência de API](https://lucianoedipo.github.io/react-lgpd-consent/docs/)**: Documentação completa da API gerada automaticamente.
|
|
78
|
+
- **[🏠 Portal de Documentação](https://lucianoedipo.github.io/react-lgpd-consent/)**: Página inicial com navegação entre todas as documentações.
|
|
133
79
|
---
|
|
134
80
|
|
|
135
81
|
## 🤝 Como Contribuir
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
1. **Reporte Bugs ou Sugira Melhorias**: Abra uma [Issue no GitHub](https://github.com/lucianoedipo/react-lgpd-consent/issues).
|
|
140
|
-
2. **Envie um Pull Request**: Siga as instruções no nosso [Guia de Desenvolvimento (`DEVELOPMENT.md`)](./DEVELOPMENT.md).
|
|
82
|
+
1. Abra uma [Issue](https://github.com/lucianoedipo/react-lgpd-consent/issues) para bugs ou melhorias.
|
|
83
|
+
2. Siga o Guia de Desenvolvimento em `DEVELOPMENT.md` para enviar um PR.
|
|
141
84
|
|
|
142
85
|
---
|
|
143
|
-
|
|
144
86
|
## 📄 Licença
|
|
145
87
|
|
|
146
|
-
|
|
88
|
+
MIT — veja o arquivo `LICENSE`.
|
|
@@ -737,6 +737,7 @@ var linkStyles = {
|
|
|
737
737
|
};
|
|
738
738
|
function Branding({ variant, hidden = false }) {
|
|
739
739
|
const texts = useConsentTexts();
|
|
740
|
+
const designTokens = useDesignTokens();
|
|
740
741
|
if (hidden) return null;
|
|
741
742
|
return /* @__PURE__ */ jsxs(
|
|
742
743
|
Typography,
|
|
@@ -744,7 +745,7 @@ function Branding({ variant, hidden = false }) {
|
|
|
744
745
|
variant: "caption",
|
|
745
746
|
sx: (theme) => ({
|
|
746
747
|
...brandingStyles[variant],
|
|
747
|
-
color: theme.palette.text.secondary
|
|
748
|
+
color: designTokens?.colors?.text ?? theme.palette.text.secondary
|
|
748
749
|
}),
|
|
749
750
|
children: [
|
|
750
751
|
texts.brandingPoweredBy || "fornecido por",
|
|
@@ -757,7 +758,7 @@ function Branding({ variant, hidden = false }) {
|
|
|
757
758
|
rel: "noopener noreferrer",
|
|
758
759
|
sx: (theme) => ({
|
|
759
760
|
...linkStyles,
|
|
760
|
-
color: theme.palette.primary.main
|
|
761
|
+
color: designTokens?.colors?.primary ?? theme.palette.primary.main
|
|
761
762
|
}),
|
|
762
763
|
children: "L\xC9dipO.eti.br"
|
|
763
764
|
}
|
|
@@ -864,6 +865,13 @@ function CookieBanner({
|
|
|
864
865
|
width: designTokens?.layout?.width?.desktop ?? "100%",
|
|
865
866
|
p: 2
|
|
866
867
|
};
|
|
868
|
+
let backdropColor = "rgba(0, 0, 0, 0.4)";
|
|
869
|
+
const backdropToken = designTokens?.layout?.backdrop;
|
|
870
|
+
if (backdropToken === false) {
|
|
871
|
+
backdropColor = "transparent";
|
|
872
|
+
} else if (typeof backdropToken === "string") {
|
|
873
|
+
backdropColor = backdropToken;
|
|
874
|
+
}
|
|
867
875
|
if (blocking) {
|
|
868
876
|
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
869
877
|
/* @__PURE__ */ jsx5(
|
|
@@ -875,7 +883,7 @@ function CookieBanner({
|
|
|
875
883
|
left: 0,
|
|
876
884
|
right: 0,
|
|
877
885
|
bottom: 0,
|
|
878
|
-
backgroundColor:
|
|
886
|
+
backgroundColor: backdropColor,
|
|
879
887
|
zIndex: 1299
|
|
880
888
|
}
|
|
881
889
|
}
|
|
@@ -932,6 +940,7 @@ function FloatingPreferencesButton({
|
|
|
932
940
|
const { openPreferences, consented } = useConsent();
|
|
933
941
|
const texts = useConsentTexts();
|
|
934
942
|
const safeTheme = useThemeWithFallbacks();
|
|
943
|
+
const designTokens = useDesignTokens();
|
|
935
944
|
logger.componentRender("FloatingPreferencesButton", {
|
|
936
945
|
position,
|
|
937
946
|
offset,
|
|
@@ -971,9 +980,9 @@ function FloatingPreferencesButton({
|
|
|
971
980
|
onClick: openPreferences,
|
|
972
981
|
sx: {
|
|
973
982
|
...getPosition(),
|
|
974
|
-
backgroundColor: safeTheme.palette.primary.main,
|
|
983
|
+
backgroundColor: designTokens?.colors?.primary ?? safeTheme.palette.primary.main,
|
|
975
984
|
"&:hover": {
|
|
976
|
-
backgroundColor: safeTheme.palette.primary.dark
|
|
985
|
+
backgroundColor: designTokens?.colors?.primary ? designTokens?.colors?.primary : safeTheme.palette.primary.dark
|
|
977
986
|
},
|
|
978
987
|
transition: `all ${safeTheme.transitions.duration.short}ms`
|
|
979
988
|
},
|
|
@@ -987,7 +996,7 @@ function FloatingPreferencesButton({
|
|
|
987
996
|
// src/context/ConsentContext.tsx
|
|
988
997
|
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
989
998
|
var PreferencesModal = React5.lazy(
|
|
990
|
-
() => import("./PreferencesModal-
|
|
999
|
+
() => import("./PreferencesModal-XYBFROAB.js").then((m) => ({
|
|
991
1000
|
default: m.PreferencesModal
|
|
992
1001
|
}))
|
|
993
1002
|
);
|
|
@@ -1121,6 +1130,8 @@ function ConsentProvider({
|
|
|
1121
1130
|
FloatingPreferencesButtonComponent,
|
|
1122
1131
|
floatingPreferencesButtonProps = {},
|
|
1123
1132
|
disableFloatingPreferencesButton = false,
|
|
1133
|
+
blocking = false,
|
|
1134
|
+
blockingStrategy = "auto",
|
|
1124
1135
|
hideBranding = false,
|
|
1125
1136
|
onConsentGiven,
|
|
1126
1137
|
onPreferencesSaved,
|
|
@@ -1211,6 +1222,12 @@ function ConsentProvider({
|
|
|
1211
1222
|
_registerGlobalOpenPreferences(api.openPreferences);
|
|
1212
1223
|
return () => _unregisterGlobalOpenPreferences();
|
|
1213
1224
|
}, [api.openPreferences]);
|
|
1225
|
+
const providerBackdropColor = React5.useMemo(() => {
|
|
1226
|
+
const backdrop = designTokens?.layout?.backdrop;
|
|
1227
|
+
if (backdrop === false) return "transparent";
|
|
1228
|
+
if (typeof backdrop === "string") return backdrop;
|
|
1229
|
+
return "rgba(0, 0, 0, 0.4)";
|
|
1230
|
+
}, [designTokens]);
|
|
1214
1231
|
return /* @__PURE__ */ jsx7(SafeThemeProvider, { theme: appliedTheme, children: /* @__PURE__ */ jsx7(StateCtx.Provider, { value: state, children: /* @__PURE__ */ jsx7(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ jsx7(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ jsx7(HydrationCtx.Provider, { value: isHydrated, children: /* @__PURE__ */ jsx7(DesignProvider, { tokens: designTokens, children: /* @__PURE__ */ jsxs3(
|
|
1215
1232
|
CategoriesProvider,
|
|
1216
1233
|
{
|
|
@@ -1229,6 +1246,22 @@ function ConsentProvider({
|
|
|
1229
1246
|
...preferencesModalProps
|
|
1230
1247
|
}
|
|
1231
1248
|
) : /* @__PURE__ */ jsx7(PreferencesModal, { hideBranding }) }),
|
|
1249
|
+
blocking && isHydrated && !state.consented && blockingStrategy === "provider" && /* @__PURE__ */ jsx7(
|
|
1250
|
+
"div",
|
|
1251
|
+
{
|
|
1252
|
+
style: {
|
|
1253
|
+
position: "fixed",
|
|
1254
|
+
top: 0,
|
|
1255
|
+
left: 0,
|
|
1256
|
+
right: 0,
|
|
1257
|
+
bottom: 0,
|
|
1258
|
+
backgroundColor: providerBackdropColor,
|
|
1259
|
+
zIndex: 1299
|
|
1260
|
+
},
|
|
1261
|
+
"data-testid": "lgpd-provider-overlay",
|
|
1262
|
+
"aria-hidden": true
|
|
1263
|
+
}
|
|
1264
|
+
),
|
|
1232
1265
|
!state.consented && isHydrated && (CookieBannerComponent ? /* @__PURE__ */ jsx7(
|
|
1233
1266
|
CookieBannerComponent,
|
|
1234
1267
|
{
|
|
@@ -1237,9 +1270,17 @@ function ConsentProvider({
|
|
|
1237
1270
|
rejectAll: api.rejectAll,
|
|
1238
1271
|
openPreferences: api.openPreferences,
|
|
1239
1272
|
texts,
|
|
1273
|
+
blocking,
|
|
1274
|
+
...cookieBannerProps
|
|
1275
|
+
}
|
|
1276
|
+
) : /* @__PURE__ */ jsx7(
|
|
1277
|
+
CookieBanner,
|
|
1278
|
+
{
|
|
1279
|
+
blocking,
|
|
1280
|
+
hideBranding,
|
|
1240
1281
|
...cookieBannerProps
|
|
1241
1282
|
}
|
|
1242
|
-
)
|
|
1283
|
+
)),
|
|
1243
1284
|
state.consented && !disableFloatingPreferencesButton && (FloatingPreferencesButtonComponent ? /* @__PURE__ */ jsx7(
|
|
1244
1285
|
FloatingPreferencesButtonComponent,
|
|
1245
1286
|
{
|
|
@@ -1247,7 +1288,10 @@ function ConsentProvider({
|
|
|
1247
1288
|
consented: api.consented,
|
|
1248
1289
|
...floatingPreferencesButtonProps
|
|
1249
1290
|
}
|
|
1250
|
-
) :
|
|
1291
|
+
) : (
|
|
1292
|
+
// Encaminha `floatingPreferencesButtonProps` para o componente padrão
|
|
1293
|
+
/* @__PURE__ */ jsx7(FloatingPreferencesButton, { ...floatingPreferencesButtonProps })
|
|
1294
|
+
))
|
|
1251
1295
|
]
|
|
1252
1296
|
}
|
|
1253
1297
|
) }) }) }) }) }) });
|
|
@@ -1323,6 +1367,7 @@ function PreferencesModal2({
|
|
|
1323
1367
|
}) {
|
|
1324
1368
|
const { preferences, setPreferences, closePreferences, isModalOpen } = useConsent();
|
|
1325
1369
|
const texts = useConsentTexts();
|
|
1370
|
+
const designTokens = useDesignTokens();
|
|
1326
1371
|
const { toggleableCategories } = useCategories();
|
|
1327
1372
|
const [tempPreferences, setTempPreferences] = useState2(() => {
|
|
1328
1373
|
const initialPrefs = { necessary: true };
|
|
@@ -1349,9 +1394,23 @@ function PreferencesModal2({
|
|
|
1349
1394
|
closePreferences();
|
|
1350
1395
|
};
|
|
1351
1396
|
return /* @__PURE__ */ jsxs4(Dialog, { "aria-labelledby": "cookie-pref-title", open, onClose: handleCancel, ...DialogProps2, children: [
|
|
1352
|
-
/* @__PURE__ */ jsx8(
|
|
1353
|
-
|
|
1354
|
-
|
|
1397
|
+
/* @__PURE__ */ jsx8(
|
|
1398
|
+
DialogTitle,
|
|
1399
|
+
{
|
|
1400
|
+
id: "cookie-pref-title",
|
|
1401
|
+
sx: { fontSize: designTokens?.typography?.fontSize?.modal ?? void 0 },
|
|
1402
|
+
children: texts.modalTitle
|
|
1403
|
+
}
|
|
1404
|
+
),
|
|
1405
|
+
/* @__PURE__ */ jsxs4(DialogContent, { dividers: true, sx: { p: designTokens?.spacing?.padding?.modal ?? void 0 }, children: [
|
|
1406
|
+
/* @__PURE__ */ jsx8(
|
|
1407
|
+
Typography3,
|
|
1408
|
+
{
|
|
1409
|
+
variant: "body2",
|
|
1410
|
+
sx: { mb: 2, fontSize: designTokens?.typography?.fontSize?.modal ?? void 0 },
|
|
1411
|
+
children: texts.modalIntro
|
|
1412
|
+
}
|
|
1413
|
+
),
|
|
1355
1414
|
/* @__PURE__ */ jsxs4(FormGroup, { children: [
|
|
1356
1415
|
toggleableCategories.map((category) => /* @__PURE__ */ jsx8(
|
|
1357
1416
|
FormControlLabel,
|
package/dist/index.cjs
CHANGED
|
@@ -761,6 +761,7 @@ var init_DesignContext = __esm({
|
|
|
761
761
|
// src/components/Branding.tsx
|
|
762
762
|
function Branding({ variant, hidden = false }) {
|
|
763
763
|
const texts = useConsentTexts();
|
|
764
|
+
const designTokens = useDesignTokens();
|
|
764
765
|
if (hidden) return null;
|
|
765
766
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
766
767
|
import_Typography.default,
|
|
@@ -768,7 +769,7 @@ function Branding({ variant, hidden = false }) {
|
|
|
768
769
|
variant: "caption",
|
|
769
770
|
sx: (theme) => ({
|
|
770
771
|
...brandingStyles[variant],
|
|
771
|
-
color: theme.palette.text.secondary
|
|
772
|
+
color: designTokens?.colors?.text ?? theme.palette.text.secondary
|
|
772
773
|
}),
|
|
773
774
|
children: [
|
|
774
775
|
texts.brandingPoweredBy || "fornecido por",
|
|
@@ -781,7 +782,7 @@ function Branding({ variant, hidden = false }) {
|
|
|
781
782
|
rel: "noopener noreferrer",
|
|
782
783
|
sx: (theme) => ({
|
|
783
784
|
...linkStyles,
|
|
784
|
-
color: theme.palette.primary.main
|
|
785
|
+
color: designTokens?.colors?.primary ?? theme.palette.primary.main
|
|
785
786
|
}),
|
|
786
787
|
children: "L\xC9dipO.eti.br"
|
|
787
788
|
}
|
|
@@ -795,6 +796,7 @@ var init_Branding = __esm({
|
|
|
795
796
|
"src/components/Branding.tsx"() {
|
|
796
797
|
"use strict";
|
|
797
798
|
init_useConsent();
|
|
799
|
+
init_DesignContext();
|
|
798
800
|
import_Link = __toESM(require("@mui/material/Link"), 1);
|
|
799
801
|
import_Typography = __toESM(require("@mui/material/Typography"), 1);
|
|
800
802
|
import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -923,6 +925,13 @@ function CookieBanner({
|
|
|
923
925
|
width: designTokens?.layout?.width?.desktop ?? "100%",
|
|
924
926
|
p: 2
|
|
925
927
|
};
|
|
928
|
+
let backdropColor = "rgba(0, 0, 0, 0.4)";
|
|
929
|
+
const backdropToken = designTokens?.layout?.backdrop;
|
|
930
|
+
if (backdropToken === false) {
|
|
931
|
+
backdropColor = "transparent";
|
|
932
|
+
} else if (typeof backdropToken === "string") {
|
|
933
|
+
backdropColor = backdropToken;
|
|
934
|
+
}
|
|
926
935
|
if (blocking) {
|
|
927
936
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
928
937
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
@@ -934,7 +943,7 @@ function CookieBanner({
|
|
|
934
943
|
left: 0,
|
|
935
944
|
right: 0,
|
|
936
945
|
bottom: 0,
|
|
937
|
-
backgroundColor:
|
|
946
|
+
backgroundColor: backdropColor,
|
|
938
947
|
zIndex: 1299
|
|
939
948
|
}
|
|
940
949
|
}
|
|
@@ -1004,6 +1013,7 @@ function FloatingPreferencesButton({
|
|
|
1004
1013
|
const { openPreferences, consented } = useConsent();
|
|
1005
1014
|
const texts = useConsentTexts();
|
|
1006
1015
|
const safeTheme = useThemeWithFallbacks();
|
|
1016
|
+
const designTokens = useDesignTokens();
|
|
1007
1017
|
logger.componentRender("FloatingPreferencesButton", {
|
|
1008
1018
|
position,
|
|
1009
1019
|
offset,
|
|
@@ -1043,9 +1053,9 @@ function FloatingPreferencesButton({
|
|
|
1043
1053
|
onClick: openPreferences,
|
|
1044
1054
|
sx: {
|
|
1045
1055
|
...getPosition(),
|
|
1046
|
-
backgroundColor: safeTheme.palette.primary.main,
|
|
1056
|
+
backgroundColor: designTokens?.colors?.primary ?? safeTheme.palette.primary.main,
|
|
1047
1057
|
"&:hover": {
|
|
1048
|
-
backgroundColor: safeTheme.palette.primary.dark
|
|
1058
|
+
backgroundColor: designTokens?.colors?.primary ? designTokens?.colors?.primary : safeTheme.palette.primary.dark
|
|
1049
1059
|
},
|
|
1050
1060
|
transition: `all ${safeTheme.transitions.duration.short}ms`
|
|
1051
1061
|
},
|
|
@@ -1063,6 +1073,7 @@ var init_FloatingPreferencesButton = __esm({
|
|
|
1063
1073
|
import_Fab = __toESM(require("@mui/material/Fab"), 1);
|
|
1064
1074
|
import_Tooltip = __toESM(require("@mui/material/Tooltip"), 1);
|
|
1065
1075
|
import_styles3 = require("@mui/material/styles");
|
|
1076
|
+
init_DesignContext();
|
|
1066
1077
|
init_useConsent();
|
|
1067
1078
|
init_logger();
|
|
1068
1079
|
import_jsx_runtime6 = require("react/jsx-runtime");
|
|
@@ -1159,6 +1170,8 @@ function ConsentProvider({
|
|
|
1159
1170
|
FloatingPreferencesButtonComponent,
|
|
1160
1171
|
floatingPreferencesButtonProps = {},
|
|
1161
1172
|
disableFloatingPreferencesButton = false,
|
|
1173
|
+
blocking = false,
|
|
1174
|
+
blockingStrategy = "auto",
|
|
1162
1175
|
hideBranding = false,
|
|
1163
1176
|
onConsentGiven,
|
|
1164
1177
|
onPreferencesSaved,
|
|
@@ -1249,6 +1262,12 @@ function ConsentProvider({
|
|
|
1249
1262
|
_registerGlobalOpenPreferences(api.openPreferences);
|
|
1250
1263
|
return () => _unregisterGlobalOpenPreferences();
|
|
1251
1264
|
}, [api.openPreferences]);
|
|
1265
|
+
const providerBackdropColor = React5.useMemo(() => {
|
|
1266
|
+
const backdrop = designTokens?.layout?.backdrop;
|
|
1267
|
+
if (backdrop === false) return "transparent";
|
|
1268
|
+
if (typeof backdrop === "string") return backdrop;
|
|
1269
|
+
return "rgba(0, 0, 0, 0.4)";
|
|
1270
|
+
}, [designTokens]);
|
|
1252
1271
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SafeThemeProvider, { theme: appliedTheme, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(StateCtx.Provider, { value: state, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HydrationCtx.Provider, { value: isHydrated, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DesignProvider, { tokens: designTokens, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1253
1272
|
CategoriesProvider,
|
|
1254
1273
|
{
|
|
@@ -1267,6 +1286,22 @@ function ConsentProvider({
|
|
|
1267
1286
|
...preferencesModalProps
|
|
1268
1287
|
}
|
|
1269
1288
|
) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PreferencesModal, { hideBranding }) }),
|
|
1289
|
+
blocking && isHydrated && !state.consented && blockingStrategy === "provider" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1290
|
+
"div",
|
|
1291
|
+
{
|
|
1292
|
+
style: {
|
|
1293
|
+
position: "fixed",
|
|
1294
|
+
top: 0,
|
|
1295
|
+
left: 0,
|
|
1296
|
+
right: 0,
|
|
1297
|
+
bottom: 0,
|
|
1298
|
+
backgroundColor: providerBackdropColor,
|
|
1299
|
+
zIndex: 1299
|
|
1300
|
+
},
|
|
1301
|
+
"data-testid": "lgpd-provider-overlay",
|
|
1302
|
+
"aria-hidden": true
|
|
1303
|
+
}
|
|
1304
|
+
),
|
|
1270
1305
|
!state.consented && isHydrated && (CookieBannerComponent ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1271
1306
|
CookieBannerComponent,
|
|
1272
1307
|
{
|
|
@@ -1275,9 +1310,17 @@ function ConsentProvider({
|
|
|
1275
1310
|
rejectAll: api.rejectAll,
|
|
1276
1311
|
openPreferences: api.openPreferences,
|
|
1277
1312
|
texts,
|
|
1313
|
+
blocking,
|
|
1314
|
+
...cookieBannerProps
|
|
1315
|
+
}
|
|
1316
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1317
|
+
CookieBanner,
|
|
1318
|
+
{
|
|
1319
|
+
blocking,
|
|
1320
|
+
hideBranding,
|
|
1278
1321
|
...cookieBannerProps
|
|
1279
1322
|
}
|
|
1280
|
-
)
|
|
1323
|
+
)),
|
|
1281
1324
|
state.consented && !disableFloatingPreferencesButton && (FloatingPreferencesButtonComponent ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1282
1325
|
FloatingPreferencesButtonComponent,
|
|
1283
1326
|
{
|
|
@@ -1285,7 +1328,10 @@ function ConsentProvider({
|
|
|
1285
1328
|
consented: api.consented,
|
|
1286
1329
|
...floatingPreferencesButtonProps
|
|
1287
1330
|
}
|
|
1288
|
-
) :
|
|
1331
|
+
) : (
|
|
1332
|
+
// Encaminha `floatingPreferencesButtonProps` para o componente padrão
|
|
1333
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FloatingPreferencesButton, { ...floatingPreferencesButtonProps })
|
|
1334
|
+
))
|
|
1289
1335
|
]
|
|
1290
1336
|
}
|
|
1291
1337
|
) }) }) }) }) }) });
|
|
@@ -1437,6 +1483,7 @@ function PreferencesModal2({
|
|
|
1437
1483
|
}) {
|
|
1438
1484
|
const { preferences, setPreferences, closePreferences, isModalOpen } = useConsent();
|
|
1439
1485
|
const texts = useConsentTexts();
|
|
1486
|
+
const designTokens = useDesignTokens();
|
|
1440
1487
|
const { toggleableCategories } = useCategories();
|
|
1441
1488
|
const [tempPreferences, setTempPreferences] = (0, import_react2.useState)(() => {
|
|
1442
1489
|
const initialPrefs = { necessary: true };
|
|
@@ -1463,9 +1510,23 @@ function PreferencesModal2({
|
|
|
1463
1510
|
closePreferences();
|
|
1464
1511
|
};
|
|
1465
1512
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_Dialog.default, { "aria-labelledby": "cookie-pref-title", open, onClose: handleCancel, ...DialogProps2, children: [
|
|
1466
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1467
|
-
|
|
1468
|
-
|
|
1513
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1514
|
+
import_DialogTitle.default,
|
|
1515
|
+
{
|
|
1516
|
+
id: "cookie-pref-title",
|
|
1517
|
+
sx: { fontSize: designTokens?.typography?.fontSize?.modal ?? void 0 },
|
|
1518
|
+
children: texts.modalTitle
|
|
1519
|
+
}
|
|
1520
|
+
),
|
|
1521
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_DialogContent.default, { dividers: true, sx: { p: designTokens?.spacing?.padding?.modal ?? void 0 }, children: [
|
|
1522
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1523
|
+
import_Typography3.default,
|
|
1524
|
+
{
|
|
1525
|
+
variant: "body2",
|
|
1526
|
+
sx: { mb: 2, fontSize: designTokens?.typography?.fontSize?.modal ?? void 0 },
|
|
1527
|
+
children: texts.modalIntro
|
|
1528
|
+
}
|
|
1529
|
+
),
|
|
1469
1530
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_FormGroup.default, { children: [
|
|
1470
1531
|
toggleableCategories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1471
1532
|
import_FormControlLabel.default,
|
|
@@ -1510,6 +1571,7 @@ var init_PreferencesModal = __esm({
|
|
|
1510
1571
|
import_react2 = require("react");
|
|
1511
1572
|
init_CategoriesContext();
|
|
1512
1573
|
init_useConsent();
|
|
1574
|
+
init_DesignContext();
|
|
1513
1575
|
init_Branding();
|
|
1514
1576
|
import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1515
1577
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -567,7 +567,7 @@ interface DesignTokens {
|
|
|
567
567
|
mobile?: string;
|
|
568
568
|
desktop?: string;
|
|
569
569
|
};
|
|
570
|
-
backdrop?: boolean;
|
|
570
|
+
backdrop?: boolean | string;
|
|
571
571
|
};
|
|
572
572
|
}
|
|
573
573
|
/**
|
|
@@ -713,6 +713,22 @@ interface ConsentProviderProps {
|
|
|
713
713
|
* - `true`: Banner bloqueia interação até decisão (compliance rigorosa)
|
|
714
714
|
*/
|
|
715
715
|
blocking?: boolean;
|
|
716
|
+
/**
|
|
717
|
+
* Estratégia de bloqueio quando `blocking` estiver habilitado.
|
|
718
|
+
* - 'auto' (padrão):
|
|
719
|
+
* - Se usar o banner padrão da lib, o bloqueio visual/funcional fica a cargo do próprio banner.
|
|
720
|
+
* - Se usar `CookieBannerComponent` custom, o Provider NÃO cria overlay; o bloqueio fica a cargo do componente custom (compatibilidade atual).
|
|
721
|
+
* - 'provider': o Provider cria um overlay de bloqueio por cima da aplicação (e abaixo do banner),
|
|
722
|
+
* garantindo que cliques sejam bloqueados, independentemente do banner custom implementar ou não esse comportamento.
|
|
723
|
+
* - 'component': nenhum overlay do Provider; espera-se que o banner (padrão ou custom) trate o bloqueio.
|
|
724
|
+
*
|
|
725
|
+
* Observações:
|
|
726
|
+
* - Visual do overlay do Provider controlado por `designTokens.layout.backdrop`:
|
|
727
|
+
* - `false`: overlay transparente (bloqueia cliques sem escurecer — útil quando o app já possui um dark-filter visual próprio).
|
|
728
|
+
* - `string` (ex.: 'rgba(0,0,0,0.4)'): overlay com escurecimento gerenciado pela lib.
|
|
729
|
+
* - A11y: recomenda-se que o banner use semântica de diálogo (role="dialog", aria-modal="true") e trap de foco.
|
|
730
|
+
*/
|
|
731
|
+
blockingStrategy?: 'auto' | 'provider' | 'component';
|
|
716
732
|
/** Oculta o branding "fornecido por LÉdipO.eti.br" dos componentes. */
|
|
717
733
|
hideBranding?: boolean;
|
|
718
734
|
/**
|
|
@@ -776,6 +792,12 @@ interface CustomCookieBannerProps {
|
|
|
776
792
|
rejectAll: () => void;
|
|
777
793
|
openPreferences: () => void;
|
|
778
794
|
texts: ConsentTexts;
|
|
795
|
+
/**
|
|
796
|
+
* Indica se o modo bloqueante está ativo no contexto.
|
|
797
|
+
* Esta prop é apenas informativa para banners customizados ajustarem sua UI.
|
|
798
|
+
* O bloqueio funcional pode ser garantido pelo Provider quando `blockingStrategy='provider'`.
|
|
799
|
+
*/
|
|
800
|
+
blocking?: boolean;
|
|
779
801
|
}
|
|
780
802
|
/**
|
|
781
803
|
* Props esperadas por um componente customizado de PreferencesModal.
|
|
@@ -883,7 +905,7 @@ interface ConsentContextValue {
|
|
|
883
905
|
* </ConsentProvider>
|
|
884
906
|
* ```
|
|
885
907
|
*/
|
|
886
|
-
declare function ConsentProvider({ initialState, categories, texts: textsProp, theme, designTokens, PreferencesModalComponent, preferencesModalProps, CookieBannerComponent, cookieBannerProps, FloatingPreferencesButtonComponent, floatingPreferencesButtonProps, disableFloatingPreferencesButton, hideBranding, onConsentGiven, onPreferencesSaved, cookie: cookieOpts, disableDeveloperGuidance, children, }: Readonly<ConsentProviderProps>): react_jsx_runtime.JSX.Element;
|
|
908
|
+
declare function ConsentProvider({ initialState, categories, texts: textsProp, theme, designTokens, PreferencesModalComponent, preferencesModalProps, CookieBannerComponent, cookieBannerProps, FloatingPreferencesButtonComponent, floatingPreferencesButtonProps, disableFloatingPreferencesButton, blocking, blockingStrategy, hideBranding, onConsentGiven, onPreferencesSaved, cookie: cookieOpts, disableDeveloperGuidance, children, }: Readonly<ConsentProviderProps>): react_jsx_runtime.JSX.Element;
|
|
887
909
|
declare const defaultTexts: ConsentTexts;
|
|
888
910
|
|
|
889
911
|
/**
|
|
@@ -916,7 +938,7 @@ declare const defaultTexts: ConsentTexts;
|
|
|
916
938
|
* - **`setPreferences(preferences)`**: Define múltiplas categorias de uma vez
|
|
917
939
|
* - **`openPreferences()`**: Abre o modal de preferências
|
|
918
940
|
* - **`closePreferences()`**: Fecha o modal de preferências
|
|
919
|
-
* - **`resetConsent()`**: Limpa
|
|
941
|
+
* - **`resetConsent()`**: Limpa all consentimento (volta ao estado inicial)
|
|
920
942
|
*
|
|
921
943
|
* ### Performance e SSR
|
|
922
944
|
* - O hook é otimizado com `useMemo` interno para evitar re-renders desnecessários
|
|
@@ -1972,7 +1994,7 @@ interface CookieBannerProps {
|
|
|
1972
1994
|
* <ConsentProvider CookieBannerComponent={CustomBanner}>
|
|
1973
1995
|
* ```
|
|
1974
1996
|
*
|
|
1975
|
-
* @param props - Propriedades para customizar comportamento e aparência do banner
|
|
1997
|
+
* @param props - Propriedades para customizar comportamento e aparência do banner (tipado via CookieBannerProps)
|
|
1976
1998
|
* @returns Banner de consentimento ou `null` se não deve ser exibido
|
|
1977
1999
|
*
|
|
1978
2000
|
* @example Uso básico (renderizado automaticamente pelo ConsentProvider)
|