/* @oracle/oraclejet-preact: undefined */
import { jsxs, Fragment, jsx } from 'preact/jsx-runtime';
import { u as useUser } from './useUser-1cd223a9.js';
import { useMemo, useRef, useState, useEffect } from 'preact/hooks';
import { m as mergeProps } from './mergeProps-88ea8306.js';
import { c as classNames } from './classNames-4e12b00d.js';
import { v as validateRange, h as hasLabelledReferenceLine, b as getDefaultReferenceLineLabelFontSize, c as getMaxRefLabelDims, g as getMeterAriaProps, a as getTrackAndIndicatorColor } from './meterUtils-e23f6da6.js';
import { a as getCenterCoord, c as convertToPolar, b as getPositiveAngle, d as getClipPath, e as getCircleSection } from './circleUtils-90dae0a2.js';
import { g as getVisThresholdColor } from './utils-f1da3836.js';
import { styles } from './UNSAFE_MeterCircle/themes/MeterCircleStyles.css.js';
import { meterCircleVars } from './UNSAFE_MeterCircle/themes/MeterCircleContract.css.js';
import { colorSchemeVars, typographyVars } from './Common/themes/themeContract.css.js';
import { x as xUnits } from './utils-a4102e03.js';
import { T as TrackResizeContainer } from './TrackResizeContainer-04a2c642.js';
import { u as usePointerEvents, a as useMeterDatatip } from './useMeterDatatip-834e67e1.js';
import { u as useKeyboardEvents } from './useKeyboardEvents-2378a650.js';
import './TabbableModeContext-7d8ad946.js';
import { u as useTabbableMode } from './useTabbableMode-a3a351d0.js';
import { u as useComponentTheme } from './useComponentTheme-d2f9e47f.js';
import { MeterCircleRedwoodTheme } from './UNSAFE_MeterCircle/themes/redwood/MeterCircleTheme.js';
import { u as useTestId } from './useTestId-9b504481.js';
import { u as useCssVars } from './useCssVars-d72a8439.js';
import { u as useTextDimensions } from './useTextDimensions-e08928cc.js';
import { C as CircleWrapper, a as CircleInner } from './CircularMeter-f2c0ae34.js';

/**
 * Returns the true dimensions of the meter circle after initial render. All dimensions are 0 for initial render.
 * @param element The HTML element that wraps the track and indicator div.
 * @param section The section in which the meter circle lies.
 * @returns The dimensions of the meter circle.
 */
function getDimensions(element, section) {
    if (!element) {
        return {
            width: 0,
            height: 0,
            innerRadius: 0,
            outerRadius: 0
        };
    }
    const circleTrack = element.children[0];
    const rect = circleTrack.getBoundingClientRect();
    return {
        width: Math.round(rect.width),
        height: Math.round(rect.height),
        ...getInnerAndOuterRadius(circleTrack, rect, section)
    };
}
/**
 * Returns the inner and outer radius of the meter circle.
 * @param element The HTML element that wraps the track and indicator div.
 * @param rect The bounding rect of the wrapper HTML element.
 * @param section The section in which the meter circle lies.
 * @returns The inner and outer radius of the meter circle.
 */
function getInnerAndOuterRadius(element, rect, section) {
    const width = element.clientWidth;
    const height = element.clientHeight;
    if (section === 'bottom' || section === 'top') {
        return { outerRadius: rect.width / 2, innerRadius: height };
    }
    else if (section === 'left' || section === 'right') {
        return { outerRadius: rect.height / 2, innerRadius: width };
    }
    return { innerRadius: width / 2, outerRadius: rect.width / 2 };
}
/**
 * Returns the value corresponding to clicked point in the meter circle. Returns undefined if the clicked point is
 * outside the track of the meter circle.
 * @param pageX The pageX of the click event
 * @param pageY The pageY of the click event
 * @param max The max value of the meter circle.
 * @param min The min value of the meter circle.
 * @param step The step of the metercircle.
 * @param dimensionsRef The ref that stores dimensions reference of meter circle.
 * @param startAngle The startAngle of the meter circle.
 * @param angleExtent The angleExtent of the meter circle
 * @returns {number} The value corresponding to clicked point in the meter circle.
 */
function getValue(event, min, max, step, dimensionsRef, startAngle, angleExtent, section, isRtl) {
    const dims = dimensionsRef.current;
    if (!dims) {
        return undefined;
    }
    const center = getCenterCoord(section);
    const { angle } = convertToPolar(dims.width * center.x, dims.height * center.y, event.offsetX, event.offsetY);
    const positiveAngle = getPositiveAngle(angle);
    let val;
    if (isRtl && startAngle + angleExtent > positiveAngle) {
        val = (getPositiveAngle(angle - startAngle) / angleExtent) * (max - min);
    }
    if (!isRtl) {
        const clockwiseArc = getPositiveAngle(startAngle - positiveAngle);
        if (clockwiseArc <= angleExtent) {
            val = (clockwiseArc * (max - min)) / angleExtent;
        }
    }
    if (val != undefined) {
        val = Math.round(val / step) * step;
        val = Math.max(Math.min(max, val), min);
    }
    return val;
}
/**
 * Returns the fraction of angle extent for given delta.
 * @param delta The delta of metric values.
 * @param min The minimum value of the meter circle.
 * @param max The maximum value of the meter circle.
 * @param angleExtent The angle extent of the meter circle.
 * @returns The angle extent corresponding to delta in metric value.
 */
