2020-08-06 23:25:12 +03:00
|
|
|
|
import React, { cloneElement, Children, Component } from 'react';
|
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
import Dock from 'react-dock';
|
|
|
|
|
import { POSITIONS } from './constants';
|
|
|
|
|
import {
|
|
|
|
|
toggleVisibility,
|
|
|
|
|
changeMonitor,
|
|
|
|
|
changePosition,
|
2020-08-08 23:26:39 +03:00
|
|
|
|
changeSize,
|
2020-08-06 23:25:12 +03:00
|
|
|
|
} from './actions';
|
|
|
|
|
import reducer from './reducers';
|
|
|
|
|
import parseKey from 'parse-key';
|
|
|
|
|
|
|
|
|
|
export default class DockMonitor extends Component {
|
|
|
|
|
static update = reducer;
|
|
|
|
|
|
|
|
|
|
static propTypes = {
|
|
|
|
|
defaultPosition: PropTypes.oneOf(POSITIONS),
|
|
|
|
|
defaultIsVisible: PropTypes.bool.isRequired,
|
|
|
|
|
defaultSize: PropTypes.number.isRequired,
|
|
|
|
|
toggleVisibilityKey: PropTypes.string.isRequired,
|
|
|
|
|
changePositionKey: PropTypes.string.isRequired,
|
|
|
|
|
changeMonitorKey: PropTypes.string,
|
|
|
|
|
fluid: PropTypes.bool,
|
|
|
|
|
|
|
|
|
|
dispatch: PropTypes.func,
|
|
|
|
|
monitorState: PropTypes.shape({
|
|
|
|
|
position: PropTypes.oneOf(POSITIONS).isRequired,
|
|
|
|
|
size: PropTypes.number.isRequired,
|
|
|
|
|
isVisible: PropTypes.bool.isRequired,
|
2020-08-08 23:26:39 +03:00
|
|
|
|
childMonitorState: PropTypes.any,
|
|
|
|
|
}),
|
2020-08-06 23:25:12 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static defaultProps = {
|
|
|
|
|
defaultIsVisible: true,
|
|
|
|
|
defaultPosition: 'right',
|
|
|
|
|
defaultSize: 0.3,
|
2020-08-08 23:26:39 +03:00
|
|
|
|
fluid: true,
|
2020-08-06 23:25:12 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
|
super(props);
|
|
|
|
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
|
|
|
this.handleSizeChange = this.handleSizeChange.bind(this);
|
|
|
|
|
|
|
|
|
|
const childrenCount = Children.count(props.children);
|
|
|
|
|
if (childrenCount === 0) {
|
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
|
console.error(
|
|
|
|
|
'<DockMonitor> requires at least one monitor inside. ' +
|
|
|
|
|
'Why don’t you try <LogMonitor>? You can get it at ' +
|
|
|
|
|
'https://github.com/gaearon/redux-devtools-log-monitor.'
|
|
|
|
|
);
|
|
|
|
|
} else if (childrenCount > 1 && !props.changeMonitorKey) {
|
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
|
console.error(
|
|
|
|
|
'You specified multiple monitors inside <DockMonitor> ' +
|
|
|
|
|
'but did not provide `changeMonitorKey` prop to change them. ' +
|
|
|
|
|
'Try specifying <DockMonitor changeMonitorKey="ctrl-m" /> ' +
|
|
|
|
|
'and then press Ctrl-M.'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
|
window.addEventListener('keydown', this.handleKeyDown);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
|
window.removeEventListener('keydown', this.handleKeyDown);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
matchesKey(key, event) {
|
|
|
|
|
if (!key) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const charCode = event.keyCode || event.which;
|
|
|
|
|
const char = String.fromCharCode(charCode);
|
|
|
|
|
return (
|
|
|
|
|
key.name.toUpperCase() === char.toUpperCase() &&
|
|
|
|
|
key.alt === event.altKey &&
|
|
|
|
|
key.ctrl === event.ctrlKey &&
|
|
|
|
|
key.meta === event.metaKey &&
|
|
|
|
|
key.shift === event.shiftKey
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleKeyDown(e) {
|
|
|
|
|
// Ignore regular keys when focused on a field
|
|
|
|
|
// and no modifiers are active.
|
|
|
|
|
if (
|
|
|
|
|
!e.ctrlKey &&
|
|
|
|
|
!e.metaKey &&
|
|
|
|
|
!e.altKey &&
|
|
|
|
|
(e.target.tagName === 'INPUT' ||
|
|
|
|
|
e.target.tagName === 'SELECT' ||
|
|
|
|
|
e.target.tagName === 'TEXTAREA' ||
|
|
|
|
|
e.target.isContentEditable)
|
|
|
|
|
) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const visibilityKey = parseKey(this.props.toggleVisibilityKey);
|
|
|
|
|
const positionKey = parseKey(this.props.changePositionKey);
|
|
|
|
|
|
|
|
|
|
let monitorKey;
|
|
|
|
|
if (this.props.changeMonitorKey) {
|
|
|
|
|
monitorKey = parseKey(this.props.changeMonitorKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.matchesKey(visibilityKey, e)) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
this.props.dispatch(toggleVisibility());
|
|
|
|
|
} else if (this.matchesKey(positionKey, e)) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
this.props.dispatch(changePosition());
|
|
|
|
|
} else if (this.matchesKey(monitorKey, e)) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
this.props.dispatch(changeMonitor());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleSizeChange(requestedSize) {
|
|
|
|
|
this.props.dispatch(changeSize(requestedSize));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
renderChild(child, index, otherProps) {
|
|
|
|
|
const { monitorState } = this.props;
|
|
|
|
|
const { childMonitorIndex, childMonitorStates } = monitorState;
|
|
|
|
|
|
|
|
|
|
if (index !== childMonitorIndex) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cloneElement(child, {
|
|
|
|
|
monitorState: childMonitorStates[index],
|
2020-08-08 23:26:39 +03:00
|
|
|
|
...otherProps,
|
2020-08-06 23:25:12 +03:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
const { monitorState, children, fluid, ...rest } = this.props;
|
|
|
|
|
const { position, isVisible, size } = monitorState;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Dock
|
|
|
|
|
position={position}
|
|
|
|
|
isVisible={isVisible}
|
|
|
|
|
size={size}
|
|
|
|
|
fluid={fluid}
|
|
|
|
|
onSizeChange={this.handleSizeChange}
|
|
|
|
|
dimMode="none"
|
|
|
|
|
>
|
|
|
|
|
{Children.map(children, (child, index) =>
|
|
|
|
|
this.renderChild(child, index, rest)
|
|
|
|
|
)}
|
|
|
|
|
</Dock>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|