@spaced-out/ui-design-system
Version:
Sense UI components library
171 lines (154 loc) • 3.98 kB
Flow
//@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>
);
},
);