UNPKG

@spaced-out/ui-design-system

Version:
151 lines (141 loc) 4.09 kB
// @flow strict import * as React from 'react'; import { // $FlowFixMe[untyped-import] autoUpdate, // $FlowFixMe[untyped-import] flip, // $FlowFixMe[untyped-import] FloatingFocusManager, // $FlowFixMe[untyped-import] FloatingPortal, // $FlowFixMe[untyped-import] offset, // $FlowFixMe[untyped-import] shift, // $FlowFixMe[untyped-import] useFloating, } from '@floating-ui/react'; import {includes} from 'lodash'; import {spaceNone, spaceXXSmall} from '../../styles/variables/_space'; import classify from '../../utils/classify'; import {ClickAway} from '../../utils/click-away'; import {mergeRefs} from '../../utils/merge-refs'; import type {AnchorType} from '../ButtonDropdown'; import {Menu} from '../Menu'; import type {ElevationType} from '../Tooltip'; import {getElevationValue} from '../Tooltip'; import type {ButtonTabProps} from './ButtonTab'; import {ButtonTab} from './ButtonTab'; import css from './ButtonTabDropdown.module.css'; export type ButtonTabDropdownProps = { ...ButtonTabProps, title: string, elevation?: ElevationType, dropdownClass?: string, anchorPosition?: AnchorType, ... }; export const ButtonTabDropdown = ({ title, elevation = 'modal', anchorPosition = 'bottom-end', ...buttonTabProps }: ButtonTabDropdownProps): React.Node => { const { size, children, selectedButtonTabId, onButtonTabSelect: onTabSelect, dropdownClass, } = buttonTabProps; const childrenArray = React.Children.toArray(children); const menuOptions = childrenArray.map((child) => { const { id, children, disabled, iconName, iconType, classNames, size: buttonSize, } = child.props; return { key: id, disabled, classNames, label: children, iconLeft: iconName, iconLeftType: iconType, customComponent: children, optionSize: buttonSize ?? size, }; }); const moreTabSelectedId = includes( menuOptions.map(({key}) => key), selectedButtonTabId, ) ? 'more-tab' : selectedButtonTabId; const {x, y, refs, strategy, context} = useFloating({ open: true, strategy: 'absolute', placement: anchorPosition, whileElementsMounted: autoUpdate, middleware: [shift(), flip(), offset(parseInt(spaceXXSmall))], }); return ( <ClickAway> {({isOpen, onOpen, clickAway, boundaryRef, triggerRef}) => ( <div data-testid="ButtonTabDropdown" className={classify(css.buttonTabDropDownWrapper, dropdownClass)} > <ButtonTab {...buttonTabProps} ref={mergeRefs([refs.setReference, triggerRef])} selectedButtonTabId={moreTabSelectedId} onButtonTabSelect={(id, e) => { e?.stopPropagation(); onOpen(); }} > {title} </ButtonTab> {isOpen && ( <FloatingPortal> <FloatingFocusManager modal={false} context={context} initialFocus={refs.reference} > <div className={css.menuWrapper} ref={mergeRefs([refs.setFloating, boundaryRef])} style={{ display: 'flex', position: strategy, top: y ?? spaceNone, left: x ?? spaceNone, '--menu-elevation': getElevationValue(elevation), }} > <Menu onSelect={(option, e) => { onTabSelect && onTabSelect(option.key, e); clickAway(); }} size={size} options={menuOptions} onTabOut={clickAway} selectedKeys={[selectedButtonTabId ?? '']} /> </div> </FloatingFocusManager> </FloatingPortal> )} </div> )} </ClickAway> ); };