sendou.ink/app/components/elements/Menu.tsx
Kalle fef1ffc955
Design refresh + a bunch of stuff (#2864)
Co-authored-by: hfcRed <hfcred@gmx.net>
2026-03-19 17:51:42 +02:00

107 lines
2.1 KiB
TypeScript

import clsx from "clsx";
import {
Header,
Menu,
MenuItem,
type MenuItemProps,
MenuTrigger,
Popover,
type PopoverProps,
Section,
} from "react-aria-components";
import { Image } from "../Image";
import styles from "./Menu.module.css";
interface SendouMenuProps {
trigger: React.ReactNode;
scrolling?: boolean;
opensLeft?: boolean;
children: React.ReactNode;
popoverClassName?: string;
placement?: PopoverProps["placement"];
}
export function SendouMenu({
children,
trigger,
opensLeft,
scrolling,
placement,
}: SendouMenuProps) {
return (
<MenuTrigger>
{trigger}
<Popover
placement={placement}
className={clsx(styles.popover, "scrollbar", {
[styles.scrolling]: scrolling,
[styles.popoverOpensLeft]: !opensLeft,
})}
>
<Menu className={styles.itemsContainer}>{children}</Menu>
</Popover>
</MenuTrigger>
);
}
export interface SendouMenuItemProps extends MenuItemProps {
icon?: React.ReactNode;
imagePath?: string;
isActive?: boolean;
isDestructive?: boolean;
}
export function SendouMenuSection({
children,
headerText,
}: {
children: React.ReactNode;
headerText?: string;
}) {
return (
<Section>
{headerText ? (
<Header className={styles.menuHeader}>{headerText}</Header>
) : null}
{children}
</Section>
);
}
export function SendouMenuItem(props: SendouMenuItemProps) {
const textValue =
props.textValue ??
(typeof props.children === "string" ? props.children : undefined);
return (
<MenuItem
{...props}
textValue={textValue}
className={({ isSelected, isDisabled }) =>
clsx(styles.item, {
[styles.itemSelected]: isSelected,
[styles.itemDisabled]: isDisabled,
[styles.itemActive]: props.isActive,
[styles.itemDestructive]: props.isDestructive,
})
}
>
{/** biome-ignore lint/complexity/noUselessFragments: Biome v2 migration */}
<>
{props.icon ? (
<span className={styles.itemIcon}>{props.icon}</span>
) : null}
{props.imagePath ? (
<Image
path={props.imagePath}
alt=""
width={20}
height={20}
className={styles.itemImg}
/>
) : null}
{props.children}
</>
</MenuItem>
);
}