This commit is contained in:
Nathan Bierema 2020-08-15 17:21:26 -04:00
parent 5437311620
commit 51c73ad0b3
2 changed files with 158 additions and 153 deletions

View File

@ -5,7 +5,7 @@ import autoprefix from './autoprefix';
function autoprefixes(styles) { function autoprefixes(styles) {
return Object.keys(styles).reduce( return Object.keys(styles).reduce(
(obj, key) => (obj[key] = autoprefix(styles[key]), obj), (obj, key) => ((obj[key] = autoprefix(styles[key])), obj),
{} {}
); );
} }
@ -16,7 +16,7 @@ const styles = autoprefixes({
width: 0, width: 0,
height: 0, height: 0,
top: 0, top: 0,
left: 0 left: 0,
}, },
dim: { dim: {
@ -27,19 +27,19 @@ const styles = autoprefixes({
bottom: 0, bottom: 0,
zIndex: 0, zIndex: 0,
background: 'rgba(0, 0, 0, 0.2)', background: 'rgba(0, 0, 0, 0.2)',
opacity: 1 opacity: 1,
}, },
dimAppear: { dimAppear: {
opacity: 0 opacity: 0,
}, },
dimTransparent: { dimTransparent: {
pointerEvents: 'none' pointerEvents: 'none',
}, },
dimHidden: { dimHidden: {
opacity: 0 opacity: 0,
}, },
dock: { dock: {
@ -50,33 +50,34 @@ const styles = autoprefixes({
left: 0, left: 0,
top: 0, top: 0,
width: '100%', width: '100%',
height: '100%' height: '100%',
}, },
dockHidden: { dockHidden: {
opacity: 0 opacity: 0,
}, },
dockResizing: { dockResizing: {
transition: 'none' transition: 'none',
}, },
dockContent: { dockContent: {
width: '100%', width: '100%',
height: '100%', height: '100%',
overflow: 'auto' overflow: 'auto',
}, },
resizer: { resizer: {
position: 'absolute', position: 'absolute',
zIndex: 2, zIndex: 2,
opacity: 0 opacity: 0,
} },
}); });
function getTransitions(duration) { function getTransitions(duration) {
return ['left', 'top', 'width', 'height'] return ['left', 'top', 'width', 'height'].map(
.map(p => `${p} ${duration/1000}s ease-out`); (p) => `${p} ${duration / 1000}s ease-out`
);
} }
function getDockStyles( function getDockStyles(
@ -84,41 +85,37 @@ function getDockStyles(
{ size, isResizing, fullWidth, fullHeight } { size, isResizing, fullWidth, fullHeight }
) { ) {
let posStyle; let posStyle;
const absSize = fluid ? const absSize = fluid ? size * 100 + '%' : size + 'px';
(size * 100) + '%' :
size + 'px';
function getRestSize(fullSize) { function getRestSize(fullSize) {
return fluid ? return fluid ? 100 - size * 100 + '%' : fullSize - size + 'px';
(100 - size * 100) + '%' :
(fullSize - size) + 'px';
} }
switch(position) { switch (position) {
case 'left': case 'left':
posStyle = { posStyle = {
width: absSize, width: absSize,
left: isVisible ? 0 : '-' + absSize left: isVisible ? 0 : '-' + absSize,
}; };
break; break;
case 'right': case 'right':
posStyle = { posStyle = {
left: isVisible ? getRestSize(fullWidth) : fullWidth, left: isVisible ? getRestSize(fullWidth) : fullWidth,
width: absSize width: absSize,
}; };
break; break;
case 'top': case 'top':
posStyle = { posStyle = {
top: isVisible ? 0 : '-' + absSize, top: isVisible ? 0 : '-' + absSize,
height: absSize height: absSize,
}; };
break; break;
case 'bottom': case 'bottom':
posStyle = { posStyle = {
top: isVisible ? getRestSize(fullHeight) : fullHeight, top: isVisible ? getRestSize(fullHeight) : fullHeight,
height: absSize height: absSize,
}; };
break; break;
} }
const transitions = getTransitions(duration); const transitions = getTransitions(duration);
@ -128,8 +125,10 @@ function getDockStyles(
autoprefix({ autoprefix({
transition: [ transition: [
...transitions, ...transitions,
!isVisible && `opacity 0.01s linear ${duration/1000}s` !isVisible && `opacity 0.01s linear ${duration / 1000}s`,
].filter(t => t).join(',') ]
.filter((t) => t)
.join(','),
}), }),
dockStyle, dockStyle,
autoprefix(posStyle), autoprefix(posStyle),
@ -152,7 +151,7 @@ function getDimStyles(
dimMode === 'transparent' && styles.dimTransparent, dimMode === 'transparent' && styles.dimTransparent,
!isVisible && styles.dimHidden, !isVisible && styles.dimHidden,
isTransitionStarted && isVisible && styles.dimAppear, isTransitionStarted && isVisible && styles.dimAppear,
isTransitionStarted && !isVisible && styles.dimDisappear isTransitionStarted && !isVisible && styles.dimDisappear,
]; ];
} }
@ -160,55 +159,50 @@ function getResizerStyles(position) {
let resizerStyle; let resizerStyle;
const size = 10; const size = 10;
switch(position) { switch (position) {
case 'left': case 'left':
resizerStyle = { resizerStyle = {
right: -size / 2, right: -size / 2,
width: size, width: size,
top: 0, top: 0,
height: '100%', height: '100%',
cursor: 'col-resize' cursor: 'col-resize',
}; };
break; break;
case 'right': case 'right':
resizerStyle = { resizerStyle = {
left: -size / 2, left: -size / 2,
width: size, width: size,
top: 0, top: 0,
height: '100%', height: '100%',
cursor: 'col-resize' cursor: 'col-resize',
}; };
break; break;
case 'top': case 'top':
resizerStyle = { resizerStyle = {
bottom: -size / 2, bottom: -size / 2,
height: size, height: size,
left: 0, left: 0,
width: '100%', width: '100%',
cursor: 'row-resize' cursor: 'row-resize',
}; };
break; break;
case 'bottom': case 'bottom':
resizerStyle = { resizerStyle = {
top: -size / 2, top: -size / 2,
height: size, height: size,
left: 0, left: 0,
width: '100%', width: '100%',
cursor: 'row-resize' cursor: 'row-resize',
}; };
break; break;
} }
return [ return [styles.resizer, autoprefix(resizerStyle)];
styles.resizer,
autoprefix(resizerStyle)
];
} }
function getFullSize(position, fullWidth, fullHeight) { function getFullSize(position, fullWidth, fullHeight) {
return position === 'left' || position === 'right' ? return position === 'left' || position === 'right' ? fullWidth : fullHeight;
fullWidth :
fullHeight;
} }
export default class Dock extends Component { export default class Dock extends Component {
@ -218,10 +212,10 @@ export default class Dock extends Component {
isControlled: typeof props.size !== 'undefined', isControlled: typeof props.size !== 'undefined',
size: props.size || props.defaultSize, size: props.size || props.defaultSize,
isDimHidden: !props.isVisible, isDimHidden: !props.isVisible,
fullWidth: typeof(window) !== 'undefined' && window.innerWidth, fullWidth: typeof window !== 'undefined' && window.innerWidth,
fullHeight: typeof(window) !== 'undefined' && window.innerHeight, fullHeight: typeof window !== 'undefined' && window.innerHeight,
isTransitionStarted: false, isTransitionStarted: false,
isWindowResizing: false isWindowResizing: false,
}; };
} }
@ -237,8 +231,8 @@ export default class Dock extends Component {
onSizeChange: PropTypes.func, onSizeChange: PropTypes.func,
dimStyle: PropTypes.object, dimStyle: PropTypes.object,
dockStyle: PropTypes.object, dockStyle: PropTypes.object,
duration: PropTypes.number duration: PropTypes.number,
} };
static defaultProps = { static defaultProps = {
position: 'left', position: 'left',
@ -246,8 +240,8 @@ export default class Dock extends Component {
fluid: true, fluid: true,
defaultSize: 0.3, defaultSize: 0.3,
dimMode: 'opaque', dimMode: 'opaque',
duration: 200 duration: 200,
} };
componentDidMount() { componentDidMount() {
window.addEventListener('mouseup', this.handleMouseUp); window.addEventListener('mouseup', this.handleMouseUp);
@ -265,7 +259,7 @@ export default class Dock extends Component {
window.removeEventListener('resize', this.handleResize); window.removeEventListener('resize', this.handleResize);
} }
componentWillReceiveProps(nextProps) { UNSAFE_componentWillReceiveProps(nextProps) {
const isControlled = typeof nextProps.size !== 'undefined'; const isControlled = typeof nextProps.size !== 'undefined';
this.setState({ isControlled }); this.setState({ isControlled });
@ -278,7 +272,7 @@ export default class Dock extends Component {
if (this.props.isVisible !== nextProps.isVisible) { if (this.props.isVisible !== nextProps.isVisible) {
this.setState({ this.setState({
isTransitionStarted: true isTransitionStarted: true,
}); });
} }
} }
@ -287,9 +281,9 @@ export default class Dock extends Component {
const { fullWidth, fullHeight } = this.state; const { fullWidth, fullHeight } = this.state;
this.setState({ this.setState({
size: props.fluid ? size: props.fluid
this.state.size / getFullSize(props.position, fullWidth, fullHeight) : ? this.state.size / getFullSize(props.position, fullWidth, fullHeight)
getFullSize(props.position, fullWidth, fullHeight) * this.state.size : getFullSize(props.position, fullWidth, fullHeight) * this.state.size,
}); });
} }
@ -307,40 +301,44 @@ export default class Dock extends Component {
transitionEnd = () => { transitionEnd = () => {
this.setState({ isTransitionStarted: false }); this.setState({ isTransitionStarted: false });
} };
hideDim = () => { hideDim = () => {
if (!this.props.isVisible) { if (!this.props.isVisible) {
this.setState({ isDimHidden: true }); this.setState({ isDimHidden: true });
} }
} };
render() { render() {
const { children, zIndex, dimMode, position, isVisible } = this.props; const { children, zIndex, dimMode, position, isVisible } = this.props;
const { isResizing, size, isDimHidden } = this.state; const { isResizing, size, isDimHidden } = this.state;
const dimStyles = Object.assign({}, ...getDimStyles(this.props, this.state)); const dimStyles = Object.assign(
const dockStyles = Object.assign({}, ...getDockStyles(this.props, this.state)); {},
...getDimStyles(this.props, this.state)
);
const dockStyles = Object.assign(
{},
...getDockStyles(this.props, this.state)
);
const resizerStyles = Object.assign({}, ...getResizerStyles(position)); const resizerStyles = Object.assign({}, ...getResizerStyles(position));
return ( return (
<div style={Object.assign({}, styles.wrapper, { zIndex })}> <div style={Object.assign({}, styles.wrapper, { zIndex })}>
{dimMode !== 'none' && !isDimHidden && {dimMode !== 'none' && !isDimHidden && (
<div style={dimStyles} onClick={this.handleDimClick} /> <div style={dimStyles} onClick={this.handleDimClick} />
} )}
<div style={dockStyles}> <div style={dockStyles}>
<div style={resizerStyles} <div style={resizerStyles} onMouseDown={this.handleMouseDown} />
onMouseDown={this.handleMouseDown} />
<div style={styles.dockContent}> <div style={styles.dockContent}>
{typeof children === 'function' ? {typeof children === 'function'
children({ ? children({
position, position,
isResizing, isResizing,
size, size,
isVisible isVisible,
}) : })
children : children}
}
</div> </div>
</div> </div>
</div> </div>
@ -351,7 +349,7 @@ export default class Dock extends Component {
if (this.props.dimMode === 'opaque') { if (this.props.dimMode === 'opaque') {
this.props.onVisibleChange && this.props.onVisibleChange(false); this.props.onVisibleChange && this.props.onVisibleChange(false);
} }
} };
handleResize = () => { handleResize = () => {
if (window.requestAnimationFrame) { if (window.requestAnimationFrame) {
@ -359,7 +357,7 @@ export default class Dock extends Component {
} else { } else {
this.updateWindowSize(true); this.updateWindowSize(true);
} }
} };
updateWindowSize = (windowResize) => { updateWindowSize = (windowResize) => {
const sizeState = { const sizeState = {
@ -371,37 +369,37 @@ export default class Dock extends Component {
this.setState({ this.setState({
...sizeState, ...sizeState,
isResizing: true, isResizing: true,
isWindowResizing: windowResize isWindowResizing: windowResize,
}); });
this.debouncedUpdateWindowSizeEnd(); this.debouncedUpdateWindowSizeEnd();
} else { } else {
this.setState(sizeState); this.setState(sizeState);
} }
} };
updateWindowSizeEnd = () => { updateWindowSizeEnd = () => {
this.setState({ this.setState({
isResizing: false, isResizing: false,
isWindowResizing: false isWindowResizing: false,
}); });
} };
debouncedUpdateWindowSizeEnd = debounce(this.updateWindowSizeEnd, 30) debouncedUpdateWindowSizeEnd = debounce(this.updateWindowSizeEnd, 30);
handleWrapperLeave = () => { handleWrapperLeave = () => {
this.setState({ isResizing: false }); this.setState({ isResizing: false });
} };
handleMouseDown = () => { handleMouseDown = () => {
this.setState({ isResizing: true }); this.setState({ isResizing: true });
} };
handleMouseUp = () => { handleMouseUp = () => {
this.setState({ isResizing: false }); this.setState({ isResizing: false });
} };
handleMouseMove = e => { handleMouseMove = (e) => {
if (!this.state.isResizing || this.state.isWindowResizing) return; if (!this.state.isResizing || this.state.isWindowResizing) return;
e.preventDefault(); e.preventDefault();
@ -410,19 +408,19 @@ export default class Dock extends Component {
const { clientX: x, clientY: y } = e; const { clientX: x, clientY: y } = e;
let size; let size;
switch(position) { switch (position) {
case 'left': case 'left':
size = fluid ? x / fullWidth : x; size = fluid ? x / fullWidth : x;
break; break;
case 'right': case 'right':
size = fluid ? (fullWidth - x) / fullWidth : (fullWidth - x); size = fluid ? (fullWidth - x) / fullWidth : fullWidth - x;
break; break;
case 'top': case 'top':
size = fluid ? y / fullHeight : y; size = fluid ? y / fullHeight : y;
break; break;
case 'bottom': case 'bottom':
size = fluid ? (fullHeight - y) / fullHeight : (fullHeight - y); size = fluid ? (fullHeight - y) / fullHeight : fullHeight - y;
break; break;
} }
this.props.onSizeChange && this.props.onSizeChange(size); this.props.onSizeChange && this.props.onSizeChange(size);
@ -430,5 +428,5 @@ export default class Dock extends Component {
if (!isControlled) { if (!isControlled) {
this.setState({ size }); this.setState({ size });
} }
} };
} }

View File

@ -29,22 +29,29 @@ const vendorSpecificProperties = [
'transitionTimingFunction', 'transitionTimingFunction',
'perspective', 'perspective',
'perspectiveOrigin', 'perspectiveOrigin',
'userSelect' 'userSelect',
]; ];
const prefixes = ['Moz', 'Webkit', 'ms', 'O']; const prefixes = ['Moz', 'Webkit', 'ms', 'O'];
function prefixProp(key, value) { function prefixProp(key, value) {
return prefixes.reduce( return prefixes.reduce(
(obj, pre) => (obj[pre + key[0].toUpperCase() + key.substr(1)] = value, obj), (obj, pre) => (
(obj[pre + key[0].toUpperCase() + key.substr(1)] = value), obj
),
{} {}
); );
} }
export default function autoprefix(style) { export default function autoprefix(style) {
return Object.keys(style).reduce((obj, key) => ( return Object.keys(style).reduce(
vendorSpecificProperties.indexOf(key) !== -1 ? { (obj, key) =>
...obj, vendorSpecificProperties.indexOf(key) !== -1
...prefixProp(key, style[key]) ? {
} : obj), style); ...obj,
...prefixProp(key, style[key]),
}
: obj,
style
);
} }