function getAngleExtentFromDelta(delta, min, max, angleExtent) {
    return (delta * angleExtent) / (max - min);
}
/**
 * Returns the start angle for given metric value.
 * @param value The metric value
 * @param min The minimum value of the meter circle.
 * @param max The maximum value of the meter circle.
 * @param startAngle The startAngle of the meter circle.
 * @param angleExtent The angleExtent of the meter circle.
 * @param isRtl Whether the reading mode is 'rtl'
 * @returns The startAngle for the metric value.
 */
function getStartAngleForValue(value, min, max, startAngle, angleExtent, isRtl) {
    const extent = getAngleExtentFromDelta(value - min, min, max, angleExtent);
    return startAngle + (isRtl ? 1 : -1) * extent;
}
/**
 * Returns the center context of for the meter circle.
 */
function getCenterContext(dimensionsRef, section) {
    const dims = dimensionsRef.current;
    if (!dims) {
        return;
    }
    const center = getCenterCoord(section);
    const cx = center.x * dims.width;
    const cy = center.y * dims.height;
    const isHoriz = section === 'top' || section === 'bottom';
    let innerX, innerY, innerW, innerH;
    let outerX, outerY, outerW, outerH;
    if (isHoriz || section === 'full') {
        outerW = 2 * dims.innerRadius;
        outerH = section === 'full' ? 2 * dims.innerRadius : dims.innerRadius;
        outerX = cx - dims.innerRadius;
        outerY = section === 'bottom' ? 0 : cy - dims.innerRadius;
        innerW = Math.sqrt(2) * dims.innerRadius;
        innerH = section === 'full' ? innerW : dims.innerRadius / Math.sqrt(2);
        innerX = cx - dims.innerRadius / Math.sqrt(2);
        innerY = section === 'bottom' ? 0 : cy - dims.innerRadius / Math.sqrt(2);
    }
    else {
        outerH = 2 * dims.innerRadius;
        outerW = dims.innerRadius;
        outerX = section === 'left' ? cx - dims.innerRadius : 0;
        outerY = cy - dims.innerRadius;
        innerH = Math.sqrt(2) * dims.innerRadius;
        innerW = dims.innerRadius / Math.sqrt(2);
        innerX = section === 'left' ? cx - dims.innerRadius / Math.sqrt(2) : 0;
        innerY = cy - dims.innerRadius / Math.sqrt(2);
    }
    return {
        outerBounds: {
            x: outerX,
            y: outerY,
            width: outerW,
            height: outerH
        },
        innerBounds: {
            x: innerX,
            y: innerY,
            width: innerW,
            height: innerH
        }
    };
}

/**
 * @license
 * Copyright (c) %FIRST_YEAR% %CURRENT_YEAR%, Oracle and/or its affiliates.
 * The Universal Permissive License (UPL), Version 1.0
 * as shown at https://oss.oracle.com/licenses/upl/
 * @ignore
 */
// reduce the max width of text by 8px. There were some inconsistency on exact
// truncation width between browsers, viewport, container width, which led to some ellipses
// bleeding out. Reducing the max width provides a buffer so that labels are truncated
// slightly before reaching the exact max width.
const TRUCATION_THRESHOLD = xUnits(2);
//max left (right) offset for right (left) half circle for sized meter circle
const SIZED_HALF_METER_HORIZ_OFFSET = xUnits(7.5);
// max ref line protrusion
const MAX_PROTUSION = 16;
/**
 * Returns the css variable corresponding to the default size of the meter circle.
 * @param size The size of the meter circle.
 * @returns The css variable corresponding to the default size of the meter circle.
 */
function getSizeVar(size, diameter) {
    return size
        ? size === 'fit'
            ? `${diameter}px`
            : meterCircleVars.sizes[size]
        : meterCircleVars.size;
}
/**
 * Returns the css variable corresponding to the default track size of the meter circle.
 * @param size The size of the meter circle.
 * @returns The css variable corresponding to the default track size of the meter circle.
 */
function getTrackSizeVar(size) {
    return size ? meterCircleVars.trackSizes[size] : meterCircleVars.trackSize;
}
/**
 * Returns the calculated css variable string for the inner radius when given size and innerRadius of meter circle.
 * @param size The size of the meter circle.
 * @param innerRadius The inner radius of the meter circle.
 * @returns {string} CSS varible string for the calculated inner radius of the meter circle.
 */
function getInnerRadius(size, innerRadius, diameter) {
    if (innerRadius != undefined) {
        return `(${getSizeVar(size, diameter)} * ${innerRadius / 2})`;
    }
    return `(${getSizeVar(size, diameter)} * 0.5 - ${getTrackSizeVar(size)})`;
}
/**
 * Returns the calculated css variable string for meter circle track for a given size and innerRadius of meter circle.
 * @param size The size of the meter circle.
 * @param innerRadius The inner radius of the meter circle.
 * @returns {string} CSS variable for the calculated track size of the meter circle.
 */
function getTrackSize(size, innerRadius, diameter) {
    if (innerRadius != undefined) {
        return `(${getSizeVar(size, diameter)} * ${1 - innerRadius} / 2)`;
    }
    return getTrackSizeVar(size);
}
/**
 * Returns the array of calculated props for InnerCircle representing each threshold.
 * @param meterInfo MeterInfo object containing info about given meter circle.
 * @param thresholds thresholds array of the meter circle.
 * @param isTrackRendered Whether track is rendered.
 * @param trackColor The track color of the meter circle.
 * @param innerRadius The inner radius of the meter circle.
 * @returns Array of calculated props object for InnerCircle representing each threshold.
 */
