All files / src/components tile.tsx

100% Statements 6/6
90.9% Branches 10/11
100% Functions 2/2
100% Lines 6/6

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                                                                                                              7x 2x       7x                           2x   2x   2x                                                                                        
import {
  type CSSProperties,
  type FC,
  type HTMLAttributes,
  type PropsWithChildren,
  type ReactElement,
  type ReactNode,
} from 'react';
import cn from 'classnames';
 
import type { HeadingLevels } from '../types/common';
 
import '../styles/components/tile.scss';
 
type Props = {
  /**
   * The tile title
   */
  title: ReactNode;
  /**
   * The tile title heading level
   */
  headingLevel?: Exclude<HeadingLevels, 'h6'>;
  /**
   * The tile subtitle
   */
  subtitle?: ReactNode;
  /**
   * The background color
   */
  backgroundColor?: string;
  /**
   * The background image
   */
  backgroundImage?: ReactNode;
  /**
   * Whether to create a gradient based on the backgroung color or not
   */
  gradient?: boolean;
  /**
   * The width Tile square (css value). By default it will use the
   * width of the provided container.
   */
  width?: string;
  /**
   * Whether to slide up the description when the mouse is over the tile.
   * Can be useful if the description text is long.
   */
  descriptionSlideUp?: boolean;
  /**
   * Target/link of the list item when clicking on it
   */
  link?: ReactElement<{ [key: string]: unknown }>;
};
 
const nextHeading = (level: Exclude<HeadingLevels, 'h6'>): HeadingLevels =>
  `h${+level[1] + 1}` as HeadingLevels;
 
export const Tile: FC<
  PropsWithChildren<Props> & HTMLAttributes<HTMLDivElement>
> = ({
  title,
  headingLevel = 'h2',
  subtitle,
  backgroundColor,
  backgroundImage,
  gradient = false,
  width,
  className,
  style,
  children,
  descriptionSlideUp = false,
  link,
}) => {
  const TitleHeadingLevel = headingLevel;
  // eslint-disable-next-line @eslint-react/static-components
  const SubtitleHeadingLevel = nextHeading(headingLevel);
 
  return (
    <div
      className={cn(className, 'tile', {
        'tile-gradient': gradient,
        'tile--has-link': link,
      })}
      style={
        {
          ...style,
          '--tile-background': backgroundColor,
          width,
        } as CSSProperties
      }
    >
      {link && <link.type {...link.props} aria-hidden="true" tabIndex={-1} />}
      <div className="tile__background-image" aria-hidden="true">
        {backgroundImage}
      </div>
      <div className="tile__main-content">
        <TitleHeadingLevel className="tile__header big">
          {title}
        </TitleHeadingLevel>
        {subtitle && (
          // eslint-disable-next-line @eslint-react/static-components
          <SubtitleHeadingLevel className="tile__subtitle small">
            {subtitle}
          </SubtitleHeadingLevel>
        )}
      </div>
      {children && (
        <small
          className={cn(
            'tile__description',
            descriptionSlideUp && 'tile__description--animated'
          )}
        >
          {children}
        </small>
      )}
    </div>
  );
};
 
export default Tile;