feat(redux-devtools-log-monitor): convert to TypeScript (#613)

* Stash

* And that

* finish

* fix up dependencies
This commit is contained in:
Nathan Bierema 2020-08-27 09:19:37 -04:00 committed by GitHub
parent c154405c6c
commit 2faa16319b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 345 additions and 190 deletions

View File

@ -1,7 +1,8 @@
{ {
"presets": ["@babel/preset-env", "@babel/preset-react"], "presets": [
"plugins": [ "@babel/preset-env",
"@babel/plugin-proposal-class-properties", "@babel/preset-react",
"@babel/plugin-proposal-export-default-from" "@babel/preset-typescript"
] ],
"plugins": ["@babel/plugin-proposal-class-properties"]
} }

View File

@ -0,0 +1 @@
lib

View File

@ -0,0 +1,13 @@
module.exports = {
extends: '../../.eslintrc',
overrides: [
{
files: ['*.ts', '*.tsx'],
extends: '../../eslintrc.ts.react.base.json',
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
},
},
],
};

View File

@ -2,21 +2,6 @@
"name": "redux-devtools-log-monitor", "name": "redux-devtools-log-monitor",
"version": "2.0.1", "version": "2.0.1",
"description": "The default tree view monitor for Redux DevTools", "description": "The default tree view monitor for Redux DevTools",
"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"
},
"keywords": [ "keywords": [
"redux", "redux",
"devtools", "devtools",
@ -26,31 +11,53 @@
"time travel", "time travel",
"live edit" "live edit"
], ],
"author": "Dan Abramov <dan.abramov@me.com> (http://github.com/gaearon)", "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-log-monitor",
"license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/reduxjs/redux-devtools/issues" "url": "https://github.com/reduxjs/redux-devtools/issues"
}, },
"homepage": "https://github.com/reduxjs/redux-devtools", "license": "MIT",
"devDependencies": { "author": "Dan Abramov <dan.abramov@me.com> (http://github.com/gaearon)",
"@babel/cli": "^7.10.5", "files": [
"@babel/core": "^7.11.1", "lib",
"@babel/plugin-proposal-class-properties": "^7.10.4", "src"
"@babel/plugin-proposal-export-default-from": "^7.10.4", ],
"@babel/preset-env": "^7.11.0", "main": "lib/index.js",
"@babel/preset-react": "^7.10.4", "types": "lib/index.d.ts",
"babel-loader": "^8.1.0", "repository": {
"rimraf": "^3.0.2" "type": "git",
"url": "https://github.com/reduxjs/redux-devtools"
}, },
"peerDependencies": { "scripts": {
"react": "^16.3.0", "build": "npm run build:types && npm run build:js",
"redux-devtools": "^3.4.0" "build:types": "tsc --emitDeclarationOnly",
"build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline",
"clean": "rimraf lib",
"lint": "eslint . --ext .ts,.tsx",
"lint:fix": "eslint . --ext .ts,.tsx --fix",
"type-check": "tsc --noEmit",
"type-check:watch": "npm run type-check -- --watch",
"preversion": "npm run type-check && npm run lint && npm run test",
"prepublishOnly": "npm run clean && npm run build"
}, },
"dependencies": { "dependencies": {
"@types/lodash.debounce": "^4.0.6",
"@types/prop-types": "^15.7.3",
"@types/redux-devtools-themes": "^1.0.0",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react-json-tree": "^0.12.1", "react-json-tree": "^0.12.1",
"react-pure-render": "^1.0.2",
"redux-devtools-themes": "^1.0.0" "redux-devtools-themes": "^1.0.0"
},
"devDependencies": {
"@types/react": "^16.9.46",
"react": "^16.13.1",
"redux": "^4.0.5",
"redux-devtools": "^3.6.1"
},
"peerDependencies": {
"@types/react": "^16.9.46",
"react": "^16.3.0",
"redux": "^4.0.5",
"redux-devtools": "^3.4.0"
} }
} }

View File

