From 3ff4c37a7a2c40340c17f9e6c1754444bce0f839 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Tue, 31 Oct 2023 16:00:45 +0100
Subject: refactor(components): rewrite Modal component

* add an optional close button
* add an icon prop
---
 src/components/molecules/modals/modal/modal.tsx | 103 ++++++++++++++++++++++++
 1 file changed, 103 insertions(+)
 create mode 100644 src/components/molecules/modals/modal/modal.tsx

(limited to 'src/components/molecules/modals/modal/modal.tsx')

diff --git a/src/components/molecules/modals/modal/modal.tsx b/src/components/molecules/modals/modal/modal.tsx
new file mode 100644
index 0000000..ed55488
--- /dev/null
+++ b/src/components/molecules/modals/modal/modal.tsx
@@ -0,0 +1,103 @@
+import {
+  type ForwardRefRenderFunction,
+  type HTMLAttributes,
+  type ReactNode,
+  forwardRef,
+} from 'react';
+import { Button, Icon } from '../../../atoms';
+import styles from './modal.module.scss';
+
+export type ModalProps = HTMLAttributes<HTMLDivElement> & {
+  /**
+   * The modal body.
+   */
+  children: ReactNode;
+  /**
+   * The close button label.
+   */
+  closeBtnLabel?: string;
+  /**
+   * The modal title.
+   */
+  heading?: ReactNode;
+  /**
+   * Define an icon to illustrate the modal.
+   */
+  icon?: ReactNode;
+  /**
+   * The modal kind.
+   *
+   * @default 'primary'
+   */
+  kind?: 'primary' | 'secondary';
+  /**
+   * A callback function to handle close button action.
+   */
+  onClose?: () => void;
+};
+
+const ModalWithRef: ForwardRefRenderFunction<HTMLDivElement, ModalProps> = (
+  {
+    children,
+    className = '',
+    closeBtnLabel,
+    heading,
+    icon,
+    kind = 'primary',
+    onClose,
+    ...props
+  },
+  ref
+) => {
+  const hasHeader = !!heading || !!icon || !!closeBtnLabel;
+  const modalClass = [
+    styles.modal,
+    styles[hasHeader ? 'modal--has-header' : ''],
+    styles[closeBtnLabel ? 'modal--has-btn' : ''],
+    styles[`modal--${kind}`],
+    className,
+  ].join(' ');
+
+  return (
+    <div {...props} className={modalClass} ref={ref}>
+      {hasHeader ? (
+        <div className={styles.header}>
+          {icon ? (
+            <div aria-hidden className={styles.icon}>
+              {icon}
+            </div>
+          ) : null}
+          {heading ? <div className={styles.title}>{heading}</div> : null}
+          {closeBtnLabel ? (
+            <Button
+              aria-label={closeBtnLabel}
+              className={styles.btn}
+              onClick={onClose}
+              // eslint-disable-next-line react/jsx-no-literals
+              kind="neutral"
+              // eslint-disable-next-line react/jsx-no-literals
+              shape="initial"
+            >
+              <Icon
+                aria-hidden
+                className={styles.icon}
+                // eslint-disable-next-line react/jsx-no-literals
+                shape="cross"
+                // eslint-disable-next-line react/jsx-no-literals
+                size="xs"
+              />
+            </Button>
+          ) : null}
+        </div>
+      ) : null}
+      {children}
+    </div>
+  );
+};
+
+/**
+ * Modal component
+ *
+ * Render a modal component.
+ */
+export const Modal = forwardRef(ModalWithRef);
-- 
cgit v1.2.3

