/* @oracle/oraclejet-preact: undefined */
import { jsxs, Fragment, jsx } from 'preact/jsx-runtime';
import { T as TrackResizeContainer } from './TrackResizeContainer-04a2c642.js';
import { c as classNames } from './classNames-4e12b00d.js';
import { m as mergeProps } from './mergeProps-88ea8306.js';
import { useRef, useEffect, useMemo } from 'preact/hooks';
import { u as useUser } from './useUser-1cd223a9.js';
import { u as usePointerEvents, a as useMeterDatatip } from './useMeterDatatip-834e67e1.js';
import { u as useKeyboardEvents } from './useKeyboardEvents-2378a650.js';
import { v as validateRange, g as getMeterAriaProps, a as getTrackAndIndicatorColor, h as hasLabelledReferenceLine, b as getDefaultReferenceLineLabelFontSize, c as getMaxRefLabelDims } from './meterUtils-e23f6da6.js';
import { x as xUnits } from './utils-a4102e03.js';
import { meterBarVars } from './UNSAFE_MeterBar/themes/MeterBarContract.css.js';
import { s as sizeToCSS } from './size-18139a3a.js';
import { styles } from './UNSAFE_MeterBar/themes/MeterBarStyles.css.js';
import { g as getVisThresholdColor } from './utils-f1da3836.js';
import './TabbableModeContext-7d8ad946.js';
import { u as useTabbableMode } from './useTabbableMode-a3a351d0.js';
import { u as useComponentTheme } from './useComponentTheme-d2f9e47f.js';
import { MeterBarRedwoodTheme } from './UNSAFE_MeterBar/themes/redwood/MeterBarTheme.js';
import { u as useTestId } from './useTestId-9b504481.js';
import { u as useTextDimensions } from './useTextDimensions-e08928cc.js';
import { u as useCssVars } from './useCssVars-d72a8439.js';
import { typographyVars } from './Common/themes/themeContract.css.js';
import { B as BarTrack, a as BarValue } from './LinearMeter-268f7b2f.js';

/**
 * @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 FIT_REF_BAR_PROTRUSION = 16;
const MAX_VERTICAL_LABEL_WIDTH_IN_XUNITS = 15;
const REF_LINE_LENGTH_IN_XUNITS = 5;
const LABEL_GAP = 4;
/**
 * Returns the metric value of the clicked point.
 * @param event The PointerEvent
 * @param dimensionsRef RefObject to stored dimensions of the meter bar.
 * @param min The minimum value of the meter bar.
 * @param max The maximum value of the meter bar.
 * @param step The step value of the meter bar.
 * @param orientation The orientation of the meter bar.
 * @param isRtl Whether the reading mode is 'rtl'
 * @returns The metric value of the clicked point.
 */
function getValue(event, dimensionsRef, min, max, step, orientation, isRtl) {
    const dims = dimensionsRef.current;
    if (!dims || dims.width === 0) {
        return undefined;
    }
    let val;
    if (orientation === 'horizontal') {
        const width = event.offsetX;
        val = min + ((max - min) * (isRtl ? dims.width - width : width)) / dims.width;
    }
    else {
        const height = dims.height - event.offsetY;
        val = min + ((max - min) * height) / dims.height;
    }
    val = Math.round(val / step) * step;
    return Math.max(min, Math.min(max, val));
}
/**
 * Returns the true dimension of the meter bar after first render. All dimensions are 0 for initial render.
 * @param element The meter bar track HTML element
 * @returns The dimension of the meter bar.
 */
function getDimensions(element) {
    if (!element) {
        return {
            width: 0,
            height: 0
        };
    }
    const trackDims = element.getBoundingClientRect();
    return {
        width: trackDims.width,
        height: trackDims.height
    };
}
/**
 * Returns object with 'start' and 'end' keys. Value for each key will be true if at least one ref line with correposnding position is present in meter bar.
 * @param lines The array of reference lines.
 * @returns Returns object with start and end keys.
 */
