react-modern-audio-player 1.4.0-rc.2 → 2.0.0-beta.1

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.
Files changed (120) hide show
  1. package/README.md +294 -100
  2. package/dist/index.css +1 -1
  3. package/dist/index.es.js +1914 -7975
  4. package/dist/types/api/index.d.ts +6 -0
  5. package/dist/types/api/useAudioPlayer.d.ts +27 -0
  6. package/dist/types/api/useAudioPlayerElement.d.ts +6 -0
  7. package/dist/types/api/useAudioPlayerPlayback.d.ts +9 -0
  8. package/dist/types/api/useAudioPlayerTime.d.ts +6 -0
  9. package/dist/types/api/useAudioPlayerTrack.d.ts +11 -0
  10. package/dist/types/api/useAudioPlayerVolume.d.ts +7 -0
  11. package/dist/types/components/AudioPlayer/Audio/index.d.ts +2 -2
  12. package/dist/types/components/AudioPlayer/Audio/useAudio.d.ts +1 -1
  13. package/dist/types/components/AudioPlayer/Container/AudioPlayerContainer.d.ts +5 -0
  14. package/dist/types/components/AudioPlayer/Container/index.d.ts +1 -0
  15. package/dist/types/components/AudioPlayer/Context/AudioAttrsContext.d.ts +15 -0
  16. package/dist/types/components/AudioPlayer/Context/PlaybackContext.d.ts +10 -0
  17. package/dist/types/components/AudioPlayer/Context/ResourceContext.d.ts +7 -0
  18. package/dist/types/components/AudioPlayer/Context/StateContext/audio.d.ts +18 -8
  19. package/dist/types/components/AudioPlayer/Context/StateContext/element.d.ts +8 -13
  20. package/dist/types/components/AudioPlayer/Context/StateContext/index.d.ts +9 -8
  21. package/dist/types/components/AudioPlayer/Context/StateContext/placement.d.ts +9 -9
  22. package/dist/types/components/AudioPlayer/Context/TimeContext.d.ts +6 -0
  23. package/dist/types/components/AudioPlayer/Context/TrackContext.d.ts +7 -0
  24. package/dist/types/components/AudioPlayer/Context/UIContext.d.ts +11 -0
  25. package/dist/types/components/AudioPlayer/Context/dispatchContext.d.ts +11 -7
  26. package/dist/types/components/AudioPlayer/Context/index.d.ts +10 -3
  27. package/dist/types/components/AudioPlayer/Context/providerProps.d.ts +14 -0
  28. package/dist/types/components/AudioPlayer/Context/reducer.d.ts +2 -2
  29. package/dist/types/components/AudioPlayer/Interface/Controller/Button/NextBtn.d.ts +6 -0
  30. package/dist/types/components/AudioPlayer/Interface/Controller/Button/PlayBtn.d.ts +1 -1
  31. package/dist/types/components/AudioPlayer/Interface/Controller/Button/PrevBtn.d.ts +6 -0
  32. package/dist/types/components/AudioPlayer/Interface/Controller/Button/RepeatTypeBtn.d.ts +1 -1
  33. package/dist/types/components/AudioPlayer/Interface/Controller/Button/VolumeTriggerBtn.d.ts +1 -1
  34. package/dist/types/components/AudioPlayer/Interface/Controller/Button/index.d.ts +5 -5
  35. package/dist/types/components/AudioPlayer/Interface/Controller/Drawer/SortablePlayList/Content/PlayListItem.d.ts +3 -3
  36. package/dist/types/components/AudioPlayer/Interface/Controller/Drawer/SortablePlayList/Content/index.d.ts +2 -6
  37. package/dist/types/components/AudioPlayer/Interface/Controller/Drawer/SortablePlayList/Content/usePlayList.d.ts +3 -4
  38. package/dist/types/components/AudioPlayer/Interface/Controller/Drawer/SortablePlayList/PlayListIcon.d.ts +2 -0
  39. package/dist/types/components/AudioPlayer/Interface/Controller/Drawer/SortablePlayList/index.d.ts +1 -1
  40. package/dist/types/components/AudioPlayer/Interface/Controller/Drawer/index.d.ts +1 -1
  41. package/dist/types/components/AudioPlayer/Interface/Controller/Icon.d.ts +3 -3
  42. package/dist/types/components/AudioPlayer/Interface/Controller/Input/Progress/BarProgress.d.ts +2 -4
  43. package/dist/types/components/AudioPlayer/Interface/Controller/Input/Progress/WaveformProgress.d.ts +1 -1
  44. package/dist/types/components/AudioPlayer/Interface/Controller/Input/Progress/index.d.ts +1 -1
  45. package/dist/types/components/AudioPlayer/Interface/Controller/Input/Progress/useProgress.d.ts +1 -1
  46. package/dist/types/components/AudioPlayer/Interface/Controller/Input/Progress/useProgressKeyDown.d.ts +2 -0
  47. package/dist/types/components/AudioPlayer/Interface/Controller/Input/index.d.ts +1 -1
  48. package/dist/types/components/AudioPlayer/Interface/Controller/Tooltip/Volume/Content.d.ts +2 -2
  49. package/dist/types/components/AudioPlayer/Interface/Controller/Tooltip/Volume/index.d.ts +1 -1
  50. package/dist/types/components/AudioPlayer/Interface/Controller/Tooltip/Volume/useVolume.d.ts +2 -2
  51. package/dist/types/components/AudioPlayer/Interface/Controller/Tooltip/index.d.ts +1 -1
  52. package/dist/types/components/AudioPlayer/Interface/Controller/index.d.ts +1 -1
  53. package/dist/types/components/AudioPlayer/Interface/CustomComponent/index.d.ts +2 -2
  54. package/dist/types/components/AudioPlayer/Interface/Information/Artwork.d.ts +1 -1
  55. package/dist/types/components/AudioPlayer/Interface/Information/TrackInfo.d.ts +1 -1
  56. package/dist/types/components/AudioPlayer/Interface/Information/TrackTime/Current.d.ts +2 -2
  57. package/dist/types/components/AudioPlayer/Interface/Information/TrackTime/Duration.d.ts +2 -2
  58. package/dist/types/components/AudioPlayer/Interface/Information/TrackTime/TrackTimeContainer.d.ts +6 -0
  59. package/dist/types/components/AudioPlayer/Interface/Information/TrackTime/Types.d.ts +1 -1
  60. package/dist/types/components/AudioPlayer/Interface/Information/TrackTime/index.d.ts +1 -1
  61. package/dist/types/components/AudioPlayer/Interface/Information/index.d.ts +1 -1
  62. package/dist/types/components/AudioPlayer/Interface/index.d.ts +1 -1
  63. package/dist/types/components/AudioPlayer/Player/index.d.ts +9 -14
  64. package/dist/types/components/AudioPlayer/Player/usePropsStateEffect.d.ts +1 -1
  65. package/dist/types/components/AudioPlayer/Provider/AudioPlayerStateProvider.d.ts +7 -0
  66. package/dist/types/components/AudioPlayer/Provider/index.d.ts +1 -0
  67. package/dist/types/components/AudioPlayer/index.d.ts +10 -11
  68. package/dist/types/components/Drawer/Drawer.d.ts +5 -6
  69. package/dist/types/components/Drawer/DrawerContent.d.ts +4 -3
  70. package/dist/types/components/Drawer/DrawerContext.d.ts +2 -1
  71. package/dist/types/components/Drawer/DrawerTrigger.d.ts +7 -2
  72. package/dist/types/components/Drawer/index.d.ts +2 -2
  73. package/dist/types/components/Dropdown/Dropdown.d.ts +6 -6
  74. package/dist/types/components/Dropdown/DropdownContent.d.ts +3 -3
  75. package/dist/types/components/Dropdown/DropdownContext.d.ts +2 -1
  76. package/dist/types/components/Dropdown/DropdownTrigger.d.ts +2 -2
  77. package/dist/types/components/Dropdown/index.d.ts +2 -2
  78. package/dist/types/components/Dropdown/useDropdown.d.ts +3 -3
  79. package/dist/types/components/Dropdown/useDropdownPlacementStyle.d.ts +3 -0
  80. package/dist/types/components/Grid/Grid.d.ts +12 -8
  81. package/dist/types/components/Grid/Item.d.ts +8 -5
  82. package/dist/types/components/Grid/index.d.ts +8 -1
  83. package/dist/types/components/SortableList/SortableList.d.ts +4 -4
  84. package/dist/types/components/SortableList/SortableListItem.d.ts +5 -5
  85. package/dist/types/components/SortableList/index.d.ts +5 -5
  86. package/dist/types/components/SortableList/useSortableListItem.d.ts +1 -1
  87. package/dist/types/components/icons/index.d.ts +16 -0
  88. package/dist/types/hooks/context/index.d.ts +7 -0
  89. package/dist/types/hooks/context/useAudioAttrsContext.d.ts +2 -0
  90. package/dist/types/hooks/{useNonNullableContext.d.ts → context/useNonNullableContext.d.ts} +1 -1
  91. package/dist/types/hooks/context/usePlaybackContext.d.ts +2 -0
  92. package/dist/types/hooks/context/useResourceContext.d.ts +2 -0
  93. package/dist/types/hooks/context/useTimeContext.d.ts +2 -0
  94. package/dist/types/hooks/context/useTrackContext.d.ts +2 -0
  95. package/dist/types/hooks/context/useUIContext.d.ts +1 -0
  96. package/dist/types/hooks/index.d.ts +5 -4
  97. package/dist/types/hooks/useClickOutside.d.ts +1 -1
  98. package/dist/types/hooks/useDidUpdateEffect.d.ts +16 -0
  99. package/dist/types/hooks/useRefsDispatch.d.ts +1 -1
  100. package/dist/types/hooks/useVariableColor.d.ts +2 -2
  101. package/dist/types/index.d.ts +7 -5
  102. package/dist/types/test/setup.d.ts +0 -0
  103. package/dist/types/{components → ui}/CssTransition.d.ts +1 -3
  104. package/dist/types/ui/StyledBtn.d.ts +1 -0
  105. package/dist/types/utils/clampVolume.d.ts +5 -0
  106. package/dist/types/utils/generateUnionNumType.d.ts +2 -2
  107. package/dist/types/utils/refs.d.ts +1 -0
  108. package/dist/types/utils/safeRatio.d.ts +5 -0
  109. package/dist/types/utils/ssr.d.ts +5 -0
  110. package/dist/wavesurfer-_j5aw4gZ.mjs +4471 -0
  111. package/package.json +32 -22
  112. package/dist/types/components/AudioPlayer/Interface/Controller/Button/PlayListTriggerBtn.d.ts +0 -5
  113. package/dist/types/components/AudioPlayer/Interface/Controller/Button/PrevNnextBtn.d.ts +0 -7
  114. package/dist/types/components/AudioPlayer/Interface/Controller/Button/StyledBtn.d.ts +0 -1
  115. package/dist/types/components/AudioPlayer/Interface/Information/TrackTime/Styles.d.ts +0 -6
  116. package/dist/types/components/Provider/AudioPlayerProvider.d.ts +0 -3
  117. package/dist/types/components/Provider/SpectrumProvider.d.ts +0 -7
  118. package/dist/types/components/Provider/index.d.ts +0 -2
  119. package/dist/types/styles/GlobalStyle.d.ts +0 -1
  120. package/dist/types/utils/resetAudioValues.d.ts +0 -2
