UNPKG

@spaced-out/ui-design-system

Version:
124 lines (115 loc) 3.56 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 {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 type {MenuOption, MenuProps} from '../../Menu'; import {Menu} from '../../Menu'; import type {ElevationType} from '../../Tooltip'; import {getElevationValue} from '../../Tooltip'; import type {TabProps} from '../Tab'; import {Tab} from '../Tab'; import css from './TabDropdown.module.css'; type ClassNames = $ReadOnly<{wrapper?: string}>; export type TabDropdownProps = { anchorPosition?: AnchorType, size?: 'medium' | 'small', props?: { tab: TabProps, menu: MenuProps, }, onOptionSelect?: (option: MenuOption, ?SyntheticEvent<HTMLElement>) => mixed, classNames?: ClassNames, selected?: boolean, disabled?: boolean, elevation?: ElevationType, }; export const TabDropdown = ({ anchorPosition = 'bottom-start', size, onOptionSelect, props, elevation = 'modal', classNames, }: TabDropdownProps): React.Node => { 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="TabDropdown" className={classify(css.tabDropdownContainer, classNames?.wrapper)} > <Tab {...props?.tab} size={size} ref={mergeRefs([refs.setReference, triggerRef])} onClick={(e) => { e.stopPropagation(); onOpen(); }} classNames={{ wrapper: css.dotTabWrapper, iconTextWrap: css.dotTextWrap, }} /> {isOpen && props?.menu && ( <FloatingPortal> <FloatingFocusManager modal={false} context={context} initialFocus={refs.reference} > <div ref={mergeRefs([refs.setFloating, boundaryRef])} className={css.menuWrapper} style={{ display: 'flex', position: strategy, top: y ?? spaceNone, left: x ?? spaceNone, '--menu-elevation': getElevationValue(elevation), }} > <Menu {...props.menu} onSelect={(option, e) => { onOptionSelect && onOptionSelect(option, e); clickAway(); }} size={props.menu.size || size} onTabOut={clickAway} /> </div> </FloatingFocusManager> </FloatingPortal> )} </div> )} </ClickAway> ); };