function getRefLinesInfo(lines) {
    let refLineInfo = { start: false, end: false };
    if (lines) {
        refLineInfo = lines.reduce((acc, cur) => {
            acc.start = acc.start || cur.position === 'start';
            acc.end = acc.end || cur.position === 'end' || cur.position == null;
            return acc;
        }, refLineInfo);
    }
    return refLineInfo;
}
const getFitMarginClass = function (info, isHoriz, barTrackMarginTopFitStyle, barTrackMarginStartFitStyle, barTrackMarginBottomFitStyle, barTrackMarginEndFitStyle) {
    const className = [];
    if (info.start) {
        className.push(isHoriz ? barTrackMarginTopFitStyle : barTrackMarginStartFitStyle);
    }
    if (info.end) {
        className.push(isHoriz ? barTrackMarginBottomFitStyle : barTrackMarginEndFitStyle);
    }
    return className;
};
const getFitTrackWidth = function (info, maxLabelWidth, width, isHoriz) {
    if (width) {
        if (info.start && !isHoriz) {
            width = width - FIT_REF_BAR_PROTRUSION;
        }
        if (info.end && !isHoriz) {
            width = width - FIT_REF_BAR_PROTRUSION;
        }
    }
    if (maxLabelWidth && width) {
        width -= 2 * maxLabelWidth + 2 * LABEL_GAP;
    }
    return width;
};
const getFitTrackHeight = function (info, maxLabelHeight, height, isHoriz) {
    if (height) {
        if (info.start && isHoriz) {
            height = height - FIT_REF_BAR_PROTRUSION;
        }
        if (info.end && isHoriz) {
            height = height - FIT_REF_BAR_PROTRUSION;
        }
    }
    if (maxLabelHeight && height) {
        height -= 2 * maxLabelHeight + 2 * LABEL_GAP;
    }
    return height;
};
const getFitMarginStyle = function (maxLabelWidth, maxLabelHeight, isHoriz) {
    const refMargin = `${xUnits(4)} + ${LABEL_GAP}px`;
    if (isHoriz) {
        return `calc(${refMargin} + ${maxLabelHeight}px) 0 calc(${refMargin} + ${maxLabelHeight}px) 0`;
    }
    return `0 calc(${refMargin} + ${maxLabelWidth}px) 0 calc(${refMargin} + ${maxLabelWidth}px)`;
};
/**
 * Returns the translation offset for the reference line label
 */
function getReferenceLineLabelTranslationOffset(isLeft, isBottom, isHoriz, isRtl, isStartPos, length, size) {
    const refLineLength = length || xUnits(REF_LINE_LENGTH_IN_XUNITS);
    const barSize = size || meterBarVars.size;
    const overHang = `calc(${refLineLength} - ${barSize})`;
    if (isHoriz) {
        if (isStartPos) {
            return `${isLeft ? '-50%' : '50%'} calc(-100% - ${overHang} - ${LABEL_GAP}px)`;
        }
        else {
            return `${isLeft ? '-50%' : '50%'} calc(${refLineLength} + ${LABEL_GAP}px)`;
        }
    }
    else {
        if (isRtl) {
            return isStartPos
                ? `calc(100% + ${overHang} + ${LABEL_GAP}px) ${isBottom ? '50%' : '-50%'}`
                : `calc(0px - ${refLineLength} - ${LABEL_GAP}px) ${isBottom ? '50%' : '-50%'}`;
        }
        else {
            return isStartPos
                ? `calc(-100% - ${overHang} - ${LABEL_GAP}px) ${isBottom ? '50%' : '-50%'}`
                : `calc(${refLineLength} + ${LABEL_GAP}px) ${isBottom ? '50%' : '-50%'}`;
        }
    }
}
/**
 * Returns the margin needed to accomodate reference line and label in a sized meter circle.
 */
