Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Orthogroup tree table protein filter #1252

Merged
merged 11 commits into from
Oct 31, 2024
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { ReactNode, useState, useEffect, useMemo } from 'react';
import {
ReactNode,
useState,
useEffect,
useMemo,
forwardRef,
useImperativeHandle,
} from 'react';
import { Popover } from '@material-ui/core';
import SwissArmyButton from '../SwissArmyButton';
import { gray } from '../../../definitions/colors';
Expand Down Expand Up @@ -66,6 +73,11 @@ const defaultStyle: ButtonStyleSpec = {
},
};

export interface PopoverButtonHandle {
/** Closes the popover */
close: () => void;
}

export interface PopoverButtonProps {
/** Contents of the menu when opened */
children: ReactNode;
Expand All @@ -87,86 +99,96 @@ export interface PopoverButtonProps {
/**
* Renders a button that display `children` in a popover widget.
*/
export default function PopoverButton(props: PopoverButtonProps) {
const {
children,
buttonDisplayContent,
onClose,
setIsPopoverOpen,
isDisabled = false,
styleOverrides = {},
} = props;
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);

const finalStyle = useMemo(
() => merge({}, defaultStyle, styleOverrides),
[styleOverrides]
);

const onCloseHandler = () => {
setAnchorEl(null);
onClose && onClose();
};

useEffect(() => {
if (!setIsPopoverOpen) return;
if (anchorEl) {
setIsPopoverOpen(true);
} else {
setIsPopoverOpen(false);
}
}, [anchorEl, setIsPopoverOpen]);

const menu = (
<Popover
id="dropdown"
aria-expanded={!!anchorEl}
open={Boolean(anchorEl)}
onClose={onCloseHandler}
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
keepMounted
>
{children}
</Popover>
);

const button = (
<SwissArmyButton
text={buttonDisplayContent}
textTransform="none"
onPress={(event) => setAnchorEl(event.currentTarget)}
disabled={isDisabled}
styleSpec={finalStyle}
icon={ArrowDown}
iconPosition="right"
additionalAriaProperties={{
'aria-controls': 'dropdown',
'aria-haspopup': 'true',
}}
/>
);

return (
<div
style={{
width: 'fit-content',
...(isDisabled ? { cursor: 'not-allowed' } : {}),
}}
onClick={(event) => {
// prevent click event from propagating to ancestor nodes
event.stopPropagation();
}}
>
{button}
{menu}
</div>
);
}

const PopoverButton = forwardRef<PopoverButtonHandle, PopoverButtonProps>(
function PopoverButton(props, ref) {
const {
children,
buttonDisplayContent,
onClose,
setIsPopoverOpen,
isDisabled = false,
styleOverrides = {},
} = props;
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);

const finalStyle = useMemo(
() => merge({}, defaultStyle, styleOverrides),
[styleOverrides]
);

const onCloseHandler = () => {
setAnchorEl(null);
onClose && onClose();
};

// Expose the `close()` method to external components via ref
useImperativeHandle(ref, () => ({
close: onCloseHandler,
}));

useEffect(() => {
if (!setIsPopoverOpen) return;
if (anchorEl) {
setIsPopoverOpen(true);
} else {
setIsPopoverOpen(false);
}
}, [anchorEl, setIsPopoverOpen]);

const menu = (
<Popover
id="dropdown"
aria-expanded={!!anchorEl}
open={Boolean(anchorEl)}
onClose={onCloseHandler}
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
keepMounted
>
{children}
</Popover>
);

const button = (
<SwissArmyButton
text={buttonDisplayContent}
textTransform="none"
onPress={(event) => setAnchorEl(event.currentTarget)}
disabled={isDisabled}
styleSpec={finalStyle}
icon={ArrowDown}
iconPosition="right"
additionalAriaProperties={{
'aria-controls': 'dropdown',
'aria-haspopup': 'true',
}}
/>
);

return (
<div
style={{
width: 'fit-content',
...(isDisabled ? { cursor: 'not-allowed' } : {}),
}}
onClick={(event) => {
// prevent click event from propagating to ancestor nodes
event.stopPropagation();
}}
>
{button}
{menu}
</div>
);
}
);

export default PopoverButton;
Loading
Loading