@nocios/crudify-ui 3.0.58 → 3.0.62

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.d.mts CHANGED
@@ -399,6 +399,7 @@ type NotificationOptions = {
399
399
  vertical: "top" | "bottom";
400
400
  horizontal: "left" | "center" | "right";
401
401
  };
402
+ allowHtml?: boolean;
402
403
  };
403
404
  type SessionProviderProps = {
404
405
  children: ReactNode;
@@ -751,11 +752,13 @@ interface Notification {
751
752
  severity: NotificationSeverity;
752
753
  autoHideDuration?: number;
753
754
  persistent?: boolean;
755
+ allowHtml?: boolean;
754
756
  }
755
757
  interface GlobalNotificationContextValue {
756
758
  showNotification: (message: string, severity?: NotificationSeverity, options?: {
757
759
  autoHideDuration?: number;
758
760
  persistent?: boolean;
761
+ allowHtml?: boolean;
759
762
  }) => string;
760
763
  hideNotification: (id: string) => void;
761
764
  clearAllNotifications: () => void;
@@ -769,6 +772,7 @@ interface GlobalNotificationProviderProps {
769
772
  horizontal: "left" | "center" | "right";
770
773
  };
771
774
  enabled?: boolean;
775
+ allowHtml?: boolean;
772
776
  }
773
777
  declare const GlobalNotificationProvider: React.FC<GlobalNotificationProviderProps>;
774
778
  declare const useGlobalNotification: () => GlobalNotificationContextValue;
package/dist/index.d.ts CHANGED
@@ -399,6 +399,7 @@ type NotificationOptions = {
399
399
  vertical: "top" | "bottom";
400
400
  horizontal: "left" | "center" | "right";
401
401
  };
402
+ allowHtml?: boolean;
402
403
  };
