@medalsocial/meda
Version:
Shared Meda UI shell and runtime package.
32 lines (31 loc) • 2.26 kB
JavaScript
'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import * as React from 'react';
import { cn } from '../lib/utils.js';
const BAR_COUNT = 9;
export function VoiceLevel({ level, variant = 'bars', width = 140, height = 48, className, }) {
const historyRef = React.useRef(Array(BAR_COUNT).fill(0));
const [, force] = React.useState(0);
// Only the 'bars' variant reads historyRef, so gate history updates and the
// resulting forced rerender to that variant — avoids a superfluous render on
// every level tick for 'ring' and 'wave'.
React.useEffect(() => {
if (variant !== 'bars')
return;
historyRef.current = [...historyRef.current.slice(1), Math.min(1, Math.max(0, level))];
force((v) => v + 1);
}, [level, variant]);
if (variant === 'bars') {
return (_jsx("div", { role: "presentation", className: cn('flex items-end gap-1', className), style: { width, height }, children: historyRef.current.map((v, i) => (_jsx("span", { className: "flex-1 rounded-sm bg-primary", style: { height: `${15 + v * 85}%`, opacity: 0.4 + v * 0.6 } }, i))) }));
}
if (variant === 'ring') {
const r = Math.min(width, height) / 2 - 4;
const c = 2 * Math.PI * r;
const filled = c * Math.min(1, Math.max(0, level));
return (_jsxs("svg", { width: width, height: height, className: className, role: "presentation", children: [_jsx("circle", { cx: width / 2, cy: height / 2, r: r, stroke: "hsl(var(--border))", strokeWidth: "3", fill: "none" }), _jsx("circle", { cx: width / 2, cy: height / 2, r: r, stroke: "hsl(var(--primary))", strokeWidth: "3", fill: "none", strokeDasharray: `${filled} ${c}`, strokeLinecap: "round", transform: `rotate(-90 ${width / 2} ${height / 2})` })] }));
}
// 'wave' — simple bezier that scales with level
const peak = height / 2 - 2;
const amp = peak * Math.min(1, Math.max(0, level));
return (_jsx("svg", { width: width, height: height, className: className, role: "presentation", children: _jsx("path", { d: `M 0 ${height / 2} Q ${width / 4} ${height / 2 - amp}, ${width / 2} ${height / 2} T ${width} ${height / 2}`, stroke: "hsl(var(--primary))", strokeWidth: "2", fill: "none" }) }));
}