Skip to content

Commit e8016cb

Browse files
committed
mapStateToProps, mapVideoElToProps and mergeProps
1 parent dc02f61 commit e8016cb

File tree

11 files changed

+479
-164
lines changed

11 files changed

+479
-164
lines changed

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"preinstall:demo": "npm run build",
1212
"install:demo": "cd demo && npm i",
1313
"i:demo": "npm run install:demo",
14-
"test": "jest",
14+
"test": "jest --env=jsdom",
1515
"test:watch": "npm run test -- --watch",
1616
"build": "webpack",
1717
"build:demo": "cd demo && webpack",
@@ -59,7 +59,7 @@
5959
"devDependencies": {
6060
"babel": "^6.5.2",
6161
"babel-core": "^6.18.2",
62-
"babel-jest": "^17.0.2",
62+
"babel-jest": "^18.0.0",
6363
"babel-loader": "^6.2.7",
6464
"babel-plugin-transform-object-rest-spread": "^6.19.0",
6565
"babel-preset-es2015": "^6.18.0",
@@ -77,7 +77,7 @@
7777
"gh-pages": "^0.12.0",
7878
"html-webpack-plugin": "^2.24.1",
7979
"identity-obj-proxy": "^3.0.0",
80-
"jest": "^17.0.3",
80+
"jest": "^18.0.0",
8181
"json-loader": "^0.5.4",
8282
"lodash.throttle": "^4.1.1",
8383
"open": "0.0.5",

src/DefaultPlayer/DefaultPlayer.js

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import React from 'react';
2-
import video from './../Video/Video';
2+
import video from './../video/video';
3+
import {
4+
setVolume,
5+
toggleMute,
6+
togglePause,
7+
setCurrentTime
8+
} from './../video/api';
39
import styles from './DefaultPlayer.css';
410
import PlayPause from './PlayPause/PlayPause';
511
import Seek from './Seek/Seek';
@@ -8,27 +14,45 @@ import Volume from './Volume/Volume';
814
const DefaultPlayer = (props) => {
915
const {
1016
video,
17+
style,
1118
children,
1219
className,
20+
setVolume,
21+
toggleMute,
22+
togglePause,
23+
setCurrentTime,
1324
...restProps
1425
} = props;
1526
return (
1627
<div className={[
1728
styles.component,
1829
className
19-
].join(' ')}>
30+
].join(' ')}
31+
style={style}>
2032
<video
2133
className={styles.video}
2234
{...restProps}>
2335
{ children }
2436
</video>
2537
<div className={styles.controls}>
26-
<PlayPause {...video} />
27-
<Seek {...video} />
28-
<Volume {...video} />
38+
<PlayPause
39+
togglePause={togglePause}
40+
{...video} />
41+
<Seek
42+
setCurrentTime={setCurrentTime}
43+
{...video} />
44+
<Volume
45+
setVolume={setVolume}
46+
toggleMute={toggleMute}
47+
{...video} />
2948
</div>
3049
</div>
3150
);
3251
};
3352

34-
export default video(DefaultPlayer);
53+
export default video(DefaultPlayer, undefined, (videoEl, state) => ({
54+
toggleMute: () => toggleMute(videoEl, state),
55+
togglePause: () => togglePause(videoEl, state),
56+
setVolume: (value) => setVolume(videoEl, state, value),
57+
setCurrentTime: (value) => setCurrentTime(videoEl, state, value)
58+
}));

src/DefaultPlayer/PlayPause/PlayPause.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
import React from 'react';
22
import styles from './PlayPause.css';
33