403
404
  type SessionProviderProps = {
404
405
  children: ReactNode;
@@ -751,11 +752,13 @@ interface Notification {
751
752
  severity: NotificationSeverity;
752
753
  autoHideDuration?: number;
753
754
  persistent?: boolean;
755
+ allowHtml?: boolean;
754
756
  }
755
757
  interface GlobalNotificationContextValue {
756
758
  showNotification: (message: string, severity?: NotificationSeverity, options?: {
757
759
  autoHideDuration?: number;
758
760
  persistent?: boolean;
761
+ allowHtml?: boolean;
759
762
  }) => string;
760
763
  hideNotification: (id: string) => void;
761
764
  clearAllNotifications: () => void;
@@ -769,6 +772,7 @@ interface GlobalNotificationProviderProps {
769
772
  horizontal: "left" | "center" | "right";
770
773
  };
771
774
  enabled?: boolean;
775
+ allowHtml?: boolean;
772
776
  }
773
777
  declare const GlobalNotificationProvider: React.FC<GlobalNotificationProviderProps>;
774
778
  declare const useGlobalNotification: () => GlobalNotificationContextValue;
package/dist/index.js CHANGED
@@ -1401,15 +1401,33 @@ var isTokenExpired = (token) => {
1401
1401
  var import_react6 = require("react");
1402
1402
  var import_material = require("@mui/material");
1403
1403
  var import_uuid = require("uuid");
1404
+ var import_dompurify = __toESM(require("dompurify"));
1404
1405
  var import_jsx_runtime4 = require("react/jsx-runtime");
1405
1406
  var GlobalNotificationContext = (0, import_react6.createContext)(null);
1407
+ var sanitizeNotificationContent = (html) => {
1408
+ return import_dompurify.default.sanitize(html, {
1409
+ // Solo permitir tags seguros para notificaciones
1410
+ ALLOWED_TAGS: ["b", "i", "em", "strong", "br", "span"],
1411
+ ALLOWED_ATTR: ["class"],
1412
+ // Remover scripts y eventos
1413
+ FORBID_TAGS: ["script", "iframe", "object", "embed"],
1414
+ FORBID_ATTR: ["onload", "onerror", "onclick", "onmouseover", "onfocus", "onblur"],
1415
+ // Configuración adicional de seguridad
1416
+ WHOLE_DOCUMENT: false,
1417
+ RETURN_DOM: false,
1418
+ RETURN_DOM_FRAGMENT: false,
1419
+ RETURN_TRUSTED_TYPE: false
1420
+ });
1421
+ };
1406
1422
  var GlobalNotificationProvider = ({
1407
1423
  children,
1408
1424
  maxNotifications = 5,
1409
1425
  defaultAutoHideDuration = 6e3,
1410
1426
  position = { vertical: "top", horizontal: "right" },
1411
- enabled = false
1427
+ enabled = false,
1412
1428
  // ✅ Por defecto DESACTIVADO
1429
+ allowHtml = false
1430
+ // Por defecto no permitir HTML
1413
1431
  }) => {
1414
1432
  const [notifications, setNotifications] = (0, import_react6.useState)([]);
1415
1433
  const showNotification = (0, import_react6.useCallback)(
@@ -1417,13 +1435,23 @@ var GlobalNotificationProvider = ({
1417
1435
  if (!enabled) {
1418
1436
  return "";
1419
1437
  }
1438
+ if (!message || typeof message !== "string") {
1439
+ console.warn("\u26A0\uFE0F GlobalNotificationProvider: Invalid message provided");
1440
+ return "";
1441
+ }
1442
+ if (message.length > 1e3) {
1443
+ console.warn("\u26A0\uFE0F GlobalNotificationProvider: Message too long, truncating");
1444
+ message = message.substring(0, 1e3) + "...";
1445
+ }
1420
1446
  const id = (0, import_uuid.v4)();
1421
1447
  const newNotification = {
1422
1448
  id,
1423
1449
  message,
1424
1450
  severity,
1425
1451
  autoHideDuration: options?.autoHideDuration ?? defaultAutoHideDuration,
1426
- persistent: options?.persistent ?? false
1452
+ persistent: options?.persistent ?? false,
1453
+ allowHtml: options?.allowHtml ?? allowHtml
1454
+ // Usar valor del provider por defecto
1427
1455
  };
1428
1456
  setNotifications((prev) => {
1429
1457
  const updatedNotifications = prev.length >= maxNotifications ? prev.slice(-(maxNotifications - 1)) : prev;
@@ -1431,7 +1459,7 @@ var GlobalNotificationProvider = ({
1431
1459
  });
1432
1460
  return id;
1433
1461
  },
1434
- [maxNotifications, defaultAutoHideDuration, enabled]
1462
+ [maxNotifications, defaultAutoHideDuration, enabled, allowHtml]
1435
1463
  );
1436
1464
  const hideNotification = (0, import_react6.useCallback)((id) => {
1437
1465
  setNotifications((prev) => prev.filter((notification) => notification.id !== id));
@@ -1513,7 +1541,7 @@ var NotificationItem = ({ notification, onClose }) => {
1513
1541
  maxWidth: "400px",
1514
1542
  wordBreak: "break-word"
1515
1543
  },
1516
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { dangerouslySetInnerHTML: { __html: notification.message } })
1544
+ children: notification.allowHtml ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { dangerouslySetInnerHTML: { __html: sanitizeNotificationContent(notification.message) } }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: notification.message })
1517
1545
  }
1518
1546
  )
1519
1547
  }
@@ -1657,7 +1685,9 @@ function SessionProvider(props) {
1657
1685
  enabled: props.showNotifications,
1658
1686
  maxNotifications: props.notificationOptions?.maxNotifications || 5,
1659
1687
  defaultAutoHideDuration: props.notificationOptions?.defaultAutoHideDuration || 6e3,
1660
- position: props.notificationOptions?.position || { vertical: "top", horizontal: "right" }
1688
+ position: props.notificationOptions?.position || { vertical: "top", horizontal: "right" },
1689
+ allowHtml: props.notificationOptions?.allowHtml || false
1690
+ // Pasar allowHtml desde notificationOptions
1661
1691
  };
1662
1692
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GlobalNotificationProvider, { ...notificationConfig, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InnerSessionProvider, { ...props }) });
1663
1693
  }
@@ -4778,10 +4808,7 @@ var useCrudifyWithNotifications = (options = {}) => {
4778
4808
  moduleKey = actionConfig.moduleKey;
4779
4809
  }
4780
4810
  }
4781
- if (operation === "validateAndResetPassword") {
4782
- const message = getSafeTranslation("resetPassword.successMessage", "Contrase\xF1a restablecida exitosamente");
4783
- showNotification(message, "success", { autoHideDuration });
4784
- } else if (shouldShowSuccessNotification(operation, moduleKey)) {
4811
+ if (shouldShowSuccessNotification(operation, moduleKey)) {
4785
4812
  const message = getSuccessMessage(operation, moduleKey, actionConfig);
4786
4813
  showNotification(message, "success", { autoHideDuration });
4787
4814
  }
package/dist/index.mjs CHANGED
@@ -1328,15 +1328,33 @@ var isTokenExpired = (token) => {
1328
1328
  import { useState as useState4, createContext as createContext4, useContext as useContext4, useCallback as useCallback2, useEffect as useEffect5 } from "react";
1329
1329
  import { Snackbar, Alert, Box, Portal } from "@mui/material";
1330
1330
  import { v4 as uuidv4 } from "uuid";
1331
+ import DOMPurify from "dompurify";
1331
1332
  import { jsx as jsx4, jsxs } from "react/jsx-runtime";
1332
1333
  var GlobalNotificationContext = createContext4(null);
1334
+ var sanitizeNotificationContent = (html) => {
1335
+ return DOMPurify.sanitize(html, {
1336
+ // Solo permitir tags seguros para notificaciones
1337
+ ALLOWED_TAGS: ["b", "i", "em", "strong", "br", "span"],
1338
+ ALLOWED_ATTR: ["class"],
1339
+ // Remover scripts y eventos
1340
+ FORBID_TAGS: ["script", "iframe", "object", "embed"],
1341
+ FORBID_ATTR: ["onload", "onerror", "onclick", "onmouseover", "onfocus", "onblur"],
1342
+ // Configuración adicional de seguridad
1343
+ WHOLE_DOCUMENT: false,
1344
+ RETURN_DOM: false,
1345
+ RETURN_DOM_FRAGMENT: false,
1346
+ RETURN_TRUSTED_TYPE: false
1347
+ });
1348
+ };
1333
1349
  var GlobalNotificationProvider = ({
1334
1350
  children,
1335
1351
  maxNotifications = 5,
1336
1352
  defaultAutoHideDuration = 6e3,
1337
1353
  position = { vertical: "top", horizontal: "right" },
1338
- enabled = false
1354
+ enabled = false,
1339
1355
  // ✅ Por defecto DESACTIVADO
1356
+ allowHtml = false
1357
+ // Por defecto no permitir HTML
1340
1358
  }) => {
1341
1359
  const [notifications, setNotifications] = useState4([]);
1342
1360
  const showNotification = useCallback2(
@@ -1344,13 +1362,23 @@ var GlobalNotificationProvider = ({
1344
1362
  if (!enabled) {
1345
1363
  return "";
1346
1364
  }
1365
+ if (!message || typeof message !== "string") {
1366
+ console.warn("\u26A0\uFE0F GlobalNotificationProvider: Invalid message provided");
1367
+ return "";
1368
+ }
1369
+ if (message.length > 1e3) {
1370
+ console.warn("\u26A0\uFE0F GlobalNotificationProvider: Message too long, truncating");
1371
+ message = message.substring(0, 1e3) + "...";
1372
+ }
1347
1373
  const id = uuidv4();
1348
1374
  const newNotification = {
1349
1375
  id,
1350
1376
  message,
1351
1377
  severity,
1352
1378
  autoHideDuration: options?.autoHideDuration ?? defaultAutoHideDuration,
1353
- persistent: options?.persistent ?? false
1379
+ persistent: options?.persistent ?? false,
1380
+ allowHtml: options?.allowHtml ?? allowHtml
1381
+ // Usar valor del provider por defecto
1354
1382
  };
1355
1383
  setNotifications((prev) => {
1356
1384
  const updatedNotifications = prev.length >= maxNotifications ? prev.slice(-(maxNotifications - 1)) : prev;
@@ -1358,7 +1386,7 @@ var GlobalNotificationProvider = ({
1358
1386
  });
1359
1387
  return id;
1360
1388
  },
1361
- [maxNotifications, defaultAutoHideDuration, enabled]
1389
+ [maxNotifications, defaultAutoHideDuration, enabled, allowHtml]
1362
1390
  );
1363
1391
  const hideNotification = useCallback2((id) => {
1364
1392
  setNotifications((prev) => prev.filter((notification) => notification.id !== id));
@@ -1440,7 +1468,7 @@ var NotificationItem = ({ notification, onClose }) => {
1440
1468
  maxWidth: "400px",
1441
1469
  wordBreak: "break-word"
1442
1470
  },
1443
- children: /* @__PURE__ */ jsx4("span", { dangerouslySetInnerHTML: { __html: notification.message } })
1471
+ children: notification.allowHtml ? /* @__PURE__ */ jsx4("span", { dangerouslySetInnerHTML: { __html: sanitizeNotificationContent(notification.message) } }) : /* @__PURE__ */ jsx4("span", { children: notification.message })
1444
1472
  }
1445
1473
  )
1446
1474
  }
@@ -1584,7 +1612,9 @@ function SessionProvider(props) {
1584
1612
  enabled: props.showNotifications,
1585
1613
  maxNotifications: props.notificationOptions?.maxNotifications || 5,
1586
1614
  defaultAutoHideDuration: props.notificationOptions?.defaultAutoHideDuration || 6e3,
1587
- position: props.notificationOptions?.position || { vertical: "top", horizontal: "right" }
1615
+ position: props.notificationOptions?.position || { vertical: "top", horizontal: "right" },
1616
+ allowHtml: props.notificationOptions?.allowHtml || false
1617
+ // Pasar allowHtml desde notificationOptions
1588
1618
  };
1589
1619
  return /* @__PURE__ */ jsx5(GlobalNotificationProvider, { ...notificationConfig, children: /* @__PURE__ */ jsx5(InnerSessionProvider, { ...props }) });
1590
1620
  }
@@ -4764,10 +4794,7 @@ var useCrudifyWithNotifications = (options = {}) => {
4764
4794
  moduleKey = actionConfig.moduleKey;
4765
4795
  }
4766
4796
  }
4767
- if (operation === "validateAndResetPassword") {
4768
- const message = getSafeTranslation("resetPassword.successMessage", "Contrase\xF1a restablecida exitosamente");
4769
- showNotification(message, "success", { autoHideDuration });
4770
- } else if (shouldShowSuccessNotification(operation, moduleKey)) {
4797
+ if (shouldShowSuccessNotification(operation, moduleKey)) {
4771
4798
  const message = getSuccessMessage(operation, moduleKey, actionConfig);
4772
4799
  showNotification(message, "success", { autoHideDuration });
4773
4800
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocios/crudify-ui",
3
- "version": "3.0.58",
3
+ "version": "3.0.62",
4
4
  "description": "Biblioteca de componentes UI para Crudify",
5
5
  "author": "Nocios",
6
6
  "license": "MIT",
@@ -26,8 +26,10 @@
26
26
  "@mui/material": "^7.1.0",
27
27
  "@mui/x-data-grid": "^8.5.1",
28
28
  "@nocios/crudify-browser": "^2.0.6",
29
+ "@types/dompurify": "^3.0.5",
29
30
  "@types/uuid": "^10.0.0",
30
31
  "crypto-js": "^4.2.0",
32
+ "dompurify": "^3.2.7",
31
33
  "i18next-browser-languagedetector": "^8.1.0",
32
34
  "i18next-http-backend": "^3.0.2",
33
35
  "react": "^19.1.0",