@spaced-out/ui-design-system
Version:
Sense UI components library
168 lines (143 loc) • 4.21 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 {AnchorType} from '../ButtonDropdown';
import type {MenuOption, MenuOptionsVariant, Virtualization} from '../Menu';
import type {ElevationType} from '../Tooltip';
import {InlineDropdown} from './InlineDropdown';
type ClassNames = $ReadOnly<{
buttonWrapper?: string,
dropdownContainer?: string,
}>;
export type SimpleInlineDropdownRef = {
selectedKeys?: Array<string>,
};
export type SimpleInlineDropdownProps = {
// Input props
...ButtonProps,
elevation?: ElevationType,
classNames?: ClassNames,
anchorPosition?: AnchorType,
// Menu props
options?: Array<MenuOption>,
optionsVariant?: MenuOptionsVariant,
allowSearch?: boolean,
selectedKeys?: Array<string>,
showLabelTooltip?: MenuLabelTooltip,
allowWrap?: boolean,
// events
onOptionSelect?: (option: MenuOption, ?SyntheticEvent<HTMLElement>) => mixed,
onMenuOpen?: () => mixed,
onMenuClose?: () => mixed,
menuVirtualization?: Virtualization,
header?: React.Node,
footer?: React.Node,
menuClassNames?: MenuClassNames,
// Resolvers
resolveLabel?: (option: MenuOption) => string | React.Node,
resolveSecondaryLabel?: (option: MenuOption) => string | React.Node,
clickAwayRef?: ClickAwayRefType,
...
};
const SimpleInlineDropdownBase = (props: SimpleInlineDropdownProps, ref) => {
const {
size = 'medium',
classNames,
anchorPosition,
options,
optionsVariant,
allowSearch,
selectedKeys,
onOptionSelect,
onMenuOpen,
onMenuClose,
resolveLabel,
resolveSecondaryLabel,
children,
isFluid,
menuVirtualization,
header,
footer,
menuClassNames,
showLabelTooltip,
clickAwayRef,
allowWrap = false,
elevation = 'modal',
...buttonProps
} = props;
const [btnText, setBtnText] = React.useState('');
const [inlineDropdownSelectedKeys, setInlineDropdownSelectedKeys] =
React.useState(selectedKeys);
React.useEffect(() => {
const newBtnText = getButtonLabelFromSelectedKeys(selectedKeys, children);
setInlineDropdownSelectedKeys(selectedKeys);
setBtnText(newBtnText);
}, [selectedKeys]);
const handleOptionChange = (selectedOption: MenuOption, e) => {
e?.stopPropagation();
let newSelectedKeys = [];
if (optionsVariant === 'checkbox') {
newSelectedKeys = getSelectedKeysFromSelectedOption(
selectedOption,
inlineDropdownSelectedKeys,
);
} else {
newSelectedKeys = [selectedOption.key];
}
const newBtnText = getButtonLabelFromSelectedKeys(
newSelectedKeys,
children,
);
setInlineDropdownSelectedKeys(newSelectedKeys);
setBtnText(newBtnText);
setTimeout(() => {
onOptionSelect?.(selectedOption, e);
});
};
React.useImperativeHandle(ref, () => ({
selectedKeys: inlineDropdownSelectedKeys,
}));
return (
<InlineDropdown
{...buttonProps}
anchorPosition={anchorPosition}
classNames={classNames}
size={size}
onOptionSelect={handleOptionChange}
onMenuOpen={onMenuOpen}
onMenuClose={onMenuClose}
clickAwayRef={clickAwayRef}
elevation={elevation}
menu={{
isFluid,
options,
selectedKeys: inlineDropdownSelectedKeys,
optionsVariant,
allowSearch,
resolveLabel,
resolveSecondaryLabel,
size: size === 'extraSmall' ? 'small' : size,
virtualization: menuVirtualization,
header,
footer,
classNames: menuClassNames,
showLabelTooltip,
allowWrap,
}}
>
{optionsVariant === 'checkbox' ? btnText : children}
</InlineDropdown>
);
};
export const SimpleInlineDropdown: React.AbstractComponent<
SimpleInlineDropdownProps,
SimpleInlineDropdownRef,
> = React.forwardRef<SimpleInlineDropdownProps, SimpleInlineDropdownRef>(
SimpleInlineDropdownBase,
);