redux-devtools/packages/redux-devtools-dock-monitor/src/DockMonitor.tsx
Nathan Bierema b82de74592
Add ESM builds (#997)
* Use rollup for d3tooltip

* Use rollup for map2tree

* Set moduleResolution

* Use rollup for d3-state-visualizer

* Use rollup for react-base16-styling

* Use rollup for react-dock

* Use rollup for react-json-tree

* Use rollup for redux-devtools

* Use rollup for redux-devtools-intrument

* Use rollup for redux-devtools-chart-monitor

* Update export

* Use rollup for redux-devtools-dock-monitor

* Use rollup for redux-devtools-inspector-monitor

* Fix inspector demo

* Fix invalid eslint config

* Use rollup for inspector-monitor-test-tab

* Use rollup for inspector-monitor-trace-tab

* Use rollup for redux-devtools-log-monitor

* Use rollup for redux-devtools-remote

* Use rollup in redux-devtools-rtk-query-monitor

* Use rollup for redux-devtools-serialize

* Fix redux-devtools examples

* Use rollup for redux-devtools-slider-monitor

* Fix slider examples

* Use rollup for redux-devtools-ui

* Use rollup for redux-devtools-utils

* Use rollup for redux-devtools-extension

* Use rollup for redux-devtools-app

* Fix Webpack app build

* Fix extension build

* Turn on minimization

* Update CLI
2022-01-10 15:41:53 +00:00

248 lines
6.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { cloneElement, Children, Component } from 'react';
import PropTypes from 'prop-types';
import { Dock } from 'react-dock';
import { Action, Dispatch } from 'redux';
import { LiftedState, Monitor } from '@redux-devtools/core';
import { POSITIONS } from './constants';
import {
toggleVisibility,
changeMonitor,
changePosition,
changeSize,
DockMonitorAction,
} from './actions';
import reducer, { DockMonitorState } from './reducers';
import parseKey from 'parse-key';
interface KeyObject {
name: string;
ctrl: boolean;
meta: boolean;
shift: boolean;
alt: boolean;
sequence: string;
}
interface ExternalProps<S, A extends Action<unknown>> {
defaultPosition: 'left' | 'top' | 'right' | 'bottom';
defaultIsVisible: boolean;
defaultSize: number;
toggleVisibilityKey: string;
changePositionKey: string;
changeMonitorKey?: string;
fluid: boolean;
dispatch: Dispatch<DockMonitorAction>;
children:
| Monitor<S, A, LiftedState<S, A, unknown>, unknown, Action<unknown>>
| Monitor<S, A, LiftedState<S, A, unknown>, unknown, Action<unknown>>[];
}
interface DefaultProps {
defaultIsVisible: boolean;
defaultPosition: 'left' | 'top' | 'right' | 'bottom';
defaultSize: number;
fluid: boolean;
}
export interface DockMonitorProps<S, A extends Action<unknown>>
extends LiftedState<S, A, DockMonitorState> {
defaultPosition: 'left' | 'top' | 'right' | 'bottom';
defaultIsVisible: boolean;
defaultSize: number;
toggleVisibilityKey: string;
changePositionKey: string;
changeMonitorKey?: string;
fluid: boolean;
dispatch: Dispatch<DockMonitorAction>;
children:
| Monitor<S, A, LiftedState<S, A, unknown>, unknown, Action<unknown>>
| Monitor<S, A, LiftedState<S, A, unknown>, unknown, Action<unknown>>[];
}
class DockMonitor<S, A extends Action<unknown>> extends Component<
DockMonitorProps<S, A>
> {
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: DefaultProps = {
defaultIsVisible: true,
defaultPosition: 'right',
defaultSize: 0.3,
fluid: true,
};
constructor(props: DockMonitorProps<S, A>) {
super(props);
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 dont you try <LogMonitor>? You can get it at ' +
'https://github.com/reduxjs/redux-devtools/tree/master/packages/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: KeyObject | undefined, event: KeyboardEvent) {
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: KeyboardEvent) => {
// Ignore regular keys when focused on a field
// and no modifiers are active.
if (
!e.ctrlKey &&
!e.metaKey &&
!e.altKey &&
((e.target! as { tagName?: string }).tagName === 'INPUT' ||
(e.target! as { tagName?: string }).tagName === 'SELECT' ||
(e.target! as { tagName?: string }).tagName === 'TEXTAREA' ||
(e.target! as { isContentEditable?: boolean }).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: number) => {
this.props.dispatch(changeSize(requestedSize));
};
renderChild(
child: Monitor<S, A, LiftedState<S, A, unknown>, unknown, Action<unknown>>,
index: number,
otherProps: Omit<
DockMonitorProps<S, A>,
'monitorState' | 'children' | 'fluid'
>
) {
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 as
| Monitor<
S,
A,
LiftedState<S, A, unknown>,
unknown,
Action<unknown>
>
| Monitor<
S,
A,
LiftedState<S, A, unknown>,
unknown,
Action<unknown>
>[],
(child, index) => this.renderChild(child, index, rest)
)}
</Dock>
);
}
}
export default DockMonitor as unknown as React.ComponentType<
ExternalProps<unknown, Action<unknown>>
> & {
update(
monitorProps: ExternalProps<unknown, Action<unknown>>,
state: DockMonitorState | undefined,
action: DockMonitorAction
): DockMonitorState;
defaultProps: DefaultProps;
};