Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e0ac972

Browse files
committed
Add resizing support
1 parent e769646 commit e0ac972

File tree

6 files changed

+331
-31
lines changed

6 files changed

+331
-31
lines changed

‎index.css‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
.playground {
2+
width: 100%;
3+
position: relative;
4+
}
5+
6+
.iframe {
7+
width: 100%;
8+
border: none;
9+
}
10+
11+
.resize-controller {
12+
background-color: #ebeef3;
13+
border: 1px solid #d7dce4;
14+
position: absolute;
15+
display: flex;
16+
align-items: center;
17+
justify-content: center;
18+
}
19+
20+
.resize-controller::before {
21+
content: '';
22+
background-color: #bfc7d4;
23+
margin: 2px;
24+
}
25+
26+
.resize-controller::after {
27+
content: '';
28+
background-color: #bfc7d4;
29+
margin: 2px;
30+
}
31+
32+
.height-resize-controller {
33+
height: 20px;
34+
bottom: 0;
35+
left: 0;
36+
flex-direction: column;
37+
transform: translateY(25px);
38+
cursor: row-resize;
39+
}
40+
41+
.height-resize-controller::before {
42+
width: 25px;
43+
height: 2px;
44+
}
45+
46+
.height-resize-controller::after {
47+
width: 25px;
48+
height: 2px;
49+
}
50+
51+
.width-resize-controller {
52+
width: 20px;
53+
height: 100%;
54+
top: 0;
55+
flex-direction: row;
56+
transform: translateX(10px);
57+
cursor: col-resize;
58+
}
59+
60+
.width-resize-controller::before {
61+
width: 2px;
62+
height: 25px;
63+
}
64+
65+
.width-resize-controller::after {
66+
width: 2px;
67+
height: 25px;
68+
}

‎index.js‎

Lines changed: 120 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom';
3+
import PropTypes from 'prop-types';
4+
import classNames from 'classnames/bind';
5+
6+
import styles from './index.css';
7+
const cx = classNames.bind(styles);
38

49
class IFramePlayground extends React.Component {
510
ref = React.createRef(); // <iframe> ref
611
state = {
712
container: null, // container within which the user content should be rendered
13+
width: 0, // iframe width
814
height: 0, // iframe height
15+
isResizing: false, // is the user currently resizing IFramePlayground?
16+
direction: 'horizontal', // resizing direction
917
};
1018

1119
/**
@@ -29,13 +37,23 @@ class IFramePlayground extends React.Component {
2937
});
3038
};
3139

32-
updateHeight = iFrameNode => {
33-
const children = Array.from(iFrameNode.contentDocument.body.childNodes);
34-
const height = children.reduce(
35-
(prevVal, child) => prevVal + child.offsetHeight,
40+
/** Once <iframe> is fully loaded, we can then determine its size */
41+
setSize = iFrameNode => {
42+
const { enableResizing } = this.props;
43+
44+
// Determine width
45+
const parentNode = iFrameNode.parentNode;
46+
const width = enableResizing ? parentNode.offsetWidth : '100%';
47+
48+
// Determine height
49+
const childNodes = Array.from(iFrameNode.contentDocument.body.childNodes);
50+
const height = childNodes.reduce(
51+
(prevVal, childNode) => prevVal + childNode.offsetHeight,
3652
0,
3753
);
54+
3855
this.setState({
56+
width,
3957
height,
4058
});
4159
};
@@ -51,31 +69,90 @@ class IFramePlayground extends React.Component {
5169
container: iFrameNode.contentDocument.body,
5270
});
5371
this.copyStyles(iFrameNode);
54-
this.updateHeight(iFrameNode);
72+
this.setSize(iFrameNode);
73+
}
74+
};
75+
76+
handleResizeStart = (e, direction) => {
77+
e.preventDefault();
78+
window.addEventListener('mousemove', this.handleResize);
79+
window.addEventListener('mouseup', this.handleResizeStop);
80+
this.setState({
81+
isResizing: true,
82+
direction,
83+
});
84+
};
85+
86+
handleResize = e => {
87+
const { minWidth, minHeight } = this.props;
88+
const { direction, width, height } = this.state;
89+
if (direction === 'vertical') {
90+
const newHeight = height + e.movementY;
91+
this.setState({
92+
height: newHeight < minHeight ? minHeight : newHeight,
93+
});
94+
} else {
95+
const newWidth = width + e.movementX;
96+
this.setState({
97+
width: newWidth < minWidth ? minWidth : newWidth,
98+
});
5599
}
56100
};
57101

