├── .babelrc
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── docs
├── components
│ ├── Head.js
│ └── Page.js
└── index.html
├── lib
└── .gitkeep
├── package-lock.json
├── package.json
├── src
└── index.js
└── test
└── index.test.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"]
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib/index.js
2 | node_modules
3 | *.log
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | docs
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Oli Evans
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 ResponsiveEmbed
2 |
3 | You want to embed a YouTube or other `iframe` style embedded content, and you'd
4 | like it to take up the available width, and retain it's aspect ratio.
5 |
6 | Much like the [Bootstrap responsive embed helpers] of old, but for react.
7 |
8 | ## Usage
9 |
10 | ```sh
11 | npm install --save react-responsive-embed
12 | ```
13 |
14 | Then in your app import `ResponsiveEmbed` and in JSX flavour you might do:
15 |
16 | ```html
17 |
18 | ```
19 |
20 | Which'd give you an `iframe` element pointing at the `src` and any other props.
21 | It's wrapped in a `div` with just the right amount of `padding-bottom` to
22 | preserve a **16:9** aspect ratio like so:
23 |
24 | ```html
25 |
26 | VIDEO
30 |
31 | ```
32 |
33 | Pass in a `ratio` prop to pick a different one. Any ratio will do:
34 |
35 | ```html
36 |
37 | ```
38 |
39 | `frameborder="0"` is applied by default.
40 |
41 |
42 | ## Browserify / Webpack / Other?
43 |
44 | **This module is just a function**. It's been babelified so it'll work with
45 | whatever your set up is. Use browserify or webpack or any other npm module
46 | consuming bundle whizzbang; ResponsiveEmbed don't mind.
47 |
48 | ---
49 |
50 | A [(╯°□°)╯︵TABLEFLIP] side project.
51 |
52 |
53 | [Bootstrap responsive embed helpers]: https://v4-alpha.getbootstrap.com/utilities/responsive-helpers/#responsive-embeds
54 | [(╯°□°)╯︵TABLEFLIP]: https://tableflip.io
55 |
--------------------------------------------------------------------------------
/docs/components/Head.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const style = `
4 | html { background-color: #50E3C2;}
5 | body {
6 | color: #4A4A4A;
7 | background-color: #fff;
8 | padding: 2em 1em;
9 | margin:0px 0 6px;
10 | line-height: 1.6;
11 | font-size:20px;
12 | letter-spacing: 0.2px;
13 | min-height:100vh;
14 | font-family: -apple-system, BlinkMacSystemFont,
15 | "avenir next", avenir,
16 | helvetica, "helvetica neue",
17 | ubuntu,
18 | roboto, noto,
19 | "segoe ui", arial,
20 | sans-serif;
21 | }
22 | code {
23 | font-size: .875rem;
24 | font-family: Consolas, monaco, monospace;
25 | }
26 | a {
27 | color: #333;
28 | }
29 | a:hover {
30 | color: #319C84;
31 | }
32 | blockquote {
33 | color: #888;
34 | padding: .5rem 1.2rem;
35 | margin: 1rem 0;
36 | font-size: 1.1rem;
37 | border-left: .25rem solid #eceeef;
38 | }
39 | blockquote p:first-child {
40 | margin-top: 0.25rem;
41 | }
42 | blockquote p:last-child {
43 | margin-bottom: 0.25rem;
44 | }
45 | h1 { font-size: 3rem; }
46 | h2 { font-size: 2.25rem; }
47 | h3 { font-size: 1.5rem; }
48 | h4 { font-size: 1.25rem; }
49 | h5 { font-size: 1rem; }
50 | h6 { font-size: .875rem; }
51 | img { max-width: 100%; }
52 | .m-b-1 {
53 | margin-bottom: 1rem !important;
54 | }
55 | .m-t-3 {
56 | margin-top: 3rem !important;
57 | }
58 | .max-width-md {
59 | max-width: 700px;
60 | margin:0 auto;
61 | }
62 | .text-decoration-none {
63 | text-decoration: none;
64 | }
65 | .tracked {
66 | letter-spacing: 0.5px;
67 | }
68 | `
69 |
70 | const Head = () => (
71 |
72 |
73 | React ResponsiveEmbed
74 |
75 |
76 |
77 | )
78 |
79 | export default Head
--------------------------------------------------------------------------------
/docs/components/Page.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ResponsiveEmbed from '../../lib/index'
3 | import Head from './head'
4 |
5 | const Page = () => (
6 |
7 |
9 |
10 |
16 |
19 |
20 | You want to embed a YouTube or other `iframe` style embedded content, and you'd
21 | like it to take up the available width, and retain it's aspect ratio.
22 |
23 |
24 | Much like the Bootstrap responsive embed helpers of old, but for react.
25 |
26 |
27 |
28 | <ResponsiveEmbed ratio='16:9' src='https://www.youtube.com/embed/2yqz9zgoC-U' />
29 |
30 |
31 |
32 |
33 |
34 | <ResponsiveEmbed ratio='4:3' src='https://www.youtube.com/embed/mM5_T-F1Yn4' />
35 |
36 |
37 |
38 |
39 | https://github.com/tableflip/react-responsive-embed
40 |
41 |
47 |
48 |
49 |
50 | )
51 |
52 | export default Page
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 | React ResponsiveEmbed You want to embed a YouTube or other `iframe` style embedded content, and you'd like it to take up the available width, and retain it's aspect ratio.
Much like the Bootstrap responsive embed helpers of old, but for react.
<ResponsiveEmbed ratio='16:9' src='https://www.youtube.com/embed/2yqz9zgoC-U' />
VIDEO
<ResponsiveEmbed ratio='4:3' src='https://www.youtube.com/embed/mM5_T-F1Yn4' />
VIDEO
https://github.com/tableflip/react-responsive-embed
--------------------------------------------------------------------------------
/lib/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tableflip/react-responsive-embed/60519bd5112de7b00b8eb8f882e4ab2affa741df/lib/.gitkeep
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-responsive-embed",
3 | "version": "2.1.0",
4 | "description": "Embed iframes responsively",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "test": "ava",
8 | "prepublish": "npm run build",
9 | "build": "babel src -d lib",
10 | "docs": "static-react docs/components/Page.js > docs/index.html"
11 | },
12 | "author": "oilzilla ",
13 | "license": "MIT",
14 | "devDependencies": {
15 | "ava": "^0.23.0",
16 | "babel-cli": "^6.26.0",
17 | "babel-preset-env": "^1.6.1",
18 | "prop-types": "^15.6.0",
19 | "react": "^16.0",
20 | "react-dom": "^16.0.0",
21 | "react-test-renderer": "^16.0.0",
22 | "standard": "^10.0.3",
23 | "static-react": "^3.2.0"
24 | },
25 | "peerDependencies": {
26 | "prop-types": ">=15",
27 | "react": ">=15"
28 | },
29 | "engines": {
30 | "node": ">=6"
31 | },
32 | "directories": {
33 | "doc": "docs",
34 | "test": "test"
35 | },
36 | "repository": {
37 | "type": "git",
38 | "url": "git+https://github.com/tableflip/react-responsive-embed.git"
39 | },
40 | "keywords": [
41 | "react",
42 | "responsive",
43 | "iframe",
44 | "aspect",
45 | "ratio"
46 | ],
47 | "bugs": {
48 | "url": "https://github.com/tableflip/react-responsive-embed/issues"
49 | },
50 | "homepage": "https://github.com/tableflip/react-responsive-embed#readme"
51 | }
52 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | const React = require('react')
2 | const PropTypes = require('prop-types')
3 | const div = React.createElement.bind(React, 'div')
4 | const iframe = React.createElement.bind(React, 'iframe')
5 |
6 | const divStyle = {
7 | position: 'relative',
8 | height: 0,
9 | overflow: 'hidden',
10 | maxWidth: '100%'
11 | }
12 |
13 | const iframeStyle = {
14 | position: 'absolute',
15 | top: 0,
16 | left: 0,
17 | width: '100%',
18 | height: '100%'
19 | }
20 |
21 | /*
22 | * Turn `16:9` into `9 / 16` into `56.25%`
23 | * Turn `4:3` into `3 / 4` into `75%`
24 | */
25 | const ratioToPercent = (ratio) => {
26 | const [w, h] = ratio.split(':').map((num) => Number(num))
27 | return `${(h / w) * 100}%`
28 | }
29 |
30 | /*
31 | * Usage:
32 | */
33 | const ResponsiveEmbed = (props) => {
34 | const paddingBottom = ratioToPercent(props.ratio)
35 | const style = Object.assign({}, divStyle, {paddingBottom})
36 | const iframeProps = Object.assign({frameBorder: 0}, props, {style: iframeStyle})
37 | delete iframeProps.ratio
38 | return div({style},
39 | iframe(iframeProps)
40 | )
41 | }
42 |
43 | ResponsiveEmbed.defaultProps = {
44 | src: 'https://www.youtube.com/embed/dQw4w9WgXcQ',
45 | ratio: '16:9'
46 | }
47 |
48 | ResponsiveEmbed.propTypes = {
49 | src: PropTypes.string,
50 | ratio: (props, propName, componentName) => {
51 | if (!/\d+:\d+/.test(props[propName])) {
52 | return new Error(
53 | 'Invalid ratio supplied to ResponsiveEmbed. Expected a string like "16:9" or any 2 numbers seperated by a colon'
54 | )
55 | }
56 | }
57 | }
58 |
59 | module.exports = ResponsiveEmbed
60 |
--------------------------------------------------------------------------------
/test/index.test.js:
--------------------------------------------------------------------------------
1 | const test = require('ava')
2 | const React = require('react')
3 | const ShallowRenderer = require('react-test-renderer/shallow')
4 | const ResponsiveEmbed = require('../src/index')
5 |
6 | test('ResponsiveEmbed renders OK', (t) => {
7 | const src = 'https://www.youtube.com/embed/zc1g_hSuxVE'
8 | const element = React.createElement(ResponsiveEmbed, {src})
9 | const renderer = new ShallowRenderer()
10 | renderer.render(element)
11 | const root = renderer.getRenderOutput()
12 | const child = root.props.children
13 |
14 | t.plan(4)
15 | t.is(root.type, 'div', 'Root element is a div')
16 | t.is(root.props.style.paddingBottom, '56.25%', 'Aspect ratio of 16x9 is manifest as a paddingBottom style of 56.25%')
17 | t.is(child.type, 'iframe', 'Child element is an iframe')
18 | t.is(child.props.src, src, 'Provided `src` is used')
19 | })
20 |
21 | test('ResponsiveEmbed renders other ratios', (t) => {
22 | const src = 'https://www.youtube.com/embed/zc1g_hSuxVE'
23 | const ratio = '1.43:1' // imax
24 | const element = React.createElement(ResponsiveEmbed, {src, ratio})
25 | const renderer = new ShallowRenderer()
26 | renderer.render(element)
27 | const root = renderer.getRenderOutput()
28 | const child = root.props.children
29 |
30 | t.plan(4)
31 | t.is(root.type, 'div', 'Root element is a div')
32 | t.is(root.props.style.paddingBottom, '69.93006993006993%', 'IMAX aspect ratio is preserved')
33 | t.is(child.type, 'iframe', 'Child element is an iframe')
34 | t.is(child.props.src, src, 'Provided `src` is used')
35 | })
36 |
37 | test('ResponsiveEmbed renders with default props', (t) => {
38 | const element = React.createElement(ResponsiveEmbed)
39 | const renderer = new ShallowRenderer()
40 | renderer.render(element)
41 | const root = renderer.getRenderOutput()
42 | const child = root.props.children
43 |
44 | t.plan(4)
45 | t.is(root.type, 'div', 'Root element is a div')
46 | t.is(root.props.style.paddingBottom, '56.25%', 'Aspect ratio of 16x9 is manifest as a paddingBottom style of 56.25%')
47 | t.is(child.type, 'iframe', 'Child element is an iframe')
48 | t.is(child.props.src, 'https://www.youtube.com/embed/dQw4w9WgXcQ', 'Default `src` is used')
49 | })
--------------------------------------------------------------------------------