UNPKG

@spaced-out/ui-design-system

Version:
171 lines (154 loc) 3.98 kB
//@flow strict import * as React from 'react'; import type {ColorTypes} from '../../types/typography'; import classify from '../../utils/classify'; import type {IconProps} from '../Icon'; import {Icon} from '../Icon'; import type {TextProps} from '../Text'; import {ButtonTextMedium, TEXT_COLORS} from '../Text'; import {Truncate} from '../Truncate'; import css from './SubMenu.module.css'; export const SubMenuItemIcon = ({ className, ...props }: IconProps): React.Node => ( <Icon {...props} size="small" color={TEXT_COLORS.inverseSecondary} className={classify(css.menuIcon, className)} /> ); SubMenuItemIcon.displayName = 'SubMenuItemIcon'; export const SubMenuItemText = ({ children, className, ...props }: TextProps): React.Node => ( <ButtonTextMedium {...props} className={classify(css.subMenuItemText, className)} color={TEXT_COLORS.inversePrimary} > <Truncate showFullTextOnHover={true}>{children}</Truncate> </ButtonTextMedium> ); SubMenuItemText.displayName = 'SubMenuItemText'; export type SubMenuItemBadgesProps = { children?: React.Node, className?: string, ... }; export const SubMenuItemBadges = ({ children, className, ...props }: SubMenuItemBadgesProps): React.Node => ( <div {...props} className={classify(css.subMenuItemBadges, className)}> {children} </div> ); SubMenuItemBadges.displayName = 'SubMenuItemBadges'; export type SubMenuItemActionProps = { isMenuItemSelected?: boolean, children?: React.Node, color?: ColorTypes, className?: string, ... }; export const SubMenuItemAction: React$AbstractComponent< SubMenuItemActionProps, HTMLElement, > = React.forwardRef( ( {children, className, ...props}: SubMenuItemActionProps, ref, ): React.Node => ( <div {...props} className={classify(css.actionItems, className)} ref={ref}> {children} </div> ), ); SubMenuItemAction.displayName = 'SubMenuItemAction'; type ClassNames = $ReadOnly<{wrapper?: string}>; export type SubMenuItemProps = { classNames?: ClassNames, children?: React.Node, selectedMenuKey?: string, disabled?: boolean, onChange?: (selectedMenuKey: string) => mixed, menuKey: string, ... }; export const SubMenuItem: React$AbstractComponent< SubMenuItemProps, HTMLElement, > = React.forwardRef( ( { children, selectedMenuKey, disabled, classNames, onChange, menuKey, ...props }: SubMenuItemProps, ref, ): React.Node => { const onChangeHandler = () => { if (!disabled) { onChange?.(menuKey); } }; const onKeyDownHandler = (e) => { if (e.key === 'Enter') { onChangeHandler(); } }; const selected = selectedMenuKey === menuKey; const getNamedComp = (comp: string) => { const childrenArray = React.Children.toArray(children); if (childrenArray.length) { const nodes: React.Node[] = []; for (const child of childrenArray) { if (child?.type?.displayName === comp) { nodes.push( React.cloneElement(child, { selected, disabled, }), ); } } return nodes.length > 1 ? nodes : nodes[0]; } return null; }; return ( <div {...props} className={classify( css.menuItem, { [css.selected]: selected, [css.disabled]: disabled, }, classNames?.wrapper, )} onKeyDown={onKeyDownHandler} onClick={onChangeHandler} tabIndex={disabled ? '-1' : 0} disabled={disabled} ref={ref} > <div className={css.menuIconName}> {getNamedComp('SubMenuItemIcon')} {getNamedComp('SubMenuItemText')} {getNamedComp('SubMenuItemBadges')} </div> {getNamedComp('SubMenuItemAction')} </div> ); }, );