@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 CHANGED
@@ -247,8 +247,12 @@ interface UseMessageTTSReturn {
247
247
  isSynthesizing: boolean;
248
248
  /** 错误信息 */
249
249
  error: string | null;
250
- /** 播放进度(0-1) */
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
- /** 高度(px) */
682
- height?: number;
683
- /** 宽度(px) */
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-1) */
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
- /** 高度(px) */
682
- height?: number;
683
- /** 宽度(px) */
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({ progress });
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: { display: "block" }
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 rounded = Math.round(next);
2031
- if (progressTextRef.current.textContent !== `${rounded}%`) {
2032
- progressTextRef.current.textContent = `${rounded}%`;
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 rounded = Math.round(percentage);
2065
- if (progressTextRef.current.textContent !== `${rounded}%`) {
2066
- progressTextRef.current.textContent = `${rounded}%`;
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.jsxs)(
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({ progress });
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: { display: "block" }
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 rounded = Math.round(next);
1987
- if (progressTextRef.current.textContent !== `${rounded}%`) {
1988
- progressTextRef.current.textContent = `${rounded}%`;
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 rounded = Math.round(percentage);
2021
- if (progressTextRef.current.textContent !== `${rounded}%`) {
2022
- progressTextRef.current.textContent = `${rounded}%`;
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__ */ jsxs(
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
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wq-hook/volcano-react",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Volcano Engine ASR & TTS React Hooks",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",