Files
helm-dashboard/frontend/src/components/common/DropDown.tsx
yuri-sakharov 7572f00f7c Huge bump of versions + husky + fixed DropDown key issue and pointer (#628)
* Bump lint-staged

* Check

* Check

* Added husky

* Check

* Check

* Check

* Check

* Check

* Check

* Check

* Check

* Fix husky

* Used * instead **/* in lint-staged

* Bump tailwindcss and related

* Added @tailwindcss/vite and removed postcss

* Added lint into staged

* Bump @babel/core and updated .prettierignore

* Removed tailwind.config.cjs

* Added ThemeInit

* Added cursor-pointer to Help dropdown

* Bump react-router

* Removed @types/uuid and react-router-dom

* Bump diff2html, prettier, @typescript-eslint/eslint-plugin, @typescript-eslint/parser

* removed vite-plugin-html-config and @babel/core

* removed "@eslint/eslintrc" and "@eslint/js"

* Removed redundant link

* Returned plugins and source to index.css

* Set dark to false in tailwindcss

* Fixed storybook

* Fixed useGetLatestVersion with correct gcTime: 0 option

* Added eslint-plugin-prettier

* Removed spaces

* ClustersList.tsx improved and type fixes for another files

* Repository.tsx improved

* Huge fix of types

* Huge fix of types missed

* Fixed type of SingleValue

* Added cursor pointer
2025-11-29 16:49:51 +00:00

108 lines
2.8 KiB
TypeScript

import { Fragment, ReactNode, useEffect, useRef, useState } from "react";
import ArrowDownIcon from "../../assets/arrow-down-icon.svg";
export type DropDownItem = {
id: string;
text?: string;
icon?: ReactNode;
onClick?: () => void;
isSeparator?: boolean;
isDisabled?: boolean;
};
export type DropDownProps = {
items: DropDownItem[];
};
type PopupState = {
isOpen: boolean;
X: number;
Y: number;
};
function DropDown({ items }: DropDownProps) {
const [popupState, setPopupState] = useState<PopupState>({
isOpen: false,
X: 0,
Y: 0,
});
const modalRef = useRef<HTMLDivElement>(null);
const handleClickOutside = (event: MouseEvent) => {
if (modalRef.current && !modalRef.current.contains(event.target as Node)) {
setPopupState((prev) => ({
...prev,
isOpen: false,
}));
}
};
useEffect(() => {
if (popupState.isOpen) {
document.addEventListener("mousedown", handleClickOutside);
} else {
document.removeEventListener("mousedown", handleClickOutside);
}
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [popupState.isOpen]);
return (
<>
<div className="relative flex flex-col items-center">
<button
onClick={(e) => {
setPopupState((prev) => ({
...prev,
isOpen: !prev.isOpen,
X: e.pageX,
Y: e.pageY,
}));
}}
className="flex items-center justify-between cursor-pointer"
>
Help
<img src={ArrowDownIcon} className="ml-2 w-[10px] h-[10px]" />
</button>
</div>
{popupState.isOpen && (
<div
ref={modalRef}
className={`z-10 flex flex-col py-1 gap-1 bg-white mt-3 absolute rounded-sm border top-[${popupState.Y}] left-[${popupState.X}] border-gray-200`}
>
{items.map((item) => (
<Fragment key={item.id}>
{item.isSeparator ? (
<div className="bg-gray-300 h-[1px]" />
) : (
<div
onClick={() => {
item.onClick?.();
setPopupState((prev) => ({
...prev,
isOpen: false,
}));
}}
className={`cursor-pointer font-normal flex items-center gap-2 py-1 pl-3 pr-7 hover:bg-dropdown ${
item.isDisabled
? "cursor-default hover:bg-transparent text-gray-400"
: ""
}`}
>
{item.icon && <span> {item.icon ?? null}</span>}
<span>{item.text}</span>
</div>
)}
</Fragment>
))}
</div>
)}
</>
);
}
export default DropDown;