icon.tsx 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. import classNames from 'classnames';
  2. import CheckBoxOutlineBlankIcon from '@/material-icons/400-24px/check_box_outline_blank.svg?react';
  3. import { isProduction } from 'mastodon/utils/environment';
  4. interface SVGPropsWithTitle extends React.SVGProps<SVGSVGElement> {
  5. title?: string;
  6. }
  7. export type IconProp = React.FC<SVGPropsWithTitle>;
  8. interface Props extends React.SVGProps<SVGSVGElement> {
  9. children?: never;
  10. id: string;
  11. icon: IconProp;
  12. title?: string;
  13. }
  14. export const Icon: React.FC<Props> = ({
  15. id,
  16. icon: IconComponent,
  17. className,
  18. title: titleProp,
  19. ...other
  20. }) => {
  21. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
  22. if (!IconComponent) {
  23. if (!isProduction()) {
  24. throw new Error(
  25. `<Icon id="${id}" className="${className}"> is missing an "icon" prop.`,
  26. );
  27. }
  28. IconComponent = CheckBoxOutlineBlankIcon;
  29. }
  30. const ariaHidden = titleProp ? undefined : true;
  31. const role = !ariaHidden ? 'img' : undefined;
  32. // Set the title to an empty string to remove the built-in SVG one if any
  33. // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
  34. const title = titleProp || '';
  35. return (
  36. <IconComponent
  37. className={classNames('icon', `icon-${id}`, className)}
  38. title={title}
  39. aria-hidden={ariaHidden}
  40. role={role}
  41. {...other}
  42. />
  43. );
  44. };