react-lgpd-consent 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -30,162 +30,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
- // src/utils/cookieUtils.ts
34
- function readConsentCookie(name = DEFAULT_COOKIE_OPTS.name) {
35
- if (typeof document === "undefined") return null;
36
- const raw = import_js_cookie.default.get(name);
37
- if (!raw) return null;
38
- try {
39
- const data = JSON.parse(raw);
40
- if (!data.version) {
41
- return migrateLegacyCookie(data);
42
- }
43
- if (data.version !== COOKIE_SCHEMA_VERSION) {
44
- console.warn(
45
- `[react-lgpd-consent] Cookie version mismatch: ${data.version} != ${COOKIE_SCHEMA_VERSION}`
46
- );
47
- return null;
48
- }
49
- return data;
50
- } catch {
51
- return null;
52
- }
53
- }
54
- function migrateLegacyCookie(legacyData) {
55
- try {
56
- const now = (/* @__PURE__ */ new Date()).toISOString();
57
- return {
58
- version: COOKIE_SCHEMA_VERSION,
59
- consented: legacyData.consented || false,
60
- preferences: legacyData.preferences || { necessary: true },
61
- consentDate: now,
62
- // Não temos o original, usar data atual
63
- lastUpdate: now,
64
- source: "banner",
65
- // Assumir origem banner
66
- isModalOpen: false
67
- // Nunca persistir estado de UI
68
- };
69
- } catch {
70
- return null;
71
- }
72
- }
73
- function writeConsentCookie(state, source = "banner", opts) {
74
- if (typeof document === "undefined") return;
75
- const now = (/* @__PURE__ */ new Date()).toISOString();
76
- const o = { ...DEFAULT_COOKIE_OPTS, ...opts };
77
- const cookieData = {
78
- version: COOKIE_SCHEMA_VERSION,
79
- consented: state.consented,
80
- preferences: state.preferences,
81
- consentDate: state.consentDate || now,
82
- // Preservar data original ou usar atual
83
- lastUpdate: now,
84
- source
85
- // isModalOpen NÃO é persistido (campo de UI apenas)
86
- };
87
- import_js_cookie.default.set(o.name, JSON.stringify(cookieData), {
88
- expires: o.maxAgeDays,
89
- sameSite: o.sameSite,
90
- secure: o.secure,
91
- path: o.path
92
- });
93
- }
94
- function removeConsentCookie(opts) {
95
- if (typeof document === "undefined") return;
96
- const o = { ...DEFAULT_COOKIE_OPTS, ...opts };
97
- import_js_cookie.default.remove(o.name, { path: o.path });
98
- }
99
- var import_js_cookie, DEFAULT_COOKIE_OPTS, COOKIE_SCHEMA_VERSION;
100
- var init_cookieUtils = __esm({
101
- "src/utils/cookieUtils.ts"() {
102
- "use strict";
103
- import_js_cookie = __toESM(require("js-cookie"), 1);
104
- DEFAULT_COOKIE_OPTS = {
105
- name: "cookieConsent",
106
- maxAgeDays: 365,
107
- sameSite: "Lax",
108
- secure: typeof window !== "undefined" ? window.location.protocol === "https:" : false,
109
- path: "/"
110
- };
111
- COOKIE_SCHEMA_VERSION = "1.0";
112
- }
113
- });
114
-
115
- // src/utils/theme.ts
116
- var import_styles, defaultConsentTheme;
117
- var init_theme = __esm({
118
- "src/utils/theme.ts"() {
119
- "use strict";
120
- import_styles = require("@mui/material/styles");
121
- defaultConsentTheme = (0, import_styles.createTheme)({
122
- palette: {
123
- primary: {
124
- main: "#1976d2",
125
- contrastText: "#ffffff"
126
- },
127
- secondary: {
128
- main: "#dc004e",
129
- contrastText: "#ffffff"
130
- },
131
- background: {
132
- default: "#fafafa",
133
- paper: "#ffffff"
134
- },
135
- text: {
136
- primary: "#333333",
137
- secondary: "#666666"
138
- },
139
- action: {
140
- hover: "rgba(25, 118, 210, 0.04)"
141
- }
142
- },
143
- typography: {
144
- fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
145
- body2: {
146
- fontSize: "0.875rem",
147
- lineHeight: 1.43
148
- },
149
- button: {
150
- fontWeight: 500,
151
- textTransform: "none"
152
- }
153
- },
154
- components: {
155
- MuiButton: {
156
- styleOverrides: {
157
- root: {
158
- borderRadius: 8,
159
- paddingX: 16,
160
- paddingY: 8
161
- },
162
- contained: {
163
- boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
164
- "&:hover": {
165
- boxShadow: "0 4px 8px rgba(0,0,0,0.15)"
166
- }
167
- }
168
- }
169
- },
170
- MuiPaper: {
171
- styleOverrides: {
172
- root: {
173
- borderRadius: 12
174
- }
175
- }
176
- },
177
- MuiDialog: {
178
- styleOverrides: {
179
- paper: {
180
- borderRadius: 16
181
- }
182
- }
183
- }
184
- }
185
- });
186
- }
187
- });
188
-
189
33
  // src/utils/developerGuidance.ts
190
34
  function analyzeDeveloperConfiguration(config) {
191
35
  const guidance = {
@@ -244,17 +88,6 @@ function analyzeDeveloperConfiguration(config) {
244
88
  });
245
89
  }
246
90
  });
247
- const customCategories = finalConfig.customCategories || [];
248
- customCategories.forEach((category) => {
249
- guidance.activeCategoriesInfo.push({
250
- id: category.id,
251
- name: category.name,
252
- description: category.description,
253
- essential: category.essential === true,
254
- uiRequired: category.essential !== true
255
- // Apenas não-essenciais precisam toggle
256
- });
257
- });
258
91
  const totalToggleable = guidance.activeCategoriesInfo.filter(
259
92
  (c) => c.uiRequired
260
93
  ).length;
@@ -269,18 +102,10 @@ function analyzeDeveloperConfiguration(config) {
269
102
  'prejudicar experi\xEAncia do usu\xE1rio. Considere agrupar categorias similares.`
270
103
  );
271
104
  }
272
- const poorDescriptions = customCategories.filter(
273
- (c) => !c.description || c.description.length < 10
274
- );
275
- if (poorDescriptions.length > 0) {
276
- guidance.warnings.push(
277
- `Categorias customizadas com descri\xE7\xF5es inadequadas: ${poorDescriptions.map((c) => c.id).join(", ")}. Descri\xE7\xF5es claras s\xE3o obrigat\xF3rias para compliance LGPD.`
278
- );
279
- }
280
105
  return guidance;
281
106
  }