function getThresholdsProps(meterInfo, thresholds, isTrackRendered, trackColor, innerRadius, diameter) {
    const { min, max, startAngle, angleExtent, size, section, isRtl, innerRadius: innerDim } = meterInfo;
    const trackSize = `calc(${getTrackSize(size, innerRadius, diameter)})`;
    const thresholdProps = [];
    const validThresholds = thresholds
        .filter((threshold) => threshold.max > min && threshold.max <= max)
        .sort((a, b) => a.max - b.max);
    const numOfThreshold = validThresholds.length;
    for (let i = 0; i < numOfThreshold; i++) {
        const threshold = validThresholds[i];
        const startValue = i === 0 ? min : validThresholds[i - 1].max;
        const diff = i === 0 ? threshold.max : threshold.max - validThresholds[i - 1].max;
        let thresholdStart = getStartAngleForValue(startValue, min, max, startAngle, angleExtent, isRtl);
        let thresholdExtent = getAngleExtentFromDelta(diff, min, max, angleExtent);
        const { startOffset, extentOffset } = getThresholdsBuffer(innerDim, angleExtent, i === 0, threshold.max === max, isRtl);
        const clipPath = getClipPath(thresholdStart + startOffset, thresholdExtent + extentOffset, isRtl, section);
        thresholdProps.push({
            clipPath,
            color: getVisThresholdColor(threshold.color),
            size: trackSize,
            section
        });
        if (i === numOfThreshold - 1 && threshold.max < max && isTrackRendered) {
            thresholdStart = thresholdStart + (isRtl ? 1 : -1) * thresholdExtent;
            thresholdExtent = getAngleExtentFromDelta(max - threshold.max, min, max, angleExtent);
            const { startOffset, extentOffset } = getThresholdsBuffer(innerDim, angleExtent, false, true, isRtl);
            thresholdProps.push({
                clipPath: getClipPath(thresholdStart + startOffset, thresholdExtent + extentOffset, isRtl, section),
                color: trackColor,
                size: trackSize,
                section
            });
        }
    }
    return thresholdProps;
}
/**
 * Returns the calculated props for InnerCircle representing the track.
 * @param meterInfo MeterInfo object containing info about the meter circle.
 * @param trackColor The color of the track.
 * @param istrackRendered Whether the track is rendered.
 * @param thresholdDisplay Specifies whether the current threshold is displayed in the track, on the indicator, or if all thresholds are displayed in the track.
 * @param innerRadius The innerRadius of the meter circle.
 * @param thresholds thresholds array of the meter circle.
 * @returns An object with calculated props for InnerCircle that represents the track.
 */
function getTrackProps(meterInfo, isTrackRendered, thresholdDisplay, trackColor, innerRadius, thresholds, diameter) {
    const { startAngle, angleExtent, size, section, isRtl } = meterInfo;
    const color = !isTrackRendered
        ? 'transparent'
        : thresholdDisplay === 'all' && thresholds
            ? `${colorSchemeVars.dvt.contrastLine}`
            : trackColor;
    return {
        section,
        color,
        clipPath: getClipPath(startAngle, angleExtent, isRtl, section),
        size: `calc(${getTrackSize(size, innerRadius, diameter)})`
    };
}
/**
 * Returns the calculated props for InnerCircle representing the indicator.
 * @param meterInfo MeterInfo object containing info about the meter circle.
 * @param indicatorSize Relative thickness of the indicator to the track.
 * @param innerRadius The innerRadius of the meter circle.
 * @returns An object with calculated props for InnerCircle that represents the indicator.
 */
function getIndicatorProps(meterInfo, indicatorSize, innerRadius, fitDiameter) {
    const { value, min, max, startAngle, angleExtent, size, section, isRtl } = meterInfo;
    const valueExtent = ((value - min) * angleExtent) / (max - min);
    const validIndicatorSize = Math.min(Math.max(0, indicatorSize), 1);
    const isHoriz = section === 'left' || section === 'right';
    const isVert = section === 'top' || section === 'bottom';
    const valueTrackSize = `calc(${getTrackSize(size, innerRadius, fitDiameter)} * ${validIndicatorSize})`;
    const diameter = `${getSizeVar(size, fitDiameter)} - ((1 - ${validIndicatorSize}) * ${getTrackSize(size, innerRadius, fitDiameter)})`;
    const radius = `(${diameter}) / 2`;
    return {
        section,
        width: isHoriz ? `calc(${radius})` : `calc(${diameter})`,
        height: isVert ? `calc(${radius})` : `calc(${diameter})`,
        size: valueTrackSize,
        clipPath: getClipPath(startAngle, valueExtent, isRtl, section)
    };
}
/**
 * Returns the threshold offsets to create the whitespace between the thresholds.
 * @param innerRadius The innerRadius of the meter circle.
 * @param angleExtent The angleExtent of the meter circle.
 * @param firstThreshold Whether the current threshold is the first threshold.
 * @param lastThreshold  Whether the current threshold is the last threshold.
 * @param isRtl Whether the document reading mode is 'rtl'
 * @returns The offsets (startOffset and extentOffset) to add to calculated threshold startAngle and threhsold extent.
 */
