react-modern-audio-player 2.0.0 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  <!-- markdownlint-disable MD033 MD041 MD028 -->
2
2
 
3
3
  <p align="center">
4
- <img width="20%" src="https://user-images.githubusercontent.com/70849655/180391190-2b268d23-c9f3-4e95-9fce-090897842c04.png" alt="rm-audio-player" />
4
+ <img width="12%" src="https://raw.githubusercontent.com/slash9494/react-modern-audio-player/main/package/assets/icon.png" alt="rm-audio-player" />
5
5
  <h1 align="center">React Modern Audio Player</h1>
6
6
  </p>
7
7
 
@@ -15,31 +15,56 @@
15
15
  <a href="https://www.npmjs.com/package/react-modern-audio-player">
16
16
  <img src="https://img.shields.io/npm/dt/react-modern-audio-player" alt="Download">
17
17
  </a>
18
- <a href="https://bundlephobia.com/package/react-modern-audio-player@0.0.3">
18
+ <a href="https://bundlephobia.com/package/react-modern-audio-player@2.0.0">
19
19
  <img src="https://img.shields.io/bundlephobia/minzip/react-modern-audio-player" alt="BundleSize">
20
20
  </a>
21
+ <a href="https://github.com/slash9494/react-modern-audio-player/actions/workflows/integration.yml">
22
+ <img src="https://github.com/slash9494/react-modern-audio-player/actions/workflows/integration.yml/badge.svg?branch=main" alt="CI">
23
+ </a>
24
+ <img src="https://img.shields.io/badge/TypeScript-first-3178C6?logo=typescript&logoColor=white" alt="TypeScript">
21
25
  </p>
22
26
 
27
+ ## Highlights
28
+
29
+ - **Waveform** progress bar powered by `wavesurfer.js`
30
+ - **Playlist** with drag-and-drop reorder, repeat, shuffle
31
+ - **Fully customizable** — swap any sub-component, CSS variable theming, light & dark themes
32
+ - **Accessible** — WAI-ARIA patterns, full keyboard navigation, axe-tested
33
+ - **TypeScript-first** — typed props and hooks (`useAudioPlayer`, sub-hooks)
34
+ - **SSR-friendly** — works with Next.js App Router / Server Components
35
+
23
36
  ## DEMO
24
37
 
25
- <https://codesandbox.io/s/basic-91y82y?file=/src/App.tsx>
38
+ <https://codesandbox.io/p/sandbox/basic-nfrpfq>
26
39
 
27
40
  # **Flexible and Customizable UI**
28
41
 
29
- ## This can offer waveform by `wavesurfer.js`
42
+ ## Waveform progress with `wavesurfer.js`
30
43
 
31
- <img width="100%" src="https://user-images.githubusercontent.com/70849655/180435472-f043dbb4-54df-43e0-bc5c-67492510e817.png" alt="">
44
+ <img width="100%" src="https://raw.githubusercontent.com/slash9494/react-modern-audio-player/main/package/assets/screenshots/waveform-light.png" alt="Waveform view" />
32
45
 
33
- ## This can offer various UI and you can also customize each component position
46
+ ## Customizable layout and placement with light & dark themes
34
47
 
35
- > Full View
36
- > <img width="100%" src="https://user-images.githubusercontent.com/70849655/180435489-263fae23-f066-4a37-a524-58918eb40b0c.png" alt="">
48
+ ### Full View
37
49
 
38
- > Position Change
39
- > <img width="110%" src="https://user-images.githubusercontent.com/70849655/180435493-2c2e08c5-b67b-4ab7-aded-5a0403d42050.png" alt="">
50
+ <p align="center">
51
+ <img width="49%" src="https://raw.githubusercontent.com/slash9494/react-modern-audio-player/main/package/assets/screenshots/full-view-light.png" alt="Full view — light" />
52
+ <img width="49%" src="https://raw.githubusercontent.com/slash9494/react-modern-audio-player/main/package/assets/screenshots/full-view-dark.png" alt="Full view — dark" />
53
+ </p>
54
+
55
+ ### Position Change
56
+
57
+ <p align="center">
58
+ <img width="49%" src="https://raw.githubusercontent.com/slash9494/react-modern-audio-player/main/package/assets/screenshots/position-change-light.png" alt="Position change — light" />
59
+ <img width="49%" src="https://raw.githubusercontent.com/slash9494/react-modern-audio-player/main/package/assets/screenshots/position-change-dark.png" alt="Position change — dark" />
60
+ </p>
40
61
 
