(react) add a popover component

A design system needs a popover mecanism.
In the select component, this logic is handled by downshift.
We introduce a new component, responsible to open an element in
a popin and close it when the user click outside of it.
This commit is contained in:
Lebaud Antoine
2023-06-02 12:04:36 +02:00
committed by aleb_the_flash
parent f967775fb6
commit 1d1cf81cf6
6 changed files with 99 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
---
"@openfun/cunningham-react": minor
---
add a popover component

View File

@@ -0,0 +1,11 @@
.c__popover {
position: absolute;
display: flex;
width: fit-content;
z-index: 1;
&:not(&--borderless) {
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
background-color: var(--c--components--forms-datepicker--menu-background-color);
}
}

View File

@@ -0,0 +1,36 @@
import React, { useRef, useState } from "react";
import { Meta } from "@storybook/react";
import { Button } from ":/components/Button";
import { Popover } from ":/components/Popover/index";
export default {
title: "Components/Popover",
component: Popover,
} as Meta<typeof Popover>;
export const Default = () => {
const [isOpen, setIsOpen] = useState(false);
const parentRef = useRef<HTMLDivElement>(null);
return (
<div ref={parentRef} style={{ width: "fit-content" }}>
<Button onClick={() => setIsOpen(!isOpen)}>Toggle</Button>
{isOpen && (
<Popover parentRef={parentRef} onClickOutside={() => setIsOpen(false)}>
<div
style={{
height: "200px",
width: "200px",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
I am open
</div>
</Popover>
)}
</div>
);
};

View File

@@ -0,0 +1,28 @@
import React, { PropsWithChildren, RefObject } from "react";
import classNames from "classnames";
import { useHandleClickOutside } from ":/hooks/useHandleClickOutside";
type PopoverProps = PropsWithChildren & {
parentRef: RefObject<HTMLDivElement>;
onClickOutside: () => void;
borderless?: boolean;
};
export const Popover = ({
parentRef,
children,
onClickOutside,
borderless = false,
}: PopoverProps) => {
useHandleClickOutside(parentRef, onClickOutside);
return (
<div
className={classNames("c__popover", {
"c__popover--borderless": borderless,
})}
>
{children}
</div>
);
};

View File

@@ -0,0 +1,18 @@
import { RefObject, useEffect } from "react";
export const useHandleClickOutside = (
ref: RefObject<HTMLDivElement>,
onClickOutside: any
) => {
useEffect(() => {
const outsideListenerEvent = (event: MouseEvent) => {
if (!ref.current || ref.current.contains(event.target as Node)) {
return;
}
onClickOutside();
};
document.addEventListener("click", outsideListenerEvent, true);
return () =>
document.removeEventListener("click", outsideListenerEvent, true);
}, []);
};

View File

@@ -13,6 +13,7 @@
@import './components/Forms/Switch';
@import './components/Loader';
@import './components/Pagination';
@import './components/Popover';
* {
font-family: var(--c--theme--font--families--base);