├── .gitignore
├── LICENSE
├── README.md
├── examples
├── simple.html
└── simple.js
├── index.js
├── package.json
└── src
├── Mask.jsx
├── Source.jsx
└── index.jsx
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.log
3 | .idea
4 | .ipr
5 | .iws
6 | *~
7 | ~*
8 | *.diff
9 | *.patch
10 | *.bak
11 | .DS_Store
12 | Thumbs.db
13 | .project
14 | .*proj
15 | .svn
16 | *.swp
17 | *.swo
18 | *.pyc
19 | *.pyo
20 | node_modules
21 | .cache
22 | *.css
23 | build
24 | lib
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Benjy Cui
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-sublime-video
2 |
3 | [](https://www.npmjs.org/package/react-sublime-video)
4 | [](https://npmjs.org/package/react-sublime-video)
5 | [](https://david-dm.org/benjycui/react-sublime-video)
6 |
7 | A sublime video player in React.
8 |
9 | # Installation
10 |
11 | ```bash
12 | npm install --save react-sublime-video
13 | ```
14 |
15 | ## Usage
16 |
17 | ```jsx
18 | import SublimeVideo from 'react-sublime-video;
19 |
20 | ReactDOM.render(
21 |
24 | , mountNode
25 | );
26 | ```
27 |
28 | ## API
29 |
30 | ### SublimeVideo
31 |
32 | The same as native ``, see: [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video).
33 |
34 | ### SublimeVidoe.Source
35 |
36 | The same as native ``, see: [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source).
37 |
38 | ## Liscense
39 |
40 | MIT
41 |
--------------------------------------------------------------------------------
/examples/simple.html:
--------------------------------------------------------------------------------
1 | placeholder
2 |
--------------------------------------------------------------------------------
/examples/simple.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const ReactDOM = require('react-dom');
3 | const SublimeVideo = require('react-sublime-video');
4 | const Source = SublimeVideo.Source;
5 |
6 | const style = {
7 | width: '49%',
8 | margin: '0.5%',
9 | float: 'left',
10 | };
11 |
12 | ReactDOM.render(
13 |
14 |
17 |
20 |
23 |
24 |
27 |
28 |
29 | , document.getElementById('__react-content'));
30 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = require('./src');
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-sublime-video",
3 | "version": "0.2.5",
4 | "description": "A sublime video player in React.",
5 | "main": "./lib/index.js",
6 | "files": [
7 | "lib"
8 | ],
9 | "scripts": {
10 | "start": "rc-tools run server",
11 | "lint": "rc-tools run lint",
12 | "pub": "rc-tools run pub",
13 | "test": "echo \"Error: no test specified\" && exit 1"
14 | },
15 | "config": {
16 | "port": 8000
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/benjycui/react-sublime-video.git"
21 | },
22 | "keywords": [
23 | "react",
24 | "sublime",
25 | "video",
26 | "player",
27 | "simple"
28 | ],
29 | "author": "Benjy Cui",
30 | "license": "MIT",
31 | "bugs": {
32 | "url": "https://github.com/benjycui/react-sublime-video/issues"
33 | },
34 | "homepage": "https://github.com/benjycui/react-sublime-video#readme",
35 | "dependencies": {
36 | "prop-types": "^15.5.10",
37 | "rc-tween-one": "^1.2.5"
38 | },
39 | "devDependencies": {
40 | "rc-tools": "^5.5.11",
41 | "react": "^15.2.0",
42 | "react-dom": "^15.2.0"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Mask.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import TweenOne from 'rc-tween-one';
4 | import SvgMorphPlugin from 'rc-tween-one/lib/plugin/SvgMorphPlugin';
5 | TweenOne.plugins.push(SvgMorphPlugin);
6 | const maskStyle = {
7 | position: 'absolute',
8 | top: 0,
9 | left: 0,
10 | width: '100%',
11 | height: '100%',
12 | backgroundColor: 'rgba(0, 0, 0, 0.35)',
13 | cursor: 'pointer',
14 | };
15 |
16 | const buttonStyle = {
17 | position: 'absolute',
18 | top: '50%',
19 | left: '50%',
20 | margin: -30,
21 | borderRadius: 30,
22 | backgroundColor: '#fff',
23 | };
24 |
25 |
26 | export default class Mask extends React.Component {
27 | constructor(props) {
28 | super(props);
29 |
30 | this.state = {
31 | visible: props.defaultVisible,
32 | animation: [],
33 | };
34 | this.childrenToRender = this.getIconChildren();
35 | this.handleClick = this.handleClick.bind(this);
36 | }
37 |
38 | getAnimation(visible) {
39 | return visible ?
40 | [
41 | [
42 | { style: { rotate: 90 }, duration: 0 },
43 | {
44 | d: 'M20 15L20 45L45 30Z', style: { rotate: 0 },
45 | delay: 150, duration: 300, ease: 'easeOutQuint',
46 | },
47 | ],
48 | [
49 | { style: { rotate: 90 }, duration: 0 },
50 | {
51 | d: 'M20 15L20 45L45 30Z', style: { rotate: 0 },
52 | delay: 150, duration: 300, ease: 'easeOutQuint',
53 | },
54 | ],
55 | ] :
56 | [
57 | [
58 | { style: { rotate: 0 }, duration: 0 },
59 | {
60 | d: 'M15 18L15 27L45 27L45 18Z', style: { rotate: 90 },
61 | duration: 300, ease: 'easeOutQuint',
62 | },
63 | ],
64 | [
65 | { style: { rotate: 0 }, duration: 0 },
66 | {
67 | d: 'M15 33L15 42L45 42L45 33Z', style: { rotate: 90 },
68 | duration: 300, ease: 'easeOutQuint',
69 | },
70 | ],
71 | ];
72 | }
73 |
74 | getIconChildren() {
75 | return this.state.visible ?
76 | ['M20 15L20 45L45 30Z', 'M20 15L20 45L45 30Z'] :
77 | ['M15 18L15 27L45 27L45 18Z', 'M15 33L15 42L45 42L45 33Z'];
78 | }
79 |
80 | handleClick() {
81 | const visible = this.state.visible;
82 | const animation = this.getAnimation(!visible);
83 | this.setState({
84 | visible: !visible,
85 | animation,
86 | });
87 |
88 | // If mask is visible now, the video is going to play. Otherwise...
89 | const shouldPlay = visible;
90 | this.props.onClick(shouldPlay);
91 | }
92 |
93 | render() {
94 | const style = {
95 | ...maskStyle,
96 | opacity: this.state.visible ? 1 : 0,
97 | transition: this.state.visible ?
98 | 'opacity 0.3s cubic-bezier(0.215, 0.61, 0.355, 1)' :
99 | 'opacity 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0.2s',
100 | };
101 | return (
102 |
103 |
123 |
124 | );
125 | }
126 | }
127 |
128 | Mask.propTypes = {
129 | defaultVisible: PropTypes.bool,
130 | onClick: PropTypes.func,
131 | };
132 |
--------------------------------------------------------------------------------
/src/Source.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function Source(props) {
4 | return ;
5 | }
6 |
--------------------------------------------------------------------------------
/src/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import ReactDOM from 'react-dom';
4 | import Mask from './Mask';
5 | import Source from './Source';
6 |
7 | const wrapperStyle = {
8 | position: 'relative',
9 | };
10 |
11 | const videoStyle = {
12 | width: '100%',
13 | };
14 |
15 | export default class SublimeVideo extends React.Component {
16 | constructor(props) {
17 | super(props);
18 |
19 | this.handleMaskClick = this.handleMaskClick.bind(this);
20 | }
21 |
22 | handleMaskClick(shouldPlay) {
23 | const video = ReactDOM.findDOMNode(this.refs.video);
24 | if (shouldPlay) {
25 | setTimeout(() => video.play(), 300);
26 | } else {
27 | video.pause();
28 | }
29 | }
30 |
31 | render() {
32 | const { style, autoPlay, children, ...rest } = this.props;
33 | return (
34 |
35 |
38 |
41 |
42 | );
43 | }
44 | }
45 |
46 | SublimeVideo.propTypes = {
47 | autoPlay: PropTypes.bool,
48 | style: PropTypes.object,
49 | children: PropTypes.object,
50 | };
51 |
52 | SublimeVideo.Source = Source;
53 |
--------------------------------------------------------------------------------