282
107
  function logDeveloperGuidance(guidance, disableGuidanceProp) {
283
- if (disableGuidanceProp === true) {
108
+ if (disableGuidanceProp) {
284
109
  return;
285
110
  }
286
111
  const isProduction = (
@@ -304,7 +129,8 @@ function logDeveloperGuidance(guidance, disableGuidanceProp) {
304
129
  console.groupEnd();
305
130
  }
306
131
  if (guidance.usingDefaults) {
307
- console.info(
132
+ console.warn(
133
+ // Changed from console.info to console.warn
308
134
  `${PREFIX} \u{1F4CB} Usando configura\xE7\xE3o padr\xE3o. Para personalizar, use a prop "categories" no ConsentProvider.`
309
135
  );
310
136
  }
@@ -329,6 +155,9 @@ function useDeveloperGuidance(config, disableGuidanceProp) {
329
155
  [config]
330
156
  );
331
157
  React.useEffect(() => {
158
+ if (disableGuidanceProp === true) {
159
+ return;
160
+ }
332
161
  logDeveloperGuidance(guidance, disableGuidanceProp);
333
162
  }, [guidance, stringifiedConfig, disableGuidanceProp]);
334
163
  return guidance;
@@ -339,9 +168,8 @@ var init_developerGuidance = __esm({
339
168
  "use strict";
340
169
  React = __toESM(require("react"), 1);
341
170
  DEFAULT_PROJECT_CATEGORIES = {
342
- enabledCategories: ["analytics"],
171
+ enabledCategories: ["analytics"]
343
172
  // Só analytics além de necessary
344
- customCategories: []
345
173
  };
346
174
  }
347
175
  });
@@ -349,24 +177,13 @@ var init_developerGuidance = __esm({
349
177
  // src/context/CategoriesContext.tsx
350
178
  function CategoriesProvider({
351
179
  children,
352
- categories,
353
- // LEGACY: prop antiga (apenas customCategories)
354
- config
180
+ config,
355
181
  // NOVO: configuração completa
182
+ disableDeveloperGuidance
356
183
  }) {
357
184
  const contextValue = React2.useMemo(() => {
358
- let finalConfig;
359
- if (categories && !config) {
360
- finalConfig = {
361
- enabledCategories: DEFAULT_PROJECT_CATEGORIES.enabledCategories,
362
- customCategories: categories
363
- };
364
- } else {
365
- finalConfig = config || DEFAULT_PROJECT_CATEGORIES;
366
- }
367
- const guidance = analyzeDeveloperConfiguration(
368
- config || (categories ? { customCategories: categories } : void 0)
369
- );
185
+ const finalConfig = config || DEFAULT_PROJECT_CATEGORIES;
186
+ const guidance = analyzeDeveloperConfiguration(config);
370
187
  const toggleableCategories = guidance.activeCategoriesInfo.filter(
371
188
  (cat) => cat.uiRequired
372
189
  );
@@ -374,14 +191,13 @@ function CategoriesProvider({
374
191
  config: finalConfig,
375
192
  guidance,
376
193
  toggleableCategories,
377
- allCategories: guidance.activeCategoriesInfo,
378
- legacyCategories: categories || []
194
+ allCategories: guidance.activeCategoriesInfo
379
195
  };
380
- }, [config, categories]);
196
+ }, [config]);
381
197
  React2.useEffect(() => {
382
- logDeveloperGuidance(contextValue.guidance);
383
- }, [contextValue.guidance]);
384
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CategoriesContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CategoriesCtx.Provider, { value: contextValue.legacyCategories, children }) });
198
+ logDeveloperGuidance(contextValue.guidance, disableDeveloperGuidance);
199
+ }, [contextValue.guidance, disableDeveloperGuidance]);
200
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CategoriesContext.Provider, { value: contextValue, children });
385
201
  }
386
202
  function useCategories() {
387
203
  const context = React2.useContext(CategoriesContext);
@@ -403,10 +219,7 @@ function useCategoryStatus(categoryId) {
403
219
  description: category?.description
404
220
  };
405
221
  }
