improve notepad features and add drawing canvas
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s
This commit is contained in:
parent
e73d754082
commit
de1b8a5638
20 changed files with 1732 additions and 141 deletions
65
website/src/components/CompactDropdown.jsx
Normal file
65
website/src/components/CompactDropdown.jsx
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Rôle : fournit un dropdown compact réutilisable pour menus d'icônes, couleurs et actions rapides.
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
export function CompactDropdown({
|
||||
className = "",
|
||||
menuClassName = "",
|
||||
label,
|
||||
openOnHover = false,
|
||||
closeOnMouseLeave = false,
|
||||
preventMouseDown = false,
|
||||
renderTrigger,
|
||||
children
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const rootRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return undefined;
|
||||
|
||||
function handlePointerDown(event) {
|
||||
if (!rootRef.current?.contains(event.target)) setOpen(false);
|
||||
}
|
||||
|
||||
function handleKeyDown(event) {
|
||||
if (event.key === "Escape") setOpen(false);
|
||||
}
|
||||
|
||||
document.addEventListener("pointerdown", handlePointerDown);
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
return () => {
|
||||
document.removeEventListener("pointerdown", handlePointerDown);
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, [open]);
|
||||
|
||||
function close() {
|
||||
setOpen(false);
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
setOpen((value) => !value);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${className} ${open ? "is-open" : ""}`.trim()}
|
||||
ref={rootRef}
|
||||
onMouseEnter={openOnHover ? () => setOpen(true) : undefined}
|
||||
onMouseLeave={closeOnMouseLeave ? close : undefined}
|
||||
onFocusCapture={openOnHover ? () => setOpen(true) : undefined}
|
||||
onBlurCapture={(event) => {
|
||||
if (!event.currentTarget.contains(event.relatedTarget)) close();
|
||||
}}
|
||||
onMouseDown={preventMouseDown ? (event) => event.preventDefault() : undefined}
|
||||
aria-label={label}
|
||||
>
|
||||
{renderTrigger({ open, toggle, close })}
|
||||
{open && (
|
||||
<div className={`${menuClassName} is-open`.trim()} aria-label={label}>
|
||||
{children({ close })}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue