react-lgpd-consent 0.3.3 → 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-HTTMUZND.js → PreferencesModal-XYBFROAB.js} +1 -1
- package/dist/{chunk-GPLNN3FD.js → chunk-7D2F6JFW.js} +69 -11
- package/dist/index.cjs +71 -10
- package/dist/index.d.cts +25 -3
- package/dist/index.d.ts +25 -3
- package/dist/index.js +1 -1
- package/package.json +33 -17
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,7 +865,13 @@ function CookieBanner({
|
|
|
864
865
|
width: designTokens?.layout?.width?.desktop ?? "100%",
|
|
865
866
|
p: 2
|
|
866
867
|
};
|
|
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
|
+
}
|
|
868
875
|
if (blocking) {
|
|
869
876
|
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
870
877
|
/* @__PURE__ */ jsx5(
|
|
@@ -933,6 +940,7 @@ function FloatingPreferencesButton({
|
|
|
933
940
|
const { openPreferences, consented } = useConsent();
|
|
934
941
|
const texts = useConsentTexts();
|
|
935
942
|
const safeTheme = useThemeWithFallbacks();
|
|
943
|
+
const designTokens = useDesignTokens();
|
|
936
944
|
logger.componentRender("FloatingPreferencesButton", {
|
|
937
945
|
position,
|
|
938
946
|
offset,
|
|
@@ -972,9 +980,9 @@ function FloatingPreferencesButton({
|
|
|
972
980
|
onClick: openPreferences,
|
|
973
981
|
sx: {
|
|
974
982
|
...getPosition(),
|
|
975
|
-
backgroundColor: safeTheme.palette.primary.main,
|
|
983
|
+
backgroundColor: designTokens?.colors?.primary ?? safeTheme.palette.primary.main,
|
|
976
984
|
"&:hover": {
|
|
977
|
-
backgroundColor: safeTheme.palette.primary.dark
|
|
985
|
+
backgroundColor: designTokens?.colors?.primary ? designTokens?.colors?.primary : safeTheme.palette.primary.dark
|
|
978
986
|
},
|
|
979
987
|
transition: `all ${safeTheme.transitions.duration.short}ms`
|
|
980
988
|
},
|
|
@@ -988,7 +996,7 @@ function FloatingPreferencesButton({
|
|
|
988
996
|
// src/context/ConsentContext.tsx
|
|
989
997
|
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
990
998
|
var PreferencesModal = React5.lazy(
|
|
991
|
-
() => import("./PreferencesModal-
|
|
999
|
+
() => import("./PreferencesModal-XYBFROAB.js").then((m) => ({
|
|
992
1000
|
default: m.PreferencesModal
|
|
993
1001
|
}))
|
|
994
1002
|
);
|
|
@@ -1122,6 +1130,8 @@ function ConsentProvider({
|
|
|
1122
1130
|
FloatingPreferencesButtonComponent,
|
|
1123
1131
|
floatingPreferencesButtonProps = {},
|
|
1124
1132
|
disableFloatingPreferencesButton = false,
|
|
1133
|
+
blocking = false,
|
|
1134
|
+
blockingStrategy = "auto",
|
|
1125
1135
|
hideBranding = false,
|
|
1126
1136
|
onConsentGiven,
|
|
1127
1137
|
onPreferencesSaved,
|
|
@@ -1212,6 +1222,12 @@ function ConsentProvider({
|
|
|
1212
1222
|
_registerGlobalOpenPreferences(api.openPreferences);
|
|
1213
1223
|
return () => _unregisterGlobalOpenPreferences();
|
|
1214
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]);
|
|
1215
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(
|
|
1216
1232
|
CategoriesProvider,
|
|
1217
1233
|
{
|
|
@@ -1230,6 +1246,22 @@ function ConsentProvider({
|
|
|
1230
1246
|
...preferencesModalProps
|
|
1231
1247
|
}
|
|
1232
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
|
+
),
|
|
1233
1265
|
!state.consented && isHydrated && (CookieBannerComponent ? /* @__PURE__ */ jsx7(
|
|
1234
1266
|
CookieBannerComponent,
|
|
1235
1267
|
{
|
|
@@ -1238,9 +1270,17 @@ function ConsentProvider({
|
|
|
1238
1270
|
rejectAll: api.rejectAll,
|
|
1239
1271
|
openPreferences: api.openPreferences,
|
|
1240
1272
|
texts,
|
|
1273
|
+
blocking,
|
|
1274
|
+
...cookieBannerProps
|
|
1275
|
+
}
|
|
1276
|
+
) : /* @__PURE__ */ jsx7(
|
|
1277
|
+
CookieBanner,
|
|
1278
|
+
{
|
|
1279
|
+
blocking,
|
|
1280
|
+
hideBranding,
|
|
1241
1281
|
...cookieBannerProps
|
|
1242
1282
|
}
|
|
1243
|
-
)
|
|
1283
|
+
)),
|
|
1244
1284
|
state.consented && !disableFloatingPreferencesButton && (FloatingPreferencesButtonComponent ? /* @__PURE__ */ jsx7(
|
|
1245
1285
|
FloatingPreferencesButtonComponent,
|
|
1246
1286
|
{
|
|
@@ -1248,7 +1288,10 @@ function ConsentProvider({
|
|
|
1248
1288
|
consented: api.consented,
|
|
1249
1289
|
...floatingPreferencesButtonProps
|
|
1250
1290
|
}
|
|
1251
|
-
) :
|
|
1291
|
+
) : (
|
|
1292
|
+
// Encaminha `floatingPreferencesButtonProps` para o componente padrão
|
|
1293
|
+
/* @__PURE__ */ jsx7(FloatingPreferencesButton, { ...floatingPreferencesButtonProps })
|
|
1294
|
+
))
|
|
1252
1295
|
]
|
|
1253
1296
|
}
|
|
1254
1297
|
) }) }) }) }) }) });
|
|
@@ -1324,6 +1367,7 @@ function PreferencesModal2({
|
|
|
1324
1367
|
}) {
|
|
1325
1368
|
const { preferences, setPreferences, closePreferences, isModalOpen } = useConsent();
|
|
1326
1369
|
const texts = useConsentTexts();
|
|
1370
|
+
const designTokens = useDesignTokens();
|
|
1327
1371
|
const { toggleableCategories } = useCategories();
|
|
1328
1372
|
const [tempPreferences, setTempPreferences] = useState2(() => {
|
|
1329
1373
|
const initialPrefs = { necessary: true };
|
|
@@ -1350,9 +1394,23 @@ function PreferencesModal2({
|
|
|
1350
1394
|
closePreferences();
|
|
1351
1395
|
};
|
|
1352
1396
|
return /* @__PURE__ */ jsxs4(Dialog, { "aria-labelledby": "cookie-pref-title", open, onClose: handleCancel, ...DialogProps2, children: [
|
|
1353
|
-
/* @__PURE__ */ jsx8(
|
|
1354
|
-
|
|
1355
|
-
|
|
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
|
+
),
|
|
1356
1414
|
/* @__PURE__ */ jsxs4(FormGroup, { children: [
|
|
1357
1415
|
toggleableCategories.map((category) => /* @__PURE__ */ jsx8(
|
|
1358
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,7 +925,13 @@ function CookieBanner({
|
|
|
923
925
|
width: designTokens?.layout?.width?.desktop ?? "100%",
|
|
924
926
|
p: 2
|
|
925
927
|
};
|
|
926
|
-
|
|
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
|
+
}
|
|
927
935
|
if (blocking) {
|
|
928
936
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
929
937
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
@@ -1005,6 +1013,7 @@ function FloatingPreferencesButton({
|
|
|
1005
1013
|
const { openPreferences, consented } = useConsent();
|
|
1006
1014
|
const texts = useConsentTexts();
|
|
1007
1015
|
const safeTheme = useThemeWithFallbacks();
|
|
1016
|
+
const designTokens = useDesignTokens();
|
|
1008
1017
|
logger.componentRender("FloatingPreferencesButton", {
|
|
1009
1018
|
position,
|
|
1010
1019
|
offset,
|
|
@@ -1044,9 +1053,9 @@ function FloatingPreferencesButton({
|
|
|
1044
1053
|
onClick: openPreferences,
|
|
1045
1054
|
sx: {
|
|
1046
1055
|
...getPosition(),
|
|
1047
|
-
backgroundColor: safeTheme.palette.primary.main,
|
|
1056
|
+
backgroundColor: designTokens?.colors?.primary ?? safeTheme.palette.primary.main,
|
|
1048
1057
|
"&:hover": {
|
|
1049
|
-
backgroundColor: safeTheme.palette.primary.dark
|
|
1058
|
+
backgroundColor: designTokens?.colors?.primary ? designTokens?.colors?.primary : safeTheme.palette.primary.dark
|
|
1050
1059
|
},
|
|
1051
1060
|
transition: `all ${safeTheme.transitions.duration.short}ms`
|
|
1052
1061
|
},
|
|
@@ -1064,6 +1073,7 @@ var init_FloatingPreferencesButton = __esm({
|
|
|
1064
1073
|
import_Fab = __toESM(require("@mui/material/Fab"), 1);
|
|
1065
1074
|
import_Tooltip = __toESM(require("@mui/material/Tooltip"), 1);
|
|
1066
1075
|
import_styles3 = require("@mui/material/styles");
|
|
1076
|
+
init_DesignContext();
|
|
1067
1077
|
init_useConsent();
|
|
1068
1078
|
init_logger();
|
|
1069
1079
|
import_jsx_runtime6 = require("react/jsx-runtime");
|
|
@@ -1160,6 +1170,8 @@ function ConsentProvider({
|
|
|
1160
1170
|
FloatingPreferencesButtonComponent,
|
|
1161
1171
|
floatingPreferencesButtonProps = {},
|
|
1162
1172
|
disableFloatingPreferencesButton = false,
|
|
1173
|
+
blocking = false,
|
|
1174
|
+
blockingStrategy = "auto",
|
|
1163
1175
|
hideBranding = false,
|
|
1164
1176
|
onConsentGiven,
|
|
1165
1177
|
onPreferencesSaved,
|
|
@@ -1250,6 +1262,12 @@ function ConsentProvider({
|
|
|
1250
1262
|
_registerGlobalOpenPreferences(api.openPreferences);
|
|
1251
1263
|
return () => _unregisterGlobalOpenPreferences();
|
|
1252
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]);
|
|
1253
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)(
|
|
1254
1272
|
CategoriesProvider,
|
|
1255
1273
|
{
|
|
@@ -1268,6 +1286,22 @@ function ConsentProvider({
|
|
|
1268
1286
|
...preferencesModalProps
|
|
1269
1287
|
}
|
|
1270
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
|
+
),
|
|
1271
1305
|
!state.consented && isHydrated && (CookieBannerComponent ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1272
1306
|
CookieBannerComponent,
|
|
1273
1307
|
{
|
|
@@ -1276,9 +1310,17 @@ function ConsentProvider({
|
|
|
1276
1310
|
rejectAll: api.rejectAll,
|
|
1277
1311
|
openPreferences: api.openPreferences,
|
|
1278
1312
|
texts,
|
|
1313
|
+
blocking,
|
|
1314
|
+
...cookieBannerProps
|
|
1315
|
+
}
|
|
1316
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1317
|
+
CookieBanner,
|
|
1318
|
+
{
|
|
1319
|
+
blocking,
|
|
1320
|
+
hideBranding,
|
|
1279
1321
|
...cookieBannerProps
|
|
1280
1322
|
}
|
|
1281
|
-
)
|
|
1323
|
+
)),
|
|
1282
1324
|
state.consented && !disableFloatingPreferencesButton && (FloatingPreferencesButtonComponent ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1283
1325
|
FloatingPreferencesButtonComponent,
|
|
1284
1326
|
{
|
|
@@ -1286,7 +1328,10 @@ function ConsentProvider({
|
|
|
1286
1328
|
consented: api.consented,
|
|
1287
1329
|
...floatingPreferencesButtonProps
|
|
1288
1330
|
}
|
|
1289
|
-
) :
|
|
1331
|
+
) : (
|
|
1332
|
+
// Encaminha `floatingPreferencesButtonProps` para o componente padrão
|
|
1333
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FloatingPreferencesButton, { ...floatingPreferencesButtonProps })
|
|
1334
|
+
))
|
|
1290
1335
|
]
|
|
1291
1336
|
}
|
|
1292
1337
|
) }) }) }) }) }) });
|
|
@@ -1438,6 +1483,7 @@ function PreferencesModal2({
|
|
|
1438
1483
|
}) {
|
|
1439
1484
|
const { preferences, setPreferences, closePreferences, isModalOpen } = useConsent();
|
|
1440
1485
|
const texts = useConsentTexts();
|
|
1486
|
+
const designTokens = useDesignTokens();
|
|
1441
1487
|
const { toggleableCategories } = useCategories();
|
|
1442
1488
|
const [tempPreferences, setTempPreferences] = (0, import_react2.useState)(() => {
|
|
1443
1489
|
const initialPrefs = { necessary: true };
|
|
@@ -1464,9 +1510,23 @@ function PreferencesModal2({
|
|
|
1464
1510
|
closePreferences();
|
|
1465
1511
|
};
|
|
1466
1512
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_Dialog.default, { "aria-labelledby": "cookie-pref-title", open, onClose: handleCancel, ...DialogProps2, children: [
|
|
1467
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1468
|
-
|
|
1469
|
-
|
|
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
|
+
),
|
|
1470
1530
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_FormGroup.default, { children: [
|
|
1471
1531
|
toggleableCategories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1472
1532
|
import_FormControlLabel.default,
|
|
@@ -1511,6 +1571,7 @@ var init_PreferencesModal = __esm({
|
|
|
1511
1571
|
import_react2 = require("react");
|
|
1512
1572
|
init_CategoriesContext();
|
|
1513
1573
|
init_useConsent();
|
|
1574
|
+
init_DesignContext();
|
|
1514
1575
|
init_Branding();
|
|
1515
1576
|
import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1516
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
|