remirror/remirror

View on GitHub
packages/remirror__react-components/src/menus/command-menu-item.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import { ListItemIcon, ListItemText, MenuItem, MenuItemProps, Typography } from '@mui/material';
import React, { FC, MouseEventHandler, ReactNode, useCallback } from 'react';
import { CoreIcon, isString } from '@remirror/core';

import { Icon } from '../icons';
import { useCommandOptionValues, UseCommandOptionValuesParams } from '../use-command-option-values';

interface ButtonIconProps {
  icon: CoreIcon | JSX.Element | null;
}

const MenuItemIcon: FC<ButtonIconProps> = ({ icon }) => {
  if (icon) {
    return (
      <ListItemIcon>{isString(icon) ? <Icon name={icon} size='1rem' /> : <>{icon}</>}</ListItemIcon>
    );
  }

  return null;
};

export interface CommandMenuItemProps
  extends MenuItemProps,
    Omit<UseCommandOptionValuesParams, 'active' | 'attrs'> {
  active?: UseCommandOptionValuesParams['active'];
  commandName: string;
  displayShortcut?: boolean;
  onSelect: () => void;
  icon?: CoreIcon | JSX.Element | null;
  attrs?: UseCommandOptionValuesParams['attrs'];
  label?: NonNullable<ReactNode>;
  description?: NonNullable<ReactNode>;
  displayDescription?: boolean;
}

export const CommandMenuItem: FC<CommandMenuItemProps> = ({
  commandName,
  active = false,
  enabled,
  attrs,
  onSelect,
  onClick,
  icon,
  displayShortcut = true,
  label,
  description,
  displayDescription = true,
  ...rest
}) => {
  const handleClick: MouseEventHandler<HTMLLIElement> = useCallback(
    (e) => {
      onSelect();
      onClick?.(e);
    },
    [onSelect, onClick],
  );

  const handleMouseDown: MouseEventHandler<HTMLLIElement> = useCallback((e) => {
    e.preventDefault();
  }, []);

  const commandOptions = useCommandOptionValues({ commandName, active, enabled, attrs });

  let fallbackIcon = null;

  if (commandOptions.icon) {
    fallbackIcon = isString(commandOptions.icon) ? commandOptions.icon : commandOptions.icon.name;
  }

  const primary = label ?? commandOptions.label ?? '';
  const secondary = displayDescription && (description ?? commandOptions.description);

  return (
    <MenuItem
      selected={active}
      disabled={!enabled}
      onMouseDown={handleMouseDown}
      {...rest}
      onClick={handleClick}
    >
      {icon !== null && <MenuItemIcon icon={icon ?? fallbackIcon} />}
      <ListItemText primary={primary} secondary={secondary} />
      {displayShortcut && commandOptions.shortcut && (
        <Typography variant='body2' color='text.secondary' sx={{ ml: 2 }}>
          {commandOptions.shortcut}
        </Typography>
      )}
    </MenuItem>
  );
};