package/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ <!-- markdownlint-disable MD033 MD041 MD028 -->
2
+
1
3
  <p align="center">
2
4
  <img width="20%" src="https://user-images.githubusercontent.com/70849655/180391190-2b268d23-c9f3-4e95-9fce-090897842c04.png" alt="rm-audio-player" />
3
5
  <h1 align="center">React Modern Audio Player</h1>
@@ -19,56 +21,111 @@
19
21
  </p>
20
22
 
21
23
  ## DEMO
22
- https://codesandbox.io/s/basic-91y82y?file=/src/App.tsx
23
24
 
24
- # ****Flexible and Customizable UI****
25
+ <https://codesandbox.io/s/basic-91y82y?file=/src/App.tsx>
26
+
27
+ # **Flexible and Customizable UI**
28
+
25
29
  ## This can offer waveform by `wavesurfer.js`
30
+
26
31
  <img width="100%" src="https://user-images.githubusercontent.com/70849655/180435472-f043dbb4-54df-43e0-bc5c-67492510e817.png" alt="">
27
32
 
28
33
  ## This can offer various UI and you can also customize each component position
34
+
29
35
  > Full View
30
36
  > <img width="100%" src="https://user-images.githubusercontent.com/70849655/180435489-263fae23-f066-4a37-a524-58918eb40b0c.png" alt="">
