mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-11-25 11:03:57 +03:00
Add redux-devtools-dock-monitor package (#561)
* Stash * Cleanup * Fix * Add export default from plugin * Remove empty test
This commit is contained in:
parent
c924091e8c
commit
ebdf32661e
|
@ -7,7 +7,7 @@
|
||||||
"clean": "rimraf lib",
|
"clean": "rimraf lib",
|
||||||
"build": "babel src --out-dir lib",
|
"build": "babel src --out-dir lib",
|
||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
"prepublishOnly": "npm run lint && npm run clean && npm run build"
|
"prepublishOnly": "npm run clean && npm run build"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"lib",
|
"lib",
|
||||||
|
|
4
packages/redux-devtools-dock-monitor/.babelrc
Normal file
4
packages/redux-devtools-dock-monitor/.babelrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"presets": ["@babel/preset-env", "@babel/preset-react"],
|
||||||
|
"plugins": ["@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-export-default-from"]
|
||||||
|
}
|
63
packages/redux-devtools-dock-monitor/README.md
Normal file
63
packages/redux-devtools-dock-monitor/README.md
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
# Redux DevTools Dock Monitor
|
||||||
|
|
||||||
|
A resizable and movable dock for [Redux DevTools](https://github.com/reduxjs/redux-devtools).
|
||||||
|
Powered by [React Dock](https://github.com/alexkuz/react-dock).
|
||||||
|
|
||||||
|
![](http://i.imgur.com/QbNzNW4.gif)
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn add redux-devtools-dock-monitor
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Wrap any other Redux DevTools monitor in `DockMonitor` to make it dockable to different screen edges.
|
||||||
|
For example, you can use it together with [`LogMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-log-monitor):
|
||||||
|
|
||||||
|
##### `containers/DevTools.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
import React from 'react';
|
||||||
|
import { createDevTools } from 'redux-devtools';
|
||||||
|
import LogMonitor from 'redux-devtools-log-monitor';
|
||||||
|
import SliderMonitor from 'redux-slider-monitor';
|
||||||
|
import DockMonitor from 'redux-devtools-dock-monitor';
|
||||||
|
|
||||||
|
export default createDevTools(
|
||||||
|
<DockMonitor
|
||||||
|
toggleVisibilityKey="ctrl-h"
|
||||||
|
changePositionKey="ctrl-q"
|
||||||
|
changeMonitorKey="ctrl-m"
|
||||||
|
>
|
||||||
|
<LogMonitor />
|
||||||
|
<SliderMonitor />
|
||||||
|
</DockMonitor>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
[Read how to start using Redux DevTools.](https://github.com/reduxjs/redux-devtools)
|
||||||
|
|
||||||
|
#### Multiple Monitors
|
||||||
|
|
||||||
|
You can put more than one monitor inside `<DockMonitor>`. There will still be a single dock, but you will be able to switch between different monitors by pressing a key specified as `changeMonitorKey` prop.
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| `children` | Any valid Redux DevTools monitor. Required. |
|
||||||
|
| `toggleVisibilityKey` | A key or a key combination that toggles the dock visibility. Must be recognizable by [parse-key](https://github.com/thlorenz/parse-key) (for example, `'ctrl-h'`). Required. |
|
||||||
|
| `changePositionKey` | A key or a key combination that toggles the dock position. Must be recognizable by [parse-key](https://github.com/thlorenz/parse-key) (for example, `'ctrl-w'`). Required. |
|
||||||
|
| `changeMonitorKey` | A key or a key combination that switches the currently visible monitor. Must be recognizable by [parse-key](https://github.com/thlorenz/parse-key) (for example, `'ctrl-m'`). Required if you use more than one monitor. |
|
||||||
|
| `fluid` | When `true`, the dock size is a fraction of the window size, fixed otherwise. Optional. By default set to `true`. |
|
||||||
|
| `defaultSize` | Size of the dock. When `fluid` is `true`, a float (`0.5` means half the window size). When `fluid` is `false`, a width in pixels. Optional. By default set to `0.3` (3/10th of the window size). |
|
||||||
|
| `defaultPosition` | Where the dock appears on the screen. Valid values: `'left'`, `'top'`, `'right'`, `'bottom'`. Optional. By default set to `'right'`. |
|
||||||
|
| `defaultIsVisible` | Defines whether dock should be open by default. A value of `true` means that it's open when the page/app loads. |
|
||||||
|
|
||||||
|
The current size and the position are persisted between sessions with `persistState()` enhancer from Redux DevTools.
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
MIT
|
56
packages/redux-devtools-dock-monitor/package.json
Normal file
56
packages/redux-devtools-dock-monitor/package.json
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{
|
||||||
|
"name": "redux-devtools-dock-monitor",
|
||||||
|
"version": "1.1.3",
|
||||||
|
"description": "A resizable and movable dock for Redux DevTools monitors",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"files": [
|
||||||
|
"lib",
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf lib",
|
||||||
|
"build": "babel src --out-dir lib",
|
||||||
|
"prepare": "npm run build",
|
||||||
|
"prepublishOnly": "npm run test && npm run clean && npm run build"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"redux",
|
||||||
|
"devtools",
|
||||||
|
"flux",
|
||||||
|
"react",
|
||||||
|
"hot reloading",
|
||||||
|
"time travel",
|
||||||
|
"live edit"
|
||||||
|
],
|
||||||
|
"author": "Dan Abramov <dan.abramov@me.com> (http://github.com/gaearon)",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/reduxjs/redux-devtools/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/reduxjs/redux-devtools",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.10.5",
|
||||||
|
"@babel/core": "^7.11.0",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||||
|
"@babel/plugin-proposal-export-default-from": "^7.10.4",
|
||||||
|
"@babel/preset-env": "^7.11.0",
|
||||||
|
"@babel/preset-react": "^7.10.4",
|
||||||
|
"babel-loader": "^8.1.0",
|
||||||
|
"rimraf": "^2.7.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^0.14.9 || ^15.3.0 || ^16.0.0",
|
||||||
|
"redux-devtools": "^3.4.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"babel-runtime": "^6.26.0",
|
||||||
|
"parse-key": "^0.2.1",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"react-dock": "^0.2.4",
|
||||||
|
"react-pure-render": "^1.0.2"
|
||||||
|
}
|
||||||
|
}
|
162
packages/redux-devtools-dock-monitor/src/DockMonitor.js
Normal file
162
packages/redux-devtools-dock-monitor/src/DockMonitor.js
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
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,
|
||||||
|
changeSize
|
||||||
|
} 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,
|
||||||
|
childMonitorState: PropTypes.any
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
defaultIsVisible: true,
|
||||||
|
defaultPosition: 'right',
|
||||||
|
defaultSize: 0.3,
|
||||||
|
fluid: true
|
||||||
|
};
|
||||||
|
|
||||||
|
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],
|
||||||
|
...otherProps
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
20
packages/redux-devtools-dock-monitor/src/actions.js
Normal file
20
packages/redux-devtools-dock-monitor/src/actions.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
export const TOGGLE_VISIBILITY =
|
||||||
|
'@@redux-devtools-log-monitor/TOGGLE_VISIBILITY';
|
||||||
|
export function toggleVisibility() {
|
||||||
|
return { type: TOGGLE_VISIBILITY };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CHANGE_POSITION = '@@redux-devtools-log-monitor/CHANGE_POSITION';
|
||||||
|
export function changePosition() {
|
||||||
|
return { type: CHANGE_POSITION };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CHANGE_SIZE = '@@redux-devtools-log-monitor/CHANGE_SIZE';
|
||||||
|
export function changeSize(size) {
|
||||||
|
return { type: CHANGE_SIZE, size: size };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CHANGE_MONITOR = '@@redux-devtools-log-monitor/CHANGE_MONITOR';
|
||||||
|
export function changeMonitor() {
|
||||||
|
return { type: CHANGE_MONITOR };
|
||||||
|
}
|
1
packages/redux-devtools-dock-monitor/src/constants.js
Normal file
1
packages/redux-devtools-dock-monitor/src/constants.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const POSITIONS = ['left', 'top', 'right', 'bottom'];
|
1
packages/redux-devtools-dock-monitor/src/index.js
Normal file
1
packages/redux-devtools-dock-monitor/src/index.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export default from './DockMonitor';
|
68
packages/redux-devtools-dock-monitor/src/reducers.js
Normal file
68
packages/redux-devtools-dock-monitor/src/reducers.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import {
|
||||||
|
CHANGE_MONITOR,
|
||||||
|
CHANGE_POSITION,
|
||||||
|
CHANGE_SIZE,
|
||||||
|
TOGGLE_VISIBILITY
|
||||||
|
} from './actions';
|
||||||
|
import { POSITIONS } from './constants';
|
||||||
|
import { Children } from 'react';
|
||||||
|
|
||||||
|
function position(props, state = props.defaultPosition, action) {
|
||||||
|
return action.type === CHANGE_POSITION
|
||||||
|
? POSITIONS[(POSITIONS.indexOf(state) + 1) % POSITIONS.length]
|
||||||
|
: state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function size(props, state = props.defaultSize, action) {
|
||||||
|
return action.type === CHANGE_SIZE ? action.size : state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isVisible(props, state = props.defaultIsVisible, action) {
|
||||||
|
return action.type === TOGGLE_VISIBILITY ? !state : state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function childMonitorStates(props, state = [], action) {
|
||||||
|
return Children.map(props.children, (child, index) =>
|
||||||
|
child.type.update(child.props, state[index], action)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function childMonitorIndex(props, state = 0, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case CHANGE_MONITOR:
|
||||||
|
return (state + 1) % Children.count(props.children);
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function reducer(props, state = {}, action) {
|
||||||
|
if (!state.childMonitorStates) {
|
||||||
|
Children.forEach(props.children, (child, index) => {
|
||||||
|
if (typeof child.type.update !== 'function') {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(
|
||||||
|
`Child of <DockMonitor> with the index ${index} ` +
|
||||||
|
`(${child.type.displayName || child.type.name || child.type}) ` +
|
||||||
|
'does not appear to be a valid Redux DevTools monitor.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
position: position(props, state.position, action),
|
||||||
|
isVisible: isVisible(props, state.isVisible, action),
|
||||||
|
size: size(props, state.size, action),
|
||||||
|
childMonitorIndex: childMonitorIndex(
|
||||||
|
props,
|
||||||
|
state.childMonitorIndex,
|
||||||
|
action
|
||||||
|
),
|
||||||
|
childMonitorStates: childMonitorStates(
|
||||||
|
props,
|
||||||
|
state.childMonitorStates,
|
||||||
|
action
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user