@spaced-out/ui-design-system
Version:
Sense UI components library
171 lines (147 loc) • 4.12 kB
Flow
// @flow strict
import * as React from 'react';
import type {MenuClassNames, MenuLabelTooltip} from '../../types/menu';
import type {ClickAwayRefType} from '../../utils/click-away';
import {
getSelectedKeysFromSelectedOption,
getTextLabelFromSelectedKeys,
} from '../../utils/menu';
import type {InputProps} from '../Input';
import type {MenuOption, MenuOptionsVariant, Virtualization} from '../Menu';
import type {ElevationType} from '../Tooltip';
import {Dropdown} from './Dropdown';
type ClassNames = $ReadOnly<{
wrapper?: string,
box?: string,
}>;
export type SimpleDropdownRef = {
selectedKeys?: Array<string>,
};
export type SimpleDropdownProps = {
// Input props
...InputProps,
elevation?: ElevationType,
classNames?: ClassNames,
clickAwayRef?: ClickAwayRefType,
// Menu props
options?: Array<MenuOption>,
optionsVariant?: MenuOptionsVariant,
allowSearch?: boolean,
selectedKeys?: Array<string>,
isMenuFluid?: boolean,
menuVirtualization?: Virtualization,
header?: React.Node,
footer?: React.Node,
menuClassNames?: MenuClassNames,
showLabelTooltip?: MenuLabelTooltip,
allowWrap?: boolean,
staticLabels?: {
RESULT?: string,
RESULTS?: string,
SEARCH_PLACEHOLDER?: string,
},
// events
onChange?: (option: MenuOption, ?SyntheticEvent<HTMLElement>) => mixed,
onMenuOpen?: () => mixed,
onMenuClose?: () => mixed,
// Resolvers
resolveLabel?: (option: MenuOption) => string | React.Node,
resolveSecondaryLabel?: (option: MenuOption) => string | React.Node,
...
};
const SimpleDropdownBase = (props: SimpleDropdownProps, ref) => {
const {
size = 'medium',
classNames,
placeholder = 'Select...',
options,
optionsVariant,
allowSearch,
selectedKeys,
onChange,
onMenuOpen,
onMenuClose,
resolveLabel,
elevation = 'modal',
menuVirtualization,
resolveSecondaryLabel,
isMenuFluid = true,
header,
footer,
menuClassNames,
showLabelTooltip,
clickAwayRef,
allowWrap = false,
staticLabels,
...inputProps
} = props;
const [dropdownInputText, setDropdownInputText] = React.useState('');
const [dropdownSelectedKeys, setDropdownSelectedKeys] =
React.useState(selectedKeys);
React.useEffect(() => {
const newDropdownText = getTextLabelFromSelectedKeys(selectedKeys, options);
setDropdownSelectedKeys(selectedKeys);
setDropdownInputText(newDropdownText);
}, [selectedKeys]);
const handleOptionChange = (selectedOption: MenuOption, e) => {
e?.stopPropagation();
let newSelectedKeys = [];
if (optionsVariant === 'checkbox') {
newSelectedKeys = getSelectedKeysFromSelectedOption(
selectedOption,
dropdownSelectedKeys,
);
} else {
newSelectedKeys = [selectedOption.key];
}
const newDropdownText = getTextLabelFromSelectedKeys(
newSelectedKeys,
options,
);
setDropdownSelectedKeys(newSelectedKeys);
setDropdownInputText(newDropdownText);
setTimeout(() => {
onChange?.(selectedOption, e);
});
};
React.useImperativeHandle(ref, () => ({
selectedKeys: dropdownSelectedKeys,
}));
return (
<Dropdown
{...inputProps}
classNames={classNames}
size={size}
elevation={elevation}
placeholder={placeholder}
onChange={handleOptionChange}
onMenuOpen={onMenuOpen}
onMenuClose={onMenuClose}
dropdownInputText={dropdownInputText}
clickAwayRef={clickAwayRef}
menu={{
options,
selectedKeys: dropdownSelectedKeys,
optionsVariant,
allowSearch,
resolveLabel,
resolveSecondaryLabel,
virtualization: menuVirtualization,
size,
isFluid: isMenuFluid,
header,
footer,
classNames: menuClassNames,
showLabelTooltip,
allowWrap,
staticLabels,
}}
/>
);
};
export const SimpleDropdown: React.AbstractComponent<
SimpleDropdownProps,
SimpleDropdownRef,
> = React.forwardRef<SimpleDropdownProps, SimpleDropdownRef>(
SimpleDropdownBase,
);