This PR moves the entire project to Typescript. Due to the ~1000 ignores this will lead to a messy codebase for a while, but the churn is worth it – all of those ignore comments are places that were never type-safe previously. closes #1282
116 lines
2.6 KiB
TypeScript
116 lines
2.6 KiB
TypeScript
import { find } from "lodash";
|
|
import * as React from "react";
|
|
import { useMenuState, MenuButton } from "reakit/Menu";
|
|
import styled from "styled-components";
|
|
import Button, { Inner } from "~/components/Button";
|
|
import ContextMenu from "~/components/ContextMenu";
|
|
import MenuItem from "~/components/ContextMenu/MenuItem";
|
|
import HelpText from "~/components/HelpText";
|
|
|
|
type TFilterOption = {
|
|
key: string;
|
|
label: string;
|
|
note?: string;
|
|
};
|
|
|
|
type Props = {
|
|
options: TFilterOption[];
|
|
activeKey: string | null | undefined;
|
|
defaultLabel?: string;
|
|
selectedPrefix?: string;
|
|
className?: string;
|
|
onSelect: (key: string | null | undefined) => void;
|
|
};
|
|
|
|
const FilterOptions = ({
|
|
options,
|
|
activeKey = "",
|
|
defaultLabel = "Filter options",
|
|
selectedPrefix = "",
|
|
className,
|
|
onSelect,
|
|
}: Props) => {
|
|
const menu = useMenuState({
|
|
modal: true,
|
|
});
|
|
const selected =
|
|
find(options, {
|
|
key: activeKey,
|
|
}) || options[0];
|
|
|
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'label' does not exist on type 'number | ... Remove this comment to see the full error message
|
|
const selectedLabel = selected ? `${selectedPrefix} ${selected.label}` : "";
|
|
|
|
return (
|
|
<Wrapper>
|
|
<MenuButton {...menu}>
|
|
{(props) => (
|
|
<StyledButton {...props} className={className} neutral disclosure>
|
|
{activeKey ? selectedLabel : defaultLabel}
|
|
</StyledButton>
|
|
)}
|
|
</MenuButton>
|
|
<ContextMenu aria-label={defaultLabel} {...menu}>
|
|
{options.map((option) => (
|
|
<MenuItem
|
|
key={option.key}
|
|
onClick={() => {
|
|
onSelect(option.key);
|
|
menu.hide();
|
|
}}
|
|
selected={option.key === activeKey}
|
|
{...menu}
|
|
>
|
|
{option.note ? (
|
|
<LabelWithNote>
|
|
{option.label}
|
|
<Note>{option.note}</Note>
|
|
</LabelWithNote>
|
|
) : (
|
|
option.label
|
|
)}
|
|
</MenuItem>
|
|
))}
|
|
</ContextMenu>
|
|
</Wrapper>
|
|
);
|
|
};
|
|
|
|
const Note = styled(HelpText)`
|
|
margin-top: 2px;
|
|
margin-bottom: 0;
|
|
line-height: 1.2em;
|
|
font-size: 14px;
|
|
font-weight: 400;
|
|
color: ${(props) => props.theme.textTertiary};
|
|
`;
|
|
|
|
const LabelWithNote = styled.div`
|
|
font-weight: 500;
|
|
text-align: left;
|
|
|
|
&:hover ${Note} {
|
|
color: ${(props) => props.theme.white50};
|
|
}
|
|
`;
|
|
|
|
const StyledButton = styled(Button)`
|
|
box-shadow: none;
|
|
text-transform: none;
|
|
border-color: transparent;
|
|
|
|
&:hover {
|
|
background: transparent;
|
|
}
|
|
|
|
${Inner} {
|
|
line-height: 28px;
|
|
}
|
|
`;
|
|
|
|
const Wrapper = styled.div`
|
|
margin-right: 8px;
|
|
`;
|
|
|
|
export default FilterOptions;
|