mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-02-07 23:20:46 +03:00
This API is much better
This commit is contained in:
parent
79b51a7c0f
commit
1f21d83931
|
@ -26,7 +26,7 @@
|
||||||
"babel-core": "^5.6.18",
|
"babel-core": "^5.6.18",
|
||||||
"babel-loader": "^5.1.4",
|
"babel-loader": "^5.1.4",
|
||||||
"node-libs-browser": "^0.5.2",
|
"node-libs-browser": "^0.5.2",
|
||||||
"react-dock": "^0.1.0",
|
"react-dock": "^0.2.1",
|
||||||
"react-hot-loader": "^1.3.0",
|
"react-hot-loader": "^1.3.0",
|
||||||
"redux-devtools": "^3.0.0-alpha-8",
|
"redux-devtools": "^3.0.0-alpha-8",
|
||||||
"redux-devtools-log-monitor": "^1.0.0-alpha-8",
|
"redux-devtools-log-monitor": "^1.0.0-alpha-8",
|
||||||
|
|
|
@ -4,7 +4,7 @@ import LogMonitor from 'redux-devtools-log-monitor';
|
||||||
import DockMonitor from '../dock/DockMonitor';
|
import DockMonitor from '../dock/DockMonitor';
|
||||||
|
|
||||||
export default createDevTools(
|
export default createDevTools(
|
||||||
<DockMonitor defaultPosition='bottom'>
|
<DockMonitor>
|
||||||
<LogMonitor theme='ocean' />
|
<LogMonitor theme='ocean' />
|
||||||
</DockMonitor>
|
</DockMonitor>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,41 +1,44 @@
|
||||||
//
|
import React, { cloneElement, Component, PropTypes } from 'react';
|
||||||
// TODO: extract to a separate project.
|
|
||||||
//
|
|
||||||
|
|
||||||
import React, { cloneElement, Children, Component, PropTypes } from 'react';
|
|
||||||
import Dock from 'react-dock';
|
import Dock from 'react-dock';
|
||||||
import { combineReducers } from 'redux';
|
import { POSITIONS } from './constants';
|
||||||
|
import { toggleVisibility, changePosition, changeSize } from './actions';
|
||||||
const POSITIONS = ['left', 'top', 'right', 'bottom'];
|
import reducer from './reducers';
|
||||||
|
|
||||||
export default class DockMonitor extends Component {
|
export default class DockMonitor extends Component {
|
||||||
|
static reducer = reducer;
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
defaultPosition: PropTypes.oneOf(POSITIONS).isRequired,
|
defaultPosition: PropTypes.oneOf(POSITIONS).isRequired,
|
||||||
defaultIsVisible: PropTypes.bool.isRequired,
|
defaultIsVisible: PropTypes.bool.isRequired,
|
||||||
|
defaultSize: PropTypes.number.isRequired,
|
||||||
toggleVisibilityShortcut: PropTypes.string.isRequired,
|
toggleVisibilityShortcut: PropTypes.string.isRequired,
|
||||||
changePositionShortcut: PropTypes.string.isRequired,
|
changePositionShortcut: PropTypes.string.isRequired,
|
||||||
|
children: PropTypes.element,
|
||||||
|
|
||||||
|
dispatch: PropTypes.func,
|
||||||
monitorState: PropTypes.shape({
|
monitorState: PropTypes.shape({
|
||||||
position: PropTypes.oneOf(POSITIONS).isRequired,
|
position: PropTypes.oneOf(POSITIONS).isRequired,
|
||||||
|
size: PropTypes.number.isRequired,
|
||||||
isVisible: PropTypes.bool.isRequired,
|
isVisible: PropTypes.bool.isRequired,
|
||||||
child: PropTypes.any
|
childMonitorState: PropTypes.any
|
||||||
}),
|
|
||||||
|
|
||||||
monitorActions: PropTypes.shape({
|
|
||||||
toggleVisibility: PropTypes.func.isRequired,
|
|
||||||
changePosition: PropTypes.func.isRequired
|
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
defaultIsVisible: true,
|
defaultIsVisible: true,
|
||||||
defaultPosition: 'right',
|
defaultPosition: 'right',
|
||||||
|
defaultSize: 0.3,
|
||||||
toggleVisibilityShortcut: 'H',
|
toggleVisibilityShortcut: 'H',
|
||||||
changePositionShortcut: 'Q'
|
changePositionShortcut: 'Q'
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||||
|
this.handleSizeChange = this.handleSizeChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
window.addEventListener('keydown', this.handleKeyDown);
|
window.addEventListener('keydown', this.handleKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,81 +56,36 @@ export default class DockMonitor extends Component {
|
||||||
const char = String.fromCharCode(key);
|
const char = String.fromCharCode(key);
|
||||||
switch (char.toUpperCase()) {
|
switch (char.toUpperCase()) {
|
||||||
case this.props.toggleVisibilityShortcut.toUpperCase():
|
case this.props.toggleVisibilityShortcut.toUpperCase():
|
||||||
this.props.monitorActions.toggleVisibility();
|
this.props.dispatch(toggleVisibility());
|
||||||
break;
|
break;
|
||||||
case this.props.changePositionShortcut.toUpperCase():
|
case this.props.changePositionShortcut.toUpperCase():
|
||||||
this.props.monitorActions.changePosition();
|
this.props.dispatch(changePosition());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
handleSizeChange(requestedSize) {
|
||||||
const {
|
this.props.dispatch(changeSize(requestedSize));
|
||||||
monitorState,
|
}
|
||||||
monitorActions,
|
|
||||||
historyState,
|
|
||||||
historyActions,
|
|
||||||
children
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const {
|
render() {
|
||||||
position,
|
const { monitorState, children, ...rest } = this.props;
|
||||||
isVisible
|
const { position, isVisible, size } = monitorState;
|
||||||
} = monitorState;
|
const childProps = {
|
||||||
|
...rest,
|
||||||
|
monitorState: monitorState.childMonitorState
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dock position={position}
|
<Dock position={position}
|
||||||
isVisible={isVisible}
|
isVisible={isVisible}
|
||||||
|
size={size}
|
||||||
|
onSizeChange={this.handleSizeChange}
|
||||||
dimMode='none'>
|
dimMode='none'>
|
||||||
{cloneElement(Children.only(children), {
|
{cloneElement(children, childProps)}
|
||||||
monitorState: monitorState.child,
|
|
||||||
monitorActions: monitorActions.child,
|
|
||||||
historyState,
|
|
||||||
historyActions
|
|
||||||
})}
|
|
||||||
</Dock>
|
</Dock>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TOGGLE_VISIBILITY = '@@redux-devtools/dock/TOGGLE_VISIBILITY';
|
|
||||||
function toggleVisibility() {
|
|
||||||
return { type: TOGGLE_VISIBILITY };
|
|
||||||
}
|
|
||||||
|
|
||||||
const CHANGE_POSITION = '@@redux-devtools/dock/CHANGE_POSITION';
|
|
||||||
function changePosition() {
|
|
||||||
return { type: CHANGE_POSITION };
|
|
||||||
}
|
|
||||||
|
|
||||||
DockMonitor.setup = function setup(props) {
|
|
||||||
function position(state = props.defaultPosition, action) {
|
|
||||||
return (action.type === CHANGE_POSITION) ?
|
|
||||||
POSITIONS[(POSITIONS.indexOf(state) + 1) % POSITIONS.length] :
|
|
||||||
state;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isVisible(state = props.defaultIsVisible, action) {
|
|
||||||
return (action.type === TOGGLE_VISIBILITY) ?
|
|
||||||
!state :
|
|
||||||
state;
|
|
||||||
}
|
|
||||||
|
|
||||||
const child = Children.only(props.children);
|
|
||||||
const childSetupResult = child.type.setup(child.props);
|
|
||||||
|
|
||||||
return {
|
|
||||||
reducer: combineReducers({
|
|
||||||
position,
|
|
||||||
isVisible,
|
|
||||||
child: childSetupResult.reducer
|
|
||||||
}),
|
|
||||||
actionCreators: {
|
|
||||||
toggleVisibility,
|
|
||||||
changePosition,
|
|
||||||
child: childSetupResult.actionCreators
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
14
examples/counter/src/dock/actions.js
Normal file
14
examples/counter/src/dock/actions.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
export const TOGGLE_VISIBILITY = '@@redux-devtools/dock/TOGGLE_VISIBILITY';
|
||||||
|
export function toggleVisibility() {
|
||||||
|
return { type: TOGGLE_VISIBILITY };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CHANGE_POSITION = '@@redux-devtools/dock/CHANGE_POSITION';
|
||||||
|
export function changePosition() {
|
||||||
|
return { type: CHANGE_POSITION };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CHANGE_SIZE = '@@redux-devtools/dock/CHANGE_SIZE';
|
||||||
|
export function changeSize(size) {
|
||||||
|
return { type: CHANGE_SIZE, size: size };
|
||||||
|
}
|
1
examples/counter/src/dock/constants.js
Normal file
1
examples/counter/src/dock/constants.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const POSITIONS = ['left', 'top', 'right', 'bottom'];
|
34
examples/counter/src/dock/reducers.js
Normal file
34
examples/counter/src/dock/reducers.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { CHANGE_POSITION, CHANGE_SIZE, TOGGLE_VISIBILITY } from './actions';
|
||||||
|
import { POSITIONS } from './constants';
|
||||||
|
|
||||||
|
function position(state = props.defaultPosition, action, props) {
|
||||||
|
return (action.type === CHANGE_POSITION) ?
|
||||||
|
POSITIONS[(POSITIONS.indexOf(state) + 1) % POSITIONS.length] :
|
||||||
|
state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function size(state = props.defaultSize, action, props) {
|
||||||
|
return (action.type === CHANGE_SIZE) ?
|
||||||
|
action.size :
|
||||||
|
state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isVisible(state = props.defaultIsVisible, action, props) {
|
||||||
|
return (action.type === TOGGLE_VISIBILITY) ?
|
||||||
|
!state :
|
||||||
|
state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function childMonitorState(state, action, props) {
|
||||||
|
const child = props.children;
|
||||||
|
return child.type.reducer(state, action, child.props);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function reducer(state = {}, action, props) {
|
||||||
|
return {
|
||||||
|
position: position(state.position, action, props),
|
||||||
|
isVisible: isVisible(state.isVisible, action, props),
|
||||||
|
size: size(state.size, action, props),
|
||||||
|
childMonitorState: childMonitorState(state.childMonitorState, action, props)
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
|
|
||||||
export default function bindActionCreatorsDeep(actionCreators, dispatch) {
|
|
||||||
return Object.keys(actionCreators).reduce((result, key) => {
|
|
||||||
if (!actionCreators[key]) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
switch (typeof actionCreators[key]) {
|
|
||||||
case 'object':
|
|
||||||
result[key] = bindActionCreatorsDeep(actionCreators[key], dispatch);
|
|
||||||
break;
|
|
||||||
case 'function':
|
|
||||||
result[key] = bindActionCreators(actionCreators[key], dispatch);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}, {});
|
|
||||||
}
|
|
|
@ -1,39 +1,30 @@
|
||||||
import React, { Children, Component, PropTypes } from 'react';
|
import React, { Children, Component, PropTypes } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import instrument from './instrument';
|
||||||
import bindActionCreatorsDeep from './bindActionCreatorsDeep';
|
|
||||||
import instrument, { ActionCreators as historyActionCreators } from './instrument';
|
|
||||||
|
|
||||||
export default function createDevTools(children) {
|
export default function createDevTools(children) {
|
||||||
const child = Children.only(children);
|
const monitorElement = Children.only(children);
|
||||||
const { type: Monitor } = child;
|
const monitorProps = monitorElement.props;
|
||||||
const { reducer, actionCreators } = Monitor.setup(child.props);
|
const Monitor = monitorElement.type;
|
||||||
|
|
||||||
|
const enhancer = instrument((state, action) =>
|
||||||
|
Monitor.reducer(state, action, monitorProps)
|
||||||
|
);
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
return {
|
return {
|
||||||
historyState: state.historyState,
|
...state.historyState,
|
||||||
monitorState: state.monitorState
|
monitorState: state.monitorState
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
const ConnectedMonitor = connect(mapStateToProps)(Monitor);
|
||||||
function mapDispatchToProps(dispatch) {
|
|
||||||
return {
|
|
||||||
historyActions: bindActionCreators(historyActionCreators, dispatch),
|
|
||||||
monitorActions: bindActionCreatorsDeep(actionCreators, dispatch)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const ConnectedMonitor = connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(Monitor);
|
|
||||||
|
|
||||||
return class DevTools extends Component {
|
return class DevTools extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
store: PropTypes.object.isRequired
|
store: PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
static instrument = () => instrument(reducer);
|
static instrument = () => enhancer;
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
@ -42,7 +33,7 @@ export default function createDevTools(children) {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ConnectedMonitor {...child.props}
|
<ConnectedMonitor {...monitorProps}
|
||||||
store={this.instrumentedStore} />
|
store={this.instrumentedStore} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
export { default as instrument, ActionTypes } from './instrument';
|
export { default as instrument, ActionCreators, ActionTypes } from './instrument';
|
||||||
export { default as persistState } from './persistState';
|
export { default as persistState } from './persistState';
|
||||||
export { default as createDevTools } from './createDevTools';
|
export { default as createDevTools } from './createDevTools';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user