31
37
 
32
38
  > Position Change
33
39
  > <img width="110%" src="https://user-images.githubusercontent.com/70849655/180435493-2c2e08c5-b67b-4ab7-aded-5a0403d42050.png" alt="">
34
40
 
35
-
36
41
  > Particular View
37
- > </br>
38
- ><img width="50%" margin='10px' src="https://user-images.githubusercontent.com/70849655/180435497-0f839cd1-e1fd-400f-a013-82ba441ca79b.png" alt="">
39
- ><img width="20%" margin='10px' src="https://user-images.githubusercontent.com/70849655/180435479-4f056620-f850-4d21-ab23-24efc4300d68.png" alt="">
40
- > </br>
41
- ><img width="20%" margin='10px' src="https://user-images.githubusercontent.com/70849655/180435484-3331b7cb-1555-4ffb-a36c-a5343f72c8c3.png" alt="">
42
- > <img width="50%" margin='10px' src="https://user-images.githubusercontent.com/70849655/180435486-2402ba80-7121-410c-9a06-9a737be72ec2.png" alt="">
43
-
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="">
44
43
 
45
- # ****Installation****
44
+ # **Installation**
46
45
 
47
46
  ```tsx
48
47
  npm install --save react-modern-audio-player
49
48
  ```
50
49
 