406
- function useCustomCategories() {
407
- return React2.useContext(CategoriesCtx);
408
- }
409
- var React2, import_jsx_runtime, CategoriesContext, CategoriesCtx;
222
+ var React2, import_jsx_runtime, CategoriesContext;
410
223
  var init_CategoriesContext = __esm({
411
224
  "src/context/CategoriesContext.tsx"() {
412
225
  "use strict";
@@ -416,192 +229,498 @@ var init_CategoriesContext = __esm({
416
229
  CategoriesContext = React2.createContext(
417
230
  null
418
231
  );
419
- CategoriesCtx = React2.createContext([]);
420
232
  }
421
233
  });
422
234
 
423
- // src/components/Branding.tsx
424
- function Branding({ variant, hidden = false }) {
425
- if (hidden) return null;
426
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
427
- import_Typography.default,
428
- {
429
- variant: "caption",
430
- sx: (theme) => ({
431
- ...brandingStyles[variant],
432
- color: theme.palette.text.secondary
433
- }),
434
- children: [
435
- "fornecido por",
436
- " ",
437
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
438
- import_Link.default,
439
- {
440
- href: "https://www.ledipo.eti.br",
441
- target: "_blank",
442
- rel: "noopener noreferrer",
443
- sx: (theme) => ({
444
- ...linkStyles,
445
- color: theme.palette.primary.main
446
- }),
447
- children: "L\xC9dipO.eti.br"
448
- }
449
- )
450
- ]
235
+ // src/utils/cookieUtils.ts
236
+ function readConsentCookie(name = DEFAULT_COOKIE_OPTS.name) {
237
+ if (typeof document === "undefined") return null;
238
+ const raw = import_js_cookie.default.get(name);
239
+ if (!raw) return null;
240
+ try {
241
+ const data = JSON.parse(raw);
242
+ if (!data.version) {
243
+ return migrateLegacyCookie(data);
451
244
  }
452
- );
245
+ if (data.version !== COOKIE_SCHEMA_VERSION) {
246
+ console.warn(
247
+ `[react-lgpd-consent] Cookie version mismatch: ${data.version} != ${COOKIE_SCHEMA_VERSION}`
248
+ );
249
+ return null;
250
+ }
251
+ return data;
252
+ } catch {
253
+ return null;
254
+ }
453
255
  }
454
- var import_Link, import_Typography, import_jsx_runtime2, brandingStyles, linkStyles;
455
- var init_Branding = __esm({
456
- "src/components/Branding.tsx"() {
457
- "use strict";
458
- import_Link = __toESM(require("@mui/material/Link"), 1);
459
- import_Typography = __toESM(require("@mui/material/Typography"), 1);
460
- import_jsx_runtime2 = require("react/jsx-runtime");
461
- brandingStyles = {
462
- banner: {
463
- fontSize: "0.65rem",
464
- textAlign: "center",
465
- mt: 1,
466
- opacity: 0.7,
467
- fontStyle: "italic"
468
- },
469
- modal: {
470
- fontSize: "0.65rem",
471
- textAlign: "center",
472
- px: 3,
473
- pb: 1,
474
- opacity: 0.7,
475
- fontStyle: "italic"
476
- }
477
- };
478
- linkStyles = {
479
- textDecoration: "none",
480
- fontWeight: 500,
481
- "&:hover": {
482
- textDecoration: "underline"
483
- }
256
+ function migrateLegacyCookie(legacyData) {
257
+ try {
258
+ const now = (/* @__PURE__ */ new Date()).toISOString();
259
+ return {
260
+ version: COOKIE_SCHEMA_VERSION,
261
+ consented: legacyData.consented || false,
262
+ preferences: legacyData.preferences || { necessary: true },
263
+ consentDate: now,
264
+ // Não temos o original, usar data atual
265
+ lastUpdate: now,
266
+ source: "banner",
267
+ // Assumir origem banner
268
+ isModalOpen: false
269
+ // Nunca persistir estado de UI
484
270
  };
271
+ } catch {
272
+ return null;
273
+ }
274
+ }
275
+ function writeConsentCookie(state, config, opts, source = "banner") {
276
+ if (typeof document === "undefined") return;
277
+ const now = (/* @__PURE__ */ new Date()).toISOString();
278
+ const o = { ...DEFAULT_COOKIE_OPTS, ...opts };
279
+ const cookieData = {
280
+ version: COOKIE_SCHEMA_VERSION,
281
+ consented: state.consented,
282
+ preferences: state.preferences,
283
+ consentDate: state.consentDate || now,
284
+ // Preservar data original ou usar atual
285
+ lastUpdate: now,
286
+ source,
287
+ projectConfig: config
288
+ // isModalOpen NÃO é persistido (campo de UI apenas)
289
+ };
290
+ import_js_cookie.default.set(o.name, JSON.stringify(cookieData), {
291
+ expires: o.maxAgeDays,
292
+ sameSite: o.sameSite,
293
+ secure: o.secure,
294
+ path: o.path
295
+ });
296
+ }
297
+ function removeConsentCookie(opts) {
298
+ if (typeof document === "undefined") return;
299
+ const o = { ...DEFAULT_COOKIE_OPTS, ...opts };
300
+ import_js_cookie.default.remove(o.name, { path: o.path });
301
+ }
302
+ var import_js_cookie, DEFAULT_COOKIE_OPTS, COOKIE_SCHEMA_VERSION;
303
+ var init_cookieUtils = __esm({
304
+ "src/utils/cookieUtils.ts"() {
305
+ "use strict";
306
+ import_js_cookie = __toESM(require("js-cookie"), 1);
307
+ DEFAULT_COOKIE_OPTS = {
308
+ name: "cookieConsent",
309
+ maxAgeDays: 365,
310
+ sameSite: "Lax",
311
+ secure: typeof window !== "undefined" ? window.location.protocol === "https:" : false,
312
+ path: "/"
313
+ };
314
+ COOKIE_SCHEMA_VERSION = "1.0";
485
315
  }
486
316
  });
487
-
488
- // src/components/PreferencesModal.tsx
489
- var PreferencesModal_exports = {};
490
- __export(PreferencesModal_exports, {
491
- PreferencesModal: () => PreferencesModal
492
- });
493
- function PreferencesModal({
494
- DialogProps: DialogProps2,
495
- hideBranding = false
317
+
318
+ // src/utils/categoryUtils.ts
319
+ function createProjectPreferences(config, defaultValue = false) {
320
+ const preferences = {
321
+ necessary: true
322
+ // Sempre presente e true (essencial)
323
+ };
324
+ const enabledCategories = config?.enabledCategories || [];
325
+ enabledCategories.forEach((category) => {
326
+ if (category !== "necessary") {
327
+ preferences[category] = defaultValue;
328
+ }
329
+ });
330
+ return preferences;
331
+ }
332
+ function validateProjectPreferences(preferences, config) {
333
+ const validPreferences = {
334
+ necessary: true
335
+ // Sempre válida
336
+ };
337
+ const enabledCategories = config?.enabledCategories || [];
338
+ enabledCategories.forEach((category) => {
339
+ if (category !== "necessary" && preferences[category] !== void 0) {
340
+ validPreferences[category] = preferences[category];
341
+ }
342
+ });
343
+ return validPreferences;
344
+ }
345
+ var init_categoryUtils = __esm({
346
+ "src/utils/categoryUtils.ts"() {
347
+ "use strict";
348
+ }
349
+ });
350
+
351
+ // src/utils/theme.ts
352
+ var import_styles, defaultConsentTheme;
353
+ var init_theme = __esm({
354
+ "src/utils/theme.ts"() {
355
+ "use strict";
356
+ import_styles = require("@mui/material/styles");
357
+ defaultConsentTheme = (0, import_styles.createTheme)({
358
+ palette: {
359
+ primary: {
360
+ main: "#1976d2",
361
+ contrastText: "#ffffff"
362
+ },
363
+ secondary: {
364
+ main: "#dc004e",
365
+ contrastText: "#ffffff"
366
+ },
367
+ background: {
368
+ default: "#fafafa",
369
+ paper: "#ffffff"
370
+ },
371
+ text: {
372
+ primary: "#333333",
373
+ secondary: "#666666"
374
+ },
375
+ action: {
376
+ hover: "rgba(25, 118, 210, 0.04)"
377
+ }
378
+ },
379
+ typography: {
380
+ fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
381
+ body2: {
382
+ fontSize: "0.875rem",
383
+ lineHeight: 1.43
384
+ },
385
+ button: {
386
+ fontWeight: 500,
387
+ textTransform: "none"
388
+ }
389
+ },
390
+ components: {
391
+ MuiButton: {
392
+ styleOverrides: {
393
+ root: {
394
+ borderRadius: 8,
395
+ paddingX: 16,
396
+ paddingY: 8
397
+ },
398
+ contained: {
399
+ boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
400
+ "&:hover": {
401
+ boxShadow: "0 4px 8px rgba(0,0,0,0.15)"
402
+ }
403
+ }
404
+ }
405
+ },
406
+ MuiPaper: {
407
+ styleOverrides: {
408
+ root: {
409
+ borderRadius: 12
410
+ }
411
+ }
412
+ },
413
+ MuiDialog: {
414
+ styleOverrides: {
415
+ paper: {
416
+ borderRadius: 16
417
+ }
418
+ }
419
+ }
420
+ }
421
+ });
422
+ }
423
+ });
424
+
425
+ // src/context/DesignContext.tsx
426
+ function DesignProvider({
427
+ tokens,
428
+ children
496
429
  }) {
497
- const { preferences, setPreferences, closePreferences, isModalOpen } = useConsent();
498
- const texts = useConsentTexts();
499
- const { toggleableCategories } = useCategories();
500
- const [tempPreferences, setTempPreferences] = (0, import_react.useState)(
501
- () => {
502
- const initialPrefs = { necessary: true };
503
- toggleableCategories.forEach((category) => {
504
- initialPrefs[category.id] = preferences[category.id] ?? false;
505
- });
506
- return initialPrefs;
430
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DesignContext.Provider, { value: tokens, children });
431
+ }
432
+ function useDesignTokens() {
433
+ return React3.useContext(DesignContext);
434
+ }
435
+ var React3, import_jsx_runtime2, DesignContext;
436
+ var init_DesignContext = __esm({
437
+ "src/context/DesignContext.tsx"() {
438
+ "use strict";
439
+ React3 = __toESM(require("react"), 1);
440
+ import_jsx_runtime2 = require("react/jsx-runtime");
441
+ DesignContext = React3.createContext(void 0);
442
+ }
443
+ });
444
+
445
+ // src/components/Branding.tsx
446
+ function Branding({ variant, hidden = false }) {
447
+ if (hidden) return null;
448
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
449
+ import_Typography.default,
450
+ {
451
+ variant: "caption",
452
+ sx: (theme) => ({
453
+ ...brandingStyles[variant],
454
+ color: theme.palette.text.secondary
455
+ }),
456
+ children: [
457
+ "fornecido por",
458
+ " ",
459
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
460
+ import_Link.default,
461
+ {
462
+ href: "https://www.ledipo.eti.br",
463
+ target: "_blank",
464
+ rel: "noopener noreferrer",
465
+ sx: (theme) => ({
466
+ ...linkStyles,
467
+ color: theme.palette.primary.main
468
+ }),
469
+ children: "L\xC9dipO.eti.br"
470
+ }
471
+ )
472
+ ]
507
473
  }
508
474
  );
509
- (0, import_react.useEffect)(() => {
510
- if (isModalOpen) {
511
- const syncedPrefs = { necessary: true };
512
- toggleableCategories.forEach((category) => {
513
- syncedPrefs[category.id] = preferences[category.id] ?? false;
514
- });
515
- setTempPreferences(syncedPrefs);
516
- }
517
- }, [isModalOpen, preferences, toggleableCategories]);
518
- const open = DialogProps2?.open ?? isModalOpen ?? false;
519
- const handleSave = () => {
520
- setPreferences(tempPreferences);
475
+ }
476
+ var import_Link, import_Typography, import_jsx_runtime3, brandingStyles, linkStyles;
477
+ var init_Branding = __esm({
478
+ "src/components/Branding.tsx"() {
479
+ "use strict";
480
+ import_Link = __toESM(require("@mui/material/Link"), 1);
481
+ import_Typography = __toESM(require("@mui/material/Typography"), 1);
482
+ import_jsx_runtime3 = require("react/jsx-runtime");
483
+ brandingStyles = {
484
+ banner: {
485
+ fontSize: "0.65rem",
486
+ textAlign: "right",
487
+ mt: 1,
488
+ opacity: 0.7,
489
+ fontStyle: "italic",
490
+ width: "100%"
491
+ },
492
+ modal: {
493
+ fontSize: "0.65rem",
494
+ textAlign: "right",
495
+ px: 3,
496
+ pb: 1,
497
+ opacity: 0.7,
498
+ fontStyle: "italic",
499
+ width: "100%"
500
+ }
501
+ };
502
+ linkStyles = {
503
+ textDecoration: "none",
504
+ fontWeight: 500,
505
+ "&:hover": {
506
+ textDecoration: "underline"
507
+ }
508
+ };
509
+ }
510
+ });
511
+
512
+ // src/components/CookieBanner.tsx
513
+ function CookieBanner({
514
+ policyLinkUrl,
515
+ debug,
516
+ blocking = true,
517
+ hideBranding = false,
518
+ SnackbarProps,
519
+ PaperProps
520
+ }) {
521
+ const { consented, acceptAll, rejectAll, openPreferences } = useConsent();
522
+ const texts = useConsentTexts();
523
+ const isHydrated = useConsentHydration();
524
+ const designTokens = useDesignTokens();
525
+ const open = debug ? true : isHydrated && !consented;
526
+ if (!open) return null;
527
+ const bannerStyle = {
528
+ p: designTokens?.spacing?.padding?.banner ?? 2,
529
+ maxWidth: 720,
530
+ mx: "auto",
531
+ backgroundColor: designTokens?.colors?.background,
532
+ color: designTokens?.colors?.text,
533
+ borderRadius: designTokens?.spacing?.borderRadius?.banner,
534
+ fontFamily: designTokens?.typography?.fontFamily
521
535
  };
522
- const handleCancel = () => {
523
- setTempPreferences(preferences);
524
- closePreferences();
536
+ const bannerContent = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_Paper.default, { elevation: 3, sx: bannerStyle, ...PaperProps, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_Stack.default, { spacing: 1, children: [
537
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
538
+ import_Typography2.default,
539
+ {
540
+ variant: "body2",
541
+ sx: { fontSize: designTokens?.typography?.fontSize?.banner },
542
+ children: [
543
+ texts.bannerMessage,
544
+ " ",
545
+ policyLinkUrl && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
546
+ import_Link2.default,
547
+ {
548
+ href: policyLinkUrl,
549
+ underline: "hover",
550
+ target: "_blank",
551
+ rel: "noopener noreferrer",
552
+ sx: { color: designTokens?.colors?.primary },
553
+ children: texts.policyLink ?? "Saiba mais"
554
+ }
555
+ )
556
+ ]
557
+ }
558
+ ),
559
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
560
+ import_Stack.default,
561
+ {
562
+ direction: { xs: "column", sm: "row" },
563
+ spacing: 1,
564
+ justifyContent: "flex-end",
565
+ children: [
566
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
567
+ import_Button.default,
568
+ {
569
+ variant: "outlined",
570
+ onClick: rejectAll,
571
+ sx: { color: designTokens?.colors?.secondary },
572
+ children: texts.declineAll
573
+ }
574
+ ),
575
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
576
+ import_Button.default,
577
+ {
578
+ variant: "contained",
579
+ onClick: acceptAll,
580
+ sx: { backgroundColor: designTokens?.colors?.primary },
581
+ children: texts.acceptAll
582
+ }
583
+ ),
584
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
585
+ import_Button.default,
586
+ {
587
+ variant: "text",
588
+ onClick: openPreferences,
589
+ sx: { color: designTokens?.colors?.text },
590
+ children: texts.preferences
591
+ }
592
+ )
593
+ ]
594
+ }
595
+ ),
596
+ !hideBranding && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Branding, { variant: "banner" })
597
+ ] }) });
598
+ const positionStyle = {
599
+ position: "fixed",
600
+ zIndex: 1300,
601
+ ...designTokens?.layout?.position === "top" ? { top: 0 } : { bottom: 0 },
602
+ left: 0,
603
+ right: 0,
604
+ width: designTokens?.layout?.width?.desktop ?? "100%",
605
+ p: 2
525
606
  };
526
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
527
- import_Dialog.default,
607
+ if (blocking) {
608
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
609
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
610
+ import_Box.default,
611
+ {
612
+ sx: {
613
+ position: "fixed",
614
+ top: 0,
615
+ left: 0,
616
+ right: 0,
617
+ bottom: 0,
618
+ backgroundColor: designTokens?.layout?.backdrop ? "rgba(0, 0, 0, 0.5)" : "transparent",
619
+ zIndex: 1299
620
+ }
621
+ }
622
+ ),
623
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_Box.default, { sx: positionStyle, children: bannerContent })
624
+ ] });
625
+ }
626
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
627
+ import_Snackbar.default,
528
628
  {
529
- "aria-labelledby": "cookie-pref-title",
530
629
  open,
531
- onClose: handleCancel,
532
- ...DialogProps2,
533
- children: [
534
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_DialogTitle.default, { id: "cookie-pref-title", children: texts.modalTitle }),
535
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_DialogContent.default, { dividers: true, children: [
536
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_Typography2.default, { variant: "body2", sx: { mb: 2 }, children: texts.modalIntro }),
537
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_FormGroup.default, { children: [
538
- toggleableCategories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
539
- import_FormControlLabel.default,
540
- {
541
- control: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
542
- import_Switch.default,
543
- {
544
- checked: tempPreferences[category.id] ?? false,
545
- onChange: (e) => setTempPreferences((prev) => ({
546
- ...prev,
547
- [category.id]: e.target.checked
548
- }))
549
- }
550
- ),
551
- label: `${category.name} - ${category.description}`
552
- },
553
- category.id
554
- )),
555
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
556
- import_FormControlLabel.default,
557
- {
558
- control: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_Switch.default, { checked: true, disabled: true }),
559
- label: texts.necessaryAlwaysOn
560
- }
561
- )
562
- ] })
563
- ] }),
564
- !hideBranding && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Branding, { variant: "modal" }),
565
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_DialogActions.default, { children: [
566
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_Button.default, { variant: "outlined", onClick: handleCancel, children: "Cancelar" }),
567
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_Button.default, { variant: "contained", onClick: handleSave, children: texts.save })
568
- ] })
569
- ]
630
+ anchorOrigin: {
631
+ vertical: designTokens?.layout?.position === "top" ? "top" : "bottom",
632
+ horizontal: "center"
633
+ },
634
+ ...SnackbarProps,
635
+ children: bannerContent
570
636
  }
