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
---
 .../molecules/modals/tooltip/tooltip.tsx           | 99 ++++++++++++++++++++++
 1 file changed, 99 insertions(+)
 create mode 100644 src/components/molecules/modals/tooltip/tooltip.tsx

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

diff --git a/src/components/molecules/modals/tooltip/tooltip.tsx b/src/components/molecules/modals/tooltip/tooltip.tsx
new file mode 100644
index 0000000..b3a3f5a
--- /dev/null
+++ b/src/components/molecules/modals/tooltip/tooltip.tsx
@@ -0,0 +1,99 @@
+import { type FC, type MouseEventHandler, useRef } from 'react';
+import { useIntl } from 'react-intl';
+import { useOnClickOutside } from '../../../../utils/hooks';
+import { Heading, Icon } from '../../../atoms';
+import { HelpButton } from '../../buttons';
+import { Modal, type ModalProps } from '../modal';
+import styles from './tooltip.module.scss';
+
+export type TooltipProps = Omit<ModalProps, 'heading'> & {
+  /**
+   * The tooltip direction when opening.
+   *
+   * @default "downwards"
+   */
+  direction?: 'downwards' | 'upwards';
+  /**
+   * The tooltip heading.
+   */
+  heading: string;
+  /**
+   * Should the tooltip be opened?
+   *
+   * @default false
+   */
+  isOpen?: boolean;
+  /**
+   * A callback function to trigger when clicking outside the modal.
+   */
+  onClickOutside?: () => void;
+  /**
+   * An event handler when clicking on the help button.
+   */
+  onToggle?: MouseEventHandler<HTMLButtonElement>;
+};
+
+/**
+ * Tooltip component
+ *
+ * Render a button and a modal. Note: you should add a CSS rule
+ * `position: relative;` on the consumer.
+ */
+export const Tooltip: FC<TooltipProps> = ({
+  children,
+  className = '',
+  direction = 'downwards',
+  heading,
+  isOpen,
+  onClickOutside,
+  onToggle,
+  ...props
+}) => {
+  const intl = useIntl();
+  const helpLabel = intl.formatMessage({
+    defaultMessage: 'Show help',
+    description: 'Tooltip: show help label',
+    id: '1Xgg7+',
+  });
+  const directionModifier =
+    direction === 'upwards' ? 'tooltip--up' : 'tooltip--down';
+  const visibilityModifier = isOpen ? 'tooltip--visible' : 'tooltip--hidden';
+  const tooltipClass = `${styles.tooltip} ${styles[directionModifier]} ${styles[visibilityModifier]} ${className}`;
+  const btnRef = useRef<HTMLButtonElement>(null);
+
+  const closeModal = (target: Node) => {
+    if (!onClickOutside) return;
+
+    if (btnRef.current && !btnRef.current.contains(target)) {
+      onClickOutside();
+    }
+  };
+
+  const modalRef = useOnClickOutside<HTMLDivElement>(closeModal);
+
+  return (
+    <>
+      <Modal
+        {...props}
+        className={tooltipClass}
+        heading={
+          <Heading className={styles.heading} isFake level={6}>
+            {heading}
+          </Heading>
+        }
+        icon={<Icon aria-hidden shape="help" size="sm" />}
+        kind="secondary"
+        ref={modalRef}
+      >
+        {children}
+      </Modal>
+      <HelpButton
+        className={styles.btn}
+        isPressed={isOpen}
+        label={helpLabel}
+        onClick={onToggle}
+        ref={btnRef}
+      />
+    </>
+  );
+};
-- 
cgit v1.2.3