function getSizedMargin(info, isHoriz, hasReferenceLine, hasReferenceLineLabel, maxRefLabelDims) {
    const marginValue = `calc(${xUnits(REF_LINE_LENGTH_IN_XUNITS)} - ${meterBarVars.size})`;
    const gap = LABEL_GAP;
    const hasBothPosition = info.start && info.end;
    if (hasReferenceLineLabel) {
        return isHoriz
            ? `calc(${maxRefLabelDims.height + gap}px + ${marginValue}) 0 calc(${maxRefLabelDims.height + gap}px + ${marginValue}) 0`
            : `0 calc(${maxRefLabelDims.width + gap}px + ${marginValue}) 0 calc(${maxRefLabelDims.width + gap}px + ${marginValue})`;
    }
    else if (hasReferenceLine) {
        if (hasBothPosition) {
            return isHoriz ? `${marginValue} 0 ${marginValue}` : `0 ${marginValue} 0 ${marginValue}`;
        }
        else if (info.start && !info.end) {
            return isHoriz ? `${marginValue} 0 0 0` : `0 ${marginValue} 0 0`;
        }
        else if (!info.start && info.end) {
            return isHoriz ? `0 0 ${marginValue} 0` : `0 0 0 ${marginValue}`;
        }
    }
    return undefined;
}
function getComponentStyle(isFit, isHoriz, length, maxRefLabelDims, fitTrackHeight, fitTrackWidth) {
    return {
        width: isFit ? fitTrackWidth : isHoriz ? sizeToCSS(length) : undefined,
        height: isFit ? fitTrackHeight : isHoriz ? undefined : sizeToCSS(length),
        margin: isFit
            ? getFitMarginStyle(maxRefLabelDims.width, maxRefLabelDims.height, isHoriz)
            : undefined
    };
}
function getReferenceLineAlignmentStyle(isLeft, isRtl, maxLabelWidth, percentage) {
    return {
        left: isLeft ? `max(${maxLabelWidth}px, ${isRtl ? 100 - percentage : percentage}%)` : undefined,
        right: !isLeft
            ? `max(${maxLabelWidth}px, ${isRtl ? percentage : 100 - percentage}%)`
            : undefined
    };
}
function getReferenceLineTranslation(isHoriz, isRtl, percent) {
    if (percent === 0 && !isRtl) {
        return;
    }
    if (percent === 100) {
        if (isRtl)
            return isHoriz ? '3px' : '0 3px';
        return isHoriz ? '-2px' : '0 2px';
    }
    return isHoriz ? (isRtl ? '1px 0' : '-1px 0') : isRtl ? '0 -1px' : '0 1px';
}
function getReferenceLinePosition(isHoriz, isLeft, isBottom, isRtl, percent, maxLabelWidth, maxLabelHeight) {
    return {
        ...(isHoriz ? getReferenceLineAlignmentStyle(isLeft, isRtl, maxLabelWidth / 2, percent) : {}),
        bottom: isHoriz
            ? undefined
            : isBottom
                ? `max(${maxLabelHeight / 2 - LABEL_GAP}px, ${percent}%)`
                : undefined,
        top: isHoriz
            ? undefined
            : !isBottom
                ? `max(${maxLabelHeight / 2 - LABEL_GAP}px, ${100 - percent}%)`
                : undefined,
        maxWidth: !isHoriz ? xUnits(MAX_VERTICAL_LABEL_WIDTH_IN_XUNITS) : undefined
    };
}

function ReferenceLineBar({ orientation, percent, color, position, length, label, maxLabelWidth, maxLabelHeight, trackSize, labelStyle }) {
    const isHoriz = orientation === 'horizontal';
    const { direction } = useUser();
    const isRtl = direction === 'rtl';
    const isStartPos = position === 'start';
    const percentage = `${percent}%`;
    const width = isHoriz ? undefined : length;
    const height = isHoriz ? length : undefined;
    const isLeft = (percent < 50 && !isRtl) || (percent > 50 && isRtl);
    const isBottom = percent < 50;
    return (jsxs(Fragment, { children: [jsx("div", { class: classNames([
                    styles.referenceLinesBaseStyle,
                    isHoriz ? styles.referenceLinesHorizontalStyle : styles.referenceLinesVerticalStyle,
                    isStartPos
                        ? isHoriz
                            ? styles.referenceLinesHoriontalStartStyle
                            : isRtl
                                ? styles.referenceLinesVerticalStartRtlStyle
                                : styles.referenceLinesVerticalStartLtrStyle
                        : ''
                ]), style: {
                    left: isHoriz && !isRtl ? percentage : undefined,
                    right: isHoriz && isRtl ? percentage : undefined,
                    bottom: isHoriz ? undefined : percentage,
                    backgroundColor: getVisThresholdColor(color),
                    width,
                    height,
                    translate: getReferenceLineTranslation(isHoriz, isRtl, percent)
                } }), label && (jsx("div", { className: styles.labelDivStyle, style: {
                    ...getReferenceLinePosition(isHoriz, isLeft, isBottom, isRtl, percent, maxLabelWidth, maxLabelHeight),
                    translate: getReferenceLineLabelTranslationOffset(isLeft, isBottom, isHoriz, isRtl, isStartPos, length, trackSize),
                    ...labelStyle
                }, children: label }))] }));
}

function ThresholdBar({ color, length, orientation, ...otherProps }) {
    const { direction } = useUser();
    const isHoriz = orientation === 'horizontal';
    const isRtl = direction === 'rtl';
    return (jsx("div", { class: classNames([
            styles.thresholdBarBaseStyle,
            isHoriz
                ? isRtl
                    ? styles.thresholdBarHorizontalBarTrackSectionRtlStyle
                    : styles.thresholdBarHorizontalBarTrackSectionLtrStyle
                : styles.thresholdBarVerticalBarTrackSectionStyle,
            otherProps.class
        ]), style: {
            width: isHoriz ? length : '100%',
            height: isHoriz ? '100%' : length,
            backgroundColor: getVisThresholdColor(color)
        } }));
}