@ -1,17 +1,26 @@
import React, { Component } from 'react'; import React, { PureComponent } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import shouldPureComponentUpdate from 'react-pure-render/function'; import { Action, Dispatch } from 'redux';
import * as themes from 'redux-devtools-themes'; import * as themes from 'redux-devtools-themes';
import { ActionCreators } from 'redux-devtools'; import { Base16Theme } from 'redux-devtools-themes';
import { updateScrollTop, startConsecutiveToggle } from './actions'; import { ActionCreators, LiftedAction, LiftedState } from 'redux-devtools';
import reducer from './reducers'; import {
updateScrollTop,
startConsecutiveToggle,
LogMonitorAction,
} from './actions';
import reducer, { LogMonitorState } from './reducers';
import LogMonitorButtonBar from './LogMonitorButtonBar'; import LogMonitorButtonBar from './LogMonitorButtonBar';
import LogMonitorEntryList from './LogMonitorEntryList'; import LogMonitorEntryList from './LogMonitorEntryList';
import debounce from 'lodash.debounce'; import debounce from 'lodash.debounce';
// eslint-disable-next-line @typescript-eslint/unbound-method
const { toggleAction, setActionsActive } = ActionCreators; const { toggleAction, setActionsActive } = ActionCreators;
const styles = { const styles: {
container: React.CSSProperties;
elements: React.CSSProperties;
} = {
container: { container: {
fontFamily: 'monaco, Consolas, Lucida Console, monospace', fontFamily: 'monaco, Consolas, Lucida Console, monospace',
position: 'relative', position: 'relative',
@ -32,7 +41,23 @@ const styles = {
}, },
}; };
export default class LogMonitor extends Component { export interface LogMonitorProps<S, A extends Action<unknown>>
extends LiftedState<S, A, LogMonitorState> {
dispatch: Dispatch<LogMonitorAction | LiftedAction<S, A, LogMonitorState>>;
preserveScrollTop: boolean;
select: (state: S) => unknown;
theme: keyof typeof themes | Base16Theme;
expandActionRoot: boolean;
expandStateRoot: boolean;
markStateDiff: boolean;
hideMainButtons?: boolean;
}
export default class LogMonitor<
S,
A extends Action<unknown>
> extends PureComponent<LogMonitorProps<S, A>> {
static update = reducer; static update = reducer;
static propTypes = { static propTypes = {
@ -56,7 +81,7 @@ export default class LogMonitor extends Component {
}; };
static defaultProps = { static defaultProps = {
select: (state) => state, select: (state: unknown) => state,
theme: 'nicinabox', theme: 'nicinabox',
preserveScrollTop: true, preserveScrollTop: true,
expandActionRoot: true, expandActionRoot: true,
@ -64,22 +89,14 @@ export default class LogMonitor extends Component {
markStateDiff: false, markStateDiff: false,
}; };
shouldComponentUpdate = shouldPureComponentUpdate; scrollDown?: boolean;
node?: HTMLDivElement | null;
updateScrollTop = debounce(() => { updateScrollTop = debounce(() => {
const node = this.node; const node = this.node;
this.props.dispatch(updateScrollTop(node ? node.scrollTop : 0)); this.props.dispatch(updateScrollTop(node ? node.scrollTop : 0));
}, 500); }, 500);
constructor(props) {
super(props);
this.handleToggleAction = this.handleToggleAction.bind(this);
this.handleToggleConsecutiveAction = this.handleToggleConsecutiveAction.bind(
this
);
this.getRef = this.getRef.bind(this);
}
scroll() { scroll() {
const node = this.node; const node = this.node;
if (!node) { if (!node) {
@ -114,7 +131,7 @@ export default class LogMonitor extends Component {
} }
} }
UNSAFE_componentWillReceiveProps(nextProps) { UNSAFE_componentWillReceiveProps(nextProps: LogMonitorProps<S, A>) {
const node = this.node; const node = this.node;
if (!node) { if (!node) {
this.scrollDown = true; this.scrollDown = true;
@ -134,11 +151,11 @@ export default class LogMonitor extends Component {
this.scroll(); this.scroll();
} }
handleToggleAction(id) { handleToggleAction = (id: number) => {
this.props.dispatch(toggleAction(id)); this.props.dispatch(toggleAction(id));
} };
handleToggleConsecutiveAction(id) { handleToggleConsecutiveAction = (id: number) => {
const { monitorState, actionsById } = this.props; const { monitorState, actionsById } = this.props;
const { consecutiveToggleStartId } = monitorState; const { consecutiveToggleStartId } = monitorState;
if (consecutiveToggleStartId && actionsById[consecutiveToggleStartId]) { if (consecutiveToggleStartId && actionsById[consecutiveToggleStartId]) {
@ -151,10 +168,10 @@ export default class LogMonitor extends Component {
} else if (id > 0) { } else if (id > 0) {
this.props.dispatch(startConsecutiveToggle(id)); this.props.dispatch(startConsecutiveToggle(id));
} }
} };
getTheme() { getTheme() {
let { theme } = this.props; const { theme } = this.props;
if (typeof theme !== 'string') { if (typeof theme !== 'string') {
return theme; return theme;
} }
@ -170,9 +187,9 @@ export default class LogMonitor extends Component {
return themes.nicinabox; return themes.nicinabox;
} }
getRef(node) { getRef: React.RefCallback<HTMLDivElement> = (node) => {
this.node = node; this.node = node;
} };
render() { render() {
const theme = this.getTheme(); const theme = this.getTheme();

View File

@ -1,8 +1,8 @@
import React from 'react'; import React, { CSSProperties } from 'react';
import { Base16Theme } from 'redux-devtools-themes';
import brighten from './brighten'; import brighten from './brighten';
import shouldPureComponentUpdate from 'react-pure-render/function';
const styles = { const styles: { base: CSSProperties } = {
base: { base: {
cursor: 'pointer', cursor: 'pointer',
fontWeight: 'bold', fontWeight: 'bold',
@ -20,48 +20,50 @@ const styles = {
}, },
}; };
export default class LogMonitorButton extends React.Component { interface State {
shouldComponentUpdate = shouldPureComponentUpdate; hovered: boolean;
active: boolean;
}
constructor(props) { interface Props {
super(props); theme: Base16Theme;
onClick: () => void;
enabled: boolean;
}
this.handleMouseEnter = this.handleMouseEnter.bind(this); export default class LogMonitorButton extends React.PureComponent<
this.handleMouseLeave = this.handleMouseLeave.bind(this); Props,
this.handleMouseDown = this.handleMouseDown.bind(this); State
this.handleMouseUp = this.handleMouseUp.bind(this); > {
this.onClick = this.onClick.bind(this); state: State = {
this.state = {
hovered: false, hovered: false,
active: false, active: false,
}; };
}
handleMouseEnter() { handleMouseEnter = () => {
this.setState({ hovered: true }); this.setState({ hovered: true });
} };
handleMouseLeave() { handleMouseLeave = () => {
this.setState({ hovered: false }); this.setState({ hovered: false });
} };
handleMouseDown() { handleMouseDown = () => {
this.setState({ active: true }); this.setState({ active: true });
} };
handleMouseUp() { handleMouseUp = () => {
this.setState({ active: false }); this.setState({ active: false });
} };
onClick() { onClick = () => {
if (!this.props.enabled) { if (!this.props.enabled) {
return; return;
} }
if (this.props.onClick) { if (this.props.onClick) {
this.props.onClick(); this.props.onClick();
} }
} };
render() { render() {
let style = { let style = {

View File

@ -1,12 +1,16 @@
import React, { Component } from 'react'; import React, { CSSProperties, PureComponent } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import shouldPureComponentUpdate from 'react-pure-render/function'; import { ActionCreators, LiftedAction } from 'redux-devtools';
import { ActionCreators } from 'redux-devtools'; import { Base16Theme } from 'redux-devtools-themes';
import { Action, Dispatch } from 'redux';
import LogMonitorButton from './LogMonitorButton'; import LogMonitorButton from './LogMonitorButton';
import { LogMonitorAction } from './actions';
import { LogMonitorState } from './reducers';
// eslint-disable-next-line @typescript-eslint/unbound-method
const { reset, rollback, commit, sweep } = ActionCreators; const { reset, rollback, commit, sweep } = ActionCreators;
const style = { const style: CSSProperties = {
textAlign: 'center', textAlign: 'center',
borderBottomWidth: 1, borderBottomWidth: 1,
borderBottomStyle: 'solid', borderBottomStyle: 'solid',
@ -16,37 +20,37 @@ const style = {
flexDirection: 'row', flexDirection: 'row',
}; };
export default class LogMonitorButtonBar extends Component { interface Props<S, A extends Action<unknown>> {
theme: Base16Theme;
dispatch: Dispatch<LogMonitorAction | LiftedAction<S, A, LogMonitorState>>;
hasStates: boolean;
hasSkippedActions: boolean;
}
export default class LogMonitorButtonBar<
S,
A extends Action<unknown>
> extends PureComponent<Props<S, A>> {
static propTypes = { static propTypes = {
dispatch: PropTypes.func, dispatch: PropTypes.func,
theme: PropTypes.object, theme: PropTypes.object,
}; };
shouldComponentUpdate = shouldPureComponentUpdate; handleRollback = () => {
constructor(props) {
super(props);
this.handleReset = this.handleReset.bind(this);
this.handleRollback = this.handleRollback.bind(this);
this.handleSweep = this.handleSweep.bind(this);
this.handleCommit = this.handleCommit.bind(this);
}
handleRollback() {
this.props.dispatch(rollback()); this.props.dispatch(rollback());
} };
handleSweep() { handleSweep = () => {
this.props.dispatch(sweep()); this.props.dispatch(sweep());
} };
handleCommit() { handleCommit = () => {
this.props.dispatch(commit()); this.props.dispatch(commit());
} };
handleReset() { handleReset = () => {
this.props.dispatch(reset()); this.props.dispatch(reset());
} };
render() { render() {
const { theme, hasStates, hasSkippedActions } = this.props; const { theme, hasStates, hasSkippedActions } = this.props;

View File

@ -1,10 +1,11 @@
import React, { Component } from 'react'; import React, { CSSProperties, MouseEventHandler, PureComponent } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import JSONTree from 'react-json-tree'; import JSONTree, { StylingValue } from 'react-json-tree';
import { Base16Theme } from 'redux-devtools-themes';
import { Action } from 'redux';
import LogMonitorEntryAction from './LogMonitorEntryAction'; import LogMonitorEntryAction from './LogMonitorEntryAction';
import shouldPureComponentUpdate from 'react-pure-render/function';
const styles = { const styles: { entry: CSSProperties; root: CSSProperties } = {
entry: { entry: {
display: 'block', display: 'block',
WebkitUserSelect: 'none', WebkitUserSelect: 'none',
@ -15,15 +16,40 @@ const styles = {
}, },
}; };
const getDeepItem = (data, path) => const getDeepItem = (data: any, path: (string | number)[]) =>
path.reduce((obj, key) => obj && obj[key], data); path.reduce((obj, key) => obj && obj[key], data);
const dataIsEqual = (data, previousData, keyPath) => { const dataIsEqual = (
data: any,
previousData: unknown,
keyPath: (string | number)[]
) => {
const path = [...keyPath].reverse().slice(1); const path = [...keyPath].reverse().slice(1);
return getDeepItem(data, path) === getDeepItem(previousData, path); return getDeepItem(data, path) === getDeepItem(previousData, path);
}; };
export default class LogMonitorEntry extends Component { interface Props<S, A extends Action<unknown>> {
theme: Base16Theme;
select: (state: any) => unknown;
action: A;
actionId: number;
state: S;
previousState: S | undefined;
collapsed: boolean;
inFuture: boolean;
selected: boolean;
error: string | undefined;
expandActionRoot: boolean;
expandStateRoot: boolean;
markStateDiff: boolean;
onActionClick: (id: number) => void;
onActionShiftClick: (id: number) => void;
}
export default class LogMonitorEntry<
S,
A extends Action<unknown>
> extends PureComponent<Props<S, A>> {
static propTypes = { static propTypes = {
state: PropTypes.object.isRequired, state: PropTypes.object.isRequired,
action: PropTypes.object.isRequired, action: PropTypes.object.isRequired,
@ -37,17 +63,10 @@ export default class LogMonitorEntry extends Component {
selected: PropTypes.bool, selected: PropTypes.bool,
expandActionRoot: PropTypes.bool, expandActionRoot: PropTypes.bool,
expandStateRoot: PropTypes.bool, expandStateRoot: PropTypes.bool,
previousState: PropTypes.object,
}; };
shouldComponentUpdate = shouldPureComponentUpdate; printState(state: S, error: string | undefined) {
constructor(props) {
super(props);
this.handleActionClick = this.handleActionClick.bind(this);
this.shouldExpandNode = this.shouldExpandNode.bind(this);
}
printState(state, error) {
let errorText = error; let errorText = error;
if (!errorText) { if (!errorText) {
try { try {
@ -59,7 +78,11 @@ export default class LogMonitorEntry extends Component {
typeof this.props.previousState !== 'undefined' typeof this.props.previousState !== 'undefined'
? this.props.select(this.props.previousState) ? this.props.select(this.props.previousState)
: undefined; : undefined;
const getValueStyle = ({ style }, nodeType, keyPath) => ({ const getValueStyle: StylingValue = (
{ style },
nodeType,
keyPath
) => ({
style: { style: {
...style, ...style,
backgroundColor: dataIsEqual(data, previousData, keyPath) backgroundColor: dataIsEqual(data, previousData, keyPath)
@ -67,7 +90,7 @@ export default class LogMonitorEntry extends Component {
: this.props.theme.base01, : this.props.theme.base01,
}, },
}); });
const getNestedNodeStyle = ({ style }, keyPath) => ({ const getNestedNodeStyle: StylingValue = ({ style }, keyPath) => ({
style: { style: {
...style, ...style,
...(keyPath.length > 1 ? {} : styles.root), ...(keyPath.length > 1 ? {} : styles.root),
@ -75,7 +98,6 @@ export default class LogMonitorEntry extends Component {
}); });
theme = { theme = {
extend: this.props.theme, extend: this.props.theme,
tree: styles.tree,
value: getValueStyle, value: getValueStyle,
nestedNode: getNestedNodeStyle, nestedNode: getNestedNodeStyle,
}; };
@ -112,7 +134,7 @@ export default class LogMonitorEntry extends Component {
); );
} }
handleActionClick(e) { handleActionClick: MouseEventHandler<HTMLDivElement> = (e) => {
const { actionId, onActionClick, onActionShiftClick } = this.props; const { actionId, onActionClick, onActionShiftClick } = this.props;
if (actionId > 0) { if (actionId > 0) {
if (e.shiftKey) { if (e.shiftKey) {
@ -121,11 +143,15 @@ export default class LogMonitorEntry extends Component {
onActionClick(actionId); onActionClick(actionId);
} }
} }
} };
shouldExpandNode(keyName, data, level) { shouldExpandNode = (
keyPath: (string | number)[],
data: any,
level: number
) => {
return this.props.expandStateRoot && level === 0; return this.props.expandStateRoot && level === 0;
} };
render() { render() {
const { const {

View File

@ -1,5 +1,7 @@
import React, { Component } from 'react'; import React, { Component, CSSProperties, MouseEventHandler } from 'react';
import JSONTree from 'react-json-tree'; import JSONTree from 'react-json-tree';
import { Base16Theme } from 'redux-devtools-themes';
import { Action } from 'redux';
const styles = { const styles = {
actionBar: { actionBar: {
@ -14,13 +16,19 @@ const styles = {
}, },
}; };
export default class LogMonitorAction extends Component { interface Props<A extends Action<unknown>> {
constructor(props) { theme: Base16Theme;
super(props); collapsed: boolean;
this.shouldExpandNode = this.shouldExpandNode.bind(this); action: A;
expandActionRoot: boolean;
onClick: MouseEventHandler<HTMLDivElement>;
style: CSSProperties;
} }
renderPayload(payload) { export default class LogMonitorAction<
A extends Action<unknown>
> extends Component<Props<A>> {
renderPayload(payload: Record<string, unknown>) {
return ( return (
<div <div
style={{ style={{
@ -43,9 +51,13 @@ export default class LogMonitorAction extends Component {
); );
} }
shouldExpandNode(keyName, data, level) { shouldExpandNode = (
keyPath: (string | number)[],
data: any,
level: number
) => {
return this.props.expandActionRoot && level === 0; return this.props.expandActionRoot && level === 0;
} };
render() { render() {
const { type, ...payload } = this.props.action; const { type, ...payload } = this.props.action;
@ -58,7 +70,7 @@ export default class LogMonitorAction extends Component {
}} }}
> >
<div style={styles.actionBar} onClick={this.props.onClick}> <div style={styles.actionBar} onClick={this.props.onClick}>
{type !== null && type.toString()} {type !== null && (type as string).toString()}
</div> </div>
{!this.props.collapsed ? this.renderPayload(payload) : ''} {!this.props.collapsed ? this.renderPayload(payload) : ''}
</div> </div>

View File

@ -1,9 +1,31 @@
import React, { Component } from 'react'; import React, { PureComponent } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Action } from 'redux';
import { PerformAction } from 'redux-devtools';
import { Base16Theme } from 'redux-devtools-themes';
import LogMonitorEntry from './LogMonitorEntry'; import LogMonitorEntry from './LogMonitorEntry';
import shouldPureComponentUpdate from 'react-pure-render/function';
export default class LogMonitorEntryList extends Component { interface Props<S, A extends Action<unknown>> {
actionsById: { [actionId: number]: PerformAction<A> };
computedStates: { state: S; error?: string }[];
stagedActionIds: number[];
skippedActionIds: number[];
currentStateIndex: number;
consecutiveToggleStartId: number | null | undefined;
select: (state: S) => unknown;
onActionClick: (id: number) => void;
theme: Base16Theme;
expandActionRoot: boolean;
expandStateRoot: boolean;
markStateDiff: boolean;
onActionShiftClick: (id: number) => void;
}
export default class LogMonitorEntryList<
S,
A extends Action<unknown>
> extends PureComponent<Props<S, A>> {
static propTypes = { static propTypes = {
actionsById: PropTypes.object, actionsById: PropTypes.object,
computedStates: PropTypes.array, computedStates: PropTypes.array,
@ -19,8 +41,6 @@ export default class LogMonitorEntryList extends Component {
expandStateRoot: PropTypes.bool, expandStateRoot: PropTypes.bool,
}; };
shouldComponentUpdate = shouldPureComponentUpdate;
render() { render() {
const elements = []; const elements = [];
const { const {

View File

@ -1,11 +0,0 @@
export const UPDATE_SCROLL_TOP =
'@@redux-devtools-log-monitor/UPDATE_SCROLL_TOP';
export function updateScrollTop(scrollTop) {
return { type: UPDATE_SCROLL_TOP, scrollTop };
}
export const START_CONSECUTIVE_TOGGLE =
'@@redux-devtools-log-monitor/START_CONSECUTIVE_TOGGLE';
export function startConsecutiveToggle(id) {
return { type: START_CONSECUTIVE_TOGGLE, id };
}

View File

@ -0,0 +1,25 @@
export const UPDATE_SCROLL_TOP =
'@@redux-devtools-log-monitor/UPDATE_SCROLL_TOP';
interface UpdateScrollTopAction {
type: typeof UPDATE_SCROLL_TOP;
scrollTop: number;
}
export function updateScrollTop(scrollTop: number): UpdateScrollTopAction {
return { type: UPDATE_SCROLL_TOP, scrollTop };
}
export const START_CONSECUTIVE_TOGGLE =
'@@redux-devtools-log-monitor/START_CONSECUTIVE_TOGGLE';
interface StartConsecutiveToggleAction {
type: typeof START_CONSECUTIVE_TOGGLE;
id: number | null;
}
export function startConsecutiveToggle(
id: number | null
): StartConsecutiveToggleAction {
return { type: START_CONSECUTIVE_TOGGLE, id };
}
export type LogMonitorAction =
| UpdateScrollTopAction
| StartConsecutiveToggleAction;

View File

@ -1,9 +1,9 @@
export default function (hexColor, lightness) { export default function (hexColor: string, lightness: number) {
let hex = String(hexColor).replace(/[^0-9a-f]/gi, ''); let hex = String(hexColor).replace(/[^0-9a-f]/gi, '');
if (hex.length < 6) { if (hex.length < 6) {
hex = hex.replace(/(.)/g, '$1$1'); hex = hex.replace(/(.)/g, '$1$1');
} }
let lum = lightness || 0; const lum = lightness || 0;
let rgb = '#'; let rgb = '#';
let c; let c;

View File

@ -1 +0,0 @@
export default from './LogMonitor';

View File

@ -0,0 +1,2 @@
import LogMonitor from './LogMonitor';
export default LogMonitor;

View File

@ -1,24 +0,0 @@
import { UPDATE_SCROLL_TOP, START_CONSECUTIVE_TOGGLE } from './actions';
function initialScrollTop(props, state = 0, action) {
if (!props.preserveScrollTop) {
return 0;
}
return action.type === UPDATE_SCROLL_TOP ? action.scrollTop : state;
}
function startConsecutiveToggle(props, state, action) {
return action.type === START_CONSECUTIVE_TOGGLE ? action.id : state;
}
export default function reducer(props, state = {}, action) {
return {
initialScrollTop: initialScrollTop(props, state.initialScrollTop, action),
consecutiveToggleStartId: startConsecutiveToggle(
props,
state.consecutiveToggleStartId,
action
),
};
}

View File

@ -0,0 +1,47 @@
import { Action } from 'redux';
import {
UPDATE_SCROLL_TOP,
START_CONSECUTIVE_TOGGLE,
LogMonitorAction,
} from './actions';
import { LogMonitorProps } from './LogMonitor';
function initialScrollTop<S, A extends Action<unknown>>(
props: LogMonitorProps<S, A>,
state = 0,
action: LogMonitorAction
) {
if (!props.preserveScrollTop) {
return 0;
}
return action.type === UPDATE_SCROLL_TOP ? action.scrollTop : state;
}
function startConsecutiveToggle<S, A extends Action<unknown>>(
props: LogMonitorProps<S, A>,
state: number | null | undefined,
action: LogMonitorAction
) {
return action.type === START_CONSECUTIVE_TOGGLE ? action.id : state;
}
export interface LogMonitorState {
initialScrollTop: number;
consecutiveToggleStartId: number | null | undefined;
}
export default function reducer<S, A extends Action<unknown>>(
props: LogMonitorProps<S, A>,
state: Partial<LogMonitorState> = {},
action: LogMonitorAction
): LogMonitorState {
return {
initialScrollTop: initialScrollTop(props, state.initialScrollTop, action),
consecutiveToggleStartId: startConsecutiveToggle(
props,
state.consecutiveToggleStartId,
action
),
};
}

View File

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.react.base.json",
"compilerOptions": {
"outDir": "lib"
},
"include": ["src"]
}

View File

@ -3045,7 +3045,7 @@
dependencies: dependencies:
"@babel/types" "^7.3.0" "@babel/types" "^7.3.0"
"@types/base16@^1.0.2": "@types/base16@*", "@types/base16@^1.0.2":
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/@types/base16/-/base16-1.0.2.tgz#eb3a07db52309bfefb9ba010dfdb3c0784971f65" resolved "https://registry.yarnpkg.com/@types/base16/-/base16-1.0.2.tgz#eb3a07db52309bfefb9ba010dfdb3c0784971f65"
integrity sha512-oYO/U4VD1DavwrKuCSQWdLG+5K22SLPem2OQaHmFcQuwHoVeGC+JGVRji2MUqZUAIQZHEonOeVfAX09hYiLsdg== integrity sha512-oYO/U4VD1DavwrKuCSQWdLG+5K22SLPem2OQaHmFcQuwHoVeGC+JGVRji2MUqZUAIQZHEonOeVfAX09hYiLsdg==
@ -3340,6 +3340,13 @@
"@types/prop-types" "*" "@types/prop-types" "*"
csstype "^3.0.2" csstype "^3.0.2"
"@types/redux-devtools-themes@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/redux-devtools-themes/-/redux-devtools-themes-1.0.0.tgz#4d22d3e8be499fc7eec220e020b0640d4bfb17bd"
integrity sha512-ul3x0MYM5Nzj57Fh9wINyHFne8vZL04RC4nWAUWLYcL105vHoa/oJyopuKOrQmqVmhqmDiL4c9FfLbUmIB7TWQ==
dependencies:
"@types/base16" "*"
"@types/serve-static@*": "@types/serve-static@*":
version "1.13.5" version "1.13.5"
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53"