function getThresholdsBuffer(innerRadius, angleExtent, firstThreshold, lastThreshold, isRtl) {
    if (!innerRadius) {
        return { startOffset: 0, extentOffset: 0 };
    }
    const offset = 360 / (2 * Math.PI * innerRadius);
    let startOffset = (offset / 2) * (isRtl ? 1 : -1);
    let extentOffset = -1 * offset;
    if (firstThreshold && angleExtent < 360) {
        startOffset = 0;
        extentOffset = -0.5 * offset;
    }
    if (lastThreshold && angleExtent < 360) {
        extentOffset = -0.5 * offset;
    }
    return { startOffset, extentOffset };
}
function getWidthAndHeight(width, height, section) {
    if (section === 'top' || section === 'bottom') {
        return {
            height: Math.min(height, width / 2),
            width: Math.min(height, width / 2) * 2
        };
    }
    else if (section === 'left' || section === 'right') {
        return {
            width: Math.min(width, height / 2),
            height: Math.min(width, height / 2) * 2
        };
    }
    else {
        return {
            width: Math.min(width, height),
            height: Math.min(width, height)
        };
    }
}
/**
 * Returns the x and y offset for absolute position of reference line.
 */
function getReferenceLineXYOffset(centerCoord, angle, radius) {
    const yOffset = `calc(${centerCoord.y * 100}% - ((${Math.sin((angle * 2 * Math.PI) / 360)} * ${radius} )))`;
    const xOffset = `calc(${centerCoord.x * 100}%  + ((${Math.cos((angle * 2 * Math.PI) / 360)} * ${radius} )))`;
    return { xOffset, yOffset };
}
/**
 * Returns the translation offset for the reference line label.
 */
function getLabelTranslateOffset(ag, section, halfMeterOffset) {
    let horizTranslate = '-50%';
    const angle = getPositiveAngle(ag);
    if (angle === 90 || angle === 270) {
        halfMeterOffset =
            typeof halfMeterOffset === 'string' ? halfMeterOffset : `${Math.abs(halfMeterOffset)}px`;
        if (section === 'left') {
            horizTranslate = `min(-50%, calc(-100% + ${halfMeterOffset}))`;
        }
        else if (section === 'right') {
            horizTranslate = `max(-50%, calc(-1 *  ${halfMeterOffset}))`;
        }
    }
    // these numbers are from the meter circle spec.
    if (angle <= 72 || angle >= 288) {
        return `0 -50%`;
    }
    else if (angle >= 108 && angle <= 252) {
        return `-100% -50%`;
    }
    else if (angle <= 108 && angle >= 72) {
        return `${horizTranslate} -100%`;
    }
    else {
        return `${horizTranslate} 0`;
    }
}
/**
 * The maxiumum width of for the reference line label in meter circle.
 */
function getMaxWidth(sizeVar, angle, radius) {
    angle = getPositiveAngle(angle);
    if ((angle < 108 && angle > 72) || (angle < 288 && angle > 252)) {
        return `calc(${sizeVar} * 1.4)`;
    }
    return `calc( (${sizeVar} * 0.7 ) - (${Math.abs(Math.cos((angle * 2 * Math.PI) / 360))} * ${radius} ))`;
}
/**
 * Returns the maximum width of label for a given angled reference line.
 */
function getFitMaxWidth(sector, width, angle, radius) {
    angle = getPositiveAngle(angle);
    if (sector === 'full' || sector === 'bottom' || sector === 'top') {
        if ((angle < 108 && angle > 72) || (angle < 288 && angle > 252)) {
            return `calc(${width}px - ${TRUCATION_THRESHOLD})`;
        }
        return `calc(${width / 2 - Math.abs(Math.cos((angle * 2 * Math.PI) / 360)) * radius}px - ${TRUCATION_THRESHOLD})`;
    }
    else {
        if (angle === 90 || angle === 270) {
            return `calc(${width}px - ${TRUCATION_THRESHOLD})`;
        }
        return `calc(${width / 2 + radius / 2 - radius * Math.abs(Math.cos((angle * 2 * Math.PI) / 360))}px - ${TRUCATION_THRESHOLD})`;
    }
}
/**
 * Returns the margin needed to accomodate reference line and label in a sized meter circle.
 */
function getSizedMargin(size, sector, hasReferenceLine, hasReferenceLineLabel, maxRefLabelDims) {
    let marginValue = '';
    if (!hasReferenceLine && !hasReferenceLine) {
        return '';
    }
    if (hasReferenceLineLabel) {
        marginValue = `calc(${meterCircleVars.size} / ${size === 'lg' || size === 'md' ? 3 : 2} )`;
    }
    else if (hasReferenceLine) {
        if (size === 'sm') {
            marginValue = xUnits(4);
        }
        else if (size === 'md') {
            marginValue = xUnits(3);
        }
        else if (size === 'lg') {
            marginValue = xUnits(2);
        }
    }
    if (sector === 'bottom') {
        return `${maxRefLabelDims.height / 2}px ${marginValue} ${marginValue} ${marginValue}`;
    }
    else if (sector === 'top') {
        return `${marginValue} ${marginValue} ${maxRefLabelDims.height / 2}px ${marginValue}`;
    }
    else if (sector === 'left') {
        return `${marginValue} ${SIZED_HALF_METER_HORIZ_OFFSET} ${marginValue} ${marginValue}`;
    }
    else if (sector === 'right') {
        return `${marginValue} ${marginValue} ${marginValue} ${SIZED_HALF_METER_HORIZ_OFFSET}`;
    }
    else {
        return marginValue;
    }
}
/**
 * Returns the breakpoint for a given width of the meter circle.
 */
