UNPKG

@spaced-out/ui-design-system

Version:
170 lines (146 loc) 4.46 kB
// @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, );