toggle-corp/react-store

View on GitHub
v2/View/Message/index.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import React, { useCallback, useState, useRef } from 'react';
import { _cs } from '@togglecorp/fujs';

import useResizeObserver from '../../General/useResizeObserver';

import styles from './styles.scss';

function calculateDimensionCost(width: number, height: number, factor: number) {
    return width * Math.sqrt(height) * factor;
}

function calculateRelativeValue(
    minFontSize: number,
    maxFontSize: number,
    width: number,
    height: number,
    factor: number,
) {
    return Math.min(
        maxFontSize,
        minFontSize + ((maxFontSize - minFontSize) * calculateDimensionCost(width, height, factor)),
    );
}

interface Props {
    children: React.ReactNode;
    className?: string;
    maxFontSize: number;
    maxPaddingSize: number;
    minFontSize: number;
    minPaddingSize: number;
    resizeFactor: number;
}

function Message(props: Props) {
    const {
        maxFontSize,
        maxPaddingSize,
        minFontSize,
        minPaddingSize,
        resizeFactor,
    } = props;

    const [isChildrenShown, setIsChildrenShown] = useState(false);

    const containerRef = useRef<HTMLDivElement>(null);

    const showChildren = useCallback(
        () => {
            setIsChildrenShown(true);
        },
        [],
    );

    const handleResize = useCallback(
        (e: ResizeObserverEntry[]) => {
            const {
                0: {
                    contentRect: {
                        width,
                        height,
                    },
                },
            } = e;

            const { current: container } = containerRef;

            const fontSize = calculateRelativeValue(
                minFontSize, maxFontSize, width, height, resizeFactor,
            );
            const padding = calculateRelativeValue(
                minPaddingSize, maxPaddingSize, width, height, resizeFactor,
            );

            if (container) {
                container.style.width = `${width}px`;
                container.style.height = `${height}px`;
                container.style.fontSize = `${fontSize}px`;
                container.style.padding = `${padding}px`;
            }
        },
        [
            maxFontSize,
            maxPaddingSize,
            minFontSize,
            minPaddingSize,
            resizeFactor,
            containerRef,
        ],
    );

    useResizeObserver(
        containerRef,
        showChildren,
        handleResize,
    );

    const {
        className: classNameFromProps,
        children,
    } = props;

    const className = _cs(
        classNameFromProps,
        styles.message,
    );

    return (
        <div
            ref={containerRef}
            className={className}
        >
            { isChildrenShown && children }
        </div>
    );
}
Message.defaultProps = {
    maxFontSize: 20,
    maxPaddingSize: 16,
    minFontSize: 8,
    minPaddingSize: 3,
    resizeFactor: 0.0001,
};

export default Message;