function getBreakPoint(width) {
    // these numbers are from the meter circle spec.
    if (width < 200) {
        return 'min';
    }
    else if (width < 320) {
        return 'xs';
    }
    else if (width < 360) {
        return 'sm';
    }
    else {
        return 'md';
    }
}
/**
 * Returns the translation needed to center the meter bar when
 * reference line and label is present.
 */
function getCenterOffsets(section, overHang, isRtl) {
    const overHangOffset = section === 'full' ? overHang / 2 : overHang;
    if (section === 'top') {
        return isRtl ? '50% -50%' : '-50%, -50%';
    }
    return isRtl
        ? `calc(50% + ${overHangOffset}px), calc(-50% - ${overHangOffset}px)`
        : `calc(-50% - ${overHangOffset}px), calc(-50% - ${overHangOffset}px)`;
}
/**
 * Returns the horizontal offset for left and right half circle for fit meter circle.
 */
function getFitHalfCircleOffset(width, radius, section, isRtl) {
    const factor = (!isRtl && section === 'right') || (isRtl && section === 'left') ? -0.5 : 0.5;
    return (width - radius) / 2 + factor * MAX_PROTUSION;
}

function CircularReferenceLine({ color, angle, radius, length, section = 'full', label, labelMaxWidth, labelOffset, labelStyle, halfMeterOffset }) {
    const centerCoord = getCenterCoord(section);
    const { xOffset: refXOffset, yOffset: refYOffset } = getReferenceLineXYOffset(centerCoord, angle, radius);
    const { xOffset: labelXOffset, yOffset: labelYOffset } = getReferenceLineXYOffset(centerCoord, angle, `calc(${length} + ${radius} + ${labelOffset}px)`);
    return (jsxs(Fragment, { children: [jsx("div", { class: classNames([
                    styles.referenceBaseLineStyle,
                    color ? undefined : styles.referenceBorderStyle
                ]), style: {
                    left: refXOffset,
                    top: refYOffset,
                    width: `calc(${length})`,
                    transform: `translate(0, -1px) rotate(${360 - angle}deg)`,
                    backgroundColor: color ? getVisThresholdColor(color) : undefined
                } }), label && (jsx("div", { className: styles.referenceLineLabelContainerStyle, style: {
                    left: labelXOffset,
                    top: labelYOffset,
                    maxWidth: labelMaxWidth,
                    translate: getLabelTranslateOffset(angle, section, halfMeterOffset),
                    ...labelStyle
                }, children: label }))] }));
}

/**
 * @license
 * Copyright (c) %FIRST_YEAR% %CURRENT_YEAR%, Oracle and/or its affiliates.
 * The Universal Permissive License (UPL), Version 1.0
 * as shown at https://oss.oracle.com/licenses/upl/
 * @ignore
 */
const LABEL_GAP = 4;
/**
 * Returns the calculated length of reference line for given size and inner radius of meter circle.
 * The length of reference line runs from the inner radius to slight outside the outer radius.
 * The length outside the outer radius depends on size of the meter circle.
 * @param size The size of the meter circle.
 * @param innerRadius The inner radius of the meter circle.
 * @returns The calculated CSS var for the length of reference line.
 */
function getReferenceLineLength(size, innerRadius, isMin, diameter) {
    return `${getTrackSize(size, innerRadius, diameter)} +  ${xUnits(size === 'fit' && !isMin ? 4 : 2)}`;
}
/**
 * Returns the calculated props for CircularReferenceLine.
 * @param meterInfo MeterInfo object containing info about the meter circle.
 * @param refLine The CircularRefLine object
 * @param innerRadius The innerRadius of the meter circle.
 * @returns An bject with calculated props for CircularReferenceLine.
 */
function getReferenceLinesProps(meterInfo, refLine, innerRadius, isMin, diameter) {
    const { min, max, startAngle, angleExtent, size, isRtl } = meterInfo;
    return {
        radius: getInnerRadius(size, innerRadius, diameter),
        length: getReferenceLineLength(size, innerRadius, isMin, diameter),
        angle: getStartAngleForValue(refLine.value, min, max, startAngle, angleExtent, isRtl),
        color: refLine.color
    };
}
/**
 * Returns the width and height of the fit meter circle when reference line
 * and reference line label is present.
 * @returns
 */
function getWidthAndHeightWithReferenceLine(_width, _height, hasReferenceLine, breakPoint, hasReferenceLineLabel, maxRefLabelDims) {
    if (!hasReferenceLine) {
        return { width: _width, height: _height, overHang: 0 };
    }
    const overHang = getReferenceLineOverHang(breakPoint);
    const labelOffset = getReferenceLineLabelGap(breakPoint);
    return {
        width: (_width) * (hasReferenceLineLabel ? 0.6 : 1) - 2 * overHang,
        height: _height -
            2 * overHang -
            2 * (maxRefLabelDims.height + labelOffset),
        overHang
    };
}
/**
 * Returns the gap for the reference line label.
 */
