Source

components/Wrapper/Wrapper.tsx

import { useEffect, useRef, useContext } from 'react';
import { store } from '../../store/store';
import styleSheet from './Wrapper.styleSheet';
import { columnsMinWidthCalc } from '../../utils/processing/columnsMinWidthCalc/columnsMinWidthCalc';
import { cx } from '../../utils/style/emotion';
import { getTableBorderWidth } from '../../utils/processing/getTableBorderWidth/getTableBorderWidth';

/**
 * @namespace Wrapper
 */

interface WrapperProps {
  className?: string;
  children: React.ReactElement | React.ReactElement[];
}

/**
 * The Wrapper component to wrap any component of the pluggin.
 * Has a useEffect to calculate the width of the pluggin container on mount + on each window resize event.
 * Has a useEffect to calculate the minimum width of each column on mount (no reason to have later change).
 * @memberof Wrapper
 * @function
 * @return {React.ReactElement} jsx to be injected in the html.
 */
export const Wrapper = ({
  children,
  className,
}: WrapperProps): React.ReactElement => {
  const { headings, data, width, style, dispatch } = useContext(store);
  const ref = useRef<HTMLElement>(null);

  useEffect(() => {
    if (ref.current) {
      const columnsMinWidth = columnsMinWidthCalc(
        headings,
        data,
        ref.current,
        style
      );
      dispatch({ type: 'setColumnsMinWidth', payload: columnsMinWidth });
    }
  }, [ref, dispatch, headings, data, style]);

  useEffect(() => {
    const updateWidth = (): void => {
      if (ref.current) {
        const refStyle: CSSStyleDeclaration = getComputedStyle(ref.current);
        const currentWidth: number =
          parseInt(refStyle.width) -
          parseInt(refStyle.borderLeftWidth) -
          parseInt(refStyle.borderRightWidth);
        const borderWidth: number = getTableBorderWidth(style);
        dispatch({ type: 'setWidth', payload: currentWidth - borderWidth });
        dispatch({
          type: 'setDisplayedColumns',
          payload: currentWidth - borderWidth,
        });
      }
    };
    updateWidth();
    window.addEventListener('resize', updateWidth);
    return () => {
      window.removeEventListener('resize', updateWidth);
    };
  }, [dispatch, style]);

  /**
   * An object containing the classnames generated from the stylesheet made with emotion and using the style state of the store
   * @memberof Wrapper
   */
  const classNames: { [Class: string]: string } = styleSheet(style);

  return (
    <figure
      ref={ref}
      className={cx(
        classNames.wrapper,
        width > 480 && classNames.wrapperLarge,
        width > 800 && classNames.wrapperExtraLarge,
        className
      )}
    >
      {width !== 0 ? children : null}
    </figure>
  );
};