Files
2024-02-15 17:01:50 +00:00

92 lines
2.1 KiB
TypeScript

import {forwardRef} from 'react';
import styled from '@emotion/styled';
import type {ButtonProps} from 'sentry/components/button';
import {Button, ButtonLabel} from 'sentry/components/button';
import {IconChevron} from 'sentry/icons';
import {space} from 'sentry/styles/space';
export interface DropdownButtonProps extends Omit<ButtonProps, 'type' | 'prefix'> {
/**
* Forward a ref to the button's root
*/
forwardedRef?: React.ForwardedRef<HTMLButtonElement>;
/**
* Whether or not the button should render as open
*/
isOpen?: boolean;
/**
* The fixed prefix text to show in the button eg: 'Sort By'
*/
prefix?: React.ReactNode;
/**
* Should a chevron icon be shown?
*/
showChevron?: boolean;
}
function DropdownButton({
children,
prefix,
isOpen = false,
showChevron = true,
disabled = false,
forwardedRef,
...props
}: DropdownButtonProps) {
return (
<StyledButton
aria-haspopup="true"
aria-expanded={isOpen}
hasPrefix={!!prefix}
disabled={disabled}
isOpen={isOpen}
ref={forwardedRef}
{...props}
>
{prefix && <LabelText>{prefix}</LabelText>}
{children}
{showChevron && (
<ChevronWrap>
<IconChevron size="xs" direction={isOpen ? 'up' : 'down'} aria-hidden="true" />
</ChevronWrap>
)}
</StyledButton>
);
}
const ChevronWrap = styled('div')`
display: flex;
align-items: center;
margin-left: auto;
padding-left: ${space(0.75)};
flex-shrink: 0;
`;
interface StyledButtonProps
extends Required<Pick<DropdownButtonProps, 'isOpen' | 'disabled'>> {
hasPrefix?: boolean;
}
const StyledButton = styled(Button)<StyledButtonProps>`
position: relative;
max-width: 100%;
z-index: 2;
${p => (p.isOpen || p.disabled) && 'box-shadow: none;'}
${p => p.hasPrefix && `${ButtonLabel} {font-weight: 400;}`}
`;
const LabelText = styled('span')`
&:after {
content: ':';
}
font-weight: 600;
padding-right: ${space(0.75)};
`;
export default forwardRef<HTMLButtonElement, DropdownButtonProps>((props, ref) => (
<DropdownButton forwardedRef={ref} {...props} />
));