function getReferenceLineLabelGap(breakPoint, angle) {
    const isMin = breakPoint === 'min' || breakPoint === 'xs';
    // vertical gap
    if (angle != null && ((angle < 108 && angle > 72) || (angle < 288 && angle > 252))) {
        return isMin ? 0 : LABEL_GAP;
    }
    // horizontal gap
    if (angle != null && (!(angle < 108 && angle > 72) || (angle < 288 && angle > 252))) {
        return 1.5 * LABEL_GAP;
    }
    return isMin ? LABEL_GAP / 2 : LABEL_GAP;
}
/**
 * Returns the length of reference line outside the diameter of the meter circle.
 */
function getReferenceLineOverHang(breakPoint) {
    // these numbers are from the meter circle spec.
    return breakPoint === 'min' || breakPoint === 'xs' ? LABEL_GAP * 2 : LABEL_GAP * 4;
}

const FIT_INNERRADIUS = 0.8;
const FIT_BUFFER = 8;
/**
 * A Meter circle displays information graphically in a circular bar, highlighting a specific metric value's progress in relation to its min, max, or thresholds.
 */
function FitMeterCircle({ max = 100, min = 0, value = 0, step = 1, size = 'fit', startAngle = 90, angleExtent = 360, isTrackRendered = true, thresholdDisplay = 'all', indicatorSize = 1, testId, isReadonly, ...props }) {
    const testIdProps = useTestId(testId);
    validateRange(min, max, value, step, isReadonly);
    const isInteractive = props.onCommit || props.onInput;
    const { classes, styles } = useComponentTheme(MeterCircleRedwoodTheme, {
        size,
        interaction: isInteractive ? 'isInteractive' : undefined
    });
    return (jsx(TrackResizeContainer, { class: classNames([classes, styles.textAlignCenter]), width: '100%', height: '100%', children: function _(_width, _height) {
            _width -= FIT_BUFFER;
            _height -= FIT_BUFFER;
            const hasReferenceLabel = hasLabelledReferenceLine(props.referenceLines);
            const { textMeasureContent, getTextDimensions } = useTextDimensions();
            const { direction } = useUser();
            const isRtl = direction === 'rtl';
            let sAngle = startAngle;
            if (isRtl) {
                sAngle = getPositiveAngle(180 - sAngle);
            }
            const section = getCircleSection(sAngle, angleExtent, isRtl);
            const { width: _w, height: _h } = getWidthAndHeight(_width, _height, section);
            const breakPoint = getBreakPoint(Math.max(_w, _h));
            const fontSize = getDefaultReferenceLineLabelFontSize(breakPoint);
            const circleVars = useMemo(() => [
                {
                    tokenVar: fontSize,
                    key: 'labelFontSize',
                    cssProp: 'font-size'
                },
                {
                    tokenVar: typographyVars.body.md.lineHeight,
                    key: 'lineHeight',
                    cssProp: 'line-height'
                }
            ], [fontSize]);
            const { resolvedVars, cssContent } = useCssVars(circleVars);
            const { maxRefLabelDims } = getMaxRefLabelDims(resolvedVars['fontSize'], resolvedVars['lineHeight'], props.referenceLines, getTextDimensions);
            const isMin = breakPoint === 'xs' || breakPoint === 'min';
            const innerR = props.innerRadius ?? FIT_INNERRADIUS;
            const { width: w, height: h, overHang } = getWidthAndHeightWithReferenceLine(_width, _height, !!props.referenceLines?.length, breakPoint, hasReferenceLabel, maxRefLabelDims);
            const { width, height } = getWidthAndHeight(w, h, section);
            const radius = section === 'full' ? Math.min(width, height) / 2 : Math.min(width, height);
            const diameter = radius * 2;
            const currentInputRef = useRef();
            const dimensionsRef = useRef(getDimensions(null, section));
            const circleWrapperRef = useRef(null);
            const [isDimsReady, setDimsReady] = useState(false);
            useEffect(() => {
                if (props.onCommit || props.onInput || props.children) {
                    dimensionsRef.current = getDimensions(circleWrapperRef.current, section);
                    setDimsReady(true);
                }
            }, [section]);
            const getValueFromEvent = (event) => {
                const circleContainer = circleWrapperRef.current;
                if (event.target == circleContainer) {
                    return getValue(event, min, max, step, dimensionsRef, sAngle, angleExtent, section, isRtl);
                }
                return;
            };
            const isPointerActiveRef = useRef(false);
            const pointerEventsProps = usePointerEvents(value, getValueFromEvent, circleWrapperRef, currentInputRef, isPointerActiveRef, props.onCommit, props.onInput);
            const keyboardEventsProps = useKeyboardEvents(value, min, max, step, currentInputRef, props.onCommit, props.onInput);
            const { datatipContent, datatipProps } = useMeterDatatip(value, isPointerActiveRef, props.datatip, props['aria-describedby']);
            const ariaProps = getMeterAriaProps(value, min, max, props['aria-label'], props['aria-labelledby'], props.thresholds);
            const mergedProps = mergeProps(pointerEventsProps, keyboardEventsProps, datatipProps, ariaProps);
            const { trackColor, indicatorColor } = getTrackAndIndicatorColor(value, thresholdDisplay, props.trackColor, props.indicatorColor, props.thresholds);
            const meterInfo = {
                min,
                max,
                value,
                startAngle: sAngle,
                angleExtent,
                size,
                section,
                isRtl,
                innerRadius: dimensionsRef.current.innerRadius
            };
            const { isTabbable } = useTabbableMode();
            const centerContext = getCenterContext(dimensionsRef, section);
            return (jsxs(Fragment, { children: [jsx("div", { class: classNames([
                            classes,
                            section === 'full' ? styles.meterCircleFullSizeStyle : '',
                            styles.textAlignInitial
                        ]), style: {
                            width: _width,
                            height: _height
                        }, tabIndex: !isTabbable ? -1 : 0, ...testIdProps, ...mergedProps, children: jsxs(CircleWrapper, { wrapperRef: circleWrapperRef, class: classNames([
                                styles.circleWrapperBaseStyle,
                                isInteractive ? styles.interactiveStyle : '',
                                props.referenceLines && props.referenceLines.length > 0
                                    ? size && styles[`${section}Fit${isMin ? 'Sm' : 'Lg'}Style`]
                                    : '',
                                isRtl ? styles.centerDivRtl : styles.centerDivLtr
                            ]), style: {
                                width: `${width}px`,
                                height: `${height}px`,
                                // correction for margin
                                transform: `translate(${getCenterOffsets(section, overHang, isRtl)})`
                            }, children: [jsx(CircleInner, { width: `${width}px`, height: `${height}px`, class: classNames([styles.circleTrackBaseStyle, styles[`${section}Style`]]), ...getTrackProps(meterInfo, isTrackRendered, thresholdDisplay, trackColor, innerR, props.thresholds, diameter) }), thresholdDisplay === 'all' &&
                                    props.thresholds &&
                                    getThresholdsProps(meterInfo, props.thresholds, isTrackRendered, trackColor, innerR, diameter).map((threshold) => {
                                        return (jsx(CircleInner, { class: classNames([styles.circleTrackBaseStyle, styles[`${section}Style`]]), ...threshold, width: `${width}px`, height: `${height}px` }));
                                    }), jsx(CircleInner, { color: indicatorColor, class: classNames([
                                        styles.circleValueBaseStyle,
                                        styles[`circleValue${section}Style`],
                                        styles[`${section}Style`]
                                    ]), ...getIndicatorProps(meterInfo, indicatorSize, innerR, 2 * radius) }), props.referenceLines?.map((refLine) => {
                                    const { radius, length, angle, color } = getReferenceLinesProps(meterInfo, refLine, innerR, isMin, diameter);
                                    const labelMaxWidth = getFitMaxWidth(section, _width, angle, diameter / 2 + overHang + getReferenceLineLabelGap(breakPoint, angle));
                                    return (jsx(CircularReferenceLine, { label: refLine.label, labelStyle: {
                                            fontSize: resolvedVars['labelFontSize'],
                                            lineHeight: typographyVars.body.md.lineHeight,
                                            ...refLine.labelStyle
                                        }, labelMaxWidth: labelMaxWidth, radius: radius, length: length, angle: angle, labelOffset: getReferenceLineLabelGap(breakPoint, angle), color: color, section: section, halfMeterOffset: getFitHalfCircleOffset(_width, diameter / 2, section, isRtl) }));
                                }), isDimsReady && props.children && centerContext && (jsx("div", { class: classNames([styles.meterCircleCenterContent]), children: props.children(centerContext) }))] }) }), datatipContent, textMeasureContent, cssContent] }));
        } }));
}