571
637
  );
572
638
  }
573
- var import_Button, import_Dialog, import_DialogActions, import_DialogContent, import_DialogTitle, import_FormControlLabel, import_FormGroup, import_Switch, import_Typography2, import_react, import_jsx_runtime3;
574
- var init_PreferencesModal = __esm({
575
- "src/components/PreferencesModal.tsx"() {
639
+ var import_Button, import_Box, import_Paper, import_Snackbar, import_Stack, import_Typography2, import_Link2, import_jsx_runtime4;
640
+ var init_CookieBanner = __esm({
641
+ "src/components/CookieBanner.tsx"() {
576
642
  "use strict";
577
643
  import_Button = __toESM(require("@mui/material/Button"), 1);
578
- import_Dialog = __toESM(require("@mui/material/Dialog"), 1);
579
- import_DialogActions = __toESM(require("@mui/material/DialogActions"), 1);
580
- import_DialogContent = __toESM(require("@mui/material/DialogContent"), 1);
581
- import_DialogTitle = __toESM(require("@mui/material/DialogTitle"), 1);
582
- import_FormControlLabel = __toESM(require("@mui/material/FormControlLabel"), 1);
583
- import_FormGroup = __toESM(require("@mui/material/FormGroup"), 1);
584
- import_Switch = __toESM(require("@mui/material/Switch"), 1);
644
+ import_Box = __toESM(require("@mui/material/Box"), 1);
645
+ import_Paper = __toESM(require("@mui/material/Paper"), 1);
646
+ import_Snackbar = __toESM(require("@mui/material/Snackbar"), 1);
647
+ import_Stack = __toESM(require("@mui/material/Stack"), 1);
585
648
  import_Typography2 = __toESM(require("@mui/material/Typography"), 1);
586
- import_react = require("react");
587
- init_CategoriesContext();
649
+ import_Link2 = __toESM(require("@mui/material/Link"), 1);
650
+ init_useConsent();
651
+ init_DesignContext();
652
+ init_Branding();
653
+ import_jsx_runtime4 = require("react/jsx-runtime");
654
+ }
655
+ });
656
+
657
+ // src/components/FloatingPreferencesButton.tsx
658
+ function FloatingPreferencesButton({
659
+ position = "bottom-right",
660
+ offset = 24,
661
+ icon = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_CookieOutlined.default, {}),
662
+ tooltip,
663
+ FabProps,
664
+ hideWhenConsented = false
665
+ }) {
666
+ const { openPreferences, consented } = useConsent();
667
+ const theme = (0, import_styles2.useTheme)();
668
+ if (hideWhenConsented && consented) {
669
+ return null;
670
+ }
671
+ const tooltipText = tooltip ?? "Gerenciar Prefer\xEAncias de Cookies";
672
+ const getPosition = () => {
673
+ const styles = {
674
+ position: "fixed",
675
+ zIndex: 1200
676
+ };
677
+ switch (position) {
678
+ case "bottom-left":
679
+ return { ...styles, bottom: offset, left: offset };
680
+ case "bottom-right":
681
+ return { ...styles, bottom: offset, right: offset };
682
+ case "top-left":
683
+ return { ...styles, top: offset, left: offset };
684
+ case "top-right":
685
+ return { ...styles, top: offset, right: offset };
686
+ default:
687
+ return { ...styles, bottom: offset, right: offset };
688
+ }
689
+ };
690
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_Tooltip.default, { title: tooltipText, placement: "top", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
691
+ import_Fab.default,
692
+ {
693
+ size: "medium",
694
+ color: "primary",
695
+ onClick: openPreferences,
696
+ sx: {
697
+ ...getPosition(),
698
+ backgroundColor: theme.palette.primary.main,
699
+ "&:hover": {
700
+ backgroundColor: theme.palette.primary.dark
701
+ }
702
+ },
703
+ "aria-label": tooltipText,
704
+ ...FabProps,
705
+ children: icon
706
+ }
707
+ ) });
708
+ }
709
+ var import_CookieOutlined, import_Fab, import_Tooltip, import_styles2, import_jsx_runtime5;
710
+ var init_FloatingPreferencesButton = __esm({
711
+ "src/components/FloatingPreferencesButton.tsx"() {
712
+ "use strict";
713
+ import_CookieOutlined = __toESM(require("@mui/icons-material/CookieOutlined"), 1);
714
+ import_Fab = __toESM(require("@mui/material/Fab"), 1);
715
+ import_Tooltip = __toESM(require("@mui/material/Tooltip"), 1);
716
+ import_styles2 = require("@mui/material/styles");
588
717
  init_useConsent();
589
- init_Branding();
590
- import_jsx_runtime3 = require("react/jsx-runtime");
718
+ import_jsx_runtime5 = require("react/jsx-runtime");
591
719
  }
592
720
  });
