index.tsx 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import React, { FC, useState, useEffect, MouseEventHandler } from "react";
  2. import { createPortal } from "react-dom";
  3. import { Modal as BsModal } from "bootstrap";
  4. // Este componente es un react portal. No se va a montar adentro de el componente donde lo uses.
  5. // Cuando lo uses, va a montarse siempre en el mismo lugar, pero tenes acceso a todos sus eventos de todas formas.
  6. const Modal: FC<ModalProps> = ({
  7. children,
  8. accept,
  9. dismiss,
  10. acceptText = "Aceptar",
  11. dismissText = "Cancelar",
  12. title,
  13. buttons = true,
  14. staticBackdrop = false,
  15. }) => {
  16. // Mounting point
  17. const root = document.getElementById("modal-portal");
  18. const [bsModal, setBsModal] = useState<BsModal | null>(null);
  19. useEffect(() => {
  20. const modalEl = document.getElementById("page-modal");
  21. let modalTemp: null | BsModal = null;
  22. if (!modalEl) return;
  23. console.log("Effect run", { staticBackdrop });
  24. if (staticBackdrop) {
  25. console.log({ modalEl });
  26. modalEl.setAttribute("data-bs-backdrop", "static");
  27. }
  28. if (!bsModal) {
  29. modalTemp = new BsModal(modalEl);
  30. setBsModal(modalTemp);
  31. }
  32. modalTemp?.show();
  33. return () => {
  34. modalTemp?.hide();
  35. modalEl?.removeAttribute("data-bs-backdrop");
  36. };
  37. }, []);
  38. const content = (
  39. <div className="modal-content">
  40. {title ? (
  41. <div className="modal-header">
  42. <h5 className="modal-title">{title}</h5>
  43. <button
  44. type="button"
  45. className="btn-close"
  46. data-bs-dismiss="modal"
  47. aria-label="Close"
  48. ></button>
  49. </div>
  50. ) : null}
  51. <div className="modal-body">{children}</div>
  52. {buttons && (dismiss || accept) && (
  53. <div className="modal-footer">
  54. {dismiss && (
  55. <button
  56. type="button"
  57. className="btn btn-secondary"
  58. data-bs-dismiss="modal"
  59. onClick={dismiss}
  60. >
  61. {dismissText}
  62. </button>
  63. )}
  64. {accept && (
  65. <button type="button" onClick={accept} className="btn btn-primary">
  66. {acceptText}
  67. </button>
  68. )}
  69. </div>
  70. )}
  71. </div>
  72. );
  73. if (!root) return null;
  74. return createPortal(content, root);
  75. };
  76. interface ModalProps {
  77. title?: string;
  78. buttons?: boolean;
  79. dismiss?: MouseEventHandler<HTMLButtonElement>;
  80. accept?: MouseEventHandler<HTMLButtonElement>;
  81. dismissText?: string;
  82. acceptText?: string;
  83. staticBackdrop?: boolean;
  84. }
  85. export default Modal;