51
- # ****Quick Start****
50
+ # **Requirements**
51
+
52
+ - React **18.0.0** or higher
53
+ - react-dom **18.0.0** or higher
54
+ > For React 16/17 projects, use v1.x of this library.
55
+
56
+ # **Quick Start**
52
57
 
53
58
  ```tsx
54
- import AudioPlayer from 'react-modern-audio-player';
59
+ import AudioPlayer from "react-modern-audio-player";
55
60
 
56
61
  const playList = [
57
62
  {
58
- name: 'name',
59
- writer: 'writer',
60
- img: 'image.jpg',
61
- src: 'audio.mp3',
63
+ name: "name",
64
+ writer: "writer",
65
+ img: "image.jpg",
66
+ src: "audio.mp3",
62
67
  id: 1,
63
68
  },
64
- ]
65
- function Player (){
66
- return (
67
- <AudioPlayer playList={playList} />
68
- )
69
+ ];
70
+ function Player() {
71
+ return <AudioPlayer playList={playList} />;
72
+ }
73
+ ```
74
+
75
+ # **Next.js / Server Components**
76
+
77
+ This library includes the `'use client'` directive and can be imported directly in Next.js App Router.
78
+
79
+ **Server Component** — render `<AudioPlayer>` with static props (no hooks, no compound components):
80
+
81
+ ```tsx
82
+ // app/page.tsx — Server Component, no 'use client' needed
83
+ import AudioPlayer from "react-modern-audio-player";
84
+
85
+ const playList = [
86
+ { name: "track", writer: "artist", img: "cover.jpg", src: "audio.mp3", id: 1 },
87
+ ];
88
+
89
+ export default function Page() {
90
+ return <AudioPlayer playList={playList} activeUI={{ playButton: true }} />;
69
91
  }
70
92
  ```
71
93
 
