UNPKG

@nafr/echo-ui

Version:

A UI library born for WAA

83 lines (82 loc) 4.24 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState } from 'react'; import { scaleLinear } from 'd3'; import { cn } from '../../../lib/utils'; import { VuMeterContext, VuMeterContextProvider } from './context'; import { checkPropsIsValid } from './utils'; import { useStyle } from './styles'; import { DEFAULT_LUMPS_QUANTITY, MIN, MAX, MIN_THRESHOLD, MAX_THRESHOLD } from './constants'; import { Axis } from '../Axis'; export const VuMeter = forwardRef((props, ref) => { const { value, horizontal = false, compact = false, lumpsQuantity = DEFAULT_LUMPS_QUANTITY, hideAxis = false, axisProps, classNames, styles, onChange, ...restProps } = props; useImperativeHandle(ref, () => vuMeterRef.current); const monoRef = useRef(null); const stereoRef = useRef(null); useEffect(() => { checkPropsIsValid(props); }, []); const vuMeterRef = useRef(null); const isStereo = Array.isArray(value); const [lumps, setLumps] = useState(Array(lumpsQuantity).fill(0)); const [stereoLumps, setStereoLumps] = useState([ Array(lumpsQuantity).fill(0), Array(lumpsQuantity).fill(0), ]); const scale = scaleLinear().domain([MIN, MAX]).range([0, lumps.length]); const updateLumps = () => { if (isStereo) { const leftDBValue = scale(value[0]); const rightDBValue = scale(value[1]); const newLumps = [ stereoLumps[0].map((_, index) => (index < leftDBValue ? 1 : 0)), stereoLumps[1].map((_, index) => (index < rightDBValue ? 1 : 0)), ]; setStereoLumps(newLumps); } else { const dBValue = scale(value); const newLumps = lumps.map((_, index) => (index < dBValue ? 1 : 0)); setLumps(newLumps); } }; useEffect(() => { onChange && onChange(value); updateLumps(); }, [value, onChange]); const { base, lumps: _lumps, lump, axis } = useStyle({ horizontal, isStereo, compact }); const contextValue = { horizontal, styles, classNames, minThresholdValue: scale(MIN_THRESHOLD), maxThresholdValue: scale(MAX_THRESHOLD), _lumps, lump, }; return (_jsx(VuMeterContextProvider, { value: contextValue, children: _jsx("div", { ...restProps, ref: vuMeterRef, className: cn(restProps.className), style: { ...restProps.style, display: 'flex', }, children: _jsxs("div", { className: cn(base()), children: [isStereo ? (_jsx(StereoVuMeter, { ref: stereoRef, stereoLumps: stereoLumps })) : (_jsx(MonoVuMeter, { ref: monoRef, lumps: lumps })), !hideAxis && (_jsx(Axis, { vertical: !horizontal, tickSize: 0, relatedRef: isStereo ? stereoRef : monoRef, ...axisProps, className: cn(axis(), classNames?.axis), style: styles?.axis, min: MIN, max: MAX }))] }) }) })); }); const StereoVuMeter = forwardRef((props, ref) => { const { stereoLumps } = props; const { horizontal } = useContext(VuMeterContext); return (_jsx("div", { ref: ref, className: cn('flex gap-0.5', horizontal && 'flex-col'), children: stereoLumps.map((lumps, index) => (_jsx(MonoVuMeter, { lumps: lumps }, index))) })); }); const MonoVuMeter = forwardRef((props, ref) => { const { lumps } = props; const { horizontal, styles, classNames, minThresholdValue, maxThresholdValue, _lumps, lump } = useContext(VuMeterContext); const dataValue = (lumpValue, index) => { if (lumpValue === 1 && index <= minThresholdValue) return 'low'; if (lumpValue === 1 && index > maxThresholdValue) return 'high'; if (lumpValue === 1 && index <= maxThresholdValue) return 'medium'; return 'none'; }; return (_jsx("div", { ref: ref, className: cn(_lumps(), classNames?.lumps), style: { ...styles?.lumps, flexDirection: horizontal ? 'row' : 'column-reverse', }, children: lumps.map((lumpValue, index) => (_jsx("span", { "data-active": dataValue(lumpValue, index), className: cn(lump(), classNames?.lump), style: styles?.lump }, index))) })); });