41
- > Particular View
42
- > <br/> > <img width="50%" margin='10px' src="https://user-images.githubusercontent.com/70849655/180435497-0f839cd1-e1fd-400f-a013-82ba441ca79b.png" alt=""> > <img width="20%" margin='10px' src="https://user-images.githubusercontent.com/70849655/180435479-4f056620-f850-4d21-ab23-24efc4300d68.png" alt=""> > <br/> > <img width="20%" margin='10px' src="https://user-images.githubusercontent.com/70849655/180435484-3331b7cb-1555-4ffb-a36c-a5343f72c8c3.png" alt=""> > <img width="50%" margin='10px' src="https://user-images.githubusercontent.com/70849655/180435486-2402ba80-7121-410c-9a06-9a737be72ec2.png" alt="">
62
+ ### Particular View
63
+
64
+ <p align="center" style="display:flex; gap: 10%;">
65
+ <img width="39%" src="https://raw.githubusercontent.com/slash9494/react-modern-audio-player/main/package/assets/screenshots/particular-view-dark.png" alt="Particular view — compact compound" />
66
+ <img width="10%" height="50%" src="https://raw.githubusercontent.com/slash9494/react-modern-audio-player/main/package/assets/screenshots/particular-view-play-only-dark.png" alt="Particular view — play button only" />
67
+ </p>
43
68
 
44
69
  # **Installation**
45
70
 
@@ -83,7 +108,13 @@ This library includes the `'use client'` directive and can be imported directly
83
108
  import AudioPlayer from "react-modern-audio-player";
84
109
 
85
110
  const playList = [
86
- { name: "track", writer: "artist", img: "cover.jpg", src: "audio.mp3", id: 1 },
111
+ {
112
+ name: "track",
113
+ writer: "artist",
114
+ img: "cover.jpg",
115
+ src: "audio.mp3",
116
+ id: 1,
117
+ },
87
118
  ];
88
119
 