94
+ **Client Component** — use `useAudioPlayer` hooks or `AudioPlayer.CustomComponent`:
95
+
96
+ ```tsx
97
+ "use client";
98
+ // app/player/page.tsx — Client Component required for hooks & compound pattern
99
+ import AudioPlayer, { useAudioPlayer } from "react-modern-audio-player";
100
+
101
+ function Controls() {
102
+ const { isPlaying, togglePlay } = useAudioPlayer();
103
+ return <button onClick={togglePlay}>{isPlaying ? "Pause" : "Play"}</button>;
104
+ }
105
+
106
+ export default function PlayerPage() {
107
+ return (
108
+ <AudioPlayer playList={playList}>
109
+ <AudioPlayer.CustomComponent id="controls">
110
+ <Controls />
111
+ </AudioPlayer.CustomComponent>
112
+ </AudioPlayer>
113
+ );
114
+ }
115
+ ```
116
+
117
+ > **Why `'use client'`?** The library's `'use client'` directive marks the **client boundary** — it allows Server Components to import and render `<AudioPlayer>`. However, `useAudioPlayer()` hooks and `AudioPlayer.CustomComponent` require client-side React features (state, context), so components using them must be Client Components.
118
+
119
+ ## Table of Contents
120
+
121
+ | Category | Sections |
122
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
123
+ | **Props** | [PlayList](#playlist) · [InitialStates](#initialstates) · [ActiveUI](#activeui) · [Placement](#placement) · [RootContainerProps](#rootcontainerprops) |
124
+ | **Override & Style** | [CustomIcons](#customicons) · [CoverImgsCss](#coverimgscss) · [Theme mode](#theme-mode-dark-mode) · [ID & Classnames](#id--classnames) |
125
+ | **Player Hook API** | [useAudioPlayer](#useaudioplayer) · [AudioPlayerControls](#audioplayercontrols) · [Sub-Hooks](#sub-hooks) |
126
+ | **Custom Component** | [Custom Component](#custom-component) |
127
+ | **Example** | [Example](#example) |
128
+
72
129
  # Props
73
130
 
74
131
  ```tsx
@@ -85,19 +142,21 @@ interface AudioPlayerProps {
85
142
  interface?: InterfacePlacement;
86
143
  volumeSlider?: VolumeSliderPlacement;
87
144
  };
88
- rootContainerProps?: RootContainerProps
145
+ rootContainerProps?: RootContainerProps;
146
+ colorScheme?: "light" | "dark";
89
147
  }
90
148
  ```
91
149
 
92
- Prop | Type | Default
93
- --- | --- | ---
94
- `playList` | [PlayList](#playlist) | [ ]
95
- `audioInitialState` | [InitialStates](#InitialStates) | isPlaying: false </br>repeatType: "ALL" </br>volume: 1
96
- `activeUI` | [ActiveUI](#activeui) | playButton : true
97
- `customIcons` | [CustomIcons](#customicons) | undefined
98
- `coverImgsCss` | [CoverImgsCss](#coverimgscss) | undefined
99
- `placement` | [Placement](#placement) | playListPlacement : "bottom" </br>interfacePlacement :[DefaultInterfacePlacement](#default-interface-placement)
100
- `rootContainerProps` | [RootContainerProps](#rootcontainerprops) | theme: spectrum-theme-default<br/>width: 100% <br/>position: 'static'<br/>UNSAFE_className: rm-audio-player-provider
150
+ | Prop | Type | Default |
151
+ | -------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
152
+ | `playList` | [PlayList](#playlist) | [ ] |
153
+ | `audioInitialState` | [InitialStates](#initialstates) | isPlaying: false </br>repeatType: "ALL" </br>volume: 1 |
154
+ | `activeUI` | [ActiveUI](#activeui) | playButton : true |
155
+ | `customIcons` | [CustomIcons](#customicons) | undefined |
156
+ | `coverImgsCss` | [CoverImgsCss](#coverimgscss) | undefined |
157
+ | `placement` | [Placement](#placement) | playListPlacement : "bottom" </br>interfacePlacement :[DefaultInterfacePlacement](#default-interface-placement) |
158
+ | `rootContainerProps` | [RootContainerProps](#rootcontainerprops) | width: 100%<br/>position: 'static'<br/>className: rmap-player-provider |
159
+ | `colorScheme` | `"light" \| "dark"` | undefined (follows OS `prefers-color-scheme`) |
101
160
 
102
161
  ## PlayList
103
162
 
@@ -106,8 +165,8 @@ type PlayList = Array<AudioData>;
106
165
  type AudioData = {
107
166
  src: string;
108
167
  id: number;
109
- name?: string | ReactNode;
110
- writer?: string | ReactNode;
168
+ name?: string;
169
+ writer?: string;
111
170
  img?: string;
112
171
  description?: string | ReactNode;
113
172
  customTrackInfo?: string | ReactNode;
@@ -121,7 +180,7 @@ type InitialStates = Omit<
121
180
  React.AudioHTMLAttributes<HTMLAudioElement>,
122
181
  "autoPlay"
123
182
  > & {
124
- isPlaying?: boolean;
183
+ isPlaying?: boolean;
125
184
  repeatType?: RepeatType;
126
185
  volume?: number;
127
186
  currentTime?: number;
@@ -203,7 +262,7 @@ type InterfacePlacementKey =
203
262
  | Exclude<keyof ActiveUI, "all" | "prevNnext" | "trackTime">
204
263
  | "trackTimeCurrent"
205
264
  | "trackTimeDuration";
206
-
265
+
207
266
  type InterfacePlacementValue = "row1-1" | "row1-2" | "row1-3" | "row1-4" | ... more ... | "row9-9"
208
267
  /** if you apply custom components, values must be "row1-1" ~ any more */
209
268
 
@@ -212,16 +271,17 @@ type InterfaceGridTemplateArea = Record<InterfacePlacementKey,InterfacePlacement
212
271
  type InterfaceGridCustomComponentsArea = Record<componentId,InterfacePlacementValue>;
213
272
 
214
273
  type InterfaceGridItemArea = Partial<Record<InterfacePlacementKey, string>>;
215
- /** example
216
- * progress : 2-4
217
- * repeatBtn : row1-4 / 2 / row1-4 / 10
218
- *
219
- * check MDN - grid area
220
- * https://developer.mozilla.org/ko/docs/Web/CSS/grid-area
221
- */
274
+ /** example
275
+ * progress : 2-4
276
+ * repeatBtn : row1-4 / 2 / row1-4 / 10
277
+ *
278
+ * check MDN - grid area
279
+ * https://developer.mozilla.org/ko/docs/Web/CSS/grid-area
280
+ */
222
281
  ```
223
282
 
224
283
  ### Default interface placement
284
+
225
285
  ```tsx
226
286
  const defaultInterfacePlacement = {
227
287
  templateArea: {
@@ -239,19 +299,27 @@ const defaultInterfacePlacement = {
239
299
  ```
240
300
 
241
301
  ## RootContainerProps
242
- > it is same with spectrum provider props
243
- > </br>
244
- > https://react-spectrum.adobe.com/react-spectrum/Provider.html#themes
245
302
 
303
+ `rootContainerProps` accepts any standard `HTMLAttributes<HTMLDivElement>` (e.g. `className`, `style`, `data-*`). The root container always has the class `rmap-player-provider` applied automatically.
304
+
305
+ > ⚠️ Setting the native CSS `color-scheme` property via `rootContainerProps={{ style: { colorScheme: "dark" } }}` will **not** toggle the player's theme. The library's theme is driven by the `prefers-color-scheme` media query and the `[data-theme]` attribute selector — use the top-level [`colorScheme`](#theme-mode-dark-mode) prop instead.
246
306
 
247
307
  # Override Style
248
308
 
249
- ### Theme mode ( dark-mode )
309
+ ## Theme mode (dark mode)
250
310
 
251
- > it apply dark-mode depending on `system-theme`
252
- > </br>
253
- > you can customize color-theme by `css-variable` of `react-spectrum` `theme-default`
311
+ > Dark mode is driven by `system-theme` (`prefers-color-scheme: dark`) by default.
312
+ > To force a specific theme regardless of OS preference, pass the top-level `colorScheme="light" | "dark"` prop on `<AudioPlayer>` — this applies a `data-theme` attribute on `.rmap-player-provider` which overrides the media query.
313
+ > You can override any color by redefining the CSS variables below on `.rmap-player-provider`.
254
314
 
315
+ ```css
316
+ @media (prefers-color-scheme: dark) {
317
+ .rmap-player-provider {
318
+ --rm-audio-player-interface-container: #1e1e1e;
319
+ /* override other variables as needed */
320
+ }
321
+ }
322
+ ```
255
323
 
256
324
  ## ID & Classnames
257
325
 
@@ -261,39 +329,175 @@ const defaultInterfacePlacement = {
261
329
 
262
330
  ### root ClassName
263
331
 
264
- - rm-audio-player-provider
332
+ - rmap-player-provider
265
333
 
266
334
  ### color variables
267
335
 
336
+ ```css
337
+ .rmap-player-provider {
338
+ --rm-audio-player-text-color: #2c2c2c;
339
+ --rm-audio-player-shadow: 0 0 0;
340
+ --rm-audio-player-interface-container: #f5f5f5;
341
+ --rm-audio-player-volume-background: #ccc;
342
+ --rm-audio-player-volume-panel-background: #f2f2f2;
343
+ --rm-audio-player-volume-panel-border: #ccc;
344
+ --rm-audio-player-volume-thumb: #5c5c5c;
345
+ --rm-audio-player-volume-fill: rgba(0, 0, 0, 0.5);
346
+ --rm-audio-player-volume-track: #ababab;
347
+ --rm-audio-player-track-current-time: #0072f5;
348
+ --rm-audio-player-track-duration: #8c8c8c;
349
+ --rm-audio-player-progress-bar: #0072f5;
350
+ --rm-audio-player-progress-bar-background: #393939;
351
+ --rm-audio-player-waveform-cursor: #4b4b4b;
352
+ --rm-audio-player-waveform-background: var(
353
+ --rm-audio-player-progress-bar-background
354
+ );
355
+ --rm-audio-player-waveform-bar: var(--rm-audio-player-progress-bar);
356
+ --rm-audio-player-sortable-list: #eaeaea;
357
+ --rm-audio-player-sortable-list-button-active: #0072f5;
358
+ --rm-audio-player-selected-list-item-background: #b3b3b3;
359
+ }
360
+ ```
361
+
362
+ # useAudioPlayer
363
+
364
+ Control the player externally using the `useAudioPlayer` hook. Must be called inside `AudioPlayerStateProvider` (or `AudioPlayer` which wraps it).
365
+
268
366
  ```tsx
269
- --rm-audio-player-interface-container:var(--spectrum-global-color-gray-100);
270
- --rm-audio-player-volume-background: #ccc;
271
- --rm-audio-player-volume-panel-background:#f2f2f2;
272
- --rm-audio-player-volume-panel-border:#ccc;
273
- --rm-audio-player-volume-thumb: #d3d3d3;
274
- --rm-audio-player-volume-fill:rgba(0, 0, 0, 0.5);
275
- --rm-audio-player-volume-track:#ababab;
276
- --rm-audio-player-track-current-time:#0072F5;
277
- --rm-audio-player-track-duration:#8c8c8c;
278
- --rm-audio-player-progress-bar:#0072F5;
279
- --rm-audio-player-progress-bar-background:#D1D1D1;
280
- --rm-audio-player-waveform-cursor:var(--spectrum-global-color-gray-800);
281
- --rm-audio-player-waveform-background:var(--rm-audio-player-progress-bar-background);
282
- --rm-audio-player-waveform-bar:var(--rm-audio-player-progress-bar);
283
- --rm-audio-player-sortable-list:var(--spectrum-global-color-gray-200);
284
- --rm-audio-player-sortable-list-button-active:#0072F5;
285
- --rm-audio-player-selected-list-item-background:var(--spectrum-global-color-gray-500);
286
-
287
- // ...spectrum theme palette and so on... //
367
+ import AudioPlayer, { useAudioPlayer } from "react-modern-audio-player";
368
+
369
+ function PlayerControls() {
370
+ const {
371
+ isPlaying,
372
+ currentTrack,
373
+ currentTime,
374
+ duration,
375
+ togglePlay,
376
+ next,
377
+ prev,
378
+ seek,
379
+ setVolume,
380
+ setTrack,
381
+ } = useAudioPlayer();
382
+
383
+ return (
384
+ <div>
385
+ <button onClick={togglePlay}>{isPlaying ? "Pause" : "Play"}</button>
386
+ <button onClick={prev}>Prev</button>
387
+ <button onClick={next}>Next</button>
388
+ <button onClick={() => seek(30)}>+30s</button>
389
+ <button onClick={() => setVolume(0.5)}>Volume 50%</button>
390
+ <button onClick={() => setTrack(1)}>Track 2</button>
391
+ <p>
392
+ {currentTrack?.name} — {currentTime.toFixed(0)}s / {duration.toFixed(0)}
393
+ s
394
+ </p>
395
+ </div>
396
+ );
397
+ }
398
+
399
+ function App() {
400
+ const playList = [{ id: 1, src: "audio.mp3", name: "Track 1" }];
401
+ return (
402
+ <AudioPlayer playList={playList}>
403
+ <PlayerControls />
404
+ </AudioPlayer>
405
+ );
406
+ }
288
407
  ```
408
+
409
+ ## AudioPlayerControls
410
+
411
+ | Property | Type | Description |
412
+ | ----------------- | -------------------------- | ------------------------- |
413
+ | `isPlaying` | `boolean` | Current playback state |
414
+ | `volume` | `number` | Current volume (0–1) |
415
+ | `currentTime` | `number` | Elapsed time in seconds |
416
+ | `duration` | `number` | Track duration in seconds |
417
+ | `repeatType` | `RepeatType` | Current repeat mode |
418
+ | `muted` | `boolean` | Whether audio is muted |
419
+ | `currentTrack` | `AudioData \| null` | Currently playing track |
420
+ | `currentIndex` | `number` | Index in playlist |
421
+ | `playList` | `PlayList` | Full playlist |
422
+ | `play()` | `() => void` | Start playback |
423
+ | `pause()` | `() => void` | Pause playback |
424
+ | `togglePlay()` | `() => void` | Toggle play/pause |
425
+ | `next()` | `() => void` | Skip to next track |
426
+ | `prev()` | `() => void` | Skip to previous track |
427
+ | `seek(time)` | `(time: number) => void` | Seek to time in seconds |
428
+ | `setVolume(vol)` | `(volume: number) => void` | Set volume (0–1, clamped) |
429
+ | `toggleMute()` | `() => void` | Toggle mute on/off |
430
+ | `setTrack(index)` | `(index: number) => void` | Jump to playlist index |
431
+
432
+ ## Sub-Hooks
433
+
434
+ `useAudioPlayer` subscribes to all context slices. For fine-grained re-render control, use domain-specific sub-hooks:
435
+
436
+ ```tsx
437
+ import {
438
+ useAudioPlayerPlayback,
439
+ useAudioPlayerTrack,
440
+ useAudioPlayerVolume,
441
+ useAudioPlayerTime,
442
+ useAudioPlayerElement,
443
+ } from "react-modern-audio-player";
444
+
445
+ // Only re-renders on play/pause and repeat type changes
446
+ function PlayButton() {
447
+ const { isPlaying, togglePlay } = useAudioPlayerPlayback();
448
+ return <button onClick={togglePlay}>{isPlaying ? "Pause" : "Play"}</button>;
449
+ }
450
+
451
+ // Only re-renders on time updates
452
+ function TimeDisplay() {
453
+ const { currentTime, duration } = useAudioPlayerTime();
454
+ return <span>{currentTime.toFixed(0)}s / {duration.toFixed(0)}s</span>;
455
+ }
456
+ ```
457
+
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) |
465
+
466
+ # Context Hooks
467
+
468
+ Components inside `AudioPlayer` can subscribe to only the state slice they need, avoiding unnecessary re-renders.
469
+
470
+ ```tsx
471
+ import {
472
+ usePlaybackContext, // curAudioState: { isPlaying, repeatType, volume, muted, isLoadedMetaData }
473
+ useTrackContext, // playList, curIdx, curPlayId
474
+ useUIContext, // activeUI, interfacePlacement, playListPlacement, playerPlacement, volumeSliderPlacement
475
+ useResourceContext, // elementRefs, customIcons, coverImgsCss
476
+ } from "react-modern-audio-player";
477
+
478
+ const MyComponent = () => {
479
+ const { curAudioState } = usePlaybackContext();
480
+ return <span>{curAudioState.isPlaying ? "Playing" : "Paused"}</span>;
481
+ };
482
+ ```
483
+
484
+ | Hook | Returns |
485
+ | -------------------- | --------------------------------------------------------------------------------------------- |
486
+ | `usePlaybackContext` | `{ curAudioState: AudioState }` |
487
+ | `useTrackContext` | `{ playList, curIdx, curPlayId }` |
488
+ | `useUIContext` | `{ activeUI, interfacePlacement, playListPlacement, playerPlacement, volumeSliderPlacement }` |
489
+ | `useResourceContext` | `{ elementRefs, customIcons, coverImgsCss }` |
490
+
289
491
  # Custom Component
290
- > you can apply custom component to `AudioPlayer` by `CustomComponent`
291
- > </br>
292
- > you can also set `viewProps` to `CustomComponent`
293
- > </br>
294
- > (https://react-spectrum.adobe.com/react-spectrum/View.html#props)
295
492
 
296
- ``` tsx
493
+ You can place a custom component anywhere in the player interface using `AudioPlayer.CustomComponent`. Use `useAudioPlayer` inside it to access player state and controls.
494
+
495
+ ```tsx
496
+ import AudioPlayer, {
497
+ useAudioPlayer,
498
+ InterfacePlacement,
499
+ } from "react-modern-audio-player";
500
+
297
501
  const activeUI: ActiveUI = {
298
502
  all: true,
299
503
  };
@@ -305,44 +509,34 @@ const placement = {
305
509
  },
306
510
  } as InterfacePlacement<11>,
307
511
  /**
308
- * you should set generic value of `InterfacePlacement` as interfaces max length for auto-complete aria type such as "row-1-10"
309
- * generic value must plus 1 than interfaces length because of 0 index
310
- */
512
+ * set the generic value of InterfacePlacement to the max interface length + 1
513
+ * for correct "row1-10" autocompletion
514
+ */
311
515
  };
312
516
 
313
- /** you can get audioPlayerState by props */
314
- const CustomComponent = ({
315
- audioPlayerState,
316
- }: {
317
- audioPlayerState?: AudioPlayerStateContext;
318
- }) => {
319
- const audioEl = audioPlayerState?.elementRefs?.audioEl;
320
- const handOverTime = () => {
321
- if (audioEl) {
322
- audioEl.currentTime += 30;
323
- }
324
- };
517
+ const CustomComponent = () => {
518
+ const { currentTime, duration, seek, isPlaying, togglePlay } =
519
+ useAudioPlayer();
325
520
  return (
326
521
  <>
327
- <button onClick={handOverTime}>+30</button>
522
+ <button onClick={() => seek(currentTime + 30)}>+30s</button>
523
+ <button onClick={togglePlay}>{isPlaying ? "Pause" : "Play"}</button>
524
+ <span>
525
+ {currentTime.toFixed(0)}s / {duration.toFixed(0)}s
526
+ </span>
328
527
  </>
329
528
  );
330
529
  };
331
530
 
332
- <AudioPlayer
333
- playList={playList}
334
- placement={placement}
335
- activeUI={activeUI}
336
- >
531
+ <AudioPlayer playList={playList} placement={placement} activeUI={activeUI}>
337
532
  <AudioPlayer.CustomComponent id="playerCustomComponent">
338
533
  <CustomComponent />
339
534
  </AudioPlayer.CustomComponent>
340
- </AudioPlayer>
535
+ </AudioPlayer>;
341
536
  ```
342
537
 
538
+ # **Example**
343
539
 
344
-
345
- # ****Example****
346
540
  ```tsx
347
541
  function App() {
348
542
  return (