@smooth-player/react 1.0.0
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/README.md +23 -0
- package/dist/SmoothAudioPlayer.d.ts +8 -0
- package/dist/SmoothAudioPlayer.js +62 -0
- package/dist/assets/next.svg +4 -0
- package/dist/assets/pause.svg +4 -0
- package/dist/assets/play.svg +3 -0
- package/dist/assets/prev.svg +4 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# @smooth-player/react
|
|
2
|
+
|
|
3
|
+
React wrapper component for [`smooth-player`](https://www.npmjs.com/package/smooth-player).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install smooth-player @smooth-player/react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import "smooth-player/dist/smooth-player.css";
|
|
15
|
+
import { SmoothAudioPlayer } from "@smooth-player/react";
|
|
16
|
+
|
|
17
|
+
<SmoothAudioPlayer
|
|
18
|
+
tracks={tracks}
|
|
19
|
+
accentColor="#0ed2a4"
|
|
20
|
+
visualizer="spectrum"
|
|
21
|
+
initialVolume={0.8}
|
|
22
|
+
/>;
|
|
23
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type AudioTrack, type VisualizerMode } from "smooth-player";
|
|
2
|
+
export interface SmoothAudioPlayerProps {
|
|
3
|
+
tracks: AudioTrack[];
|
|
4
|
+
accentColor?: string;
|
|
5
|
+
visualizer?: VisualizerMode;
|
|
6
|
+
initialVolume?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function SmoothAudioPlayer({ tracks, accentColor, visualizer, initialVolume, }: SmoothAudioPlayerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { SmoothPlayer, CanvasSpectrumVisualizer, CanvasWaveformVisualizer, } from "smooth-player";
|
|
4
|
+
import prevIcon from "./assets/prev.svg";
|
|
5
|
+
import nextIcon from "./assets/next.svg";
|
|
6
|
+
import playIcon from "./assets/play.svg";
|
|
7
|
+
import pauseIcon from "./assets/pause.svg";
|
|
8
|
+
export function SmoothAudioPlayer({ tracks, accentColor = "#0ed2a4", visualizer = "spectrum", initialVolume = 0.8, }) {
|
|
9
|
+
const rootRef = useRef(null);
|
|
10
|
+
const spectrumRef = useRef(null);
|
|
11
|
+
const waveformRef = useRef(null);
|
|
12
|
+
const playerRef = useRef(null);
|
|
13
|
+
const [index, setIndex] = useState(0);
|
|
14
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
15
|
+
const currentTrack = tracks[index] ?? null;
|
|
16
|
+
const showPlaylist = tracks.length > 1;
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const player = new SmoothPlayer({ initialVolume, visualizer, accentColor });
|
|
19
|
+
player.setPlaylist(tracks, 0);
|
|
20
|
+
playerRef.current = player;
|
|
21
|
+
let spectrum = null;
|
|
22
|
+
let waveform = null;
|
|
23
|
+
if (visualizer === "spectrum") {
|
|
24
|
+
spectrum = new CanvasSpectrumVisualizer(spectrumRef.current, player, { color: "#3cc8d9" });
|
|
25
|
+
spectrum.start();
|
|
26
|
+
}
|
|
27
|
+
if (visualizer === "waveform") {
|
|
28
|
+
waveform = new CanvasWaveformVisualizer(waveformRef.current, player, { color: "#e7f0ff" });
|
|
29
|
+
waveform.start();
|
|
30
|
+
}
|
|
31
|
+
const offTrack = player.on("trackchange", ({ index: nextIndex }) => setIndex(nextIndex));
|
|
32
|
+
const offPlay = player.on("play", () => setIsPlaying(true));
|
|
33
|
+
const offPause = player.on("pause", () => setIsPlaying(false));
|
|
34
|
+
return () => {
|
|
35
|
+
offTrack();
|
|
36
|
+
offPlay();
|
|
37
|
+
offPause();
|
|
38
|
+
spectrum?.stop();
|
|
39
|
+
waveform?.stop();
|
|
40
|
+
player.destroy();
|
|
41
|
+
};
|
|
42
|
+
}, [tracks, initialVolume, visualizer, accentColor]);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const player = playerRef.current;
|
|
45
|
+
const root = rootRef.current;
|
|
46
|
+
if (!player || !root)
|
|
47
|
+
return;
|
|
48
|
+
player.setAccentColor(accentColor);
|
|
49
|
+
player.applyAccentColor(root);
|
|
50
|
+
}, [accentColor]);
|
|
51
|
+
const handlers = useMemo(() => ({
|
|
52
|
+
toggle: async () => {
|
|
53
|
+
await playerRef.current?.toggle();
|
|
54
|
+
},
|
|
55
|
+
previous: () => playerRef.current?.previous(),
|
|
56
|
+
next: () => playerRef.current?.next(),
|
|
57
|
+
pick: async (nextIndex) => {
|
|
58
|
+
await playerRef.current?.play(nextIndex);
|
|
59
|
+
},
|
|
60
|
+
}), []);
|
|
61
|
+
return (_jsxs("section", { ref: rootRef, className: "smooth-player", children: [_jsxs("div", { className: "smooth-player__main", children: [_jsxs("div", { className: "smooth-player__row", children: [_jsx("h2", { className: "smooth-player__title", children: "Smooth Player" }), _jsxs("div", { className: "smooth-player__controls", children: [_jsx("button", { className: "secondary", onClick: handlers.previous, "aria-label": "Previous", children: _jsx("img", { className: "smooth-player__icon", src: prevIcon, alt: "" }) }), _jsx("button", { onClick: handlers.toggle, "aria-label": isPlaying ? "Pause" : "Play", children: _jsx("img", { className: "smooth-player__icon", src: isPlaying ? pauseIcon : playIcon, alt: "" }) }), _jsx("button", { className: "secondary", onClick: handlers.next, "aria-label": "Next", children: _jsx("img", { className: "smooth-player__icon", src: nextIcon, alt: "" }) })] })] }), _jsxs("div", { className: "smooth-player__meta", children: [_jsx("strong", { children: currentTrack?.metadata?.title ?? "Unknown title" }), _jsx("div", { className: "smooth-player__artist", children: currentTrack?.metadata?.artist ?? "Unknown artist" })] }), _jsx("canvas", { ref: spectrumRef, id: "spectrum", className: "smooth-player__canvas", width: 860, height: 180, hidden: visualizer !== "spectrum" }), _jsx("canvas", { ref: waveformRef, id: "waveform", className: "smooth-player__canvas", width: 860, height: 120, hidden: visualizer !== "waveform" })] }), showPlaylist ? (_jsxs("aside", { className: "smooth-player__playlist", "aria-hidden": "false", children: [_jsx("div", { className: "smooth-player__playlist-head", children: _jsx("h2", { children: "Playlist" }) }), _jsx("ul", { className: "smooth-player__playlist-list", children: tracks.map((track, listIndex) => (_jsx("li", { children: _jsxs("button", { className: "smooth-player__playlist-item", "aria-current": listIndex === index ? "true" : undefined, onClick: () => handlers.pick(listIndex), children: [_jsx("span", { className: "smooth-player__playlist-title", children: track.metadata?.title ?? track.id }), _jsx("span", { className: "smooth-player__playlist-artist", children: track.metadata?.artist ?? "Unknown artist" })] }) }, track.id))) })] })) : null] }));
|
|
62
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
|
2
|
+
<path d="M17.5 6V18" stroke="currentColor" stroke-width="2.1" stroke-linecap="round"/>
|
|
3
|
+
<path d="M7.3 6.7C6.74 6.34 6 6.74 6 7.41V16.59C6 17.26 6.74 17.66 7.3 17.3L13.85 13.09C14.35 12.77 14.35 11.23 13.85 10.91L7.3 6.7Z" fill="currentColor"/>
|
|
4
|
+
</svg>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
|
2
|
+
<path d="M6.5 6V18" stroke="currentColor" stroke-width="2.1" stroke-linecap="round"/>
|
|
3
|
+
<path d="M16.7 6.7C17.26 6.34 18 6.74 18 7.41V16.59C18 17.26 17.26 17.66 16.7 17.3L10.15 13.09C9.65 12.77 9.65 11.23 10.15 10.91L16.7 6.7Z" fill="currentColor"/>
|
|
4
|
+
</svg>
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SmoothAudioPlayer } from "./SmoothAudioPlayer";
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@smooth-player/react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "React component for Smooth Player",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"react": ">=18",
|
|
25
|
+
"react-dom": ">=18",
|
|
26
|
+
"smooth-player": "^1.0.0"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc -p tsconfig.build.json && mkdir -p dist/assets && cp -R src/assets/* dist/assets/",
|
|
30
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
31
|
+
"clean": "rm -rf dist",
|
|
32
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/react": "^18.3.12",
|
|
36
|
+
"@types/react-dom": "^18.3.1",
|
|
37
|
+
"typescript": "^5.7.3"
|
|
38
|
+
}
|
|
39
|
+
}
|