@chrisabdo/audio
Advanced tools
Comparing version 0.1.0 to 0.1.1
import React from 'react'; | ||
interface AudioProps extends React.AudioHTMLAttributes<HTMLAudioElement> { | ||
progressColor?: string; | ||
controlsColor?: string; | ||
textColor?: string; | ||
controlsBackgroundColor?: string; | ||
} | ||
@@ -5,0 +9,0 @@ declare const Audio: React.FC<AudioProps>; |
@@ -30,11 +30,15 @@ "use strict"; | ||
var import_jsx_runtime = require("react/jsx-runtime"); | ||
var Audio = ({ src, className, ...props }) => { | ||
var Audio = ({ | ||
src, | ||
className, | ||
progressColor = "#3B82F6", | ||
controlsColor = "#FFFFFF", | ||
textColor = "#FFFFFF", | ||
controlsBackgroundColor = "rgba(0, 0, 0, 0.5)", | ||
...props | ||
}) => { | ||
const audioRef = (0, import_react.useRef)(null); | ||
const [isPlaying, setIsPlaying] = (0, import_react.useState)(false); | ||
const togglePlay = () => { | ||
const audio = audioRef.current; | ||
if (!audio) | ||
return; | ||
isPlaying ? audio.pause() : audio.play(); | ||
}; | ||
const [progress, setProgress] = (0, import_react.useState)(0); | ||
const [volume, setVolume] = (0, import_react.useState)(1); | ||
(0, import_react.useEffect)(() => { | ||
@@ -44,7 +48,10 @@ const audio = audioRef.current; | ||
return; | ||
const updateProgress = () => setProgress(audio.currentTime / audio.duration * 100); | ||
const handlePlay = () => setIsPlaying(true); | ||
const handlePause = () => setIsPlaying(false); | ||
audio.addEventListener("timeupdate", updateProgress); | ||
audio.addEventListener("play", handlePlay); | ||
audio.addEventListener("pause", handlePause); | ||
return () => { | ||
audio.removeEventListener("timeupdate", updateProgress); | ||
audio.removeEventListener("play", handlePlay); | ||
@@ -54,5 +61,192 @@ audio.removeEventListener("pause", handlePause); | ||
}, []); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `audio-container ${className}`, children: [ | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("audio", { ref: audioRef, src, ...props }), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: togglePlay, children: isPlaying ? "Pause" : "Play" }) | ||
const togglePlay = () => { | ||
const audio = audioRef.current; | ||
if (!audio) | ||
return; | ||
isPlaying ? audio.pause() : audio.play(); | ||
}; | ||
const handleProgressClick = (e) => { | ||
const audio = audioRef.current; | ||
if (!audio) | ||
return; | ||
const rect = e.currentTarget.getBoundingClientRect(); | ||
const pos = (e.clientX - rect.left) / rect.width; | ||
audio.currentTime = pos * audio.duration; | ||
}; | ||
const handleVolumeChange = (e) => { | ||
const audio = audioRef.current; | ||
if (!audio) | ||
return; | ||
const newVolume = parseFloat(e.target.value); | ||
audio.volume = newVolume; | ||
setVolume(newVolume); | ||
}; | ||
const formatTime = (time) => { | ||
const minutes = Math.floor(time / 60); | ||
const seconds = Math.floor(time % 60); | ||
return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`; | ||
}; | ||
const styles = ` | ||
.audio-container { | ||
position: relative; | ||
width: 100%; | ||
height: 40px; | ||
margin: 10px 0; | ||
border-radius: 8px; | ||
overflow: hidden; | ||
} | ||
.audio-controls { | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
width: 100%; | ||
height: 100%; | ||
background: ${controlsBackgroundColor}; | ||
color: ${textColor}; | ||
padding: 0 10px; | ||
display: flex; | ||
align-items: center; | ||
} | ||
.progress-container { | ||
display: flex; | ||
align-items: center; | ||
flex-grow: 1; | ||
margin-right: 10px; | ||
max-width: calc(100% - 130px); | ||
} | ||
.progress-bar { | ||
flex-grow: 1; | ||
height: 4px; | ||
background: rgba(255, 255, 255, 0.3); | ||
cursor: pointer; | ||
margin: 0 5px; | ||
border-radius: 2px; | ||
} | ||
.progress { | ||
height: 100%; | ||
background-color: ${progressColor}; | ||
border-radius: 2px; | ||
transition: width 0.1s ease-in-out; | ||
} | ||
.play-pause, .volume-icon { | ||
background: none; | ||
border: none; | ||
color: ${controlsColor}; | ||
font-size: 1.2em; | ||
cursor: pointer; | ||
padding: 0; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
width: 30px; | ||
height: 30px; | ||
margin-right: 10px; | ||
} | ||
.time { | ||
font-size: 0.7em; | ||
white-space: nowrap; | ||
color: ${textColor}; | ||
width: 35px; | ||
text-align: center; | ||
} | ||
.volume-control { | ||
display: flex; | ||
align-items: center; | ||
width: 70px; | ||
} | ||
.volume-icon { | ||
background: none; | ||
border: none; | ||
color: ${controlsColor}; | ||
font-size: 1.2em; | ||
cursor: pointer; | ||
padding: 0; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
width: 24px; | ||
height: 24px; | ||
margin-right: 5px; | ||
} | ||
.volume-slider { | ||
width: 40px; | ||
-webkit-appearance: none; | ||
appearance: none; | ||
height: 4px; | ||
border-radius: 2px; | ||
background: rgba(255, 255, 255, 0.3); | ||
outline: none; | ||
} | ||
.volume-slider::-webkit-slider-thumb { | ||
-webkit-appearance: none; | ||
appearance: none; | ||
width: 12px; | ||
height: 12px; | ||
border-radius: 50%; | ||
background: ${controlsColor}; | ||
cursor: pointer; | ||
} | ||
.volume-slider::-moz-range-thumb { | ||
width: 12px; | ||
height: 12px; | ||
border-radius: 50%; | ||
background: ${controlsColor}; | ||
cursor: pointer; | ||
} | ||
`; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: styles }), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `audio-container ${className}`, children: [ | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("audio", { ref: audioRef, src, ...props }), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "audio-controls", children: [ | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: togglePlay, className: "play-pause", children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
"svg", | ||
{ | ||
width: "16", | ||
height: "16", | ||
viewBox: "0 0 24 24", | ||
fill: controlsColor, | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) | ||
} | ||
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
"svg", | ||
{ | ||
width: "16", | ||
height: "16", | ||
viewBox: "0 0 24 24", | ||
fill: controlsColor, | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 5v14l11-7z" }) | ||
} | ||
) }), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "progress-container", children: [ | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "time", children: formatTime(audioRef.current?.currentTime || 0) }), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "progress-bar", onClick: handleProgressClick, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "progress", style: { width: `${progress}%` } }) }), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "time", children: formatTime(audioRef.current?.duration || 0) }) | ||
] }), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "volume-control", children: [ | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "volume-icon", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
"svg", | ||
{ | ||
width: "16", | ||
height: "16", | ||
viewBox: "0 0 24 24", | ||
fill: controlsColor, | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z" }) | ||
} | ||
) }), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
"input", | ||
{ | ||
type: "range", | ||
min: "0", | ||
max: "1", | ||
step: "0.01", | ||
value: volume, | ||
onChange: handleVolumeChange, | ||
className: "volume-slider" | ||
} | ||
) | ||
] }) | ||
] }) | ||
] }) | ||
] }); | ||
@@ -59,0 +253,0 @@ }; |
{ | ||
"name": "@chrisabdo/audio", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"description": "A lightweight and customizable React audio player component", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
16784
488
1