Repository: recharts/recharts
File: src/util/YAxisUtils.tsx (TypeScript)

Code before:
import React, { isValidElement, ReactElement } from 'react';
import { isNumOrStr } from './DataUtils';

/**
 * Returns modified Y-axis label and position based on the provided label.
 * The modified props shows the y-axis rotated by 270 degrees and centered along y-axis.
 * If the label is a number or string, it returns a default label object with common properties.
 * If the label is an object, it merges common properties with the provided label properties.
 *
 * @param {Object} params - The parameters object.
 * @param {any} params.label - The label to be modified.
 * @returns {Object} An object containing the modified label
 */
export const getModifiedYAxisProps = ({
  label,
}: {
  label: string | number | ReactElement | object;
}): { label: object } => {
  let modifiedLabel = label;

  const commonLabelProps = { angle: 270, position: 'insideLeft', textAnchor: 'middle', verticalAnchor: 'start' };

  if (isNumOrStr(modifiedLabel)) {
    modifiedLabel = {
      value: label,
      ...commonLabelProps,
    };
  } else if (label && typeof label === 'object' && !isValidElement(label)) {
    modifiedLabel = {
      ...commonLabelProps,
      ...label,
    };
  }

  return { label: modifiedLabel };
};

/**
 * Calculates the width of the Y-axis based on the tick labels and the axis label.
 *
 * @param {Object} params - The parameters object.
 * @param {React.RefObject<any>} params.cartesianAxisRef - The ref to the CartesianAxis component.
 * @param {React.RefObject<SVGElement>} params.labelRef - The ref to the label element.
 * @param {number} [params.labelGapWithTick=5] - The gap between the label and the tick.
 * @returns {number} The calculated width of the Y-axis.
 */

Review comment (suggestion):
This is new.

How is this related to the automated responsive width?

Why is this inside a props modifier function? If we want to add new default behaviour, why not put this in default props?

If we change the default behaviour we also need update to the documentation.


Code after:
type IGetBoundingClient = Pick<Element, 'getBoundingClientRect'>;

/**
 * Calculates the width of the Y-axis based on the tick labels and the axis label.
 * @param {Object} params - The parameters object.
 * @param {React.RefObject<any>} params.cartesianAxisRef - The ref to the CartesianAxis component.
 * @param {React.RefObject<Element>} params.labelRef - The ref to the label element.
 * @param {number} [params.labelGapWithTick=5] - The gap between the label and the tick.
 * @returns {number} The calculated width of the Y-axis.
 */
export const getCalculatedYAxisWidth = ({
  ticks,
  label,
  labelGapWithTick = 5, // Default gap between label and tick
  tickSize = 0,
  tickMargin = 0,
}: {
  ticks: ReadonlyArray<IGetBoundingClient> | undefined;
  label: IGetBoundingClient | undefined;
  labelGapWithTick: number | undefined;
  tickSize: number | undefined;
  tickMargin: number | undefined;
}): number => {
  // find the max width of the tick labels
  let maxTickWidth = 0;
  if (ticks) {
    ticks.forEach((tickNode: Element) => {
      if (tickNode) {
        const bbox = tickNode.getBoundingClientRect();

        if (bbox.width > maxTickWidth) {
          maxTickWidth = bbox.width;
        }
      }
    });

    // calculate width of the axis label
    const labelWidth = label ? label.getBoundingClientRect().width : 0;

    const tickWidth = tickSize + tickMargin;

    // calculate the updated width of the y-axis
    const updatedYAxisWidth = maxTickWidth + tickWidth + labelWidth + (label ? labelGapWithTick : 0);

    return Math.round(updatedYAxisWidth);
  }