├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── babel.config.js
├── package.json
├── rollup.config.js
├── src
├── __tests__
│ └── frame.js
├── frame.js
└── index.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | coverage
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - node
4 | cache: yarn
5 | after_success:
6 | - bash <(curl -s https://codecov.io/bash)
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 pqx Limited
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-frame
2 |
3 | [](https://www.npmjs.com/package/react-frame)
4 | [](https://www.npmjs.com/package/react-frame)
5 | [](https://travis-ci.org/swiftcarrot/react-frame)
6 | [](https://codecov.io/gh/swiftcarrot/react-frame)
7 | [](https://github.com/prettier/prettier)
8 |
9 | React components within an iframe for isolated css styling
10 |
11 | ### Installation
12 |
13 | ```sh
14 | npm install react-frame --save
15 | yarn add react-frame
16 | ```
17 |
18 | ### Demo
19 |
20 | [https://swiftcarrot.dev/react-frame](https://swiftcarrot.dev/react-frame)
21 |
22 | ### Usage
23 |
24 | ```javascript
25 |
26 |
frame
27 |
28 | ```
29 |
30 | ### License
31 |
32 | MIT
33 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['swiftcarrot']
3 | };
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-frame",
3 | "version": "2.2.22",
4 | "description": "React components within an iframe for isolated css styling",
5 | "main": "dist/index.cjs.js",
6 | "module": "dist/index.esm.js",
7 | "sideEffects": false,
8 | "files": [
9 | "dist"
10 | ],
11 | "scripts": {
12 | "build": "rm -rf dist && NODE_ENV=production rollup -c",
13 | "test": "jest --coverage",
14 | "prepublishOnly": "npm test && npm run build"
15 | },
16 | "repository": {
17 | "type": "git",
18 | "url": "git+https://github.com/swiftcarrot/react-frame.git"
19 | },
20 | "keywords": [
21 | "iframe",
22 | "react",
23 | "react-component",
24 | "styling"
25 | ],
26 | "author": "Wang Zuo",
27 | "license": "MIT",
28 | "bugs": {
29 | "url": "https://github.com/swiftcarrot/react-frame/issues"
30 | },
31 | "homepage": "https://github.com/swiftcarrot/react-frame#readme",
32 | "peerDependencies": {
33 | "react": "^16.7.0",
34 | "react-dom": "^16.7.0"
35 | },
36 | "devDependencies": {
37 | "@rollup/plugin-babel": "^5.0.0",
38 | "@rollup/plugin-commonjs": "^11.1.0",
39 | "@rollup/plugin-node-resolve": "^7.1.3",
40 | "babel-jest": "^24.8.0",
41 | "babel-preset-swiftcarrot": "^1.0.0",
42 | "jest": "^24.8.0",
43 | "react": "^16.8.6",
44 | "react-dom": "^16.8.6",
45 | "react-test-renderer": "^16.8.6",
46 | "rollup": "^1.17.0"
47 | },
48 | "dependencies": {
49 | "@babel/runtime": "^7.5.5"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from '@rollup/plugin-babel';
2 | import commonjs from '@rollup/plugin-commonjs';
3 | import nodeResolve from '@rollup/plugin-node-resolve';
4 | import pkg from './package.json';
5 |
6 | const input = './src/index.js';
7 |
8 | const external = id => !id.startsWith('.') && !id.startsWith('/');
9 |
10 | export default [
11 | {
12 | input,
13 | output: {
14 | file: pkg.main,
15 | format: 'cjs'
16 | },
17 | external,
18 | plugins: [
19 | babel({
20 | babelHelpers: 'runtime',
21 | plugins: ['@babel/transform-runtime']
22 | }),
23 | nodeResolve(),
24 | commonjs()
25 | ]
26 | },
27 |
28 | {
29 | input,
30 | output: {
31 | file: pkg.module,
32 | format: 'esm'
33 | },
34 | external,
35 | plugins: [
36 | babel({
37 | babelHelpers: 'runtime',
38 | plugins: [['@babel/transform-runtime', { useESModules: true }]]
39 | }),
40 | nodeResolve(),
41 | commonjs()
42 | ]
43 | }
44 | ];
45 |
--------------------------------------------------------------------------------
/src/__tests__/frame.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Frame from '../frame';
4 |
5 | test('render', () => {
6 | const component = renderer.create(
7 |
8 | testing
9 |
10 | );
11 | expect(component.toJSON()).toMatchInlineSnapshot(`
12 |
15 | `);
16 | });
17 |
--------------------------------------------------------------------------------
/src/frame.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | class Frame extends Component {
5 | componentWillReceiveProps(nextProps) {
6 | if (nextProps.styleSheets.join('') !== this.props.styleSheets.join('')) {
7 | this.updateStylesheets(nextProps.styleSheets);
8 | }
9 |
10 | if (nextProps.css !== this.props.css) {
11 | this.updateCss(nextProps.css);
12 | }
13 |
14 | const frame = ReactDOM.findDOMNode(this);
15 | const root = frame.contentDocument.getElementById('root');
16 | if (root) {
17 | ReactDOM.render(nextProps.children, root);
18 | }
19 | }
20 |
21 | componentDidMount() {
22 | setTimeout(this.renderFrame, 0);
23 | }
24 |
25 | componentWillUnmount() {
26 | ReactDOM.unmountComponentAtNode(
27 | ReactDOM.findDOMNode(this).contentDocument.getElementById('root')
28 | );
29 | }
30 |
31 | updateStylesheets = styleSheets => {
32 | const links = this.head.querySelectorAll('link');
33 | for (let i = 0, l = links.length; i < l; i++) {
34 | const link = links[i];
35 | link.parentNode.removeChild(link);
36 | }
37 |
38 | if (styleSheets && styleSheets.length) {
39 | styleSheets.forEach(href => {
40 | const link = document.createElement('link');
41 | link.setAttribute('rel', 'stylesheet');
42 | link.setAttribute('type', 'text/css');
43 | link.setAttribute('href', href);
44 | this.head.appendChild(link);
45 | });
46 | }
47 | };
48 |
49 | updateCss = css => {
50 | if (!this.styleEl) {
51 | const el = document.createElement('style');
52 | el.type = 'text/css';
53 | this.head.appendChild(el);
54 | this.styleEl = el;
55 | }
56 |
57 | const el = this.styleEl;
58 |
59 | if (el.styleSheet) {
60 | el.styleSheet.cssText = css;
61 | } else {
62 | const cssNode = document.createTextNode(css);
63 | if (this.cssNode) el.removeChild(this.cssNode);
64 | el.appendChild(cssNode);
65 | this.cssNode = cssNode;
66 | }
67 | };
68 |
69 | renderFrame = () => {
70 | const { styleSheets, css } = this.props;
71 | const frame = ReactDOM.findDOMNode(this);
72 | const root = document.createElement('div');
73 |
74 | root.setAttribute('id', 'root');
75 |
76 | this.head = frame.contentDocument.head;
77 | this.body = frame.contentDocument.body;
78 | this.body.appendChild(root);
79 |
80 | this.updateStylesheets(styleSheets);
81 | setTimeout(() => {
82 | this.updateCss(css);
83 | }, 0);
84 |
85 | ReactDOM.render(this._children, root);
86 | };
87 |
88 | render() {
89 | this._children = this.props.children;
90 | const { children, styleSheets, css, ...props } = this.props;
91 | return ;
92 | }
93 | }
94 |
95 | export default Frame;
96 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export default from './frame';
2 |
--------------------------------------------------------------------------------