function MeterBarWithDimensions({ max = 100, min = 0, value = 0, step = 1, length = '100%', width, height, size, orientation = 'horizontal', isTrackRendered = true, thresholdDisplay = 'all', indicatorSize = 1, testId, baseline, isReadonly, ...props }) {
    const testIdProps = useTestId(testId);
    validateRange(min, max, value, step, isReadonly, baseline);
    const currentInputRef = useRef();
    const isHoriz = orientation === 'horizontal';
    const barTrackRef = useRef(null);
    const dimensionsRef = useRef(getDimensions(null));
    const { direction, forcedColors } = useUser();
    const isRtl = direction === 'rtl';
    useEffect(() => {
        if (props.onCommit || props.onInput) {
            dimensionsRef.current = getDimensions(barTrackRef.current);
        }
    }, [size, length, orientation, props.onCommit, props.onInput]);
    const { textMeasureContent, getTextDimensions } = useTextDimensions();
    const getValueFromEvent = (event) => {
        // only evaluate value from bar track
        if (event.target == barTrackRef.current) {
            return getValue(event, dimensionsRef, min, max, step, orientation, isRtl);
        }
        return;
    };
    const isPointerActiveRef = useRef(false);
    const pointerEventsProps = usePointerEvents(value, getValueFromEvent, barTrackRef, 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 ariaLabelProps = getMeterAriaProps(value, min, max, props['aria-label'], props['aria-labelledby'], props.thresholds);
    const mergedProps = mergeProps(pointerEventsProps, keyboardEventsProps, datatipProps, ariaLabelProps);
    const resolvedBaseline = baseline !== undefined ? Math.max(min, Math.min(baseline, max)) : min;
    const baselineOffsetPercent = ((resolvedBaseline - min) * 100) / (max - min);
    const valueBarOffsetPercent = ((value - min) * 100) / (max - min);
    const valueBarStartOffset = Math.min(baselineOffsetPercent, valueBarOffsetPercent);
    const valueBarLength = `${Math.abs(baselineOffsetPercent - valueBarOffsetPercent)}%`;
    const valueBarSize = `${Math.max(0, Math.min(1, indicatorSize)) * 100}%`;
    const { trackColor, indicatorColor } = getTrackAndIndicatorColor(value, thresholdDisplay, props.trackColor, props.indicatorColor, props.thresholds);
    const refLineInfo = getRefLinesInfo(props.referenceLines);
    const isInteractive = props.onCommit || props.onInput;
    const { isTabbable } = useTabbableMode();
    const { classes, styles: { interactiveStyle, barValueBaseStyle, barValueVerticalStyle, barValueHorizontalStyle, barValueHighContrastStyle, barTrackBaseStyle, barTrackHorizontalSizeStyle, barTrackVerticalSizeStyle, barTrackBorderStyle, barTrackMarginTopFitStyle, barTrackMarginStartFitStyle, barTrackMarginBottomFitStyle, barTrackMarginEndFitStyle, trackSectionHorizontalFirstStyle, trackSectionHorizontalLastStyle, trackSectionVerticalFirstStyle, trackSectionVerticalLastStyle, trackSectionRoundedCornersStyle } } = useComponentTheme(MeterBarRedwoodTheme, {
        size,
        orientation
    });
    const isFit = size === 'fit';
    const hasReferenceLabel = hasLabelledReferenceLine(props.referenceLines);
    const fontSize = getDefaultReferenceLineLabelFontSize('sm');
    const meterBarCssVars = useMemo(() => [
        {
            tokenVar: fontSize,
            key: 'labelFontSize',
            cssProp: 'font-size'
        },
        {
            tokenVar: typographyVars.body.md.lineHeight,
            key: 'lineHeight',
            cssProp: 'line-height'
        }
    ], [fontSize]);
    const { resolvedVars, cssContent } = useCssVars(meterBarCssVars);
    const { dims, maxRefLabelDims } = getMaxRefLabelDims(resolvedVars['fontSize'], resolvedVars['lineHeight'], props.referenceLines, getTextDimensions);
    const fitTrackWidth = getFitTrackWidth(refLineInfo, maxRefLabelDims.width, width, isHoriz);
    const fitTrackHeight = getFitTrackHeight(refLineInfo, maxRefLabelDims.height, height, isHoriz);
    const fitTrackSize = isHoriz ? fitTrackHeight : fitTrackWidth;
    return (jsxs(Fragment, { children: [jsx("div", { tabIndex: !isTabbable ? -1 : 0, ...testIdProps, ...mergedProps, style: getComponentStyle(isFit, isHoriz, length, maxRefLabelDims, fitTrackHeight, fitTrackWidth), class: classNames([
                    classes,
                    ...(isFit
                        ? getFitMarginClass(refLineInfo, isHoriz, barTrackMarginTopFitStyle, barTrackMarginStartFitStyle, barTrackMarginBottomFitStyle, barTrackMarginEndFitStyle)
                        : [])
                ]), children: jsxs(BarTrack, { ref: barTrackRef, orientation: orientation, color: !isTrackRendered || (thresholdDisplay === 'all' && props.thresholds)
                        ? 'transparent'
                        : trackColor, class: classNames([
                        barTrackBaseStyle,
                        isInteractive ? interactiveStyle : '',
                        isHoriz ? barTrackHorizontalSizeStyle : barTrackVerticalSizeStyle,
                        !isTrackRendered || (thresholdDisplay === 'all' && props.thresholds)
                            ? undefined
                            : barTrackBorderStyle
                    ]), style: {
                        margin: !isFit
                            ? getSizedMargin(refLineInfo, isHoriz, !!props.referenceLines?.length, hasReferenceLabel, maxRefLabelDims)
                            : undefined
                    }, children: [thresholdDisplay === 'all' &&
                            props.thresholds
                                ?.filter((threshold) => threshold.max > min && threshold.max <= max)
                                .sort((a, b) => a.max - b.max)
                                .map((threshold, index, thresholds) => {
                                const diff = index === 0 ? threshold.max - min : threshold.max - thresholds[index - 1].max;
                                const trackSectionLastStyle = isHoriz
                                    ? trackSectionHorizontalLastStyle
                                    : trackSectionVerticalLastStyle;
                                let trackSectionStyleClass = index === 0
                                    ? isHoriz
                                        ? trackSectionHorizontalFirstStyle
                                        : trackSectionVerticalFirstStyle
                                    : '';
                                if (threshold.max === max)
                                    trackSectionStyleClass =
                                        index === 0
                                            ? trackSectionRoundedCornersStyle // Single threshold from min to max
                                            : trackSectionLastStyle;
                                return (jsxs(Fragment, { children: [jsx(ThresholdBar, { class: trackSectionStyleClass, orientation: orientation, length: `${(diff * 100) / (max - min)}%`, color: threshold.color }), isTrackRendered && index === thresholds.length - 1 && threshold.max < max ? (jsx(ThresholdBar, { class: trackSectionLastStyle, color: trackColor, orientation: orientation, length: `${((max - thresholds[index].max) * 100) / (max - min)}%` })) : ('')] }));
                            }), jsx(BarValue, { left: isHoriz && !isRtl ? `${valueBarStartOffset}%` : undefined, bottom: !isHoriz ? `${valueBarStartOffset}%` : undefined, right: isHoriz && isRtl ? `${valueBarStartOffset}%` : undefined, width: isHoriz ? valueBarLength : '100%', height: isHoriz ? '100%' : valueBarLength, length: valueBarLength, size: valueBarSize, orientation: orientation, class: classNames([
                                barValueBaseStyle,
                                isHoriz ? barValueHorizontalStyle : barValueVerticalStyle,
                                forcedColors === 'active' ? barValueHighContrastStyle : ''
                            ]), color: indicatorColor }), props.referenceLines?.map((refLine, index) => (jsx(ReferenceLineBar, { label: refLine.label, labelStyle: {
                                fontSize: resolvedVars['labelFontSize'],
                                ...refLine.labelStyle
                            }, color: refLine.color, maxLabelWidth: dims[index]?.width, maxLabelHeight: dims[index]?.height, orientation: orientation, percent: ((refLine.value - min) * 100) / (max - min), position: refLine.position, trackSize: isFit ? `${fitTrackSize}px` : meterBarVars.size, length: isFit ? `calc(${xUnits(4)} + ${fitTrackSize}px)` : undefined })))] }) }), cssContent, datatipContent, textMeasureContent] }));
}

/**
 * A Meter bar displays information graphically in a rectangular bar, highlighting a specific metric value's progress in relation to its min, max, or thresholds.
 */
function MeterBar({ orientation, length, size, ...props }) {
    return (jsx(Fragment, { children: size === 'fit' ? (jsx(TrackResizeContainer, { width: "100%", height: "100%", children: (width, height) => (jsx(MeterBarWithDimensions, { width: width, height: height, orientation: orientation, size: size, ...props })) })) : (jsx(MeterBarWithDimensions, { size: size, length: length, orientation: orientation, ...props })) }));
}

export { MeterBar as M };
//# sourceMappingURL=MeterBar-732e3b2c.js.map