593
721
 
594
722
  // src/context/ConsentContext.tsx
595
- function createInitialPreferences(customCategories) {
596
- const prefs = { ...DEFAULT_PREFERENCES };
597
- if (customCategories) {
598
- customCategories.forEach((category) => {
599
- prefs[category.id] = category.essential === true;
600
- });
601
- }
602
- return prefs;
603
- }
604
- function createFullConsentState(consented, preferences, source, isModalOpen = false, existingState) {
723
+ function createFullConsentState(consented, preferences, source, projectConfig, isModalOpen = false, existingState) {
605
724
  const now = (/* @__PURE__ */ new Date()).toISOString();
606
725
  return {
607
726
  version: "1.0",
@@ -610,28 +729,33 @@ function createFullConsentState(consented, preferences, source, isModalOpen = fa
610
729
  consentDate: existingState?.consentDate || now,
611
730
  lastUpdate: now,
612
731
  source,
732
+ projectConfig,
613
733
  isModalOpen
614
734
  };
615
735
  }
616
736
  function reducer(state, action) {
617
737
  switch (action.type) {
618
738
  case "ACCEPT_ALL": {
619
- const prefs = createInitialPreferences(action.customCategories);
620
- Object.keys(prefs).forEach((key) => {
621
- prefs[key] = true;
622
- });
623
- return createFullConsentState(true, prefs, "banner", false, state);
739
+ const prefs = createProjectPreferences(action.config, true);
740
+ return createFullConsentState(
741
+ true,
742
+ prefs,
743
+ "banner",
744
+ action.config,
745
+ false,
746
+ state
747
+ );
624
748
  }
625
749
  case "REJECT_ALL": {
626
- const prefs = createInitialPreferences(action.customCategories);
627
- if (action.customCategories) {
628
- action.customCategories.forEach((category) => {
629
- if (category.essential) {
630
- prefs[category.id] = true;
631
- }
632
- });
633
- }
634
- return createFullConsentState(true, prefs, "banner", false, state);
750
+ const prefs = createProjectPreferences(action.config, false);
751
+ return createFullConsentState(
752
+ true,
753
+ prefs,
754
+ "banner",
755
+ action.config,
756
+ false,
757
+ state
758
+ );
635
759
  }
636
760
  case "SET_CATEGORY":
637
761
  return {
@@ -647,6 +771,7 @@ function reducer(state, action) {
647
771
  true,
648
772
  action.preferences,
649
773
  "modal",
774
+ action.config,
650
775
  false,
651
776
  state
652
777
  );
@@ -657,20 +782,30 @@ function reducer(state, action) {
657
782
  true,
658
783
  state.preferences,
659
784
  "modal",
785
+ action.config,
660
786
  false,
661
787
  state
662
788
  );
663
789
  case "RESET": {
664
790
  return createFullConsentState(
665
791
  false,
666
- createInitialPreferences(action.customCategories),
792
+ createProjectPreferences(action.config),
667
793
  "programmatic",
794
+ action.config,
668
795
  false
669
796
  );
670
797
  }
671
- case "HYDRATE":
672
- return { ...action.state, isModalOpen: false };
673
- // Nunca hidratar com modal aberto
798
+ case "HYDRATE": {
799
+ const validatedPreferences = validateProjectPreferences(
800
+ action.state.preferences,
801
+ action.config
802
+ );
803
+ return {
804
+ ...action.state,
805
+ preferences: validatedPreferences,
806
+ isModalOpen: false
807
+ };
808
+ }
674
809
  default:
675
810
  return state;
676
811
  }
@@ -678,96 +813,98 @@ function reducer(state, action) {
678
813
  function ConsentProvider({
679
814
  initialState,
680
815
  categories,
681
- // NOVO: configuração completa de categorias
816
+ // Nova prop para configuração de categorias
682
817
  texts: textsProp,
683
818
  theme,
684
- customCategories,
685
- // LEGACY: compatibilidade
819
+ designTokens,
686
820
  scriptIntegrations,
687
821
  // eslint-disable-line no-unused-vars
688
822
  PreferencesModalComponent,
689
823
  preferencesModalProps = {},
690
- disableAutomaticModal = false,
824
+ CookieBannerComponent,
825
+ cookieBannerProps = {},
826
+ FloatingPreferencesButtonComponent,
827
+ floatingPreferencesButtonProps = {},
828
+ disableFloatingPreferencesButton = false,
691
829
  hideBranding = false,
692
830
  onConsentGiven,
693
831
  onPreferencesSaved,
694
832
  cookie: cookieOpts,
695
833
  disableDeveloperGuidance,
696
- // NOVO: desabilita avisos de dev
697
834
  children
698
835
  }) {
699
- const texts = React3.useMemo(
836
+ const texts = React4.useMemo(
700
837
  () => ({ ...DEFAULT_TEXTS, ...textsProp ?? {} }),
701
838
  [textsProp]
702
839
  );
703
- const cookie = React3.useMemo(
840
+ const cookie = React4.useMemo(
704
841
  () => ({ ...DEFAULT_COOKIE_OPTS, ...cookieOpts ?? {} }),
705
842
  [cookieOpts]
706
843
  );
707
- const appliedTheme = React3.useMemo(
844
+ const appliedTheme = React4.useMemo(
708
845
  () => theme || defaultConsentTheme,
709
846
  [theme]
710
847
  );
711
- const finalCategoriesConfig = React3.useMemo(() => {
848
+ const finalCategoriesConfig = React4.useMemo(() => {
712
849
  if (categories) return categories;
713
- if (customCategories) {
714
- return {
715
- enabledCategories: ["analytics"],
716
- // padrão quando usando API antiga
717
- customCategories
718
- };
719
- }
720
- return void 0;
721
- }, [categories, customCategories]);
850
+ return DEFAULT_PROJECT_CATEGORIES;
851
+ }, [categories]);
722
852
  useDeveloperGuidance(finalCategoriesConfig, disableDeveloperGuidance);
723
- const boot = React3.useMemo(() => {
853
+ const boot = React4.useMemo(() => {
724
854
  if (initialState) return { ...initialState, isModalOpen: false };
725
855
  return createFullConsentState(
726
856
  false,
727
- createInitialPreferences(customCategories),
857
+ createProjectPreferences(finalCategoriesConfig),
728
858
  "banner",
859
+ finalCategoriesConfig,
729
860
  false
730
861
  );
731
- }, [initialState, customCategories]);
732
- const [state, dispatch] = React3.useReducer(reducer, boot);
733
- const [isHydrated, setIsHydrated] = React3.useState(false);
734
- React3.useEffect(() => {
862
+ }, [initialState, finalCategoriesConfig]);
863
+ const [state, dispatch] = React4.useReducer(reducer, boot);
864
+ const [isHydrated, setIsHydrated] = React4.useState(false);
865
+ React4.useEffect(() => {
735
866
  if (!initialState) {
736
867
  const saved = readConsentCookie(cookie.name);
737
868
  if (saved?.consented) {
738
- console.log("\u{1F680} Immediate hydration: Cookie found", saved);
739
- dispatch({ type: "HYDRATE", state: saved });
869
+ dispatch({
870
+ type: "HYDRATE",
871
+ state: saved,
872
+ config: finalCategoriesConfig
873
+ });
740
874
  }
741
875
  }
742
876
  setIsHydrated(true);
743
- }, [cookie.name, initialState]);
744
- React3.useEffect(() => {
745
- if (state.consented) writeConsentCookie(state, state.source, cookie);
746
- }, [state, cookie]);
747
- const prevConsented = React3.useRef(state.consented);
748
- React3.useEffect(() => {
877
+ }, [cookie.name, initialState, finalCategoriesConfig]);
878
+ React4.useEffect(() => {
879
+ if (state.consented)
880
+ writeConsentCookie(state, finalCategoriesConfig, cookie);
881
+ }, [state, cookie, finalCategoriesConfig]);
882
+ const prevConsented = React4.useRef(state.consented);
883
+ React4.useEffect(() => {
749
884
  if (!prevConsented.current && state.consented && onConsentGiven) {
750
885
  setTimeout(() => onConsentGiven(state), 150);
751
886
  }
752
887
  prevConsented.current = state.consented;
753
888
  }, [state, onConsentGiven]);
754
- const prevPrefs = React3.useRef(state.preferences);
755
- React3.useEffect(() => {
756
- if (state.consented && onPreferencesSaved && prevPrefs.current !== state.preferences) {
757
- setTimeout(() => onPreferencesSaved(state.preferences), 150);
758
- prevPrefs.current = state.preferences;
759
- }
760
- }, [state, onPreferencesSaved]);
761
- const api = React3.useMemo(() => {
762
- const acceptAll = () => dispatch({ type: "ACCEPT_ALL", customCategories });
763
- const rejectAll = () => dispatch({ type: "REJECT_ALL", customCategories });
889
+ const api = React4.useMemo(() => {
890
+ const acceptAll = () => dispatch({ type: "ACCEPT_ALL", config: finalCategoriesConfig });
891
+ const rejectAll = () => dispatch({ type: "REJECT_ALL", config: finalCategoriesConfig });
764
892
  const setPreference = (category, value) => dispatch({ type: "SET_CATEGORY", category, value });
765
- const setPreferences = (preferences) => dispatch({ type: "SET_PREFERENCES", preferences });
893
+ const setPreferences = (preferences) => {
894
+ dispatch({
895
+ type: "SET_PREFERENCES",
896
+ preferences,
897
+ config: finalCategoriesConfig
898
+ });
899
+ if (onPreferencesSaved) {
900
+ setTimeout(() => onPreferencesSaved(preferences), 150);
901
+ }
902
+ };
766
903
  const openPreferences = () => dispatch({ type: "OPEN_MODAL" });
767
- const closePreferences = () => dispatch({ type: "CLOSE_MODAL" });
904
+ const closePreferences = () => dispatch({ type: "CLOSE_MODAL", config: finalCategoriesConfig });
768
905
  const resetConsent = () => {
769
906
  removeConsentCookie(cookie);
770
- dispatch({ type: "RESET", customCategories });
907
+ dispatch({ type: "RESET", config: finalCategoriesConfig });
771
908
  };
772
909
  return {
773
910
  consented: !!state.consented,
@@ -781,58 +918,87 @@ function ConsentProvider({
781
918
  closePreferences,
782
919
  resetConsent
783
920
  };
784
- }, [state, cookie, customCategories]);
785
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_styles2.ThemeProvider, { theme: appliedTheme, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StateCtx.Provider, { value: state, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(HydrationCtx.Provider, { value: isHydrated, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
921
+ }, [state, cookie, finalCategoriesConfig, onPreferencesSaved]);
922
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_styles3.ThemeProvider, { theme: appliedTheme, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StateCtx.Provider, { value: state, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(HydrationCtx.Provider, { value: isHydrated, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DesignProvider, { tokens: designTokens, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
786
923
  CategoriesProvider,
787
924
  {
788
925
  config: finalCategoriesConfig,
789
- categories: customCategories,
926
+ disableDeveloperGuidance,
790
927
  children: [
791
928
  children,
792
- !disableAutomaticModal && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(React3.Suspense, { fallback: null, children: PreferencesModalComponent ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PreferencesModalComponent, { ...preferencesModalProps }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PreferencesModal2, { hideBranding }) })
929
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(React4.Suspense, { fallback: null, children: PreferencesModalComponent ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
930
+ PreferencesModalComponent,
931
+ {
932
+ preferences: api.preferences,
933
+ setPreferences: api.setPreferences,
934
+ closePreferences: api.closePreferences,
935
+ isModalOpen: api.isModalOpen,
936
+ texts,
937
+ ...preferencesModalProps
938
+ }
939
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PreferencesModal, { hideBranding }) }),
940
+ !state.consented && isHydrated && (CookieBannerComponent ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
941
+ CookieBannerComponent,
942
+ {
943
+ consented: api.consented,
944
+ acceptAll: api.acceptAll,
945
+ rejectAll: api.rejectAll,
946
+ openPreferences: api.openPreferences,
947
+ texts,
948
+ ...cookieBannerProps
949
+ }
950
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CookieBanner, {})),
951
+ state.consented && !disableFloatingPreferencesButton && (FloatingPreferencesButtonComponent ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
952
+ FloatingPreferencesButtonComponent,
953
+ {
954
+ openPreferences: api.openPreferences,
955
+ consented: api.consented,
956
+ ...floatingPreferencesButtonProps
957
+ }
958
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloatingPreferencesButton, {}))
793
959
  ]
794
960
  }
795
- ) }) }) }) }) });
961
+ ) }) }) }) }) }) });
796
962
  }