89
120
  export default function Page() {
@@ -124,6 +155,7 @@ export default function PlayerPage() {
124
155
  | **Override & Style** | [CustomIcons](#customicons) · [CoverImgsCss](#coverimgscss) · [Theme mode](#theme-mode-dark-mode) · [ID & Classnames](#id--classnames) |
125
156
  | **Player Hook API** | [useAudioPlayer](#useaudioplayer) · [AudioPlayerControls](#audioplayercontrols) · [Sub-Hooks](#sub-hooks) |
126
157
  | **Custom Component** | [Custom Component](#custom-component) |
158
+ | **Accessibility** | [Keyboard support](#keyboard-support) |
127
159
  | **Example** | [Example](#example) |
128
160
 
129
161
  # Props
@@ -173,6 +205,26 @@ type AudioData = {
173
205
  };
174
206
  ```
175
207
 
208
+ ### Empty playlist handling
209
+
210
+ Passing `playList={[]}` renders the player in an empty state without crashing. This is useful while waiting for asynchronous track data:
211
+
212
+ ```tsx
213
+ function App() {
214
+ const [tracks, setTracks] = useState<PlayList>([]);
215
+
216
+ useEffect(() => {
217
+ fetchTracks().then(setTracks);
218
+ }, []);
219
+
220
+ // Safe — the player mounts with no audio source and activates once tracks arrive.
221
+ return <AudioPlayer playList={tracks} />;
222
+ }
223
+ ```
224
+
225
+ - When the playlist becomes empty after updates, playback stops and all time state resets.
226
+ - When `audioInitialState.curPlayId` doesn't match any track in the current list, the player falls back to `playList[0]` automatically.
227
+
176
228
  ## InitialStates
177
229
 
178
230
  ```tsx
@@ -389,8 +441,7 @@ function PlayerControls() {
389
441
  <button onClick={() => setVolume(0.5)}>Volume 50%</button>
390
442
  <button onClick={() => setTrack(1)}>Track 2</button>
391
443
  <p>
392
- {currentTrack?.name} — {currentTime.toFixed(0)}s / {duration.toFixed(0)}
393
- s
444
+ {currentTrack?.name} — {currentTime.toFixed(0)}s / {duration.toFixed(0)}s
394
445
  </p>
395
446
  </div>
396
447
  );
@@ -451,17 +502,21 @@ function PlayButton() {
451
502
  // Only re-renders on time updates
452
503
  function TimeDisplay() {
453
504
  const { currentTime, duration } = useAudioPlayerTime();
454
- return <span>{currentTime.toFixed(0)}s / {duration.toFixed(0)}s</span>;
505
+ return (
506
+ <span>
507
+ {currentTime.toFixed(0)}s / {duration.toFixed(0)}s
508
+ </span>
509
+ );
455
510
  }
456
511
  ```
457
512
 
458
- | Hook | Returns |
459
- | -------------------------- | ------------------------------------------------------------------------------- |
460
- | `useAudioPlayerPlayback` | `{ isPlaying, repeatType, play, pause, togglePlay }` |
461
- | `useAudioPlayerTrack` | `{ currentPlayId, currentIndex, playList, currentTrack, setTrack, next, prev }` |
462
- | `useAudioPlayerVolume` | `{ volume, muted, setVolume, toggleMute }` |
463
- | `useAudioPlayerTime` | `{ currentTime, duration, seek }` |
464
- | `useAudioPlayerElement` | `{ audioEl, waveformInst }` (advanced) |
513
+ | Hook | Returns |
514
+ | ------------------------ | ------------------------------------------------------------------------------- |
515
+ | `useAudioPlayerPlayback` | `{ isPlaying, repeatType, play, pause, togglePlay }` |
516
+ | `useAudioPlayerTrack` | `{ currentPlayId, currentIndex, playList, currentTrack, setTrack, next, prev }` |
517
+ | `useAudioPlayerVolume` | `{ volume, muted, setVolume, toggleMute }` |
518
+ | `useAudioPlayerTime` | `{ currentTime, duration, seek }` |
519
+ | `useAudioPlayerElement` | `{ audioEl, waveformInst }` (advanced) |
465
520
 
466
521
  # Context Hooks
467
522
 
@@ -535,6 +590,24 @@ const CustomComponent = () => {
535
590
  </AudioPlayer>;
536
591
  ```
537
592
 
593
+ # **Accessibility**
594
+
595
+ The player follows WAI-ARIA patterns and is fully navigable by keyboard and screen readers.
596
+
597
+ ## Keyboard support
598
+
599
+ All controls are reachable via `Tab` and respond to standard keyboard activation. The playlist uses the WAI-ARIA "Listbox with Rearrangeable Options" pattern:
600
+
601
+ | Key | Action |
602
+ | --- | --- |
603
+ | `Tab` / `Shift+Tab` | Move focus between player controls |
604
+ | `Space` / `Enter` | Activate the focused button (play/pause, prev/next, repeat, mute, playlist) |
605
+ | `ArrowUp` / `ArrowDown` | Move focus between playlist items |
606
+ | `Alt+ArrowUp` / `Alt+ArrowDown` | Reorder the focused playlist item |
607
+ | `Enter` / `Space` on a playlist item | Select and play that track |
608
+
609
+ Drag-and-drop reordering is preserved as an alternative — keyboard and mouse both call the same `onReorder` handler.
610
+
538
611
  # **Example**
539
612
 
540
613
  ```tsx