react-lgpd-consent 0.1.8 → 0.1.12
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/README.md +50 -9
- package/dist/{PreferencesModal-4FDYT7VE.js → PreferencesModal-IFKCHTF2.js} +1 -1
- package/dist/{chunk-Y4XEAQXV.js → chunk-V54LZT2Q.js} +109 -31
- package/dist/index.cjs +202 -50
- package/dist/index.d.cts +162 -8
- package/dist/index.d.ts +162 -8
- package/dist/index.js +71 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/react-lgpd-consent)
|
|
4
4
|
[](https://github.com/lucianoedipo/react-lgpd-consent/blob/main/LICENSE)
|
|
5
|
-
[
|
|
37
|
+
|
|
6
38
|
[](https://reactjs.org/)
|
|
7
39
|
[](https://mui.com/)
|
|
8
40
|
|
|
@@ -24,6 +56,7 @@ Solução moderna, acessível e personalizável para gerenciar consentimento de
|
|
|
24
56
|
- 🎨 **Sistema de Temas**: Temas customizáveis para integração visual perfeita
|
|
25
57
|
- ⚡ **Carregamento Condicional**: Scripts só executam após consentimento explícito
|
|
26
58
|
- 🔌 **Modal Automático**: Modal de preferências incluído automaticamente com lazy loading
|
|
59
|
+
- 🎛️ **Botão Flutuante**: Componente opcional para acesso fácil às preferências
|
|
27
60
|
|
|
28
61
|
## 🚀 Instalação
|
|
29
62
|
|
|
@@ -44,7 +77,11 @@ npm install @mui/material js-cookie
|
|
|
44
77
|
## � Exemplo Completo
|
|
45
78
|
|
|
46
79
|
```tsx
|
|
47
|
-
import {
|
|
80
|
+
import {
|
|
81
|
+
ConsentProvider,
|
|
82
|
+
CookieBanner,
|
|
83
|
+
FloatingPreferencesButton,
|
|
84
|
+
} from 'react-lgpd-consent'
|
|
48
85
|
|
|
49
86
|
function App() {
|
|
50
87
|
return (
|
|
@@ -53,8 +90,11 @@ function App() {
|
|
|
53
90
|
<h1>Meu Site</h1>
|
|
54
91
|
<p>Conteúdo do site...</p>
|
|
55
92
|
|
|
56
|
-
{/* Banner de cookies */}
|
|
93
|
+
{/* Banner de cookies - Modal incluído automaticamente! */}
|
|
57
94
|
<CookieBanner policyLinkUrl="/privacy-policy" blocking={true} />
|
|
95
|
+
|
|
96
|
+
{/* Botão flutuante opcional para acesso às preferências */}
|
|
97
|
+
<FloatingPreferencesButton position="bottom-right" />
|
|
58
98
|
</div>
|
|
59
99
|
</ConsentProvider>
|
|
60
100
|
)
|
|
@@ -343,12 +383,13 @@ Para controle total, desabilite o modal automático:
|
|
|
343
383
|
|
|
344
384
|
### Components
|
|
345
385
|
|
|
346
|
-
| Componente
|
|
347
|
-
|
|
|
348
|
-
| `ConsentProvider`
|
|
349
|
-
| `CookieBanner`
|
|
350
|
-
| `PreferencesModal`
|
|
351
|
-
| `
|
|
386
|
+
| Componente | Descrição | Props Principais |
|
|
387
|
+
| --------------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------- |
|
|
388
|
+
| `ConsentProvider` | Provider principal do contexto | `initialState`, `texts`, `theme`, `hideBranding`, `PreferencesModalComponent`, callbacks |
|
|
389
|
+
| `CookieBanner` | Banner de consentimento | `policyLinkUrl`, `blocking`, `hideBranding`, `debug`, pass-through MUI props |
|
|
390
|
+
| `PreferencesModal` | Modal de preferências (incluído automaticamente) | `DialogProps`, `hideBranding` - **Opcional** |
|
|
391
|
+
| `FloatingPreferencesButton` | Botão flutuante para abrir preferências | `position`, `hideWhenConsented`, `tooltip`, `icon`, `FabProps` |
|
|
392
|
+
| `ConsentGate` | Renderização condicional por categoria | `category`, `children` |
|
|
352
393
|
|
|
353
394
|
### Hook `useConsent()`
|
|
354
395
|
|
|
@@ -7,8 +7,8 @@ import DialogTitle from "@mui/material/DialogTitle";
|
|
|
7
7
|
import FormControlLabel from "@mui/material/FormControlLabel";
|
|
8
8
|
import FormGroup from "@mui/material/FormGroup";
|
|
9
9
|
import Switch from "@mui/material/Switch";
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
10
|
+
import Typography2 from "@mui/material/Typography";
|
|
11
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
12
12
|
|
|
13
13
|
// src/context/ConsentContext.tsx
|
|
14
14
|
import * as React from "react";
|
|
@@ -20,7 +20,7 @@ var DEFAULT_COOKIE_OPTS = {
|
|
|
20
20
|
name: "cookieConsent",
|
|
21
21
|
maxAgeDays: 365,
|
|
22
22
|
sameSite: "Lax",
|
|
23
|
-
secure:
|
|
23
|
+
secure: typeof window !== "undefined" ? window.location.protocol === "https:" : false,
|
|
24
24
|
path: "/"
|
|
25
25
|
};
|
|
26
26
|
function readConsentCookie(name = DEFAULT_COOKIE_OPTS.name) {
|
|
@@ -55,12 +55,10 @@ var defaultConsentTheme = createTheme({
|
|
|
55
55
|
palette: {
|
|
56
56
|
primary: {
|
|
57
57
|
main: "#1976d2",
|
|
58
|
-
// Azul institucional
|
|
59
58
|
contrastText: "#ffffff"
|
|
60
59
|
},
|
|
61
60
|
secondary: {
|
|
62
61
|
main: "#dc004e",
|
|
63
|
-
// Rosa/vermelho para ações importantes
|
|
64
62
|
contrastText: "#ffffff"
|
|
65
63
|
},
|
|
66
64
|
background: {
|
|
@@ -84,7 +82,6 @@ var defaultConsentTheme = createTheme({
|
|
|
84
82
|
button: {
|
|
85
83
|
fontWeight: 500,
|
|
86
84
|
textTransform: "none"
|
|
87
|
-
// Manter capitalização original
|
|
88
85
|
}
|
|
89
86
|
},
|
|
90
87
|
components: {
|
|
@@ -123,7 +120,7 @@ var defaultConsentTheme = createTheme({
|
|
|
123
120
|
// src/context/ConsentContext.tsx
|
|
124
121
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
125
122
|
var PreferencesModal = React.lazy(
|
|
126
|
-
() => import("./PreferencesModal-
|
|
123
|
+
() => import("./PreferencesModal-IFKCHTF2.js").then((m) => ({
|
|
127
124
|
default: m.PreferencesModal
|
|
128
125
|
}))
|
|
129
126
|
);
|
|
@@ -191,6 +188,7 @@ function reducer(state, action) {
|
|
|
191
188
|
var StateCtx = React.createContext(null);
|
|
192
189
|
var ActionsCtx = React.createContext(null);
|
|
193
190
|
var TextsCtx = React.createContext(DEFAULT_TEXTS);
|
|
191
|
+
var HydrationCtx = React.createContext(false);
|
|
194
192
|
function ConsentProvider({
|
|
195
193
|
initialState,
|
|
196
194
|
texts: textsProp,
|
|
@@ -198,6 +196,7 @@ function ConsentProvider({
|
|
|
198
196
|
PreferencesModalComponent,
|
|
199
197
|
preferencesModalProps = {},
|
|
200
198
|
disableAutomaticModal = false,
|
|
199
|
+
hideBranding = false,
|
|
201
200
|
onConsentGiven,
|
|
202
201
|
onPreferencesSaved,
|
|
203
202
|
cookie: cookieOpts,
|
|
@@ -217,14 +216,24 @@ function ConsentProvider({
|
|
|
217
216
|
);
|
|
218
217
|
const boot = React.useMemo(() => {
|
|
219
218
|
if (initialState) return { ...initialState, isModalOpen: false };
|
|
220
|
-
|
|
221
|
-
return saved ?? {
|
|
219
|
+
return {
|
|
222
220
|
consented: false,
|
|
223
221
|
preferences: { ...DEFAULT_PREFERENCES },
|
|
224
222
|
isModalOpen: false
|
|
225
223
|
};
|
|
226
|
-
}, [initialState
|
|
224
|
+
}, [initialState]);
|
|
227
225
|
const [state, dispatch] = React.useReducer(reducer, boot);
|
|
226
|
+
const [isHydrated, setIsHydrated] = React.useState(false);
|
|
227
|
+
React.useEffect(() => {
|
|
228
|
+
if (typeof window !== "undefined" && !initialState) {
|
|
229
|
+
const saved = readConsentCookie(cookie.name);
|
|
230
|
+
if (saved?.consented) {
|
|
231
|
+
console.log("\u{1F680} Immediate hydration: Cookie found", saved);
|
|
232
|
+
dispatch({ type: "HYDRATE", state: saved });
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
setIsHydrated(true);
|
|
236
|
+
}, [cookie.name, initialState]);
|
|
228
237
|
React.useEffect(() => {
|
|
229
238
|
if (state.consented) writeConsentCookie(state, cookie);
|
|
230
239
|
}, [state, cookie]);
|
|
@@ -266,10 +275,10 @@ function ConsentProvider({
|
|
|
266
275
|
resetConsent
|
|
267
276
|
};
|
|
268
277
|
}, [state, cookie]);
|
|
269
|
-
return /* @__PURE__ */ jsx(ThemeProvider, { theme: appliedTheme, children: /* @__PURE__ */ jsx(StateCtx.Provider, { value: state, children: /* @__PURE__ */ jsx(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */
|
|
278
|
+
return /* @__PURE__ */ jsx(ThemeProvider, { theme: appliedTheme, children: /* @__PURE__ */ jsx(StateCtx.Provider, { value: state, children: /* @__PURE__ */ jsx(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ jsx(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ jsxs(HydrationCtx.Provider, { value: isHydrated, children: [
|
|
270
279
|
children,
|
|
271
|
-
!disableAutomaticModal && /* @__PURE__ */ jsx(React.Suspense, { fallback: null, children: PreferencesModalComponent ? /* @__PURE__ */ jsx(PreferencesModalComponent, { ...preferencesModalProps }) : /* @__PURE__ */ jsx(PreferencesModal, {}) })
|
|
272
|
-
] }) }) }) });
|
|
280
|
+
!disableAutomaticModal && /* @__PURE__ */ jsx(React.Suspense, { fallback: null, children: PreferencesModalComponent ? /* @__PURE__ */ jsx(PreferencesModalComponent, { ...preferencesModalProps }) : /* @__PURE__ */ jsx(PreferencesModal, { hideBranding }) })
|
|
281
|
+
] }) }) }) }) });
|
|
273
282
|
}
|
|
274
283
|
function useConsentStateInternal() {
|
|
275
284
|
const ctx = React.useContext(StateCtx);
|
|
@@ -287,6 +296,9 @@ function useConsentTextsInternal() {
|
|
|
287
296
|
const ctx = React.useContext(TextsCtx);
|
|
288
297
|
return ctx;
|
|
289
298
|
}
|
|
299
|
+
function useConsentHydrationInternal() {
|
|
300
|
+
return React.useContext(HydrationCtx);
|
|
301
|
+
}
|
|
290
302
|
|
|
291
303
|
// src/hooks/useConsent.ts
|
|
292
304
|
function useConsent() {
|
|
@@ -308,15 +320,78 @@ function useConsent() {
|
|
|
308
320
|
function useConsentTexts() {
|
|
309
321
|
return useConsentTextsInternal();
|
|
310
322
|
}
|
|
323
|
+
function useConsentHydration() {
|
|
324
|
+
return useConsentHydrationInternal();
|
|
325
|
+
}
|
|
311
326
|
|
|
312
|
-
// src/components/
|
|
327
|
+
// src/components/Branding.tsx
|
|
328
|
+
import Link from "@mui/material/Link";
|
|
329
|
+
import Typography from "@mui/material/Typography";
|
|
313
330
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
331
|
+
var brandingStyles = {
|
|
332
|
+
banner: {
|
|
333
|
+
fontSize: "0.65rem",
|
|
334
|
+
textAlign: "center",
|
|
335
|
+
mt: 1,
|
|
336
|
+
opacity: 0.7,
|
|
337
|
+
fontStyle: "italic"
|
|
338
|
+
},
|
|
339
|
+
modal: {
|
|
340
|
+
fontSize: "0.65rem",
|
|
341
|
+
textAlign: "center",
|
|
342
|
+
px: 3,
|
|
343
|
+
pb: 1,
|
|
344
|
+
opacity: 0.7,
|
|
345
|
+
fontStyle: "italic"
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
var linkStyles = {
|
|
349
|
+
textDecoration: "none",
|
|
350
|
+
fontWeight: 500,
|
|
351
|
+
"&:hover": {
|
|
352
|
+
textDecoration: "underline"
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
function Branding({ variant, hidden = false }) {
|
|
356
|
+
if (hidden) return null;
|
|
357
|
+
return /* @__PURE__ */ jsxs2(
|
|
358
|
+
Typography,
|
|
359
|
+
{
|
|
360
|
+
variant: "caption",
|
|
361
|
+
sx: (theme) => ({
|
|
362
|
+
...brandingStyles[variant],
|
|
363
|
+
color: theme.palette.text.secondary
|
|
364
|
+
}),
|
|
365
|
+
children: [
|
|
366
|
+
"fornecido por",
|
|
367
|
+
" ",
|
|
368
|
+
/* @__PURE__ */ jsx2(
|
|
369
|
+
Link,
|
|
370
|
+
{
|
|
371
|
+
href: "https://www.ledipo.eti.br",
|
|
372
|
+
target: "_blank",
|
|
373
|
+
rel: "noopener noreferrer",
|
|
374
|
+
sx: (theme) => ({
|
|
375
|
+
...linkStyles,
|
|
376
|
+
color: theme.palette.primary.main
|
|
377
|
+
}),
|
|
378
|
+
children: "L\xC9dipO.eti.br"
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
]
|
|
382
|
+
}
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/components/PreferencesModal.tsx
|
|
387
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
314
388
|
function PreferencesModal2({
|
|
315
|
-
DialogProps: DialogProps2
|
|
389
|
+
DialogProps: DialogProps2,
|
|
390
|
+
hideBranding = false
|
|
316
391
|
}) {
|
|
317
392
|
const { preferences, setPreferences, closePreferences, isModalOpen } = useConsent();
|
|
318
393
|
const texts = useConsentTexts();
|
|
319
|
-
const [tempPreferences, setTempPreferences] =
|
|
394
|
+
const [tempPreferences, setTempPreferences] = useState2(preferences);
|
|
320
395
|
useEffect2(() => {
|
|
321
396
|
if (isModalOpen) {
|
|
322
397
|
setTempPreferences(preferences);
|
|
@@ -330,7 +405,7 @@ function PreferencesModal2({
|
|
|
330
405
|
setTempPreferences(preferences);
|
|
331
406
|
closePreferences();
|
|
332
407
|
};
|
|
333
|
-
return /* @__PURE__ */
|
|
408
|
+
return /* @__PURE__ */ jsxs3(
|
|
334
409
|
Dialog,
|
|
335
410
|
{
|
|
336
411
|
"aria-labelledby": "cookie-pref-title",
|
|
@@ -338,14 +413,14 @@ function PreferencesModal2({
|
|
|
338
413
|
onClose: handleCancel,
|
|
339
414
|
...DialogProps2,
|
|
340
415
|
children: [
|
|
341
|
-
/* @__PURE__ */
|
|
342
|
-
/* @__PURE__ */
|
|
343
|
-
/* @__PURE__ */
|
|
344
|
-
/* @__PURE__ */
|
|
345
|
-
/* @__PURE__ */
|
|
416
|
+
/* @__PURE__ */ jsx3(DialogTitle, { id: "cookie-pref-title", children: texts.modalTitle }),
|
|
417
|
+
/* @__PURE__ */ jsxs3(DialogContent, { dividers: true, children: [
|
|
418
|
+
/* @__PURE__ */ jsx3(Typography2, { variant: "body2", sx: { mb: 2 }, children: texts.modalIntro }),
|
|
419
|
+
/* @__PURE__ */ jsxs3(FormGroup, { children: [
|
|
420
|
+
/* @__PURE__ */ jsx3(
|
|
346
421
|
FormControlLabel,
|
|
347
422
|
{
|
|
348
|
-
control: /* @__PURE__ */
|
|
423
|
+
control: /* @__PURE__ */ jsx3(
|
|
349
424
|
Switch,
|
|
350
425
|
{
|
|
351
426
|
checked: tempPreferences.analytics,
|
|
@@ -358,10 +433,10 @@ function PreferencesModal2({
|
|
|
358
433
|
label: "Cookies Anal\xEDticos (medem uso do site)"
|
|
359
434
|
}
|
|
360
435
|
),
|
|
361
|
-
/* @__PURE__ */
|
|
436
|
+
/* @__PURE__ */ jsx3(
|
|
362
437
|
FormControlLabel,
|
|
363
438
|
{
|
|
364
|
-
control: /* @__PURE__ */
|
|
439
|
+
control: /* @__PURE__ */ jsx3(
|
|
365
440
|
Switch,
|
|
366
441
|
{
|
|
367
442
|
checked: tempPreferences.marketing,
|
|
@@ -374,18 +449,19 @@ function PreferencesModal2({
|
|
|
374
449
|
label: "Cookies de Marketing/Publicidade"
|
|
375
450
|
}
|
|
376
451
|
),
|
|
377
|
-
/* @__PURE__ */
|
|
452
|
+
/* @__PURE__ */ jsx3(
|
|
378
453
|
FormControlLabel,
|
|
379
454
|
{
|
|
380
|
-
control: /* @__PURE__ */
|
|
455
|
+
control: /* @__PURE__ */ jsx3(Switch, { checked: true, disabled: true }),
|
|
381
456
|
label: texts.necessaryAlwaysOn
|
|
382
457
|
}
|
|
383
458
|
)
|
|
384
459
|
] })
|
|
385
460
|
] }),
|
|
386
|
-
/* @__PURE__ */
|
|
387
|
-
|
|
388
|
-
/* @__PURE__ */
|
|
461
|
+
!hideBranding && /* @__PURE__ */ jsx3(Branding, { variant: "modal" }),
|
|
462
|
+
/* @__PURE__ */ jsxs3(DialogActions, { children: [
|
|
463
|
+
/* @__PURE__ */ jsx3(Button, { variant: "outlined", onClick: handleCancel, children: "Cancelar" }),
|
|
464
|
+
/* @__PURE__ */ jsx3(Button, { variant: "contained", onClick: handleSave, children: texts.save })
|
|
389
465
|
] })
|
|
390
466
|
]
|
|
391
467
|
}
|
|
@@ -394,8 +470,10 @@ function PreferencesModal2({
|
|
|
394
470
|
|
|
395
471
|
export {
|
|
396
472
|
defaultConsentTheme,
|
|
473
|
+
Branding,
|
|
397
474
|
PreferencesModal2 as PreferencesModal,
|
|
398
475
|
ConsentProvider,
|
|
399
476
|
useConsent,
|
|
400
|
-
useConsentTexts
|
|
477
|
+
useConsentTexts,
|
|
478
|
+
useConsentHydration
|
|
401
479
|
};
|