797
963
  function useConsentStateInternal() {
798
- const ctx = React3.useContext(StateCtx);
964
+ const ctx = React4.useContext(StateCtx);
799
965
  if (!ctx)
800
966
  throw new Error("useConsentState must be used within ConsentProvider");
801
967
  return ctx;
802
968
  }
803
969
  function useConsentActionsInternal() {
804
- const ctx = React3.useContext(ActionsCtx);
970
+ const ctx = React4.useContext(ActionsCtx);
805
971
  if (!ctx)
806
972
  throw new Error("useConsentActions must be used within ConsentProvider");
807
973
  return ctx;
808
974
  }
809
975
  function useConsentTextsInternal() {
810
- const ctx = React3.useContext(TextsCtx);
976
+ const ctx = React4.useContext(TextsCtx);
811
977
  return ctx;
812
978
  }
813
979
  function useConsentHydrationInternal() {
814
- return React3.useContext(HydrationCtx);
980
+ return React4.useContext(HydrationCtx);
815
981
  }
816
- var React3, import_styles2, import_jsx_runtime4, PreferencesModal2, DEFAULT_PREFERENCES, DEFAULT_TEXTS, StateCtx, ActionsCtx, TextsCtx, HydrationCtx;
982
+ var React4, import_styles3, import_jsx_runtime6, PreferencesModal, DEFAULT_TEXTS, StateCtx, ActionsCtx, TextsCtx, HydrationCtx;
817
983
  var init_ConsentContext = __esm({
818
984
  "src/context/ConsentContext.tsx"() {
819
985
  "use strict";
820
- React3 = __toESM(require("react"), 1);
821
- import_styles2 = require("@mui/material/styles");
986
+ React4 = __toESM(require("react"), 1);
987
+ import_styles3 = require("@mui/material/styles");
822
988
  init_cookieUtils();
989
+ init_categoryUtils();
823
990
  init_theme();
824
991
  init_CategoriesContext();
992
+ init_DesignContext();
825
993
  init_developerGuidance();
826
- import_jsx_runtime4 = require("react/jsx-runtime");
827
- PreferencesModal2 = React3.lazy(
994
+ init_CookieBanner();
995
+ init_FloatingPreferencesButton();
996
+ import_jsx_runtime6 = require("react/jsx-runtime");
997
+ PreferencesModal = React4.lazy(
828
998
  () => Promise.resolve().then(() => (init_PreferencesModal(), PreferencesModal_exports)).then((m) => ({
829
999
  default: m.PreferencesModal
830
1000
  }))
831
1001
  );
832
- DEFAULT_PREFERENCES = {
833
- necessary: true
834
- // Sempre ativo (essencial)
835
- };
836
1002
  DEFAULT_TEXTS = {
837
1003
  // Textos básicos
838
1004
  bannerMessage: "Utilizamos cookies para melhorar sua experi\xEAncia.",
@@ -862,10 +1028,10 @@ var init_ConsentContext = __esm({
862
1028
  transferCountries: void 0
863
1029
  // Exibido se definido
864
1030
  };
865
- StateCtx = React3.createContext(null);
866
- ActionsCtx = React3.createContext(null);
867
- TextsCtx = React3.createContext(DEFAULT_TEXTS);
868
- HydrationCtx = React3.createContext(false);
1031
+ StateCtx = React4.createContext(null);
1032
+ ActionsCtx = React4.createContext(null);
1033
+ TextsCtx = React4.createContext(DEFAULT_TEXTS);
1034
+ HydrationCtx = React4.createContext(false);
869
1035
  }
870
1036
  });
871
1037
 
@@ -899,6 +1065,112 @@ var init_useConsent = __esm({
899
1065
  }
900
1066
  });
901
1067
 
1068
+ // src/components/PreferencesModal.tsx
1069
+ var PreferencesModal_exports = {};
1070
+ __export(PreferencesModal_exports, {
1071
+ PreferencesModal: () => PreferencesModal2
1072
+ });
1073
+ function PreferencesModal2({
1074
+ DialogProps: DialogProps2,
1075
+ hideBranding = false
1076
+ }) {
1077
+ const { preferences, setPreferences, closePreferences, isModalOpen } = useConsent();
1078
+ const texts = useConsentTexts();
1079
+ const { toggleableCategories } = useCategories();
1080
+ const [tempPreferences, setTempPreferences] = (0, import_react.useState)(
1081
+ () => {
1082
+ const initialPrefs = { necessary: true };
1083
+ toggleableCategories.forEach((category) => {
1084
+ initialPrefs[category.id] = preferences[category.id] ?? false;
1085
+ });
1086
+ return initialPrefs;
1087
+ }
1088
+ );
1089
+ (0, import_react.useEffect)(() => {
1090
+ if (isModalOpen) {
1091
+ const syncedPrefs = { necessary: true };
1092
+ toggleableCategories.forEach((category) => {
1093
+ syncedPrefs[category.id] = preferences[category.id] ?? false;
1094
+ });
1095
+ setTempPreferences(syncedPrefs);
1096
+ }
1097
+ }, [isModalOpen, preferences, toggleableCategories]);
1098
+ const open = DialogProps2?.open ?? isModalOpen ?? false;
1099
+ const handleSave = () => {
1100
+ setPreferences(tempPreferences);
1101
+ };
1102
+ const handleCancel = () => {
1103
+ setTempPreferences(preferences);
1104
+ closePreferences();
1105
+ };
1106
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1107
+ import_Dialog.default,
1108
+ {
1109
+ "aria-labelledby": "cookie-pref-title",
1110
+ open,
1111
+ onClose: handleCancel,
1112
+ ...DialogProps2,
1113
+ children: [
1114
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_DialogTitle.default, { id: "cookie-pref-title", children: texts.modalTitle }),
1115
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_DialogContent.default, { dividers: true, children: [
1116
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_Typography3.default, { variant: "body2", sx: { mb: 2 }, children: texts.modalIntro }),
1117
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_FormGroup.default, { children: [
1118
+ toggleableCategories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1119
+ import_FormControlLabel.default,
1120
+ {
1121
+ control: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1122
+ import_Switch.default,
1123
+ {
1124
+ checked: tempPreferences[category.id] ?? false,
1125
+ onChange: (e) => setTempPreferences((prev) => ({
1126
+ ...prev,
1127
+ [category.id]: e.target.checked
1128
+ }))
1129
+ }
1130
+ ),
1131
+ label: `${category.name} - ${category.description}`
1132
+ },
1133
+ category.id
1134
+ )),
1135
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1136
+ import_FormControlLabel.default,
1137
+ {
1138
+ control: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_Switch.default, { checked: true, disabled: true }),
1139
+ label: texts.necessaryAlwaysOn
1140
+ }
1141
+ )
1142
+ ] })
1143
+ ] }),
1144
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_DialogActions.default, { children: [
1145
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_Button2.default, { variant: "outlined", onClick: handleCancel, children: "Cancelar" }),
1146
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_Button2.default, { variant: "contained", onClick: handleSave, children: texts.save })
1147
+ ] }),
1148
+ !hideBranding && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Branding, { variant: "modal" })
1149
+ ]
1150
+ }
1151
+ );
1152
+ }
1153
+ var import_Button2, import_Dialog, import_DialogActions, import_DialogContent, import_DialogTitle, import_FormControlLabel, import_FormGroup, import_Switch, import_Typography3, import_react, import_jsx_runtime7;
1154
+ var init_PreferencesModal = __esm({
1155
+ "src/components/PreferencesModal.tsx"() {
1156
+ "use strict";
1157
+ import_Button2 = __toESM(require("@mui/material/Button"), 1);
1158
+ import_Dialog = __toESM(require("@mui/material/Dialog"), 1);
1159
+ import_DialogActions = __toESM(require("@mui/material/DialogActions"), 1);
1160
+ import_DialogContent = __toESM(require("@mui/material/DialogContent"), 1);
1161
+ import_DialogTitle = __toESM(require("@mui/material/DialogTitle"), 1);
1162
+ import_FormControlLabel = __toESM(require("@mui/material/FormControlLabel"), 1);
1163
+ import_FormGroup = __toESM(require("@mui/material/FormGroup"), 1);
1164
+ import_Switch = __toESM(require("@mui/material/Switch"), 1);
1165
+ import_Typography3 = __toESM(require("@mui/material/Typography"), 1);
1166
+ import_react = require("react");
1167
+ init_CategoriesContext();
1168
+ init_useConsent();
1169
+ init_Branding();
1170
+ import_jsx_runtime7 = require("react/jsx-runtime");
1171
+ }
1172
+ });
1173
+
902
1174
  // src/index.ts