/**
 * A Meter circle displays information graphically in a circular bar, highlighting a specific metric value's progress in relation to its min, max, or thresholds.
 */
function SizedMeterCircle({ max = 100, min = 0, value = 0, step = 1, size = 'lg', startAngle = 90, angleExtent = 360, isTrackRendered = true, thresholdDisplay = 'all', indicatorSize = 1, testId, isReadonly, ...props }) {
    const testIdProps = useTestId(testId);
    validateRange(min, max, value, step, isReadonly);
    const currentInputRef = useRef();
    const { direction } = useUser();
    const isRtl = direction === 'rtl';
    let sAngle = startAngle;
    if (isRtl) {
        sAngle = getPositiveAngle(180 - sAngle);
    }
    const section = getCircleSection(sAngle, angleExtent, isRtl);
    const dimensionsRef = useRef(getDimensions(null, section));
    const circleWrapperRef = useRef(null);
    const [isDimsReady, setDimsReady] = useState(false);
    useEffect(() => {
        if (props.onCommit || props.onInput || props.children) {
            dimensionsRef.current = getDimensions(circleWrapperRef.current, section);
            setDimsReady(true);
        }
    }, [size, section, props.onCommit, props.onInput, props.children]);
    const { textMeasureContent, getTextDimensions } = useTextDimensions();
    const getValueFromEvent = (event) => {
        const circleContainer = circleWrapperRef.current;
        if (event.target == circleContainer) {
            return getValue(event, min, max, step, dimensionsRef, sAngle, angleExtent, section, isRtl);
        }
        return;
    };
    const isPointerActiveRef = useRef(false);
    const pointerEventsProps = usePointerEvents(value, getValueFromEvent, circleWrapperRef, currentInputRef, isPointerActiveRef, props.onCommit, props.onInput);
    const keyboardEventsProps = useKeyboardEvents(value, min, max, step, currentInputRef, props.onCommit, props.onInput);
    const { datatipContent, datatipProps } = useMeterDatatip(value, isPointerActiveRef, props.datatip, props['aria-describedby']);
    const ariaProps = getMeterAriaProps(value, min, max, props['aria-label'], props['aria-labelledby'], props.thresholds);
    const mergedProps = mergeProps(pointerEventsProps, keyboardEventsProps, datatipProps, ariaProps);
    const { trackColor, indicatorColor } = getTrackAndIndicatorColor(value, thresholdDisplay, props.trackColor, props.indicatorColor, props.thresholds);
    const orientation = section === 'bottom' || section === 'top'
        ? 'Horizontal'
        : section === 'left' || section === 'right'
            ? 'Vertical'
            : 'Full';
    const meterInfo = {
        min,
        max,
        value,
        startAngle: sAngle,
        angleExtent,
        size,
        section,
        isRtl,
        innerRadius: dimensionsRef.current.innerRadius
    };
    const isInteractive = props.onCommit || props.onInput;
    const { classes, styles } = useComponentTheme(MeterCircleRedwoodTheme, {
        size,
        interaction: isInteractive ? 'isInteractive' : undefined
    });
    const { isTabbable } = useTabbableMode();
    const centerContext = getCenterContext(dimensionsRef, section);
    const indicatorProps = getIndicatorProps(meterInfo, indicatorSize, props.innerRadius);
    const hasReferenceLabel = hasLabelledReferenceLine(props.referenceLines);
    const breakPoint = size === 'lg' ? 'sm' : 'min';
    const fontSize = getDefaultReferenceLineLabelFontSize(breakPoint);
    const circleVars = useMemo(() => [
        {
            tokenVar: fontSize,
            key: 'labelFontSize',
            cssProp: 'font-size'
        },
        {
            tokenVar: typographyVars.body.md.lineHeight,
            key: 'lineHeight',
            cssProp: 'line-height'
        }
    ], [fontSize]);
    const { resolvedVars, cssContent } = useCssVars(circleVars);
    const { maxRefLabelDims } = getMaxRefLabelDims(resolvedVars['fontSize'], resolvedVars['lineHeight'], props.referenceLines, getTextDimensions);
    const trackProps = getTrackProps(meterInfo, isTrackRendered, thresholdDisplay, trackColor, props.innerRadius, props.thresholds);
    return (jsxs(Fragment, { children: [jsx("div", { class: classNames([classes]), tabIndex: !isTabbable ? -1 : 0, ...testIdProps, ...mergedProps, children: jsxs(CircleWrapper, { wrapperRef: circleWrapperRef, class: classNames([
                        styles.circleWrapperBaseStyle,
                        isInteractive ? styles.interactiveStyle : '',
                        styles[`meterCircle${orientation}SizeStyle`]
                    ]), style: {
                        margin: getSizedMargin(size, section, !!props.referenceLines?.length, hasReferenceLabel, maxRefLabelDims)
                    }, children: [jsx(CircleInner, { class: classNames([styles.circleTrackBaseStyle, styles[`${section}Style`]]), ...trackProps }), thresholdDisplay === 'all' &&
                            props.thresholds &&
                            getThresholdsProps(meterInfo, props.thresholds, isTrackRendered, trackColor, props.innerRadius).map((threshold) => {
                                return (jsx(CircleInner, { class: classNames([styles.circleTrackBaseStyle, styles[`${section}Style`]]), ...threshold }));
                            }), jsx(CircleInner, { color: indicatorColor, class: classNames([
                                styles.circleValueBaseStyle,
                                styles[`circleValue${section}Style`],
                                styles[`${section}Style`]
                            ]), ...indicatorProps }), props.referenceLines?.map((refLine) => {
                            const { radius, length, angle, color } = getReferenceLinesProps(meterInfo, refLine, props.innerRadius);
                            return (jsx(CircularReferenceLine, { label: refLine.label, labelStyle: {
                                    fontSize: resolvedVars['labelFontSize'],
                                    ...refLine.labelStyle
                                }, labelMaxWidth: getMaxWidth(meterCircleVars['size'], angle, `calc( ${radius} + ${length} - ${trackProps.size} + ${getReferenceLineLabelGap(breakPoint, angle)}px)`), radius: radius, labelOffset: getReferenceLineLabelGap(breakPoint, angle), length: length, angle: angle, color: color, halfMeterOffset: SIZED_HALF_METER_HORIZ_OFFSET, section: section }));
                        }), isDimsReady && props.children && centerContext && (jsx("div", { class: classNames([styles.meterCircleCenterContent]), children: props.children(centerContext) }))] }) }), datatipContent, textMeasureContent, cssContent] }));
}

/**
 * A Meter circle displays information graphically in a circular bar, highlighting a specific metric value's progress in relation to its min, max, or thresholds.
 */
function MeterCircle({ size, max = 100, min = 0, value = 0, step = 1, startAngle = 90, angleExtent = 360, isTrackRendered = true, thresholdDisplay = 'all', indicatorSize = 1, ...props }) {
    if (size === 'fit') {
        return (jsx(FitMeterCircle, { min: min, value: value, max: max, step: step, startAngle: startAngle, angleExtent: angleExtent, isTrackRendered: isTrackRendered, thresholdDisplay: thresholdDisplay, indicatorSize: indicatorSize, ...props }));
    }
    return (jsx(SizedMeterCircle, { size: size || 'lg', min: min, value: value, max: max, step: step, startAngle: startAngle, angleExtent: angleExtent, isTrackRendered: isTrackRendered, thresholdDisplay: thresholdDisplay, indicatorSize: indicatorSize, ...props }));
}

export { MeterCircle as M };
//# sourceMappingURL=MeterCircle-2156d7ff.js.map