4-
export default ({ pause, play, paused, className }) => {
5-
const toggle = () => {
6-
if (paused) {
7-
play();
8-
} else {
9-
pause();
10-
}
11-
};
4+
export default ({ togglePause, paused, className }) => {
125
return (
136
<div className={[
147
styles.component,
158
className
169
].join(' ')}>
1710
<button
18-
onClick={toggle}
11+
onClick={togglePause}
1912
type="button">
2013
{ paused
2114
? 'Play'

src/DefaultPlayer/Seek/Seek.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import React from 'react';
22
import styles from './Seek.css';
33

4-
export default ({ getVideoEl, duration, currentTime, className }) => {
4+
export default ({ setCurrentTime, duration, currentTime, className }) => {
55
const change = (e) => {
6-
getVideoEl().currentTime = e.target.value * duration / 100;
6+
setCurrentTime(e.target.value * duration / 100);
77
};
88
return (
99
<div className={[
@@ -17,7 +17,7 @@ export default ({ getVideoEl, duration, currentTime, className }) => {
1717
type="range"
1818
orient="horizontal"
1919
onChange={change}
20-
value={currentTime / duration * 100} />
20+
value={currentTime / duration * 100} />
2121
</div>
2222
);
2323
};

src/DefaultPlayer/Volume/Volume.js

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,10 @@
11
import React from 'react';
22
import styles from './Volume.css';
33

4-
export default ({ getVideoEl, volume, muted, className }) => {
5-
const setVolume = (v) => {
6-
getVideoEl().volume = v;
7-
};
4+
export default ({ setVolume, toggleMute, volume, muted, className }) => {
85
const change = (e) => {
9-
getVideoEl().muted = false;
106
setVolume(e.target.value);
117
};
12-
const toggleMute = () => {
13-
if (muted || volume <= 0) {
14-
if (volume <= 0) {
15-
setVolume(1);
16-
}
17-
getVideoEl().muted = false;
18-
} else {
19-
getVideoEl().muted = true;
20-
}
21-
};
228
return (
239
<div className={[
2410
styles.component,

src/Entry.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export { default } from './Video/Video';
1+
export { default } from './video/video';
22
export { default as DefaultPlayer } from './DefaultPlayer/DefaultPlayer';

src/Video/Video.js

Lines changed: 53 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,90 @@
11
/**
22
* This is a HoC that finds a single
33
* <video> in a component and makes
4-
* all its PROPERTIES and METHODS
5-
* available as props.
4+
* all its PROPERTIES available as props.
65
*/
76
import React, { Component } from 'react';
87
import { findDOMNode } from 'react-dom';
98
import toClass from 'recompose/toClass';
9+
import {
10+
EVENTS,
11+
PROPERTIES,
12+
} from './constants';
1013

11-
const EVENTS = [
12-
'onAbort',
13-
'onCanPlay',
14-
'onCanPlayThrough',
15-
'onDurationChange',
16-
'onEmptied',
17-
'onEncrypted',
18-
'onEnded',
19-
'onError',
20-
'onLoadedData',
21-
'onLoadedMetadata',
22-
'onLoadStart',
23-
'onPause',
24-
'onPlay',
25-
'onPlaying',
26-
'onProgress',
27-
'onRateChange',
28-
'onSeeked',
29-
'onSeeking',
30-
'onStalled',
31-
'onSuspend',
32-
'onTimeUpdate',
33-
'onVolumeChange',
34-
'onWaiting'
35-
];
14+
const defaultMapStateToProps = (state = {}) => Object.assign({
15+
video: {
16+
...state
17+
}
18+
});
3619

37-
const METHODS = [
38-
'addTextTrack',
39-
'canPlayType',
40-
'load',
41-
'play',
42-
'pause'
43-
];
20+
const defaultMapVideoElToProps = (videoEl) => ({
21+
videoEl
22+
});
4423

45-
const PROPERTIES = [
46-
'audioTracks',
47-
'autoPlay',
48-
'buffered',
49-
'controller',
50-
'controls',
51-
'currentSrc',
52-
'currentTime',
53-
'defaultMuted',
54-
'defaultPlaybackRate',
55-
'duration',
56-
'ended',
57-
'error',
58-
'loop',
59-
'mediaGroup',
60-
'muted',
61-
'networkState',
62-
'paused',
63-
'playbackRate',
64-
'played',
65-
'preload',
66-
'readyState',
67-
'seekable',
68-
'seeking',
69-
'src',
70-
'startDate',
71-
'textTracks',
72-
'videoTracks',
73-
'volume'
74-
];
24+
const defaultMergeProps = (
25+
stateProps = {},
26+
videoElProps = {},
27+
ownProps = {}
28+
) => Object.assign({}, stateProps, videoElProps, ownProps);
7529

76-
export default (BaseComponent) => {
30+
export default (
31+
BaseComponent,
32+
mapStateToProps = defaultMapStateToProps,
33+
mapVideoElToProps = defaultMapVideoElToProps,
34+
mergeProps = defaultMergeProps
35+
) => {
7736
const BaseComponentClass = toClass(BaseComponent);
7837

7938
class Video extends Component {
8039
constructor(props) {
8140
super(props);
82-
this.getVideoEl = this.getVideoEl.bind(this);
8341
this.updateState = this.updateState.bind(this);
84-
}
85-
86-
getVideoEl() {
87-
return this.videoEl;
42+
this.state = {};
8843
}
8944

9045
updateState() {
9146
this.setState(
9247
PROPERTIES.reduce((p, c) => {
93-
p[c] = this.videoEl[c];
48+
p[c] = this.videoEl && this.videoEl[c];
9449
return p;
9550
}, {})
9651
);
9752
}
9853

99-
componentDidMount() {
100-
this.videoEl = this.el.getElementsByTagName('video')[0];
54+
bindEventsToUpdateState() {
10155
EVENTS.forEach(event => {
102-
this.videoEl[event.toLowerCase()] = this.updateState.bind(this);
56+
this.videoEl[event.toLowerCase()] = this.updateState;
10357
});
104-
this.methods = METHODS.reduce((p, c) => {
105-
p[c] = (...args) => {
106-
if (this.videoEl[c]) this.videoEl[c].apply(this.videoEl, args);
107-
};
108-
return p;
109-
}, {});
58+
}
59+
60+
// Stop `this.el` from being null briefly on every render,
61+
// see: https://github.com/mderrick/react-html5video/pull/65
62+
setRef(el) {
63+
this.el = findDOMNode(el);
64+
}
65+
66+
componentDidMount() {
67+
this.videoEl = this.el.getElementsByTagName('video')[0];
68+
this.bindEventsToUpdateState();
11069
}
11170

11271
render() {
72+
const stateProps = mapStateToProps(
73+
this.state,
74+
this.props
75+
);
76+
const videoElProps = mapVideoElToProps(
77+
this.videoEl,
78+
this.state,
79+
this.props
80+
);
11381
return (
11482
<BaseComponentClass
115-
ref={(el) => this.el = findDOMNode(el)}
116-
video={Object.assign({
117-
// getVideoEl is used to update the video
118-
// using the HTMLMediaElement API.
119-
// e.g getVideoEl().muted = true;
120-
getVideoEl: this.getVideoEl,
121-
// forceUpdateState should never be used
122-
// unless changing a video property that
123-
// does not trigger an EVENT.
124-
// See CaptionMenu component.
125-
forceUpdateState: this.updateState,
126-
}, this.methods, this.state, this.props)}
127-
{...this.props} />
83+
ref={this.setRef.bind(this)}
84+
{...mergeProps(
85+
stateProps,
86+
videoElProps,
87+
this.props)} />
12888
);
12989
}
13090
}

0 commit comments

Comments
 (0)