903
1175
  var index_exports = {};
904
1176
  __export(index_exports, {
@@ -906,10 +1178,8 @@ __export(index_exports, {
906
1178
  ConsentGate: () => ConsentGate,
907
1179
  ConsentProvider: () => ConsentProvider,
908
1180
  ConsentScriptLoader: () => ConsentScriptLoader,
909
- CookieBanner: () => CookieBanner,
910
1181
  DEFAULT_PROJECT_CATEGORIES: () => DEFAULT_PROJECT_CATEGORIES,
911
- FloatingPreferencesButton: () => FloatingPreferencesButton,
912
- PreferencesModal: () => PreferencesModal,
1182
+ PreferencesModal: () => PreferencesModal2,
913
1183
  analyzeDeveloperConfiguration: () => analyzeDeveloperConfiguration,
914
1184
  createGoogleAnalyticsIntegration: () => createGoogleAnalyticsIntegration,
915
1185
  createGoogleTagManagerIntegration: () => createGoogleTagManagerIntegration,
@@ -921,193 +1191,21 @@ __export(index_exports, {
921
1191
  useConsent: () => useConsent,
922
1192
  useConsentHydration: () => useConsentHydration,
923
1193
  useConsentScriptLoader: () => useConsentScriptLoader,
924
- useConsentTexts: () => useConsentTexts,
925
- useCustomCategories: () => useCustomCategories
1194
+ useConsentTexts: () => useConsentTexts
926
1195
  });
927
1196
  module.exports = __toCommonJS(index_exports);
928
-
929
- // src/components/CookieBanner.tsx
930
- var import_Button2 = __toESM(require("@mui/material/Button"), 1);
931
- var import_Box = __toESM(require("@mui/material/Box"), 1);
932
- var import_Paper = __toESM(require("@mui/material/Paper"), 1);
933
- var import_Snackbar = __toESM(require("@mui/material/Snackbar"), 1);
934
- var import_Stack = __toESM(require("@mui/material/Stack"), 1);
935
- var import_Typography3 = __toESM(require("@mui/material/Typography"), 1);
936
- var import_Link2 = __toESM(require("@mui/material/Link"), 1);
937
- init_useConsent();
938
- init_Branding();
939
- var import_jsx_runtime5 = require("react/jsx-runtime");
940
- function CookieBanner({
941
- policyLinkUrl,
942
- debug,
943
- blocking = true,
944
- // Por padrão, bloqueia até decisão
945
- hideBranding = false,
946
- SnackbarProps,
947
- PaperProps
948
- }) {
949
- const { consented, acceptAll, rejectAll, openPreferences } = useConsent();
950
- const texts = useConsentTexts();
951
- const isHydrated = useConsentHydration();
952
- const open = debug ? true : isHydrated && !consented;
953
- if (!open) return null;
954
- const bannerContent = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
955
- import_Paper.default,
956
- {
957
- elevation: 3,
958
- sx: { p: 2, maxWidth: 720, mx: "auto" },
959
- ...PaperProps,
960
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_Stack.default, { spacing: 1, children: [
961
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_Typography3.default, { variant: "body2", children: [
962
- texts.bannerMessage,
963
- " ",
964
- policyLinkUrl && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
965
- import_Link2.default,
966
- {
967
- href: policyLinkUrl,
968
- underline: "hover",
969
- target: "_blank",
970
- rel: "noopener noreferrer",
971
- children: texts.policyLink ?? "Saiba mais"
972
- }
973
- )
974
- ] }),
975
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
976
- import_Stack.default,
977
- {
978
- direction: { xs: "column", sm: "row" },
979
- spacing: 1,
980
- justifyContent: "flex-end",
981
- children: [
982
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_Button2.default, { variant: "outlined", onClick: rejectAll, children: texts.declineAll }),
983
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_Button2.default, { variant: "contained", onClick: acceptAll, children: texts.acceptAll }),
984
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_Button2.default, { variant: "text", onClick: openPreferences, children: texts.preferences })
985
- ]
986
- }
987
- ),
988
- !hideBranding && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Branding, { variant: "banner" })
989
- ] })
990
- }
991
- );
992
- if (blocking) {
993
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
994
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
995
- import_Box.default,
996
- {
997
- sx: {
998
- position: "fixed",
999
- top: 0,
1000
- left: 0,
1001
- right: 0,
1002
- bottom: 0,
1003
- backgroundColor: "rgba(0, 0, 0, 0.5)",
1004
- zIndex: 1299
1005
- // Abaixo do banner mas acima do conteúdo
1006
- }
1007
- }
1008
- ),
1009
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1010
- import_Box.default,
1011
- {
1012
- sx: {
1013
- position: "fixed",
1014
- bottom: 0,
1015
- left: 0,
1016
- right: 0,
1017
- zIndex: 1300,
1018
- // Acima do overlay
1019
- p: 2
1020
- },
1021
- children: bannerContent
1022
- }
1023
- )
1024
- ] });
1025
- }
1026
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1027
- import_Snackbar.default,
1028
- {
1029
- open,
1030
- anchorOrigin: { vertical: "bottom", horizontal: "center" },
1031
- ...SnackbarProps,
1032
- children: bannerContent
1033
- }
1034
- );
1035
- }
1036
-
1037
- // src/index.ts
1038
1197
  init_PreferencesModal();