102+
handleResizeStop = () => {
103+
this.removeEventListeners();
104+
this.setState({
105+
isResizing: false,
106+
});
107+
};
108+
109+
removeEventListeners = () => {
110+
window.removeEventListener('mousemove', this.handleResize);
111+
window.removeEventListener('mouseup', this.handleResizeStop);
112+
};
113+
58114
render() {
59-
const { children, style } = this.props;
60-
const { container, height } = this.state;
115+
const { children, style, enableResizing } = this.props;
116+
const { container, width,height, isResizing } = this.state;
61117
const iFrameNode = this.ref.current;
62118
return (
63-
<iframe
64-
sandbox="allow-same-origin"
65-
ref={this.ref}
66-
srcDoc={'<!DOCTYPE html>'}
67-
style={{
68-
height,
69-
width: '100%',
70-
border: 'none',
71-
...style,
72-
}}
73-
>
74-
{container &&
75-
iFrameNode &&
76-
iFrameNode.contentDocument &&
77-
ReactDOM.createPortal(children, container)}
78-
</iframe>
119+
<div className={cx('playground')}>
120+
<iframe
121+
sandbox="allow-same-origin"
122+
ref={this.ref}
123+
srcDoc={'<!DOCTYPE html>'}
124+
className={cx('iframe')}
125+
style={{
126+
width,
127+
height,
128+
pointerEvents: isResizing ? 'none' : 'all',
129+
...style,
130+
}}
131+
>
132+
{container &&
133+
iFrameNode &&
134+
iFrameNode.contentDocument &&
135+
ReactDOM.createPortal(children, container)}
136+
</iframe>
137+
{enableResizing && (
138+
<React.Fragment>
139+
<div
140+
className={cx('resize-controller', 'height-resize-controller')}
141+
onMouseDown={e => this.handleResizeStart(e, 'vertical')}
142+
style={{
143+
width,
144+
}}
145+
/>
146+
<div
147+
className={cx('resize-controller', 'width-resize-controller')}
148+
onMouseDown={e => this.handleResizeStart(e, 'horizontal')}
149+
style={{
150+
left: width,
151+
}}
152+
/>
153+
</React.Fragment>
154+
)}
155+
</div>
79156
);
80157
}
81158

@@ -85,6 +162,26 @@ class IFramePlayground extends React.Component {
85162
iFrameNode.addEventListener('load', this.handleLoad);
86163
}
87164
}
165+
166+
componentWillMount() {
167+
this.removeEventListeners();
168+
}
88169
}
89170

171+
IFramePlayground.propTypes = {
172+
/**
173+
* If enabled, resize controller will be available.
174+
* You can use it to control `<frame>` viewport size instead of using Docz Playground resize controller
175+
* */
176+
enableResizing: PropTypes.bool,
177+
minWidth: PropTypes.number,
178+
minHeight: PropTypes.number,
179+
};
180+
181+
IFramePlayground.defaultProps = {
182+
enableResizing: false,
183+
minWidth: 200,
184+
minHeight: 200,
185+
};
186+
90187
export default IFramePlayground;

‎package.json‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@babel/plugin-proposal-class-properties": "^7.4.0",
3838
"@babel/preset-env": "^7.4.3",
3939
"@babel/preset-react": "^7.0.0",
40+
"classnames": "^2.2.6",
4041
"docz": "^0.13.7",
4142
"docz-plugin-css": "^0.11.0",
4243
"docz-theme-default": "^0.13.7",
@@ -46,6 +47,7 @@
4647
"rollup": "^1.10.0",
4748
"rollup-plugin-babel": "^4.3.2",
4849
"rollup-plugin-node-resolve": "^4.2.3",
50+
"rollup-plugin-postcss": "^2.0.3",
4951
"rollup-plugin-replace": "^2.2.0",
5052
"rollup-plugin-terser": "^4.0.4"
5153
}

‎rollup.config.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import resolve from 'rollup-plugin-node-resolve';
22
import babel from 'rollup-plugin-babel';
33
import replace from 'rollup-plugin-replace';
4+
import postcss from 'rollup-plugin-postcss';
45
import { terser } from 'rollup-plugin-terser';
56

67
import pkg from './package.json';
@@ -23,6 +24,9 @@ export default {
2324
babelrc: false,
2425
}),
2526
terser(),
27+
postcss({
28+
extract: true,
29+
}),
2630
],
2731
external: Object.keys(pkg.peerDependencies),
2832
};

‎test/MyComponent.mdx‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import IFramePlayground from './../index';
1717
</IFramePlayground>
1818
</Playground>
1919

20+
<IFramePlayground enableResizing>
21+
<MyComponent text="Using IFramePlayground" />
22+
</IFramePlayground>
23+
2024
## MyComponent Props
2125

2226
<PropsTable of={MyComponent} />

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /