Skip to content

Commit 06bb52a

Browse files
committed
feat: add <Audio> volume and seek controls
1 parent 41888f9 commit 06bb52a

File tree

2 files changed

+85
-14
lines changed

2 files changed

+85
-14
lines changed

src/Audio/index.ts

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export interface IAudioProps {
1111
muted?: boolean;
1212
preload?: 'none' | 'metadata' | 'auto';
1313
volume?: number;
14-
renderInner?: () => React.ReactElement<any>;
14+
noJs?: React.ReactElement<any>;
1515

1616
onAbort?: TAudioEvent,
1717
onCanPlay?: TAudioEvent,
@@ -39,24 +39,38 @@ export interface IAudioProps {
3939
}
4040

4141
export interface IAudioState {
42+
time?: number;
43+
duration?: number;
4244
isPlaying?: boolean;
45+
volume: number;
4346
}
4447

4548
export class Audio extends Component<IAudioProps, IAudioState> {
46-
el: HTMLAudioElement;
49+
el: HTMLAudioElement = null;
4750

4851
state: IAudioState = {
49-
isPlaying: false
52+
time: 0,
53+
duration: 0,
54+
isPlaying: false,
55+
volume: NaN
5056
};
5157

5258
ref = (el) => {
5359
this.el = el;
5460
};
5561

56-
componentDidMount() {
62+
componentDidMount () {
5763
if (this.props.autoplay && this.el.paused) {
5864
this.play();
5965
}
66+
67+
this.setState({
68+
volume: this.el.volume
69+
});
70+
}
71+
72+
componentWillUnmount () {
73+
this.el = null;
6074
}
6175

6276
play = () => {
@@ -71,27 +85,80 @@ export class Audio extends Component<IAudioProps, IAudioState> {
7185
}
7286
};
7387

88+
seek = (time: number) => {
89+
if (this.el) {
90+
time = Math.min(this.state.duration, Math.max(0, time));
91+
this.el.currentTime = time;
92+
}
93+
};
94+
95+
volume = (volume) => {
96+
if (this.el) {
97+
volume = Math.min(1, Math.max(0, volume));
98+
99+
this.el.volume = volume;
100+
this.setState({
101+
volume
102+
});
103+
}
104+
};
105+
74106
event = (name: string) => (event) => {
75107
const handler = this.props[name];
76108

77109
if (handler) {
78110
handler(event, this, this.state);
79111
}
112+
};
80113

81-
this.scrapDOM();
114+
onPlay = (event) => {
115+
this.setState({
116+
isPlaying: true
117+
});
118+
119+
this.event('onPlay')(event);
82120
};
83121

84-
scrapDOM() {
122+
onPause = (event) => {
123+
this.setState({
124+
isPlaying: false
125+
});
85126

86-
}
127+
this.event('onPause')(event);
128+
};
129+
130+
onVolumeChange = (event) => {
131+
this.setState({
132+
volume: this.el.volume
133+
});
134+
135+
this.event('onVolumeChange')(event);
136+
};
137+
138+
onDurationChange = (event) => {
139+
this.setState({
140+
duration: this.el.duration
141+
});
142+
143+
this.event('onDurationChange')(event);
144+
};
145+
146+
onTimeUpdate = (event) => {
147+
this.setState({
148+
time: this.el.currentTime
149+
});
150+
151+
this.event('onTimeUpdate')(event);
152+
};
87153

88154
render () {
89155
const {props, event} = this;
90-
const {children, src, autoplay, loop, muted, preload, volume, renderInner = noop as any} = props;
156+
const {children, src, autoplay, loop, muted, preload, volume, noJs = noop as any} = props;
91157

92158

93159
const audio = h('audio', {
94160
ref: this.ref,
161+
controls: false,
95162
src,
96163
autoplay,
97164
loop,
@@ -101,28 +168,28 @@ export class Audio extends Component<IAudioProps, IAudioState> {
101168
onAbort: event('onAbort'),
102169
onCanPlay: event('onCanPlay'),
103170
onCanPlayThrough: event('onCanPlayThrough'),
104-
onDurationChange: event('onDurationChange'),
171+
onDurationChange: this.onDurationChange,
105172
onEmptied: event('onEmptied'),
106173
onEncrypted: event('onEncrypted'),
107174
onEnded: event('onEnded'),
108175
onError: event('onError'),
109176
onLoadedData: event('onLoadedData'),
110177
onLoadedMetadata: event('onLoadedMetadata'),
111178
onLoadStart: event('onLoadStart'),
112-
onPause: event('onPause'),
113-
onPlay: event('onPlay'),
179+
onPause: this.onPause,
180+
onPlay: this.onPlay,
114181
onPlaying: event('onPlaying'),
115182
onProgress: event('onProgress'),
116183
onRateChange: event('onRateChange'),
117184
onSeeked: event('onSeeked'),
118185
onSeeking: event('onSeeking'),
119186
onStalled: event('onStalled'),
120187
onSuspend: event('onSuspend'),
121-
onTimeUpdate: event('onTimeUpdate'),
122-
onVolumeChange: event('onVolumeChange'),
188+
onTimeUpdate: this.onTimeUpdate,
189+
onVolumeChange: this.onVolumeChange,
123190
onWaiting: event('onWaiting')
124191
},
125-
renderInner()
192+
noJs
126193
);
127194

128195
const markup = children(this, this.state);

src/Audio/story.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ storiesOf('Generators/Audio', module)
2727
<div>
2828
<button onClick={audio.play}>Play</button>
2929
<button onClick={audio.pause}>Pause</button>
30+
<button onClick={() => audio.seek(state.time - 5)}>Seek -</button>
31+
<button onClick={() => audio.seek(state.time + 5)}>Seek +</button>
32+
<button onClick={() => audio.volume(state.volume - 0.05)}>Volume -</button>
33+
<button onClick={() => audio.volume(state.volume + 0.05)}>Volume +</button>
3034
<pre style={{fontFamily: 'monospace'}}>
3135
{JSON.stringify(state, null, 4)}
3236
</pre>

0 commit comments

Comments
 (0)