enhance BsmDropdownButton with maxHeight calculation and item height tracking

This commit is contained in:
Shidorien
2026-01-30 21:07:28 +01:00
parent 756cccf85c
commit 74b91ee277
@@ -1,4 +1,4 @@
import { forwardRef, LegacyRef, useImperativeHandle, useRef, useState } from "react";
import { forwardRef, LegacyRef, useEffect, useImperativeHandle, useRef, useState } from "react";
import { BsmIconType, BsmIcon } from "../svgs/bsm-icon.component";
import { BsmButton, BsmButtonType } from "./bsm-button.component";
import { useTranslation } from "renderer/hooks/use-translation.hook";
@@ -32,14 +32,25 @@ type Props = {
children?: JSX.Element;
text?: string;
textClassName?: string;
maxVisibleItems?: number;
};
export const BsmDropdownButton = forwardRef(({ className, classNames, buttonColor, items, align, withBar = true, icon = "settings", buttonClassName, menuTranslationY, children, text, textClassName }: Props, fowardRed) => {
export const BsmDropdownButton = forwardRef(({ className, classNames, buttonColor, items, align, withBar = true, icon = "settings", buttonClassName, menuTranslationY, children, text, textClassName, maxVisibleItems }: Props, fowardRed) => {
const [expanded, setExpanded] = useState(false);
const t = useTranslation();
const ref = useRef(fowardRed);
useClickOutside(ref, () => setExpanded(false));
const itemRef = useRef<HTMLDivElement>(null);
const [itemHeight, setItemHeight] = useState<number>();
const maxHeight = itemHeight && maxVisibleItems ? itemHeight * maxVisibleItems + 8 : undefined;
useEffect(() => {
if (itemRef.current) {
setItemHeight(itemRef.current.offsetHeight);
}
}, [items]);
useImperativeHandle(
fowardRed,
() => ({
@@ -73,13 +84,13 @@ export const BsmDropdownButton = forwardRef(({ className, classNames, buttonColo
})();
return (
<div ref={ref as unknown as LegacyRef<HTMLDivElement>} className={cn(className, classNames?.mainContainer)}>
<div ref={ref as unknown as LegacyRef<HTMLDivElement>} className={cn(className, classNames?.mainContainer)} >
<BsmButton onClick={() => setExpanded(!expanded)} className={cn(buttonClassName ?? defaultButtonClassName, classNames?.button)} icon={icon} active={expanded} textClassName={textClassName} onClickOutside={handleClickOutside} withBar={withBar} text={text} typeColor={buttonColor} iconClassName={classNames?.iconClassName}/>
<div className={cn(`py-1 w-fit absolute cursor-pointer top-[calc(100%-4px)] rounded-md bg-inherit text-sm text-gray-800 dark:text-gray-200 shadow-md shadow-black transition-[scale] duration-150 ease-in-out ${alignClass}`, classNames?.itemsContainer)} style={{ scale: expanded ? "1" : "0", translate: `0 ${menuTranslationY}` }}>
<div className={cn(`py-1 w-fit absolute cursor-pointer top-[calc(100%-4px)] rounded-md bg-inherit text-sm text-gray-800 dark:text-gray-200 shadow-md shadow-black transition-[scale] duration-150 ease-in-out ${alignClass} overflow-y-auto scrollbar-thin `, classNames?.itemsContainer)} style={{ scale: expanded ? "1" : "0", translate: `0 ${menuTranslationY}`, maxHeight}}>
{items?.map(
i =>
(i, index) =>
i && (
<div key={crypto.randomUUID()} onClick={() => { setExpanded(() => false); i.onClick?.()}} className="flex w-full px-3 py-2 hover:backdrop-brightness-150">
<div ref={index === 0 ? itemRef : undefined} key={crypto.randomUUID()} onClick={() => { setExpanded(() => false); i.onClick?.()}} className="flex w-full px-3 py-2 hover:backdrop-brightness-150">
{i.icon && <BsmIcon icon={i.icon} className="h-5 w-5 mr-1 text-inherit" />}
<span className="w-max">{t(i.text)}</span>
</div>