React Modern Audio Player
DEMO
https://codesandbox.io/s/basic-91y82y?file=/src/App.tsx
Flexible and Customizable UI
wavesurfer.js
This can offer waveform by
This can offer various UI and you can also customize each component position
Installation
npm install --save react-modern-audio-player
Quick Start
import AudioPlayer from 'react-modern-audio-player';
const playList = [
{
name: 'name',
writer: 'writer',
img: 'image.jpg',
src: 'audio.mp3',
id: 1,
},
]
function Player (){
return (
<AudioPlayer playList={playList} />
)
}
Props
interface AudioPlayerProps {
playList: PlayList;
audioInitialState?: InitialStates;
audioRef?: React.MutableRefObject<HTMLAudioElement>;
activeUI?: ActiveUI;
customIcons?: CustomIcons;
coverImgsCss?: CoverImgsCss;
placement?: {
player?: PlayerPlacement;
playList?: PlayListPlacement;
interface?: InterfacePlacement;
volumeSlider?: VolumeSliderPlacement;
};
rootContainerProps?: RootContainerProps
}
Prop | Type | Default |
---|---|---|
playList |
PlayList | [ ] |
audioInitialState |
InitialStates | isPlaying: false repeatType: "ALL" volume: 1 |
activeUI |
ActiveUI | playButton : true |
customIcons |
CustomIcons | undefined |
coverImgsCss |
CoverImgsCss | undefined |
placement |
Placement | playListPlacement : "bottom" interfacePlacement :DefaultInterfacePlacement |
rootContainerProps |
RootContainerProps | theme: spectrum-theme-default width: 100% position: 'static' UNSAFE_className: rm-audio-player-provider |
PlayList
type PlayList = Array<AudioData>;
type AudioData = {
src: string;
id: number;
name?: string | ReactNode;
writer?: string | ReactNode;
img?: string;
description?: string | ReactNode;
customTrackInfo?: string | ReactNode;
};
InitialStates
type InitialStates = Omit<
React.AudioHTMLAttributes<HTMLAudioElement>,
"autoPlay"
> & {
isPlaying?: boolean;
repeatType?: RepeatType;
volume?: number;
currentTime?: number;
duration?: number;
curPlayId: number;
};
ActiveUI
type ActiveUI = {
all: boolean;
playButton: boolean;
playList: PlayListUI;
prevNnext: boolean;
volume: boolean;
volumeSlider: boolean;
repeatType: boolean;
trackTime: boolean;
trackInfo: boolean;
artwork: boolean;
progress: ProgressUI;
};
type ProgressUI = "waveform" | "bar" | false;
type PlayListUI = "sortable" | "unSortable" | false;
CustomIcons
type CustomIcons = {
play: ReactNode;
pause: ReactNode;
prev: ReactNode;
next: ReactNode;
repeatOne: ReactNode;
repeatAll: ReactNode;
repeatNone: ReactNode;
repeatShuffle: ReactNode;
volumeFull: ReactNode;
volumeHalf: ReactNode;
volumeMuted: ReactNode;
playList: ReactNode;
};
CoverImgsCss
interface CoverImgsCss {
artwork?: React.CSSProperties;
listThumbnail?: React.CSSProperties;
}
Placement
type PlayerPlacement =
| "bottom"
| "top"
| "bottom-left"
| "bottom-right"
| "top-left"
| "top-right";
type VolumeSliderPlacement = "bottom" | "top" | 'left' | 'right';
type PlayListPlacement = "bottom" | "top";
type InterfacePlacement = {
templateArea?: InterfaceGridTemplateArea;
customComponentsArea?: InterfaceGridCustomComponentsArea<TMaxLength>;
itemCustomArea?: InterfaceGridItemArea;
};
type InterfacePlacementKey =
| Exclude<keyof ActiveUI, "all" | "prevNnext" | "trackTime">
| "trackTimeCurrent"
| "trackTimeDuration";
type InterfacePlacementValue = "row1-1" | "row1-2" | "row1-3" | "row1-4" | ... more ... | "row9-9"
/** if you apply custom components, values must be "row1-1" ~ any more */
type InterfaceGridTemplateArea = Record<InterfacePlacementKey,InterfacePlacementValue>;
type InterfaceGridCustomComponentsArea = Record<componentId,InterfacePlacementValue>;
type InterfaceGridItemArea = Partial<Record<InterfacePlacementKey, string>>;
/** example
* progress : 2-4
* repeatBtn : row1-4 / 2 / row1-4 / 10
*
* check MDN - grid area
* https://developer.mozilla.org/ko/docs/Web/CSS/grid-area
*/
Default interface placement
const defaultInterfacePlacement = {
templateArea: {
artwork: "row1-1",
trackInfo: "row1-2",
trackTimeCurrent: "row1-3",
trackTimeDuration: "row1-4",
progress: "row1-5",
repeatType: "row1-6",
volume: "row1-7",
playButton: "row1-8",
playList: "row1-9",
},
};
RootContainerProps
it is same with spectrum provider props https://react-spectrum.adobe.com/react-spectrum/Provider.html#themes
Override Style
Theme mode ( dark-mode )
it apply dark-mode depending on
system-theme
you can customize color-theme bycss-variable
ofreact-spectrum
theme-default
ID & Classnames
root ID
- rm-audio-player
root ClassName
- rm-audio-player-provider
color variables
--rm-audio-player-interface-container:var(--spectrum-global-color-gray-100);
--rm-audio-player-volume-background: #ccc;
--rm-audio-player-volume-panel-background:#f2f2f2;
--rm-audio-player-volume-panel-border:#ccc;
--rm-audio-player-volume-thumb: #d3d3d3;
--rm-audio-player-volume-fill:rgba(0, 0, 0, 0.5);
--rm-audio-player-volume-track:#ababab;
--rm-audio-player-track-current-time:#0072F5;
--rm-audio-player-track-duration:#8c8c8c;
--rm-audio-player-progress-bar:#0072F5;
--rm-audio-player-progress-bar-background:#D1D1D1;
--rm-audio-player-waveform-cursor:var(--spectrum-global-color-gray-800);
--rm-audio-player-waveform-background:var(--rm-audio-player-progress-bar-background);
--rm-audio-player-waveform-bar:var(--rm-audio-player-progress-bar);
--rm-audio-player-sortable-list:var(--spectrum-global-color-gray-200);
--rm-audio-player-sortable-list-button-active:#0072F5;
--rm-audio-player-selected-list-item-background:var(--spectrum-global-color-gray-500);
// ...spectrum theme palette and so on... //
Custom Component
you can apply custom component to
AudioPlayer
byCustomComponent
you can also setviewProps
toCustomComponent
(https://react-spectrum.adobe.com/react-spectrum/View.html#props)
const activeUI: ActiveUI = {
all: true,
};
const placement = {
interface: {
customComponentsArea: {
playerCustomComponent: "row1-10",
},
} as InterfacePlacement<11>,
/**
* you should set generic value of `InterfacePlacement` as interfaces max length for auto-complete aria type such as "row-1-10"
* generic value must plus 1 than interfaces length because of 0 index
*/
};
/** you can get audioPlayerState by props */
const CustomComponent = ({
audioPlayerState,
}: {
audioPlayerState?: AudioPlayerStateContext;
}) => {
const audioEl = audioPlayerState?.elementRefs?.audioEl;
const handOverTime = () => {
if (audioEl) {
audioEl.currentTime += 30;
}
};
return (
<>
<button onClick={handOverTime}>+30</button>
</>
);
};
<AudioPlayer
playList={playList}
placement={placement}
activeUI={activeUI}
>
<AudioPlayer.CustomComponent id="playerCustomComponent">
<CustomComponent />
</AudioPlayer.CustomComponent>
</AudioPlayer>
Example
function App() {
return (
<div>
<AudioPlayer
playList={playList}
audioInitialState={{
muted: true,
volume: 0.2,
curPlayId: 1,
}}
placement={{
interface: {
templateArea: {
trackTimeDuration: "row1-5",
progress: "row1-4",
playButton: "row1-6",
repeatType: "row1-7",
volume: "row1-8",
},
},
player: "bottom-left",
}}
activeUI={{
all: true,
progress: "waveform",
}}
/>
</div>
);
}