1039
-
1040
- // src/components/FloatingPreferencesButton.tsx
1041
- var import_CookieOutlined = __toESM(require("@mui/icons-material/CookieOutlined"), 1);
1042
- var import_Fab = __toESM(require("@mui/material/Fab"), 1);
1043
- var import_Tooltip = __toESM(require("@mui/material/Tooltip"), 1);
1044
- var import_styles3 = require("@mui/material/styles");
1045
- init_useConsent();
1046
- var import_jsx_runtime6 = require("react/jsx-runtime");
1047
- function FloatingPreferencesButton({
1048
- position = "bottom-right",
1049
- offset = 24,
1050
- icon = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_CookieOutlined.default, {}),
1051
- tooltip,
1052
- FabProps,
1053
- hideWhenConsented = false
1054
- }) {
1055
- const { openPreferences, consented } = useConsent();
1056
- const theme = (0, import_styles3.useTheme)();
1057
- if (hideWhenConsented && consented) {
1058
- return null;
1059
- }
1060
- const tooltipText = tooltip ?? "Gerenciar Prefer\xEAncias de Cookies";
1061
- const getPosition = () => {
1062
- const styles = {
1063
- position: "fixed",
1064
- zIndex: 1200
1065
- };
1066
- switch (position) {
1067
- case "bottom-left":
1068
- return { ...styles, bottom: offset, left: offset };
1069
- case "bottom-right":
1070
- return { ...styles, bottom: offset, right: offset };
1071
- case "top-left":
1072
- return { ...styles, top: offset, left: offset };
1073
- case "top-right":
1074
- return { ...styles, top: offset, right: offset };
1075
- default:
1076
- return { ...styles, bottom: offset, right: offset };
1077
- }
1078
- };
1079
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_Tooltip.default, { title: tooltipText, placement: "top", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1080
- import_Fab.default,
1081
- {
1082
- size: "medium",
1083
- color: "primary",
1084
- onClick: openPreferences,
1085
- sx: {
1086
- ...getPosition(),
1087
- backgroundColor: theme.palette.primary.main,
1088
- "&:hover": {
1089
- backgroundColor: theme.palette.primary.dark
1090
- }
1091
- },
1092
- "aria-label": tooltipText,
1093
- ...FabProps,
1094
- children: icon
1095
- }
1096
- ) });
1097
- }
1098
-
1099
- // src/index.ts
1100
1198
  init_ConsentContext();
1101
1199
  init_useConsent();
1102
1200
  init_CategoriesContext();
1103
1201
 
1104
1202
  // src/utils/ConsentGate.tsx
1105
1203
  init_useConsent();
1106
- var import_jsx_runtime7 = require("react/jsx-runtime");
1204
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1107
1205
  function ConsentGate(props) {
1108
1206
  const { preferences } = useConsent();
1109
1207
  if (!preferences[props.category]) return null;
1110
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: props.children });
1208
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: props.children });
1111
1209
  }
1112
1210
 
1113
1211
  // src/utils/scriptLoader.ts
@@ -1151,15 +1249,15 @@ function loadScript(id, src, category = null, attrs = {}) {
1151
1249
  init_theme();
1152
1250
 
1153
1251
  // src/utils/ConsentScriptLoader.tsx
1154
- var React4 = __toESM(require("react"), 1);
1252
+ var React5 = __toESM(require("react"), 1);
1155
1253
  init_useConsent();
1156
1254
  function ConsentScriptLoader({
1157
1255
  integrations,
1158
1256
  reloadOnChange = false
1159
1257
  }) {
1160
1258
  const { preferences, consented } = useConsent();
1161
- const loadedScripts = React4.useRef(/* @__PURE__ */ new Set());
1162
- React4.useEffect(() => {
1259
+ const loadedScripts = React5.useRef(/* @__PURE__ */ new Set());
1260
+ React5.useEffect(() => {
1163
1261
  if (!consented) return;
1164
1262
  integrations.forEach(async (integration) => {
1165
1263
  const shouldLoad = preferences[integration.category];
@@ -1177,9 +1275,6 @@ function ConsentScriptLoader({
1177
1275
  integration.init();
1178
1276
  }
1179
1277
  loadedScripts.current.add(integration.id);
1180
- console.log(
1181
- `\u2705 Script loaded: ${integration.id} (${integration.category})`
1182
- );
1183
1278
  } catch (error) {
1184
1279
  console.error(`\u274C Failed to load script: ${integration.id}`, error);
1185
1280
  }
@@ -1190,7 +1285,7 @@ function ConsentScriptLoader({
1190
1285
  }
1191
1286
  function useConsentScriptLoader() {
1192
1287
  const { preferences, consented } = useConsent();
1193
- return React4.useCallback(
1288
+ return React5.useCallback(
1194
1289
  async (integration) => {
1195
1290
  if (!consented) {
1196
1291
  console.warn(
@@ -1216,9 +1311,6 @@ function useConsentScriptLoader() {
1216
1311
  if (integration.init) {
1217
1312
  integration.init();
1218
1313
  }
1219
- console.log(
1220
- `\u2705 Script loaded: ${integration.id} (${integration.category})`
1221
- );
1222
1314
  return true;
1223
1315
  } catch (error) {
1224
1316
  console.error(`\u274C Failed to load script: ${integration.id}`, error);
@@ -1270,8 +1362,8 @@ function createGoogleTagManagerIntegration(config) {
1270
1362
  function createUserWayIntegration(config) {
1271
1363
  return {
1272
1364
  id: "userway",
1273
- category: "marketing",
1274
- // ou poderia ser uma categoria 'accessibility'
1365
+ category: "functional",
1366
+ // Categoria mais apropriada para acessibilidade
1275
1367
  src: `https://cdn.userway.org/widget.js`,
1276
1368
  init: () => {
1277
1369
  if (typeof window !== "undefined") {
@@ -1296,9 +1388,7 @@ init_developerGuidance();
1296
1388
  ConsentGate,
1297
1389
  ConsentProvider,
1298
1390
  ConsentScriptLoader,
1299
- CookieBanner,
1300
1391
  DEFAULT_PROJECT_CATEGORIES,
1301
- FloatingPreferencesButton,
1302
1392
  PreferencesModal,
1303
1393
  analyzeDeveloperConfiguration,
1304
1394
  createGoogleAnalyticsIntegration,
@@ -1311,6 +1401,5 @@ init_developerGuidance();
1311
1401
  useConsent,
1312
1402
  useConsentHydration,
1313
1403
  useConsentScriptLoader,
1314
- useConsentTexts,
1315
- useCustomCategories
1404
+ useConsentTexts
1316
1405
  });