@wq-hook/volcano-react 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +21 -5
- package/dist/index.d.ts +21 -5
- package/dist/index.js +94 -21
- package/dist/index.mjs +96 -23
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -247,8 +247,12 @@ interface UseMessageTTSReturn {
|
|
|
247
247
|
isSynthesizing: boolean;
|
|
248
248
|
/** 错误信息 */
|
|
249
249
|
error: string | null;
|
|
250
|
-
/** 播放进度(0-
|
|
250
|
+
/** 播放进度(0-100) */
|
|
251
251
|
progress: number;
|
|
252
|
+
/** 当前播放时间(秒) */
|
|
253
|
+
currentTime: number;
|
|
254
|
+
/** 音频总时长(秒) */
|
|
255
|
+
duration: number;
|
|
252
256
|
/** 播放文本方法 */
|
|
253
257
|
play: (text: string) => Promise<void>;
|
|
254
258
|
/** 暂停播放方法 */
|
|
@@ -348,6 +352,10 @@ interface UseStreamTTSReturn {
|
|
|
348
352
|
streamText: string;
|
|
349
353
|
/** 播放进度(0-100) */
|
|
350
354
|
progress: number;
|
|
355
|
+
/** 当前播放时间(秒) */
|
|
356
|
+
currentTime: number;
|
|
357
|
+
/** 音频总时长(秒) */
|
|
358
|
+
duration: number;
|
|
351
359
|
/** 建立 WebSocket 连接 */
|
|
352
360
|
connect: () => Promise<string>;
|
|
353
361
|
/** 接收流式文本块 */
|
|
@@ -395,6 +403,10 @@ interface StreamPlaybackState {
|
|
|
395
403
|
isPaused: boolean;
|
|
396
404
|
isSynthesizing: boolean;
|
|
397
405
|
progress: number;
|
|
406
|
+
/** 当前播放时间(秒) */
|
|
407
|
+
currentTime: number;
|
|
408
|
+
/** 音频总时长(秒) */
|
|
409
|
+
duration: number;
|
|
398
410
|
visualizationData: VisualizationData;
|
|
399
411
|
error: string | null;
|
|
400
412
|
isConnected: boolean;
|
|
@@ -678,10 +690,10 @@ interface AudioWaveVisualizerProps {
|
|
|
678
690
|
color?: string | [string, string];
|
|
679
691
|
/** 波形条数 */
|
|
680
692
|
bars?: number;
|
|
681
|
-
/**
|
|
682
|
-
height?: number;
|
|
683
|
-
/**
|
|
684
|
-
width?: number;
|
|
693
|
+
/** 高度:数字(像素)或 CSS 字符串(如 "60px"、"100%"、"5rem") */
|
|
694
|
+
height?: number | string;
|
|
695
|
+
/** 宽度:数字(像素)或 CSS 字符串(如 "100%"、"80%"、"300px") */
|
|
696
|
+
width?: number | string;
|
|
685
697
|
/** 自定义类名 */
|
|
686
698
|
className?: string;
|
|
687
699
|
/** 自定义样式 */
|
|
@@ -693,6 +705,10 @@ declare const AudioWaveVisualizer: React$1.FC<AudioWaveVisualizerProps>;
|
|
|
693
705
|
interface AudioProgressBarProps {
|
|
694
706
|
/** 播放进度(0-100) */
|
|
695
707
|
progress: number;
|
|
708
|
+
/** 当前播放时间(秒),传入后将显示时间格式 */
|
|
709
|
+
currentTime?: number;
|
|
710
|
+
/** 音频总时长(秒),传入后将显示时间格式 */
|
|
711
|
+
duration?: number;
|
|
696
712
|
/** 宽度(px 或百分比) */
|
|
697
713
|
width?: number | string;
|
|
698
714
|
/** 高度(px) */
|
package/dist/index.d.ts
CHANGED
|
@@ -247,8 +247,12 @@ interface UseMessageTTSReturn {
|
|
|
247
247
|
isSynthesizing: boolean;
|
|
248
248
|
/** 错误信息 */
|
|
249
249
|
error: string | null;
|
|
250
|
-
/** 播放进度(0-
|
|
250
|
+
/** 播放进度(0-100) */
|
|
251
251
|
progress: number;
|
|
252
|
+
/** 当前播放时间(秒) */
|
|
253
|
+
currentTime: number;
|
|
254
|
+
/** 音频总时长(秒) */
|
|
255
|
+
duration: number;
|
|
252
256
|
/** 播放文本方法 */
|
|
253
257
|
play: (text: string) => Promise<void>;
|
|
254
258
|
/** 暂停播放方法 */
|
|
@@ -348,6 +352,10 @@ interface UseStreamTTSReturn {
|
|
|
348
352
|
streamText: string;
|
|
349
353
|
/** 播放进度(0-100) */
|
|
350
354
|
progress: number;
|
|
355
|
+
/** 当前播放时间(秒) */
|
|
356
|
+
currentTime: number;
|
|
357
|
+
/** 音频总时长(秒) */
|
|
358
|
+
duration: number;
|
|
351
359
|
/** 建立 WebSocket 连接 */
|
|
352
360
|
connect: () => Promise<string>;
|
|
353
361
|
/** 接收流式文本块 */
|
|
@@ -395,6 +403,10 @@ interface StreamPlaybackState {
|
|
|
395
403
|
isPaused: boolean;
|
|
396
404
|
isSynthesizing: boolean;
|
|
397
405
|
progress: number;
|
|
406
|
+
/** 当前播放时间(秒) */
|
|
407
|
+
currentTime: number;
|
|
408
|
+
/** 音频总时长(秒) */
|
|
409
|
+
duration: number;
|
|
398
410
|
visualizationData: VisualizationData;
|
|
399
411
|
error: string | null;
|
|
400
412
|
isConnected: boolean;
|
|
@@ -678,10 +690,10 @@ interface AudioWaveVisualizerProps {
|
|
|
678
690
|
color?: string | [string, string];
|
|
679
691
|
/** 波形条数 */
|
|
680
692
|
bars?: number;
|
|
681
|
-
/**
|
|
682
|
-
height?: number;
|
|
683
|
-
/**
|
|
684
|
-
width?: number;
|
|
693
|
+
/** 高度:数字(像素)或 CSS 字符串(如 "60px"、"100%"、"5rem") */
|
|
694
|
+
height?: number | string;
|
|
695
|
+
/** 宽度:数字(像素)或 CSS 字符串(如 "100%"、"80%"、"300px") */
|
|
696
|
+
width?: number | string;
|
|
685
697
|
/** 自定义类名 */
|
|
686
698
|
className?: string;
|
|
687
699
|
/** 自定义样式 */
|
|
@@ -693,6 +705,10 @@ declare const AudioWaveVisualizer: React$1.FC<AudioWaveVisualizerProps>;
|
|
|
693
705
|
interface AudioProgressBarProps {
|
|
694
706
|
/** 播放进度(0-100) */
|
|
695
707
|
progress: number;
|
|
708
|
+
/** 当前播放时间(秒),传入后将显示时间格式 */
|
|
709
|
+
currentTime?: number;
|
|
710
|
+
/** 音频总时长(秒),传入后将显示时间格式 */
|
|
711
|
+
duration?: number;
|
|
696
712
|
/** 宽度(px 或百分比) */
|
|
697
713
|
width?: number | string;
|
|
698
714
|
/** 高度(px) */
|
package/dist/index.js
CHANGED
|
@@ -804,6 +804,8 @@ var PlaybackSession = class {
|
|
|
804
804
|
isPaused: false,
|
|
805
805
|
isSynthesizing: false,
|
|
806
806
|
progress: 0,
|
|
807
|
+
currentTime: 0,
|
|
808
|
+
duration: 0,
|
|
807
809
|
visualizationData: {
|
|
808
810
|
frequencyData: new Uint8Array(0),
|
|
809
811
|
timeDomainData: new Uint8Array(0)
|
|
@@ -907,7 +909,11 @@ var PlaybackSession = class {
|
|
|
907
909
|
}
|
|
908
910
|
if (isFinite(duration) && duration > 0) {
|
|
909
911
|
const progress = this.audio.currentTime / duration * 100;
|
|
910
|
-
this.updateState({
|
|
912
|
+
this.updateState({
|
|
913
|
+
progress,
|
|
914
|
+
currentTime: this.audio.currentTime,
|
|
915
|
+
duration
|
|
916
|
+
});
|
|
911
917
|
}
|
|
912
918
|
};
|
|
913
919
|
}
|
|
@@ -1429,6 +1435,8 @@ function useMessageTTS({
|
|
|
1429
1435
|
isPaused: false,
|
|
1430
1436
|
isSynthesizing: false,
|
|
1431
1437
|
progress: 0,
|
|
1438
|
+
currentTime: 0,
|
|
1439
|
+
duration: 0,
|
|
1432
1440
|
visualizationData: {
|
|
1433
1441
|
frequencyData: new Uint8Array(0),
|
|
1434
1442
|
timeDomainData: new Uint8Array(0)
|
|
@@ -1679,6 +1687,8 @@ function useMessageTTS({
|
|
|
1679
1687
|
isPaused: state.isPaused,
|
|
1680
1688
|
isSynthesizing: state.isSynthesizing,
|
|
1681
1689
|
progress: state.progress,
|
|
1690
|
+
currentTime: state.currentTime,
|
|
1691
|
+
duration: state.duration,
|
|
1682
1692
|
error,
|
|
1683
1693
|
play,
|
|
1684
1694
|
pause,
|
|
@@ -1717,6 +1727,8 @@ function useStreamTTS({
|
|
|
1717
1727
|
isPaused: false,
|
|
1718
1728
|
isSynthesizing: false,
|
|
1719
1729
|
progress: 0,
|
|
1730
|
+
currentTime: 0,
|
|
1731
|
+
duration: 0,
|
|
1720
1732
|
visualizationData: {
|
|
1721
1733
|
frequencyData: new Uint8Array(0),
|
|
1722
1734
|
timeDomainData: new Uint8Array(0)
|
|
@@ -1835,6 +1847,8 @@ function useStreamTTS({
|
|
|
1835
1847
|
error: state.error,
|
|
1836
1848
|
streamText,
|
|
1837
1849
|
progress: state.progress,
|
|
1850
|
+
currentTime: state.currentTime,
|
|
1851
|
+
duration: state.duration,
|
|
1838
1852
|
connect,
|
|
1839
1853
|
onMessage,
|
|
1840
1854
|
finishStream,
|
|
@@ -1865,10 +1879,40 @@ var AudioWaveVisualizer = ({
|
|
|
1865
1879
|
styleObj
|
|
1866
1880
|
}) => {
|
|
1867
1881
|
const canvasRef = (0, import_react5.useRef)(null);
|
|
1882
|
+
const containerRef = (0, import_react5.useRef)(null);
|
|
1868
1883
|
const requestRef = (0, import_react5.useRef)(null);
|
|
1884
|
+
const isWidthResponsive = typeof width === "string";
|
|
1885
|
+
const isHeightResponsive = typeof height === "string";
|
|
1886
|
+
const [canvasWidth, setCanvasWidth] = (0, import_react5.useState)(() => {
|
|
1887
|
+
return typeof width === "number" ? width : 200;
|
|
1888
|
+
});
|
|
1889
|
+
const [canvasHeight, setCanvasHeight] = (0, import_react5.useState)(() => {
|
|
1890
|
+
return typeof height === "number" ? height : 60;
|
|
1891
|
+
});
|
|
1892
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1893
|
+
(0, import_react5.useEffect)(() => {
|
|
1894
|
+
if (!containerRef.current) return;
|
|
1895
|
+
if (!isWidthResponsive && !isHeightResponsive) return;
|
|
1896
|
+
const container = containerRef.current;
|
|
1897
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
|
1898
|
+
for (const entry of entries) {
|
|
1899
|
+
const { width: containerWidth, height: containerHeight } = entry.contentRect;
|
|
1900
|
+
if (isWidthResponsive) {
|
|
1901
|
+
setCanvasWidth(Math.floor(containerWidth * dpr));
|
|
1902
|
+
}
|
|
1903
|
+
if (isHeightResponsive) {
|
|
1904
|
+
setCanvasHeight(Math.floor(containerHeight * dpr));
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
});
|
|
1908
|
+
resizeObserver.observe(container);
|
|
1909
|
+
return () => {
|
|
1910
|
+
resizeObserver.disconnect();
|
|
1911
|
+
};
|
|
1912
|
+
}, [isWidthResponsive, isHeightResponsive, dpr]);
|
|
1869
1913
|
const progressBackground = Array.isArray(color) ? `linear-gradient(90deg, ${color[0]}, ${color[1]})` : color;
|
|
1870
1914
|
const textColor = Array.isArray(color) ? color[0] : color;
|
|
1871
|
-
const draw = () => {
|
|
1915
|
+
const draw = (0, import_react5.useCallback)(() => {
|
|
1872
1916
|
const canvas = canvasRef.current;
|
|
1873
1917
|
if (!canvas) return;
|
|
1874
1918
|
const ctx = canvas.getContext("2d");
|
|
@@ -1930,7 +1974,7 @@ var AudioWaveVisualizer = ({
|
|
|
1930
1974
|
if (isPlaying && !isPaused) {
|
|
1931
1975
|
requestRef.current = requestAnimationFrame(draw);
|
|
1932
1976
|
}
|
|
1933
|
-
};
|
|
1977
|
+
}, [isPlaying, isPaused, frequencyData, timeDomainData, style, color, bars]);
|
|
1934
1978
|
(0, import_react5.useEffect)(() => {
|
|
1935
1979
|
if (isPlaying && !isPaused) {
|
|
1936
1980
|
requestRef.current = requestAnimationFrame(draw);
|
|
@@ -1947,26 +1991,36 @@ var AudioWaveVisualizer = ({
|
|
|
1947
1991
|
frequencyData,
|
|
1948
1992
|
timeDomainData,
|
|
1949
1993
|
style,
|
|
1950
|
-
color
|
|
1994
|
+
color,
|
|
1995
|
+
draw
|
|
1951
1996
|
]);
|
|
1997
|
+
const actualCanvasWidth = isWidthResponsive ? canvasWidth : width;
|
|
1998
|
+
const actualCanvasHeight = isHeightResponsive ? canvasHeight : height;
|
|
1952
1999
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1953
2000
|
"div",
|
|
1954
2001
|
{
|
|
2002
|
+
ref: containerRef,
|
|
1955
2003
|
className,
|
|
1956
2004
|
style: {
|
|
1957
2005
|
display: "inline-flex",
|
|
1958
2006
|
flexDirection: "column",
|
|
1959
2007
|
gap: "4px",
|
|
1960
|
-
width,
|
|
2008
|
+
width: isWidthResponsive ? width : width,
|
|
2009
|
+
height: isHeightResponsive ? height : height,
|
|
1961
2010
|
...styleObj
|
|
1962
2011
|
},
|
|
1963
2012
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1964
2013
|
"canvas",
|
|
1965
2014
|
{
|
|
1966
2015
|
ref: canvasRef,
|
|
1967
|
-
width,
|
|
1968
|
-
height,
|
|
1969
|
-
style: {
|
|
2016
|
+
width: actualCanvasWidth,
|
|
2017
|
+
height: actualCanvasHeight,
|
|
2018
|
+
style: {
|
|
2019
|
+
display: "block",
|
|
2020
|
+
// 响应式模式下,CSS 尺寸为 100%;固定模式下使用像素值
|
|
2021
|
+
width: isWidthResponsive ? "100%" : actualCanvasWidth,
|
|
2022
|
+
height: isHeightResponsive ? "100%" : actualCanvasHeight
|
|
2023
|
+
}
|
|
1970
2024
|
}
|
|
1971
2025
|
)
|
|
1972
2026
|
}
|
|
@@ -1977,8 +2031,20 @@ var AudioWaveVisualizer_default = AudioWaveVisualizer;
|
|
|
1977
2031
|
// src/components/AudioProgressBar.tsx
|
|
1978
2032
|
var import_react6 = require("react");
|
|
1979
2033
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2034
|
+
var formatTime = (seconds) => {
|
|
2035
|
+
if (!isFinite(seconds) || seconds < 0) return "0:00";
|
|
2036
|
+
const hours = Math.floor(seconds / 3600);
|
|
2037
|
+
const minutes = Math.floor(seconds % 3600 / 60);
|
|
2038
|
+
const secs = Math.floor(seconds % 60);
|
|
2039
|
+
if (hours > 0) {
|
|
2040
|
+
return `${hours}:${minutes.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
|
|
2041
|
+
}
|
|
2042
|
+
return `${minutes}:${secs.toString().padStart(2, "0")}`;
|
|
2043
|
+
};
|
|
1980
2044
|
var AudioProgressBar = ({
|
|
1981
2045
|
progress,
|
|
2046
|
+
currentTime,
|
|
2047
|
+
duration,
|
|
1982
2048
|
width = "100%",
|
|
1983
2049
|
height = 6,
|
|
1984
2050
|
color = "#8b5cf6",
|
|
@@ -1997,6 +2063,16 @@ var AudioProgressBar = ({
|
|
|
1997
2063
|
const isDragging = (0, import_react6.useRef)(false);
|
|
1998
2064
|
const isHovering = (0, import_react6.useRef)(false);
|
|
1999
2065
|
const isTouch = (0, import_react6.useRef)(false);
|
|
2066
|
+
const useTimeFormat = (0, import_react6.useMemo)(() => {
|
|
2067
|
+
return currentTime !== void 0 && duration !== void 0 && isFinite(currentTime) && isFinite(duration) && duration > 0;
|
|
2068
|
+
}, [currentTime, duration]);
|
|
2069
|
+
const getDisplayText = (percentage) => {
|
|
2070
|
+
if (useTimeFormat && currentTime !== void 0 && duration !== void 0) {
|
|
2071
|
+
const timeFromPercentage = percentage / 100 * duration;
|
|
2072
|
+
return `${formatTime(timeFromPercentage)} / ${formatTime(duration)}`;
|
|
2073
|
+
}
|
|
2074
|
+
return `${Math.round(percentage)}%`;
|
|
2075
|
+
};
|
|
2000
2076
|
(0, import_react6.useEffect)(() => {
|
|
2001
2077
|
const match = window.matchMedia("(pointer: coarse)");
|
|
2002
2078
|
isTouch.current = match.matches;
|
|
@@ -2027,9 +2103,9 @@ var AudioProgressBar = ({
|
|
|
2027
2103
|
thumbRef.current.style.left = `${next}%`;
|
|
2028
2104
|
}
|
|
2029
2105
|
if (showText && progressTextRef.current) {
|
|
2030
|
-
const
|
|
2031
|
-
if (progressTextRef.current.textContent !==
|
|
2032
|
-
progressTextRef.current.textContent =
|
|
2106
|
+
const newText = getDisplayText(next);
|
|
2107
|
+
if (progressTextRef.current.textContent !== newText) {
|
|
2108
|
+
progressTextRef.current.textContent = newText;
|
|
2033
2109
|
}
|
|
2034
2110
|
}
|
|
2035
2111
|
if (Math.abs(target - next) >= 0.1) {
|
|
@@ -2043,7 +2119,7 @@ var AudioProgressBar = ({
|
|
|
2043
2119
|
cancelAnimationFrame(requestRef.current);
|
|
2044
2120
|
}
|
|
2045
2121
|
};
|
|
2046
|
-
}, [progress, showText]);
|
|
2122
|
+
}, [progress, showText, currentTime, duration]);
|
|
2047
2123
|
const calculateProgress = (clientX) => {
|
|
2048
2124
|
if (!containerRef.current) return 0;
|
|
2049
2125
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -2061,9 +2137,9 @@ var AudioProgressBar = ({
|
|
|
2061
2137
|
thumbRef.current.style.left = `${percentage}%`;
|
|
2062
2138
|
}
|
|
2063
2139
|
if (showText && progressTextRef.current) {
|
|
2064
|
-
const
|
|
2065
|
-
if (progressTextRef.current.textContent !==
|
|
2066
|
-
progressTextRef.current.textContent =
|
|
2140
|
+
const newText = getDisplayText(percentage);
|
|
2141
|
+
if (progressTextRef.current.textContent !== newText) {
|
|
2142
|
+
progressTextRef.current.textContent = newText;
|
|
2067
2143
|
}
|
|
2068
2144
|
}
|
|
2069
2145
|
};
|
|
@@ -2196,22 +2272,19 @@ var AudioProgressBar = ({
|
|
|
2196
2272
|
]
|
|
2197
2273
|
}
|
|
2198
2274
|
),
|
|
2199
|
-
showText && /* @__PURE__ */ (0, import_jsx_runtime2.
|
|
2275
|
+
showText && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2200
2276
|
"span",
|
|
2201
2277
|
{
|
|
2202
2278
|
ref: progressTextRef,
|
|
2203
2279
|
style: {
|
|
2204
2280
|
fontSize: "12px",
|
|
2205
2281
|
color: textColor,
|
|
2206
|
-
minWidth: "32px",
|
|
2282
|
+
minWidth: useTimeFormat ? "80px" : "32px",
|
|
2207
2283
|
textAlign: "right",
|
|
2208
2284
|
fontFamily: "monospace",
|
|
2209
2285
|
lineHeight: 1
|
|
2210
2286
|
},
|
|
2211
|
-
children:
|
|
2212
|
-
Math.round(displayedProgress.current),
|
|
2213
|
-
"%"
|
|
2214
|
-
]
|
|
2287
|
+
children: getDisplayText(displayedProgress.current)
|
|
2215
2288
|
}
|
|
2216
2289
|
)
|
|
2217
2290
|
]
|
package/dist/index.mjs
CHANGED
|
@@ -760,6 +760,8 @@ var PlaybackSession = class {
|
|
|
760
760
|
isPaused: false,
|
|
761
761
|
isSynthesizing: false,
|
|
762
762
|
progress: 0,
|
|
763
|
+
currentTime: 0,
|
|
764
|
+
duration: 0,
|
|
763
765
|
visualizationData: {
|
|
764
766
|
frequencyData: new Uint8Array(0),
|
|
765
767
|
timeDomainData: new Uint8Array(0)
|
|
@@ -863,7 +865,11 @@ var PlaybackSession = class {
|
|
|
863
865
|
}
|
|
864
866
|
if (isFinite(duration) && duration > 0) {
|
|
865
867
|
const progress = this.audio.currentTime / duration * 100;
|
|
866
|
-
this.updateState({
|
|
868
|
+
this.updateState({
|
|
869
|
+
progress,
|
|
870
|
+
currentTime: this.audio.currentTime,
|
|
871
|
+
duration
|
|
872
|
+
});
|
|
867
873
|
}
|
|
868
874
|
};
|
|
869
875
|
}
|
|
@@ -1385,6 +1391,8 @@ function useMessageTTS({
|
|
|
1385
1391
|
isPaused: false,
|
|
1386
1392
|
isSynthesizing: false,
|
|
1387
1393
|
progress: 0,
|
|
1394
|
+
currentTime: 0,
|
|
1395
|
+
duration: 0,
|
|
1388
1396
|
visualizationData: {
|
|
1389
1397
|
frequencyData: new Uint8Array(0),
|
|
1390
1398
|
timeDomainData: new Uint8Array(0)
|
|
@@ -1635,6 +1643,8 @@ function useMessageTTS({
|
|
|
1635
1643
|
isPaused: state.isPaused,
|
|
1636
1644
|
isSynthesizing: state.isSynthesizing,
|
|
1637
1645
|
progress: state.progress,
|
|
1646
|
+
currentTime: state.currentTime,
|
|
1647
|
+
duration: state.duration,
|
|
1638
1648
|
error,
|
|
1639
1649
|
play,
|
|
1640
1650
|
pause,
|
|
@@ -1673,6 +1683,8 @@ function useStreamTTS({
|
|
|
1673
1683
|
isPaused: false,
|
|
1674
1684
|
isSynthesizing: false,
|
|
1675
1685
|
progress: 0,
|
|
1686
|
+
currentTime: 0,
|
|
1687
|
+
duration: 0,
|
|
1676
1688
|
visualizationData: {
|
|
1677
1689
|
frequencyData: new Uint8Array(0),
|
|
1678
1690
|
timeDomainData: new Uint8Array(0)
|
|
@@ -1791,6 +1803,8 @@ function useStreamTTS({
|
|
|
1791
1803
|
error: state.error,
|
|
1792
1804
|
streamText,
|
|
1793
1805
|
progress: state.progress,
|
|
1806
|
+
currentTime: state.currentTime,
|
|
1807
|
+
duration: state.duration,
|
|
1794
1808
|
connect,
|
|
1795
1809
|
onMessage,
|
|
1796
1810
|
finishStream,
|
|
@@ -1805,7 +1819,7 @@ function useStreamTTS({
|
|
|
1805
1819
|
}
|
|
1806
1820
|
|
|
1807
1821
|
// src/components/AudioWaveVisualizer.tsx
|
|
1808
|
-
import { useEffect as useEffect4, useRef as useRef5 } from "react";
|
|
1822
|
+
import { useEffect as useEffect4, useRef as useRef5, useState as useState5, useCallback as useCallback5 } from "react";
|
|
1809
1823
|
import { jsx } from "react/jsx-runtime";
|
|
1810
1824
|
var AudioWaveVisualizer = ({
|
|
1811
1825
|
isPlaying,
|
|
@@ -1821,10 +1835,40 @@ var AudioWaveVisualizer = ({
|
|
|
1821
1835
|
styleObj
|
|
1822
1836
|
}) => {
|
|
1823
1837
|
const canvasRef = useRef5(null);
|
|
1838
|
+
const containerRef = useRef5(null);
|
|
1824
1839
|
const requestRef = useRef5(null);
|
|
1840
|
+
const isWidthResponsive = typeof width === "string";
|
|
1841
|
+
const isHeightResponsive = typeof height === "string";
|
|
1842
|
+
const [canvasWidth, setCanvasWidth] = useState5(() => {
|
|
1843
|
+
return typeof width === "number" ? width : 200;
|
|
1844
|
+
});
|
|
1845
|
+
const [canvasHeight, setCanvasHeight] = useState5(() => {
|
|
1846
|
+
return typeof height === "number" ? height : 60;
|
|
1847
|
+
});
|
|
1848
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1849
|
+
useEffect4(() => {
|
|
1850
|
+
if (!containerRef.current) return;
|
|
1851
|
+
if (!isWidthResponsive && !isHeightResponsive) return;
|
|
1852
|
+
const container = containerRef.current;
|
|
1853
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
|
1854
|
+
for (const entry of entries) {
|
|
1855
|
+
const { width: containerWidth, height: containerHeight } = entry.contentRect;
|
|
1856
|
+
if (isWidthResponsive) {
|
|
1857
|
+
setCanvasWidth(Math.floor(containerWidth * dpr));
|
|
1858
|
+
}
|
|
1859
|
+
if (isHeightResponsive) {
|
|
1860
|
+
setCanvasHeight(Math.floor(containerHeight * dpr));
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
});
|
|
1864
|
+
resizeObserver.observe(container);
|
|
1865
|
+
return () => {
|
|
1866
|
+
resizeObserver.disconnect();
|
|
1867
|
+
};
|
|
1868
|
+
}, [isWidthResponsive, isHeightResponsive, dpr]);
|
|
1825
1869
|
const progressBackground = Array.isArray(color) ? `linear-gradient(90deg, ${color[0]}, ${color[1]})` : color;
|
|
1826
1870
|
const textColor = Array.isArray(color) ? color[0] : color;
|
|
1827
|
-
const draw = () => {
|
|
1871
|
+
const draw = useCallback5(() => {
|
|
1828
1872
|
const canvas = canvasRef.current;
|
|
1829
1873
|
if (!canvas) return;
|
|
1830
1874
|
const ctx = canvas.getContext("2d");
|
|
@@ -1886,7 +1930,7 @@ var AudioWaveVisualizer = ({
|
|
|
1886
1930
|
if (isPlaying && !isPaused) {
|
|
1887
1931
|
requestRef.current = requestAnimationFrame(draw);
|
|
1888
1932
|
}
|
|
1889
|
-
};
|
|
1933
|
+
}, [isPlaying, isPaused, frequencyData, timeDomainData, style, color, bars]);
|
|
1890
1934
|
useEffect4(() => {
|
|
1891
1935
|
if (isPlaying && !isPaused) {
|
|
1892
1936
|
requestRef.current = requestAnimationFrame(draw);
|
|
@@ -1903,26 +1947,36 @@ var AudioWaveVisualizer = ({
|
|
|
1903
1947
|
frequencyData,
|
|
1904
1948
|
timeDomainData,
|
|
1905
1949
|
style,
|
|
1906
|
-
color
|
|
1950
|
+
color,
|
|
1951
|
+
draw
|
|
1907
1952
|
]);
|
|
1953
|
+
const actualCanvasWidth = isWidthResponsive ? canvasWidth : width;
|
|
1954
|
+
const actualCanvasHeight = isHeightResponsive ? canvasHeight : height;
|
|
1908
1955
|
return /* @__PURE__ */ jsx(
|
|
1909
1956
|
"div",
|
|
1910
1957
|
{
|
|
1958
|
+
ref: containerRef,
|
|
1911
1959
|
className,
|
|
1912
1960
|
style: {
|
|
1913
1961
|
display: "inline-flex",
|
|
1914
1962
|
flexDirection: "column",
|
|
1915
1963
|
gap: "4px",
|
|
1916
|
-
width,
|
|
1964
|
+
width: isWidthResponsive ? width : width,
|
|
1965
|
+
height: isHeightResponsive ? height : height,
|
|
1917
1966
|
...styleObj
|
|
1918
1967
|
},
|
|
1919
1968
|
children: /* @__PURE__ */ jsx(
|
|
1920
1969
|
"canvas",
|
|
1921
1970
|
{
|
|
1922
1971
|
ref: canvasRef,
|
|
1923
|
-
width,
|
|
1924
|
-
height,
|
|
1925
|
-
style: {
|
|
1972
|
+
width: actualCanvasWidth,
|
|
1973
|
+
height: actualCanvasHeight,
|
|
1974
|
+
style: {
|
|
1975
|
+
display: "block",
|
|
1976
|
+
// 响应式模式下,CSS 尺寸为 100%;固定模式下使用像素值
|
|
1977
|
+
width: isWidthResponsive ? "100%" : actualCanvasWidth,
|
|
1978
|
+
height: isHeightResponsive ? "100%" : actualCanvasHeight
|
|
1979
|
+
}
|
|
1926
1980
|
}
|
|
1927
1981
|
)
|
|
1928
1982
|
}
|
|
@@ -1931,10 +1985,22 @@ var AudioWaveVisualizer = ({
|
|
|
1931
1985
|
var AudioWaveVisualizer_default = AudioWaveVisualizer;
|
|
1932
1986
|
|
|
1933
1987
|
// src/components/AudioProgressBar.tsx
|
|
1934
|
-
import { useEffect as useEffect5, useRef as useRef6 } from "react";
|
|
1988
|
+
import { useEffect as useEffect5, useRef as useRef6, useMemo } from "react";
|
|
1935
1989
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
1990
|
+
var formatTime = (seconds) => {
|
|
1991
|
+
if (!isFinite(seconds) || seconds < 0) return "0:00";
|
|
1992
|
+
const hours = Math.floor(seconds / 3600);
|
|
1993
|
+
const minutes = Math.floor(seconds % 3600 / 60);
|
|
1994
|
+
const secs = Math.floor(seconds % 60);
|
|
1995
|
+
if (hours > 0) {
|
|
1996
|
+
return `${hours}:${minutes.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
|
|
1997
|
+
}
|
|
1998
|
+
return `${minutes}:${secs.toString().padStart(2, "0")}`;
|
|
1999
|
+
};
|
|
1936
2000
|
var AudioProgressBar = ({
|
|
1937
2001
|
progress,
|
|
2002
|
+
currentTime,
|
|
2003
|
+
duration,
|
|
1938
2004
|
width = "100%",
|
|
1939
2005
|
height = 6,
|
|
1940
2006
|
color = "#8b5cf6",
|
|
@@ -1953,6 +2019,16 @@ var AudioProgressBar = ({
|
|
|
1953
2019
|
const isDragging = useRef6(false);
|
|
1954
2020
|
const isHovering = useRef6(false);
|
|
1955
2021
|
const isTouch = useRef6(false);
|
|
2022
|
+
const useTimeFormat = useMemo(() => {
|
|
2023
|
+
return currentTime !== void 0 && duration !== void 0 && isFinite(currentTime) && isFinite(duration) && duration > 0;
|
|
2024
|
+
}, [currentTime, duration]);
|
|
2025
|
+
const getDisplayText = (percentage) => {
|
|
2026
|
+
if (useTimeFormat && currentTime !== void 0 && duration !== void 0) {
|
|
2027
|
+
const timeFromPercentage = percentage / 100 * duration;
|
|
2028
|
+
return `${formatTime(timeFromPercentage)} / ${formatTime(duration)}`;
|
|
2029
|
+
}
|
|
2030
|
+
return `${Math.round(percentage)}%`;
|
|
2031
|
+
};
|
|
1956
2032
|
useEffect5(() => {
|
|
1957
2033
|
const match = window.matchMedia("(pointer: coarse)");
|
|
1958
2034
|
isTouch.current = match.matches;
|
|
@@ -1983,9 +2059,9 @@ var AudioProgressBar = ({
|
|
|
1983
2059
|
thumbRef.current.style.left = `${next}%`;
|
|
1984
2060
|
}
|
|
1985
2061
|
if (showText && progressTextRef.current) {
|
|
1986
|
-
const
|
|
1987
|
-
if (progressTextRef.current.textContent !==
|
|
1988
|
-
progressTextRef.current.textContent =
|
|
2062
|
+
const newText = getDisplayText(next);
|
|
2063
|
+
if (progressTextRef.current.textContent !== newText) {
|
|
2064
|
+
progressTextRef.current.textContent = newText;
|
|
1989
2065
|
}
|
|
1990
2066
|
}
|
|
1991
2067
|
if (Math.abs(target - next) >= 0.1) {
|
|
@@ -1999,7 +2075,7 @@ var AudioProgressBar = ({
|
|
|
1999
2075
|
cancelAnimationFrame(requestRef.current);
|
|
2000
2076
|
}
|
|
2001
2077
|
};
|
|
2002
|
-
}, [progress, showText]);
|
|
2078
|
+
}, [progress, showText, currentTime, duration]);
|
|
2003
2079
|
const calculateProgress = (clientX) => {
|
|
2004
2080
|
if (!containerRef.current) return 0;
|
|
2005
2081
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -2017,9 +2093,9 @@ var AudioProgressBar = ({
|
|
|
2017
2093
|
thumbRef.current.style.left = `${percentage}%`;
|
|
2018
2094
|
}
|
|
2019
2095
|
if (showText && progressTextRef.current) {
|
|
2020
|
-
const
|
|
2021
|
-
if (progressTextRef.current.textContent !==
|
|
2022
|
-
progressTextRef.current.textContent =
|
|
2096
|
+
const newText = getDisplayText(percentage);
|
|
2097
|
+
if (progressTextRef.current.textContent !== newText) {
|
|
2098
|
+
progressTextRef.current.textContent = newText;
|
|
2023
2099
|
}
|
|
2024
2100
|
}
|
|
2025
2101
|
};
|
|
@@ -2152,22 +2228,19 @@ var AudioProgressBar = ({
|
|
|
2152
2228
|
]
|
|
2153
2229
|
}
|
|
2154
2230
|
),
|
|
2155
|
-
showText && /* @__PURE__ */
|
|
2231
|
+
showText && /* @__PURE__ */ jsx2(
|
|
2156
2232
|
"span",
|
|
2157
2233
|
{
|
|
2158
2234
|
ref: progressTextRef,
|
|
2159
2235
|
style: {
|
|
2160
2236
|
fontSize: "12px",
|
|
2161
2237
|
color: textColor,
|
|
2162
|
-
minWidth: "32px",
|
|
2238
|
+
minWidth: useTimeFormat ? "80px" : "32px",
|
|
2163
2239
|
textAlign: "right",
|
|
2164
2240
|
fontFamily: "monospace",
|
|
2165
2241
|
lineHeight: 1
|
|
2166
2242
|
},
|
|
2167
|
-
children:
|
|
2168
|
-
Math.round(displayedProgress.current),
|
|
2169
|
-
"%"
|
|
2170
|
-
]
|
|
2243
|
+
children: getDisplayText(displayedProgress.current)
|
|
2171
2244
|
}
|
|
2172
2245
|
)
|
|
2173
2246
|
]
|