@spaced-out/ui-design-system
Version:
Sense UI components library
170 lines (146 loc) • 4.46 kB
Flow
// @flow strict
import * as React from 'react';
import type {MenuClassNames, MenuLabelTooltip} from '../../types/menu';
import type {ClickAwayRefType} from '../../utils/click-away';
import {
getButtonLabelFromSelectedKeys,
getSelectedKeysFromSelectedOption,
} from '../../utils/menu';
import type {ButtonProps} from '../Button';
import type {MenuOption, MenuOptionsVariant, Virtualization} from '../Menu';
import type {BaseTooltipProps, ElevationType} from '../Tooltip';
import type {AnchorType} from './ButtonDropdown';
import {ButtonDropdown} from './ButtonDropdown';
type ClassNames = $ReadOnly<{
buttonWrapper?: string,
dropdownContainer?: string,
buttonIcon?: string,
}>;
export type SimpleButtonDropdownRef = {
selectedKeys?: Array<string>,
};
export type SimpleButtonDropdownProps = {
// Input props
...ButtonProps,
elevation?: ElevationType,
classNames?: ClassNames,
anchorPosition?: AnchorType,
tooltip?: BaseTooltipProps,
// Menu props
options?: Array<MenuOption>,
optionsVariant?: MenuOptionsVariant,
allowSearch?: boolean,
selectedKeys?: Array<string>,
menuVirtualization?: Virtualization,
header?: React.Node,
footer?: React.Node,
menuClassNames?: MenuClassNames,
showLabelTooltip?: MenuLabelTooltip,
allowWrap?: boolean,
// events
onOptionSelect?: (option: MenuOption, ?SyntheticEvent<HTMLElement>) => mixed,
onMenuOpen?: () => mixed,
onMenuClose?: () => mixed,
// Resolvers
resolveLabel?: (option: MenuOption) => string | React.Node,
resolveSecondaryLabel?: (option: MenuOption) => string | React.Node,
clickAwayRef?: ClickAwayRefType,
...
};
const SimpleButtonDropdownBase = (props: SimpleButtonDropdownProps, ref) => {
const {
size = 'medium',
classNames,
anchorPosition,
options,
optionsVariant,
allowSearch,
selectedKeys,
onOptionSelect,
onMenuOpen,
onMenuClose,
resolveLabel,
resolveSecondaryLabel,
children,
isFluid,
menuVirtualization,
header,
footer,
menuClassNames,
showLabelTooltip,
allowWrap = false,
clickAwayRef,
elevation = 'modal',
...buttonProps
} = props;
const [btnText, setBtnText] = React.useState('');
const [buttonDropdownSelectedKeys, setButtonDropdownSelectedKeys] =
React.useState(selectedKeys);
React.useEffect(() => {
const newBtnText = getButtonLabelFromSelectedKeys(selectedKeys, children);
setButtonDropdownSelectedKeys(selectedKeys);
setBtnText(newBtnText);
}, [selectedKeys]);
const handleOptionChange = (selectedOption: MenuOption, e) => {
e?.stopPropagation();
let newSelectedKeys = [];
if (optionsVariant === 'checkbox') {
newSelectedKeys = getSelectedKeysFromSelectedOption(
selectedOption,
buttonDropdownSelectedKeys,
);
} else {
newSelectedKeys = [selectedOption.key];
}
const newBtnText = getButtonLabelFromSelectedKeys(
newSelectedKeys,
children,
);
setButtonDropdownSelectedKeys(newSelectedKeys);
setBtnText(newBtnText);
setTimeout(() => {
onOptionSelect?.(selectedOption, e);
});
};
React.useImperativeHandle(ref, () => ({
selectedKeys: buttonDropdownSelectedKeys,
}));
return (
<ButtonDropdown
{...buttonProps}
anchorPosition={anchorPosition}
classNames={classNames}
size={size}
onOptionSelect={handleOptionChange}
onMenuOpen={onMenuOpen}
elevation={elevation}
onMenuClose={onMenuClose}
clickAwayRef={clickAwayRef}
menu={{
// TODO (Sharad): The isFluid prop here controls menu width unlike ButtonDropdown, and is independent from the isFluid prop in ButtonDropdown. There should be a way to set the isFluid prop of ButtonDropdown.
isFluid,
options,
selectedKeys: buttonDropdownSelectedKeys,
optionsVariant,
allowSearch,
resolveLabel,
resolveSecondaryLabel,
size,
virtualization: menuVirtualization,
header,
footer,
classNames: menuClassNames,
showLabelTooltip,
allowWrap,
}}
>
{optionsVariant === 'checkbox' ? btnText : children}
</ButtonDropdown>
);
};
export const SimpleButtonDropdown: React.AbstractComponent<
SimpleButtonDropdownProps,
SimpleButtonDropdownRef,
> = React.forwardRef<SimpleButtonDropdownProps, SimpleButtonDropdownRef>(
SimpleButtonDropdownBase,
);