From c7b0c7aa6e09f46a36b382ae3ec8e38bd48aeb28 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Sun, 30 Aug 2020 17:49:06 -0400 Subject: [PATCH] feat(redux-devtools-inspector): convert to TypeScript (#623) * stash * stash * stash * stash * preset * @types/dragula --- package.json | 5 + packages/react-base16-styling/src/index.ts | 6 +- packages/react-base16-styling/src/types.ts | 2 +- packages/react-dock/demo/src/App.tsx | 2 +- packages/react-dock/webpack.config.ts | 10 +- packages/redux-devtools-inspector/.babelrc | 10 +- .../redux-devtools-inspector/.eslintignore | 1 + .../redux-devtools-inspector/.eslintrc.js | 29 ++ packages/redux-devtools-inspector/.npmignore | 8 - .../demo/config/tsconfig.json | 7 + .../config/webpack.config.ts} | 52 ++-- .../demo/src/js/{DemoApp.jsx => DemoApp.tsx} | 131 ++++++--- .../src/js/{DevTools.jsx => DevTools.tsx} | 12 +- .../demo/src/js/getOptions.js | 11 - .../demo/src/js/getOptions.ts | 20 ++ .../demo/src/js/{index.js => index.tsx} | 29 +- .../demo/src/js/reducers.js | 148 ---------- .../demo/src/js/reducers.ts | 267 ++++++++++++++++++ .../demo/tsconfig.json | 7 + .../redux-devtools-inspector/jest.config.js | 3 + .../redux-devtools-inspector/package.json | 122 ++++---- .../src/.noderequirer.json | 3 - .../src/{ActionList.jsx => ActionList.tsx} | 73 +++-- ...ionListHeader.jsx => ActionListHeader.tsx} | 32 ++- .../{ActionListRow.jsx => ActionListRow.tsx} | 74 +++-- .../{ActionPreview.jsx => ActionPreview.tsx} | 78 ++++- ...viewHeader.jsx => ActionPreviewHeader.tsx} | 29 +- ...oolsInspector.js => DevtoolsInspector.tsx} | 184 +++++++++--- .../src/RightSlider.jsx | 21 -- .../src/RightSlider.tsx | 37 +++ ...ateDiffPatcher.js => createDiffPatcher.ts} | 23 +- .../redux-devtools-inspector/src/index.js | 1 - .../redux-devtools-inspector/src/index.ts | 2 + .../redux-devtools-inspector/src/redux.js | 28 -- .../redux-devtools-inspector/src/redux.ts | 55 ++++ .../src/tabs/ActionTab.jsx | 27 -- .../src/tabs/ActionTab.tsx | 43 +++ .../src/tabs/DiffTab.jsx | 24 -- .../src/tabs/DiffTab.tsx | 42 +++ .../src/tabs/{JSONDiff.jsx => JSONDiff.tsx} | 48 +++- .../src/tabs/{StateTab.jsx => StateTab.tsx} | 18 +- .../{getItemString.js => getItemString.tsx} | 42 +-- ...etJsonTreeTheme.js => getJsonTreeTheme.ts} | 7 +- .../src/themes/{index.js => index.ts} | 0 .../src/themes/{inspector.js => inspector.ts} | 0 ...FromTheme.js => createStylingFromTheme.ts} | 16 +- .../src/utils/deepMap.js | 30 -- ...InspectedState.js => getInspectedState.ts} | 22 +- .../utils/{isIterable.js => isIterable.ts} | 2 +- .../redux-devtools-inspector/tsconfig.json | 8 + yarn.lock | 154 +++++++--- 51 files changed, 1375 insertions(+), 630 deletions(-) create mode 100644 packages/redux-devtools-inspector/.eslintignore create mode 100644 packages/redux-devtools-inspector/.eslintrc.js delete mode 100644 packages/redux-devtools-inspector/.npmignore create mode 100644 packages/redux-devtools-inspector/demo/config/tsconfig.json rename packages/redux-devtools-inspector/{webpack.config.js => demo/config/webpack.config.ts} (62%) rename packages/redux-devtools-inspector/demo/src/js/{DemoApp.jsx => DemoApp.tsx} (67%) rename packages/redux-devtools-inspector/demo/src/js/{DevTools.jsx => DevTools.tsx} (74%) delete mode 100644 packages/redux-devtools-inspector/demo/src/js/getOptions.js create mode 100644 packages/redux-devtools-inspector/demo/src/js/getOptions.ts rename packages/redux-devtools-inspector/demo/src/js/{index.js => index.tsx} (68%) delete mode 100644 packages/redux-devtools-inspector/demo/src/js/reducers.js create mode 100644 packages/redux-devtools-inspector/demo/src/js/reducers.ts create mode 100644 packages/redux-devtools-inspector/demo/tsconfig.json create mode 100644 packages/redux-devtools-inspector/jest.config.js delete mode 100644 packages/redux-devtools-inspector/src/.noderequirer.json rename packages/redux-devtools-inspector/src/{ActionList.jsx => ActionList.tsx} (63%) rename packages/redux-devtools-inspector/src/{ActionListHeader.jsx => ActionListHeader.tsx} (55%) rename packages/redux-devtools-inspector/src/{ActionListRow.jsx => ActionListRow.tsx} (69%) rename packages/redux-devtools-inspector/src/{ActionPreview.jsx => ActionPreview.tsx} (52%) rename packages/redux-devtools-inspector/src/{ActionPreviewHeader.jsx => ActionPreviewHeader.tsx} (62%) rename packages/redux-devtools-inspector/src/{DevtoolsInspector.js => DevtoolsInspector.tsx} (64%) delete mode 100644 packages/redux-devtools-inspector/src/RightSlider.jsx create mode 100644 packages/redux-devtools-inspector/src/RightSlider.tsx rename packages/redux-devtools-inspector/src/{createDiffPatcher.js => createDiffPatcher.ts} (50%) delete mode 100644 packages/redux-devtools-inspector/src/index.js create mode 100644 packages/redux-devtools-inspector/src/index.ts delete mode 100644 packages/redux-devtools-inspector/src/redux.js create mode 100644 packages/redux-devtools-inspector/src/redux.ts delete mode 100644 packages/redux-devtools-inspector/src/tabs/ActionTab.jsx create mode 100644 packages/redux-devtools-inspector/src/tabs/ActionTab.tsx delete mode 100644 packages/redux-devtools-inspector/src/tabs/DiffTab.jsx create mode 100644 packages/redux-devtools-inspector/src/tabs/DiffTab.tsx rename packages/redux-devtools-inspector/src/tabs/{JSONDiff.jsx => JSONDiff.tsx} (74%) rename packages/redux-devtools-inspector/src/tabs/{StateTab.jsx => StateTab.tsx} (52%) rename packages/redux-devtools-inspector/src/tabs/{getItemString.js => getItemString.tsx} (65%) rename packages/redux-devtools-inspector/src/tabs/{getJsonTreeTheme.js => getJsonTreeTheme.ts} (65%) rename packages/redux-devtools-inspector/src/themes/{index.js => index.ts} (100%) rename packages/redux-devtools-inspector/src/themes/{inspector.js => inspector.ts} (100%) rename packages/redux-devtools-inspector/src/utils/{createStylingFromTheme.js => createStylingFromTheme.ts} (95%) delete mode 100644 packages/redux-devtools-inspector/src/utils/deepMap.js rename packages/redux-devtools-inspector/src/utils/{getInspectedState.js => getInspectedState.ts} (61%) rename packages/redux-devtools-inspector/src/utils/{isIterable.js => isIterable.ts} (76%) create mode 100644 packages/redux-devtools-inspector/tsconfig.json diff --git a/package.json b/package.json index 026a3bf7..41b77f38 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "@babel/cli": "^7.10.5", "@babel/core": "^7.11.1", "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-transform-runtime": "^7.11.0", "@babel/preset-env": "^7.11.0", "@babel/preset-typescript": "^7.10.4", "@types/jest": "^26.0.9", @@ -14,12 +15,16 @@ "@typescript-eslint/parser": "^3.9.0", "babel-eslint": "^10.1.0", "babel-loader": "^8.1.0", + "clean-webpack-plugin": "^3.0.0", + "cross-env": "^7.0.2", "eslint": "^7.6.0", "eslint-config-prettier": "^6.11.0", "eslint-plugin-babel": "^5.3.1", "eslint-plugin-jest": "^23.20.0", "eslint-plugin-prettier": "^3.1.4", "eslint-plugin-react": "^7.20.5", + "fork-ts-checker-webpack-plugin": "^5.1.0", + "html-webpack-plugin": "^4.3.0", "jest": "^26.2.2", "lerna": "^3.22.1", "prettier": "^2.0.5", diff --git a/packages/react-base16-styling/src/index.ts b/packages/react-base16-styling/src/index.ts index 8f65c04d..43c4e27f 100644 --- a/packages/react-base16-styling/src/index.ts +++ b/packages/react-base16-styling/src/index.ts @@ -142,7 +142,7 @@ const mergeStylings = ( const getStylingByKeys = ( mergedStyling: StylingConfig, - keys: string | string[], + keys: (string | false | undefined) | (string | false | undefined)[], ...args: any[] ): Styling => { if (keys === null) { @@ -153,7 +153,9 @@ const getStylingByKeys = ( keys = [keys]; } - const styles = keys.map((key) => mergedStyling[key]).filter(Boolean); + const styles = keys + .map((key) => mergedStyling[key as string]) + .filter(Boolean); const props = styles.reduce( (obj, s) => { diff --git a/packages/react-base16-styling/src/types.ts b/packages/react-base16-styling/src/types.ts index 7226b163..6ec9dc98 100644 --- a/packages/react-base16-styling/src/types.ts +++ b/packages/react-base16-styling/src/types.ts @@ -27,6 +27,6 @@ export type StylingConfig = { export type Theme = string | Base16Theme | StylingConfig; export type StylingFunction = ( - keys: string | string[], + keys: (string | false | undefined) | (string | false | undefined)[], ...rest: any[] ) => Styling; diff --git a/packages/react-dock/demo/src/App.tsx b/packages/react-dock/demo/src/App.tsx index 68e76708..e5a06ed1 100644 --- a/packages/react-dock/demo/src/App.tsx +++ b/packages/react-dock/demo/src/App.tsx @@ -1,5 +1,5 @@ -import React, { Component } from 'react'; import { hot } from 'react-hot-loader/root'; +import React, { Component } from 'react'; import Button from 'react-bootstrap/Button'; import Form from 'react-bootstrap/Form'; import { BsX } from 'react-icons/bs'; diff --git a/packages/react-dock/webpack.config.ts b/packages/react-dock/webpack.config.ts index 6bb05aae..4207ba56 100644 --- a/packages/react-dock/webpack.config.ts +++ b/packages/react-dock/webpack.config.ts @@ -5,7 +5,6 @@ const isProduction = process.env.NODE_ENV === 'production'; module.exports = { mode: isProduction ? 'production' : 'development', - devtool: 'eval', entry: isProduction ? ['./demo/src/index'] : [ @@ -18,10 +17,6 @@ module.exports = { filename: 'bundle.js', publicPath: isProduction ? 'static/' : '/static/', }, - plugins: isProduction ? [] : [new webpack.HotModuleReplacementPlugin()], - resolve: { - extensions: ['.js', '.jsx', '.ts', '.tsx'], - }, module: { rules: [ { @@ -34,6 +29,10 @@ module.exports = { }, ], }, + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + plugins: isProduction ? [] : [new webpack.HotModuleReplacementPlugin()], devServer: isProduction ? null : { @@ -46,4 +45,5 @@ module.exports = { }, historyApiFallback: true, }, + devtool: 'eval-source-map', }; diff --git a/packages/redux-devtools-inspector/.babelrc b/packages/redux-devtools-inspector/.babelrc index 530ac9c9..7a337702 100644 --- a/packages/redux-devtools-inspector/.babelrc +++ b/packages/redux-devtools-inspector/.babelrc @@ -1,9 +1,11 @@ { - "presets": ["@babel/preset-env", "@babel/preset-react"], + "presets": [ + "@babel/preset-env", + "@babel/preset-react", + "@babel/preset-typescript" + ], "plugins": [ - "@babel/plugin-transform-runtime", "@babel/plugin-proposal-class-properties", - "@babel/plugin-proposal-export-default-from", - "@babel/plugin-proposal-do-expressions" + "@babel/plugin-transform-runtime" ] } diff --git a/packages/redux-devtools-inspector/.eslintignore b/packages/redux-devtools-inspector/.eslintignore new file mode 100644 index 00000000..a65b4177 --- /dev/null +++ b/packages/redux-devtools-inspector/.eslintignore @@ -0,0 +1 @@ +lib diff --git a/packages/redux-devtools-inspector/.eslintrc.js b/packages/redux-devtools-inspector/.eslintrc.js new file mode 100644 index 00000000..7c9be3fd --- /dev/null +++ b/packages/redux-devtools-inspector/.eslintrc.js @@ -0,0 +1,29 @@ +module.exports = { + extends: '../../.eslintrc', + overrides: [ + { + files: ['*.ts', '*.tsx'], + extends: '../../eslintrc.ts.react.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + }, + { + files: ['demo/**/*.ts', 'demo/**/*.tsx'], + extends: '../../eslintrc.ts.react.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./demo/tsconfig.json'], + }, + }, + { + files: ['demo/config/webpack.config.ts'], + extends: '../../eslintrc.ts.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./demo/config/tsconfig.json'], + }, + }, + ], +}; diff --git a/packages/redux-devtools-inspector/.npmignore b/packages/redux-devtools-inspector/.npmignore deleted file mode 100644 index 7e7ce1e8..00000000 --- a/packages/redux-devtools-inspector/.npmignore +++ /dev/null @@ -1,8 +0,0 @@ -static -src -demo -.* -webpack.config.js -index.html -*.gif -*.png diff --git a/packages/redux-devtools-inspector/demo/config/tsconfig.json b/packages/redux-devtools-inspector/demo/config/tsconfig.json new file mode 100644 index 00000000..7fd5a7b8 --- /dev/null +++ b/packages/redux-devtools-inspector/demo/config/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "resolveJsonModule": true + }, + "include": ["webpack.config.ts"] +} diff --git a/packages/redux-devtools-inspector/webpack.config.js b/packages/redux-devtools-inspector/demo/config/webpack.config.ts similarity index 62% rename from packages/redux-devtools-inspector/webpack.config.js rename to packages/redux-devtools-inspector/demo/config/webpack.config.ts index 6247c434..c7b08800 100644 --- a/packages/redux-devtools-inspector/webpack.config.js +++ b/packages/redux-devtools-inspector/demo/config/webpack.config.ts @@ -1,15 +1,14 @@ -var path = require('path'); -var webpack = require('webpack'); -var HtmlWebpackPlugin = require('html-webpack-plugin'); -var { CleanWebpackPlugin } = require('clean-webpack-plugin'); +import * as path from 'path'; +import * as webpack from 'webpack'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import { CleanWebpackPlugin } from 'clean-webpack-plugin'; +import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; +import pkg from '../../package.json'; -var pkg = require('./package.json'); - -var isProduction = process.env.NODE_ENV === 'production'; +const isProduction = process.env.NODE_ENV === 'production'; module.exports = { mode: process.env.NODE_ENV || 'development', - devtool: 'eval-source-map', entry: isProduction ? ['./demo/src/js/index'] : [ @@ -21,6 +20,21 @@ module.exports = { path: path.join(__dirname, 'demo/dist'), filename: 'js/bundle.js', }, + module: { + rules: [ + { + test: /\.(js|ts)x?$/, + loader: 'babel-loader', + include: [ + path.join(__dirname, '../../src'), + path.join(__dirname, '../src/js'), + ], + }, + ], + }, + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ @@ -28,27 +42,12 @@ module.exports = { template: 'demo/src/index.html', package: pkg, }), - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify(process.env.NODE_ENV), + new ForkTsCheckerWebpackPlugin({ + typescript: { + configFile: 'demo/tsconfig.json', }, }), ].concat(isProduction ? [] : [new webpack.HotModuleReplacementPlugin()]), - resolve: { - extensions: ['*', '.js', '.jsx'], - }, - module: { - rules: [ - { - test: /\.jsx?$/, - loader: 'babel-loader', - include: [ - path.join(__dirname, 'src'), - path.join(__dirname, 'demo/src/js'), - ], - }, - ], - }, devServer: isProduction ? {} : { @@ -61,4 +60,5 @@ module.exports = { }, historyApiFallback: true, }, + devtool: 'eval-source-map', }; diff --git a/packages/redux-devtools-inspector/demo/src/js/DemoApp.jsx b/packages/redux-devtools-inspector/demo/src/js/DemoApp.tsx similarity index 67% rename from packages/redux-devtools-inspector/demo/src/js/DemoApp.jsx rename to packages/redux-devtools-inspector/demo/src/js/DemoApp.tsx index af3103ab..50061058 100644 --- a/packages/redux-devtools-inspector/demo/src/js/DemoApp.jsx +++ b/packages/redux-devtools-inspector/demo/src/js/DemoApp.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { CSSProperties } from 'react'; import { connect } from 'react-redux'; import pkg from '../../../package.json'; import Button from 'react-bootstrap/Button'; @@ -8,12 +8,45 @@ import FormLabel from 'react-bootstrap/FormLabel'; import Form from 'react-bootstrap/Form'; import Col from 'react-bootstrap/Col'; import InputGroup from 'react-bootstrap/InputGroup'; +import Row from 'react-bootstrap/Row'; import * as base16 from 'base16'; -import * as inspectorThemes from '../../../src/themes'; -import getOptions from './getOptions'; import { push as pushRoute } from 'connected-react-router'; +import { Path } from 'history'; +import * as inspectorThemes from '../../../src/themes'; +import getOptions, { Options } from './getOptions'; +import { + AddFunctionAction, + AddHugeObjectAction, + AddImmutableMapAction, + AddIteratorAction, + AddNativeMapAction, + AddRecursiveAction, + AddSymbolAction, + ChangeImmutableNestedAction, + ChangeNestedAction, + DemoAppState, + HugePayloadAction, + IncrementAction, + PopAction, + PushAction, + PushHugeArrayAction, + ReplaceAction, + ShuffleArrayAction, + TimeoutUpdateAction, + ToggleTimeoutUpdateAction, +} from './reducers'; -const styles = { +const styles: { + wrapper: CSSProperties; + header: CSSProperties; + content: CSSProperties; + buttons: CSSProperties; + muted: CSSProperties; + button: CSSProperties; + links: CSSProperties; + link: CSSProperties; + input: CSSProperties; +} = { wrapper: { height: '100vh', width: '80%', @@ -57,18 +90,21 @@ const styles = { const themeOptions = [ ...Object.keys(inspectorThemes).map((value) => ({ value, - label: inspectorThemes[value].scheme, + label: inspectorThemes[value as keyof typeof inspectorThemes].scheme, })), null, ...Object.keys(base16) - .map((value) => ({ value, label: base16[value].scheme })) + .map((value) => ({ + value, + label: base16[value as keyof typeof base16].scheme, + })) .filter((opt) => opt.label), ]; const ROOT = process.env.NODE_ENV === 'production' ? '/redux-devtools-inspector/' : '/'; -function buildUrl(options) { +function buildUrl(options: Options) { return ( `${ROOT}?` + [ @@ -82,7 +118,32 @@ function buildUrl(options) { ); } -class DemoApp extends React.Component { +interface Props + extends Omit { + toggleTimeoutUpdate: (timeoutUpdateEnabled: boolean) => void; + timeoutUpdate: () => void; + increment: () => void; + push: () => void; + pop: () => void; + replace: () => void; + changeNested: () => void; + pushHugeArray: () => void; + addIterator: () => void; + addHugeObject: () => void; + addRecursive: () => void; + addNativeMap: () => void; + addImmutableMap: () => void; + changeImmutableNested: () => void; + hugePayload: () => void; + addFunction: () => void; + addSymbol: () => void; + shuffleArray: () => void; + pushRoute: (path: Path) => void; +} + +class DemoApp extends React.Component { + timeout?: number; + render() { const options = getOptions(this.props.router.location); @@ -98,8 +159,8 @@ class DemoApp extends React.Component {
-
- + + Theme: @@ -115,7 +176,7 @@ class DemoApp extends React.Component {
); +ActionListHeader.propTypes = { + styling: PropTypes.func.isRequired, + onSearch: PropTypes.func.isRequired, + onCommit: PropTypes.func.isRequired, + onSweep: PropTypes.func.isRequired, + hideMainButtons: PropTypes.bool, + hasSkippedActions: PropTypes.bool.isRequired, + hasStagedActions: PropTypes.bool.isRequired, +}; + export default ActionListHeader; diff --git a/packages/redux-devtools-inspector/src/ActionListRow.jsx b/packages/redux-devtools-inspector/src/ActionListRow.tsx similarity index 69% rename from packages/redux-devtools-inspector/src/ActionListRow.jsx rename to packages/redux-devtools-inspector/src/ActionListRow.tsx index a9caf7df..16c17d1d 100644 --- a/packages/redux-devtools-inspector/src/ActionListRow.jsx +++ b/packages/redux-devtools-inspector/src/ActionListRow.tsx @@ -1,15 +1,40 @@ -import React, { Component } from 'react'; -import { PropTypes } from 'prop-types'; -import shouldPureComponentUpdate from 'react-pure-render/function'; +import React, { MouseEvent, MouseEventHandler, PureComponent } from 'react'; +import PropTypes from 'prop-types'; import dateformat from 'dateformat'; import debounce from 'lodash.debounce'; +import { StylingFunction } from 'react-base16-styling'; +import { Action } from 'redux'; import RightSlider from './RightSlider'; const BUTTON_SKIP = 'Skip'; const BUTTON_JUMP = 'Jump'; -export default class ActionListRow extends Component { - state = { hover: false }; +type Button = typeof BUTTON_SKIP | typeof BUTTON_JUMP; + +interface Props> { + styling: StylingFunction; + actionId: number; + isInitAction: boolean; + isSelected: boolean; + isInFuture: boolean; + onSelect: MouseEventHandler; + timestamps: { current: number; previous: number }; + action: A; + onToggleClick: () => void; + onJumpClick: () => void; + onCommitClick: () => void; + hideActionButtons: boolean | undefined; + isSkipped: boolean; +} + +interface State { + hover: boolean; +} + +export default class ActionListRow< + A extends Action +> extends PureComponent, State> { + state: State = { hover: false }; static propTypes = { styling: PropTypes.func.isRequired, @@ -25,8 +50,6 @@ export default class ActionListRow extends Component { isSkipped: PropTypes.bool.isRequired, }; - shouldComponentUpdate = shouldPureComponentUpdate; - render() { const { styling, @@ -44,18 +67,26 @@ export default class ActionListRow extends Component { const timeDelta = timestamps.current - timestamps.previous; const showButtons = (hover && !isInitAction) || isSkipped; - const isButtonSelected = (btn) => btn === BUTTON_SKIP && isSkipped; + const isButtonSelected = (btn: Button) => btn === BUTTON_SKIP && isSkipped; let actionType = action.type; if (typeof actionType === 'undefined') actionType = ''; else if (actionType === null) actionType = ''; - else actionType = actionType.toString() || ''; + else actionType = (actionType as string).toString() || ''; return (
+ } + onMouseLeave={ + (!hideActionButtons && this.handleMouseLeave) as MouseEventHandler< + HTMLDivElement + > + } onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseEnter} data-id={actionId} @@ -76,7 +107,7 @@ export default class ActionListRow extends Component { isSkipped && 'actionListItemNameSkipped', ])} > - {actionType} + {actionType as string}
{hideActionButtons ? ( @@ -103,12 +134,12 @@ export default class ActionListRow extends Component {
- {[BUTTON_JUMP, BUTTON_SKIP].map( + {([BUTTON_JUMP, BUTTON_SKIP] as const).map( (btn) => (!isInitAction || btn !== BUTTON_SKIP) && (
this.handleButtonClick(btn, e)} {...styling( [ 'selectorButton', @@ -131,7 +162,7 @@ export default class ActionListRow extends Component { ); } - handleButtonClick(btn, e) { + handleButtonClick(btn: Button, e: MouseEvent) { e.stopPropagation(); switch (btn) { @@ -144,8 +175,8 @@ export default class ActionListRow extends Component { } } - handleMouseEnter = (e) => { - if (this.hover) return; + handleMouseEnter = (e: MouseEvent) => { + if (this.state.hover) return; this.handleMouseLeave.cancel(); this.handleMouseEnterDebounced(e.buttons); }; @@ -160,8 +191,13 @@ export default class ActionListRow extends Component { if (this.state.hover) this.setState({ hover: false }); }, 100); - handleMouseDown = (e) => { - if (e.target.className.indexOf('selectorButton') === 0) return; + handleMouseDown = (e: MouseEvent) => { + if ( + ((e.target as unknown) as { className: string[] }).className.indexOf( + 'selectorButton' + ) === 0 + ) + return; this.handleMouseLeave(); }; } diff --git a/packages/redux-devtools-inspector/src/ActionPreview.jsx b/packages/redux-devtools-inspector/src/ActionPreview.tsx similarity index 52% rename from packages/redux-devtools-inspector/src/ActionPreview.jsx rename to packages/redux-devtools-inspector/src/ActionPreview.tsx index 8de51b1c..37c7d887 100644 --- a/packages/redux-devtools-inspector/src/ActionPreview.jsx +++ b/packages/redux-devtools-inspector/src/ActionPreview.tsx @@ -1,10 +1,43 @@ import React, { Component } from 'react'; -import { DEFAULT_STATE } from './redux'; +import { Base16Theme } from 'redux-devtools-themes'; +import { Action } from 'redux'; +import { StylingFunction } from 'react-base16-styling'; +import { PerformAction } from 'redux-devtools'; +import { Delta } from 'jsondiffpatch'; +import { DEFAULT_STATE, DevtoolsInspectorState } from './redux'; import ActionPreviewHeader from './ActionPreviewHeader'; import DiffTab from './tabs/DiffTab'; import StateTab from './tabs/StateTab'; import ActionTab from './tabs/ActionTab'; +export interface TabComponentProps> { + labelRenderer: ( + keyPath: (string | number)[], + nodeType: string, + expanded: boolean, + expandable: boolean + ) => React.ReactNode; + styling: StylingFunction; + computedStates: { state: S; error?: string }[]; + actions: { [actionId: number]: PerformAction }; + selectedActionId: number | null; + startActionId: number | null; + base16Theme: Base16Theme; + invertTheme: boolean; + isWideLayout: boolean; + dataTypeKey: string | undefined; + delta: Delta | null | undefined | false; + action: A; + nextState: S; + monitorState: DevtoolsInspectorState; + updateMonitorState: (monitorState: Partial) => void; +} + +export interface Tab> { + name: string; + component: React.ComponentType>; +} + const DEFAULT_TABS = [ { name: 'Action', @@ -20,7 +53,32 @@ const DEFAULT_TABS = [ }, ]; -class ActionPreview extends Component { +interface Props> { + base16Theme: Base16Theme; + invertTheme: boolean; + isWideLayout: boolean; + tabs: Tab[] | ((tabs: Tab[]) => Tab[]); + tabName: string; + delta: Delta | null | undefined | false; + error: string | undefined; + nextState: S; + computedStates: { state: S; error?: string }[]; + action: A; + actions: { [actionId: number]: PerformAction }; + selectedActionId: number | null; + startActionId: number | null; + dataTypeKey: string | undefined; + monitorState: DevtoolsInspectorState; + updateMonitorState: (monitorState: Partial) => void; + styling: StylingFunction; + onInspectPath: (path: (string | number)[]) => void; + inspectedPath: (string | number)[]; + onSelectTab: (tabName: string) => void; +} + +class ActionPreview> extends Component< + Props +> { static defaultProps = { tabName: DEFAULT_STATE.tabName, }; @@ -49,21 +107,21 @@ class ActionPreview extends Component { updateMonitorState, } = this.props; - const renderedTabs = + const renderedTabs: Tab[] = typeof tabs === 'function' - ? tabs(DEFAULT_TABS) + ? tabs(DEFAULT_TABS as Tab[]) : tabs ? tabs - : DEFAULT_TABS; + : (DEFAULT_TABS as Tab[]); const { component: TabComponent } = renderedTabs.find((tab) => tab.name === tabName) || - renderedTabs.find((tab) => tab.name === DEFAULT_STATE.tabName); + renderedTabs.find((tab) => tab.name === DEFAULT_STATE.tabName)!; return (
>[]} {...{ styling, inspectedPath, onInspectPath, tabName, onSelectTab }} /> {!error && ( @@ -94,7 +152,11 @@ class ActionPreview extends Component { ); } - labelRenderer = ([key, ...rest], nodeType, expanded) => { + labelRenderer = ( + [key, ...rest]: (string | number)[], + nodeType: string, + expanded: boolean + ) => { const { styling, onInspectPath, inspectedPath } = this.props; return ( diff --git a/packages/redux-devtools-inspector/src/ActionPreviewHeader.jsx b/packages/redux-devtools-inspector/src/ActionPreviewHeader.tsx similarity index 62% rename from packages/redux-devtools-inspector/src/ActionPreviewHeader.jsx rename to packages/redux-devtools-inspector/src/ActionPreviewHeader.tsx index 1b65c579..ed930d5a 100644 --- a/packages/redux-devtools-inspector/src/ActionPreviewHeader.jsx +++ b/packages/redux-devtools-inspector/src/ActionPreviewHeader.tsx @@ -1,6 +1,22 @@ -import React from 'react'; +import React, { FunctionComponent } from 'react'; +import PropTypes from 'prop-types'; +import { Action } from 'redux'; +import { StylingFunction } from 'react-base16-styling'; +import { Tab } from './ActionPreview'; -const ActionPreviewHeader = ({ +interface Props> { + tabs: Tab[]; + styling: StylingFunction; + inspectedPath: (string | number)[]; + onInspectPath: (path: (string | number)[]) => void; + tabName: string; + onSelectTab: (tabName: string) => void; +} + +const ActionPreviewHeader: FunctionComponent +>> = ({ styling, inspectedPath, onInspectPath, @@ -57,4 +73,13 @@ const ActionPreviewHeader = ({
); +ActionPreviewHeader.propTypes = { + tabs: PropTypes.array.isRequired, + styling: PropTypes.func.isRequired, + inspectedPath: PropTypes.array.isRequired, + onInspectPath: PropTypes.func.isRequired, + tabName: PropTypes.string.isRequired, + onSelectTab: PropTypes.func.isRequired, +}; + export default ActionPreviewHeader; diff --git a/packages/redux-devtools-inspector/src/DevtoolsInspector.js b/packages/redux-devtools-inspector/src/DevtoolsInspector.tsx similarity index 64% rename from packages/redux-devtools-inspector/src/DevtoolsInspector.js rename to packages/redux-devtools-inspector/src/DevtoolsInspector.tsx index 4ef9193d..5800feab 100644 --- a/packages/redux-devtools-inspector/src/DevtoolsInspector.js +++ b/packages/redux-devtools-inspector/src/DevtoolsInspector.tsx @@ -1,18 +1,30 @@ -import React, { Component } from 'react'; -import { PropTypes } from 'prop-types'; +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import { Base16Theme } from 'redux-devtools-themes'; +import { + getBase16Theme, + invertTheme, + StylingFunction, +} from 'react-base16-styling'; +import { ActionCreators, LiftedAction, LiftedState } from 'redux-devtools'; +import { Action, Dispatch } from 'redux'; +import { Delta, DiffContext } from 'jsondiffpatch'; import { createStylingFromTheme, base16Themes, } from './utils/createStylingFromTheme'; -import shouldPureComponentUpdate from 'react-pure-render/function'; import ActionList from './ActionList'; -import ActionPreview from './ActionPreview'; +import ActionPreview, { Tab } from './ActionPreview'; import getInspectedState from './utils/getInspectedState'; import createDiffPatcher from './createDiffPatcher'; -import { getBase16Theme, invertTheme } from 'react-base16-styling'; -import { reducer, updateMonitorState } from './redux'; -import { ActionCreators } from 'redux-devtools'; +import { + DevtoolsInspectorAction, + DevtoolsInspectorState, + reducer, + updateMonitorState, +} from './redux'; +// eslint-disable-next-line @typescript-eslint/unbound-method const { commit, sweep, @@ -22,21 +34,26 @@ const { reorderAction, } = ActionCreators; -function getLastActionId(props) { +function getLastActionId>( + props: DevtoolsInspectorProps +) { return props.stagedActionIds[props.stagedActionIds.length - 1]; } -function getCurrentActionId(props, monitorState) { +function getCurrentActionId>( + props: DevtoolsInspectorProps, + monitorState: DevtoolsInspectorState +) { return monitorState.selectedActionId === null ? props.stagedActionIds[props.currentStateIndex] : monitorState.selectedActionId; } -function getFromState( - actionIndex, - stagedActionIds, - computedStates, - monitorState +function getFromState( + actionIndex: number, + stagedActionIds: number[], + computedStates: { state: S; error?: string }[], + monitorState: DevtoolsInspectorState ) { const { startActionId } = monitorState; if (startActionId === null) { @@ -47,7 +64,10 @@ function getFromState( return computedStates[fromStateIdx]; } -function createIntermediateState(props, monitorState) { +function createIntermediateState>( + props: DevtoolsInspectorProps, + monitorState: DevtoolsInspectorState +) { const { supportImmutable, computedStates, @@ -97,8 +117,10 @@ function createIntermediateState(props, monitorState) { }; } -function createThemeState(props) { - const base16Theme = getBase16Theme(props.theme, base16Themes); +function createThemeState>( + props: DevtoolsInspectorProps +) { + const base16Theme = getBase16Theme(props.theme, base16Themes)!; const theme = props.invertTheme ? invertTheme(props.theme) : props.theme; const styling = createStylingFromTheme(theme); @@ -106,15 +128,69 @@ function createThemeState(props) { return { base16Theme, styling }; } -export default class DevtoolsInspector extends Component { - constructor(props) { - super(props); - this.state = { - ...createIntermediateState(props, props.monitorState), - isWideLayout: false, - themeState: createThemeState(props), - }; - } +interface ExternalProps> { + dispatch: Dispatch< + DevtoolsInspectorAction | LiftedAction + >; + preserveScrollTop?: boolean; + draggableActions: boolean; + select: (state: S) => unknown; + theme: keyof typeof base16Themes | Base16Theme; + supportImmutable: boolean; + diffObjectHash?: (item: unknown, index: number) => string; + diffPropertyFilter?: (name: string, context: DiffContext) => boolean; + hideMainButtons?: boolean; + hideActionButtons?: boolean; + invertTheme: boolean; + dataTypeKey?: string; + tabs: Tab[] | ((tabs: Tab[]) => Tab[]); +} + +interface DefaultProps { + select: (state: unknown) => unknown; + supportImmutable: boolean; + draggableActions: boolean; + theme: keyof typeof base16Themes; + invertTheme: boolean; +} + +export interface DevtoolsInspectorProps> + extends LiftedState { + dispatch: Dispatch< + DevtoolsInspectorAction | LiftedAction + >; + preserveScrollTop?: boolean; + draggableActions: boolean; + select: (state: S) => unknown; + theme: keyof typeof base16Themes | Base16Theme; + supportImmutable: boolean; + diffObjectHash?: (item: unknown, index: number) => string; + diffPropertyFilter?: (name: string, context: DiffContext) => boolean; + hideMainButtons?: boolean; + hideActionButtons?: boolean; + invertTheme: boolean; + dataTypeKey?: string; + tabs: Tab[] | ((tabs: Tab[]) => Tab[]); +} + +interface State> { + delta: Delta | null | undefined | false; + nextState: S; + action: A; + error: string | undefined; + isWideLayout: boolean; + themeState: { base16Theme: Base16Theme; styling: StylingFunction }; +} + +class DevtoolsInspector> extends PureComponent< + DevtoolsInspectorProps, + State +> { + state: State = { + ...createIntermediateState(this.props, this.props.monitorState), + isWideLayout: false, + themeState: createThemeState(this.props), + }; static propTypes = { dispatch: PropTypes.func, @@ -127,7 +203,6 @@ export default class DevtoolsInspector extends Component { }), preserveScrollTop: PropTypes.bool, draggableActions: PropTypes.bool, - stagedActions: PropTypes.array, select: PropTypes.func.isRequired, theme: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), supportImmutable: PropTypes.bool, @@ -144,38 +219,42 @@ export default class DevtoolsInspector extends Component { static update = reducer; static defaultProps = { - select: (state) => state, + select: (state: unknown) => state, supportImmutable: false, draggableActions: true, theme: 'inspector', invertTheme: true, }; - shouldComponentUpdate = shouldPureComponentUpdate; + updateSizeTimeout?: number; + inspectorRef?: HTMLDivElement | null; componentDidMount() { this.updateSizeMode(); - this.updateSizeTimeout = setInterval(this.updateSizeMode.bind(this), 150); + this.updateSizeTimeout = window.setInterval( + this.updateSizeMode.bind(this), + 150 + ); } componentWillUnmount() { clearTimeout(this.updateSizeTimeout); } - updateMonitorState = (monitorState) => { + updateMonitorState = (monitorState: Partial) => { this.props.dispatch(updateMonitorState(monitorState)); }; updateSizeMode() { - const isWideLayout = this.inspectorRef.offsetWidth > 500; + const isWideLayout = this.inspectorRef!.offsetWidth > 500; if (isWideLayout !== this.state.isWideLayout) { this.setState({ isWideLayout }); } } - UNSAFE_componentWillReceiveProps(nextProps) { - let nextMonitorState = nextProps.monitorState; + UNSAFE_componentWillReceiveProps(nextProps: DevtoolsInspectorProps) { + const nextMonitorState = nextProps.monitorState; const monitorState = this.props.monitorState; if ( @@ -199,7 +278,7 @@ export default class DevtoolsInspector extends Component { } } - inspectorCreateRef = (node) => { + inspectorCreateRef: React.RefCallback = (node) => { this.inspectorRef = node; }; @@ -289,7 +368,9 @@ export default class DevtoolsInspector extends Component { monitorState={this.props.monitorState} updateMonitorState={this.updateMonitorState} styling={styling} - onInspectPath={this.handleInspectPath.bind(this, inspectedPathType)} + onInspectPath={(path: (string | number)[]) => + this.handleInspectPath(inspectedPathType, path) + } inspectedPath={monitorState[inspectedPathType]} onSelectTab={this.handleSelectTab} /> @@ -297,11 +378,11 @@ export default class DevtoolsInspector extends Component { ); } - handleToggleAction = (actionId) => { + handleToggleAction = (actionId: number) => { this.props.dispatch(toggleAction(actionId)); }; - handleJumpToState = (actionId) => { + handleJumpToState = (actionId: number) => { if (jumpToAction) { this.props.dispatch(jumpToAction(actionId)); } else { @@ -311,7 +392,7 @@ export default class DevtoolsInspector extends Component { } }; - handleReorderAction = (actionId, beforeActionId) => { + handleReorderAction = (actionId: number, beforeActionId: number) => { if (reorderAction) this.props.dispatch(reorderAction(actionId, beforeActionId)); }; @@ -324,11 +405,14 @@ export default class DevtoolsInspector extends Component { this.props.dispatch(sweep()); }; - handleSearch = (val) => { + handleSearch = (val: string) => { this.updateMonitorState({ searchValue: val }); }; - handleSelectAction = (e, actionId) => { + handleSelectAction = ( + e: React.MouseEvent, + actionId: number + ) => { const { monitorState } = this.props; let startActionId; let selectedActionId; @@ -367,11 +451,25 @@ export default class DevtoolsInspector extends Component { this.updateMonitorState({ startActionId, selectedActionId }); }; - handleInspectPath = (pathType, path) => { + handleInspectPath = ( + pathType: 'inspectedActionPath' | 'inspectedStatePath', + path: (string | number)[] + ) => { this.updateMonitorState({ [pathType]: path }); }; - handleSelectTab = (tabName) => { + handleSelectTab = (tabName: string) => { this.updateMonitorState({ tabName }); }; } + +export default (DevtoolsInspector as unknown) as React.ComponentType< + ExternalProps> +> & { + update( + monitorProps: ExternalProps>, + state: DevtoolsInspectorState | undefined, + action: DevtoolsInspectorAction + ): DevtoolsInspectorState; + defaultProps: DefaultProps; +}; diff --git a/packages/redux-devtools-inspector/src/RightSlider.jsx b/packages/redux-devtools-inspector/src/RightSlider.jsx deleted file mode 100644 index 15c93e48..00000000 --- a/packages/redux-devtools-inspector/src/RightSlider.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { PropTypes } from 'prop-types'; - -const RightSlider = ({ styling, shown, children, rotate }) => ( -
- {children} -
-); - -RightSlider.propTypes = { - shown: PropTypes.bool, -}; - -export default RightSlider; diff --git a/packages/redux-devtools-inspector/src/RightSlider.tsx b/packages/redux-devtools-inspector/src/RightSlider.tsx new file mode 100644 index 00000000..ee95bfa3 --- /dev/null +++ b/packages/redux-devtools-inspector/src/RightSlider.tsx @@ -0,0 +1,37 @@ +import React, { FunctionComponent } from 'react'; +import PropTypes from 'prop-types'; +import { StylingFunction } from 'react-base16-styling'; + +interface Props { + styling: StylingFunction; + shown?: boolean; + children: React.ReactNode; + rotate?: boolean; +} + +const RightSlider: FunctionComponent = ({ + styling, + shown, + children, + rotate, +}) => ( +
+ {children} +
+); + +RightSlider.propTypes = { + styling: PropTypes.func.isRequired, + shown: PropTypes.bool, + children: PropTypes.any.isRequired, + rotate: PropTypes.bool, +}; + +export default RightSlider; diff --git a/packages/redux-devtools-inspector/src/createDiffPatcher.js b/packages/redux-devtools-inspector/src/createDiffPatcher.ts similarity index 50% rename from packages/redux-devtools-inspector/src/createDiffPatcher.js rename to packages/redux-devtools-inspector/src/createDiffPatcher.ts index 53a7d4fc..41a8c097 100644 --- a/packages/redux-devtools-inspector/src/createDiffPatcher.js +++ b/packages/redux-devtools-inspector/src/createDiffPatcher.ts @@ -1,28 +1,37 @@ -import { DiffPatcher } from 'jsondiffpatch'; +import { DiffContext, DiffPatcher } from 'jsondiffpatch'; -const defaultObjectHash = (o, idx) => +const defaultObjectHash = (o: any, idx: number) => (o === null && '$$null') || (o && (o.id || o.id === 0) && `$$id:${JSON.stringify(o.id)}`) || (o && (o._id || o._id === 0) && `$$_id:${JSON.stringify(o._id)}`) || - '$$index:' + idx; + `$$index:${idx}`; -const defaultPropertyFilter = (name, context) => +const defaultPropertyFilter = (name: string, context: DiffContext) => typeof context.left[name] !== 'function' && typeof context.right[name] !== 'function'; const defaultDiffPatcher = new DiffPatcher({ - arrays: { detectMove: false }, + arrays: { detectMove: false } as { + detectMove: boolean; + includeValueOnMove: boolean; + }, objectHash: defaultObjectHash, propertyFilter: defaultPropertyFilter, }); -export default function createDiffPatcher(objectHash, propertyFilter) { +export default function createDiffPatcher( + objectHash: ((item: unknown, index: number) => string) | undefined, + propertyFilter: ((name: string, context: DiffContext) => boolean) | undefined +) { if (!objectHash && !propertyFilter) { return defaultDiffPatcher; } return new DiffPatcher({ - arrays: { detectMove: false }, + arrays: { detectMove: false } as { + detectMove: boolean; + includeValueOnMove: boolean; + }, objectHash: objectHash || defaultObjectHash, propertyFilter: propertyFilter || defaultPropertyFilter, }); diff --git a/packages/redux-devtools-inspector/src/index.js b/packages/redux-devtools-inspector/src/index.js deleted file mode 100644 index 2040c41e..00000000 --- a/packages/redux-devtools-inspector/src/index.js +++ /dev/null @@ -1 +0,0 @@ -export default from './DevtoolsInspector'; diff --git a/packages/redux-devtools-inspector/src/index.ts b/packages/redux-devtools-inspector/src/index.ts new file mode 100644 index 00000000..d6ea9d8f --- /dev/null +++ b/packages/redux-devtools-inspector/src/index.ts @@ -0,0 +1,2 @@ +import DevtoolsInspector from './DevtoolsInspector'; +export default DevtoolsInspector; diff --git a/packages/redux-devtools-inspector/src/redux.js b/packages/redux-devtools-inspector/src/redux.js deleted file mode 100644 index 33f6208d..00000000 --- a/packages/redux-devtools-inspector/src/redux.js +++ /dev/null @@ -1,28 +0,0 @@ -const UPDATE_MONITOR_STATE = '@@redux-devtools-inspector/UPDATE_MONITOR_STATE'; - -export const DEFAULT_STATE = { - selectedActionId: null, - startActionId: null, - inspectedActionPath: [], - inspectedStatePath: [], - tabName: 'Diff', -}; - -export function updateMonitorState(monitorState) { - return { type: UPDATE_MONITOR_STATE, monitorState }; -} - -function reduceUpdateState(state, action) { - return action.type === UPDATE_MONITOR_STATE - ? { - ...state, - ...action.monitorState, - } - : state; -} - -export function reducer(props, state = DEFAULT_STATE, action) { - return { - ...reduceUpdateState(state, action), - }; -} diff --git a/packages/redux-devtools-inspector/src/redux.ts b/packages/redux-devtools-inspector/src/redux.ts new file mode 100644 index 00000000..653bc628 --- /dev/null +++ b/packages/redux-devtools-inspector/src/redux.ts @@ -0,0 +1,55 @@ +import { Action } from 'redux'; +import { DevtoolsInspectorProps } from './DevtoolsInspector'; + +const UPDATE_MONITOR_STATE = '@@redux-devtools-inspector/UPDATE_MONITOR_STATE'; + +interface UpdateMonitorStateAction { + type: typeof UPDATE_MONITOR_STATE; + monitorState: Partial; +} +export function updateMonitorState( + monitorState: Partial +): UpdateMonitorStateAction { + return { type: UPDATE_MONITOR_STATE, monitorState }; +} + +export type DevtoolsInspectorAction = UpdateMonitorStateAction; + +export interface DevtoolsInspectorState { + selectedActionId: number | null; + startActionId: number | null; + inspectedActionPath: (string | number)[]; + inspectedStatePath: (string | number)[]; + tabName: string; + searchValue?: string; +} + +export const DEFAULT_STATE: DevtoolsInspectorState = { + selectedActionId: null, + startActionId: null, + inspectedActionPath: [], + inspectedStatePath: [], + tabName: 'Diff', +}; + +function reduceUpdateState( + state: DevtoolsInspectorState, + action: DevtoolsInspectorAction +) { + return action.type === UPDATE_MONITOR_STATE + ? { + ...state, + ...action.monitorState, + } + : state; +} + +export function reducer>( + props: DevtoolsInspectorProps, + state = DEFAULT_STATE, + action: DevtoolsInspectorAction +) { + return { + ...reduceUpdateState(state, action), + }; +} diff --git a/packages/redux-devtools-inspector/src/tabs/ActionTab.jsx b/packages/redux-devtools-inspector/src/tabs/ActionTab.jsx deleted file mode 100644 index c5cb77c8..00000000 --- a/packages/redux-devtools-inspector/src/tabs/ActionTab.jsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import JSONTree from 'react-json-tree'; -import getItemString from './getItemString'; -import getJsonTreeTheme from './getJsonTreeTheme'; - -const ActionTab = ({ - action, - styling, - base16Theme, - invertTheme, - labelRenderer, - dataTypeKey, - isWideLayout, -}) => ( - - getItemString(styling, type, data, dataTypeKey, isWideLayout) - } - invertTheme={invertTheme} - hideRoot - /> -); - -export default ActionTab; diff --git a/packages/redux-devtools-inspector/src/tabs/ActionTab.tsx b/packages/redux-devtools-inspector/src/tabs/ActionTab.tsx new file mode 100644 index 00000000..056a72cc --- /dev/null +++ b/packages/redux-devtools-inspector/src/tabs/ActionTab.tsx @@ -0,0 +1,43 @@ +import React, { FunctionComponent } from 'react'; +import PropTypes from 'prop-types'; +import JSONTree from 'react-json-tree'; +import { Action } from 'redux'; +import getItemString from './getItemString'; +import getJsonTreeTheme from './getJsonTreeTheme'; +import { TabComponentProps } from '../ActionPreview'; + +const ActionTab: FunctionComponent +>> = ({ + action, + styling, + base16Theme, + invertTheme, + labelRenderer, + dataTypeKey, + isWideLayout, +}) => ( + + getItemString(styling, type, data, dataTypeKey, isWideLayout) + } + invertTheme={invertTheme} + hideRoot + /> +); + +ActionTab.propTypes = { + action: PropTypes.any.isRequired, + styling: PropTypes.func.isRequired, + base16Theme: PropTypes.any.isRequired, + invertTheme: PropTypes.bool.isRequired, + labelRenderer: PropTypes.func.isRequired, + dataTypeKey: PropTypes.string, + isWideLayout: PropTypes.bool.isRequired, +}; + +export default ActionTab; diff --git a/packages/redux-devtools-inspector/src/tabs/DiffTab.jsx b/packages/redux-devtools-inspector/src/tabs/DiffTab.jsx deleted file mode 100644 index cb73ef3c..00000000 --- a/packages/redux-devtools-inspector/src/tabs/DiffTab.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import JSONDiff from './JSONDiff'; - -const DiffTab = ({ - delta, - styling, - base16Theme, - invertTheme, - labelRenderer, - isWideLayout, -}) => ( - -); - -export default DiffTab; diff --git a/packages/redux-devtools-inspector/src/tabs/DiffTab.tsx b/packages/redux-devtools-inspector/src/tabs/DiffTab.tsx new file mode 100644 index 00000000..2d1c6224 --- /dev/null +++ b/packages/redux-devtools-inspector/src/tabs/DiffTab.tsx @@ -0,0 +1,42 @@ +import React, { FunctionComponent } from 'react'; +import PropTypes from 'prop-types'; +import JSONDiff from './JSONDiff'; +import { TabComponentProps } from '../ActionPreview'; +import { Action } from 'redux'; + +const DiffTab: FunctionComponent +>> = ({ + delta, + styling, + base16Theme, + invertTheme, + labelRenderer, + isWideLayout, + dataTypeKey, +}) => ( + +); + +DiffTab.propTypes = { + delta: PropTypes.any, + styling: PropTypes.func.isRequired, + base16Theme: PropTypes.any.isRequired, + invertTheme: PropTypes.bool.isRequired, + labelRenderer: PropTypes.func.isRequired, + isWideLayout: PropTypes.bool.isRequired, + dataTypeKey: PropTypes.string, +}; + +export default DiffTab; diff --git a/packages/redux-devtools-inspector/src/tabs/JSONDiff.jsx b/packages/redux-devtools-inspector/src/tabs/JSONDiff.tsx similarity index 74% rename from packages/redux-devtools-inspector/src/tabs/JSONDiff.jsx rename to packages/redux-devtools-inspector/src/tabs/JSONDiff.tsx index dac8d716..efcd8038 100644 --- a/packages/redux-devtools-inspector/src/tabs/JSONDiff.jsx +++ b/packages/redux-devtools-inspector/src/tabs/JSONDiff.tsx @@ -1,10 +1,13 @@ import React, { Component } from 'react'; import JSONTree from 'react-json-tree'; import { stringify } from 'javascript-stringify'; +import { Delta } from 'jsondiffpatch'; +import { StylingFunction } from 'react-base16-styling'; +import { Base16Theme } from 'redux-devtools-themes'; import getItemString from './getItemString'; import getJsonTreeTheme from './getJsonTreeTheme'; -function stringifyAndShrink(val, isWideLayout) { +function stringifyAndShrink(val: any, isWideLayout?: boolean) { if (val === null) { return 'null'; } @@ -19,12 +22,16 @@ function stringifyAndShrink(val, isWideLayout) { return str.length > 22 ? `${str.substr(0, 15)}…${str.substr(-5)}` : str; } -const expandFirstLevel = (keyName, data, level) => level <= 1; +const expandFirstLevel = ( + keyName: (string | number)[], + data: any, + level: number +) => level <= 1; -function prepareDelta(value) { +function prepareDelta(value: any) { if (value && value._t === 'a') { - const res = {}; - for (let key in value) { + const res: { [key: string]: any } = {}; + for (const key in value) { if (key !== '_t') { if (key[0] === '_' && !value[key.substr(1)]) { res[key.substr(1)] = value[key]; @@ -41,14 +48,33 @@ function prepareDelta(value) { return value; } -export default class JSONDiff extends Component { - state = { data: {} }; +interface Props { + delta: Delta | null | undefined | false; + styling: StylingFunction; + base16Theme: Base16Theme; + invertTheme: boolean; + labelRenderer: ( + keyPath: (string | number)[], + nodeType: string, + expanded: boolean, + expandable: boolean + ) => React.ReactNode; + isWideLayout: boolean; + dataTypeKey: string | undefined; +} + +interface State { + data: any; +} + +export default class JSONDiff extends Component { + state: State = { data: {} }; componentDidMount() { this.updateData(); } - componentDidUpdate(prevProps) { + componentDidUpdate(prevProps: Props) { if (prevProps.delta !== this.props.delta) { this.updateData(); } @@ -84,7 +110,7 @@ export default class JSONDiff extends Component { ); } - getItemString = (type, data) => + getItemString = (type: string, data: any) => getItemString( this.props.styling, type, @@ -94,10 +120,10 @@ export default class JSONDiff extends Component { true ); - valueRenderer = (raw, value) => { + valueRenderer = (raw: any, value: any) => { const { styling, isWideLayout } = this.props; - function renderSpan(name, body) { + function renderSpan(name: string, body: string) { return ( {body} diff --git a/packages/redux-devtools-inspector/src/tabs/StateTab.jsx b/packages/redux-devtools-inspector/src/tabs/StateTab.tsx similarity index 52% rename from packages/redux-devtools-inspector/src/tabs/StateTab.jsx rename to packages/redux-devtools-inspector/src/tabs/StateTab.tsx index c2991458..328f0380 100644 --- a/packages/redux-devtools-inspector/src/tabs/StateTab.jsx +++ b/packages/redux-devtools-inspector/src/tabs/StateTab.tsx @@ -1,9 +1,15 @@ import React from 'react'; +import PropTypes from 'prop-types'; import JSONTree from 'react-json-tree'; +import { Action } from 'redux'; import getItemString from './getItemString'; import getJsonTreeTheme from './getJsonTreeTheme'; +import { TabComponentProps } from '../ActionPreview'; -const StateTab = ({ +const StateTab: React.FunctionComponent +>> = ({ nextState, styling, base16Theme, @@ -24,4 +30,14 @@ const StateTab = ({ /> ); +StateTab.propTypes = { + nextState: PropTypes.any.isRequired, + styling: PropTypes.func.isRequired, + base16Theme: PropTypes.any.isRequired, + invertTheme: PropTypes.bool.isRequired, + labelRenderer: PropTypes.func.isRequired, + dataTypeKey: PropTypes.string, + isWideLayout: PropTypes.bool.isRequired, +}; + export default StateTab; diff --git a/packages/redux-devtools-inspector/src/tabs/getItemString.js b/packages/redux-devtools-inspector/src/tabs/getItemString.tsx similarity index 65% rename from packages/redux-devtools-inspector/src/tabs/getItemString.js rename to packages/redux-devtools-inspector/src/tabs/getItemString.tsx index 598dd4ff..85eb261a 100644 --- a/packages/redux-devtools-inspector/src/tabs/getItemString.js +++ b/packages/redux-devtools-inspector/src/tabs/getItemString.tsx @@ -1,18 +1,15 @@ import React from 'react'; -import { Iterable } from 'immutable'; +import { isCollection, isIndexed, isKeyed } from 'immutable'; +import { StylingFunction } from 'react-base16-styling'; import isIterable from '../utils/isIterable'; const IS_IMMUTABLE_KEY = '@@__IS_IMMUTABLE__@@'; -function isImmutable(value) { - return ( - Iterable.isKeyed(value) || - Iterable.isIndexed(value) || - Iterable.isIterable(value) - ); +function isImmutable(value: any) { + return isKeyed(value) || isIndexed(value) || isCollection(value); } -function getShortTypeString(val, diff) { +function getShortTypeString(val: any, diff: boolean | undefined) { if (diff && Array.isArray(val)) { val = val[val.length === 2 ? 1 : 0]; } @@ -38,14 +35,21 @@ function getShortTypeString(val, diff) { } } -function getText(type, data, isWideLayout, isDiff) { +function getText( + type: string, + data: any, + isWideLayout: boolean, + isDiff: boolean | undefined +) { if (type === 'Object') { const keys = Object.keys(data); if (!isWideLayout) return keys.length ? '{…}' : '{}'; const str = keys .slice(0, 3) - .map((key) => `${key}: ${getShortTypeString(data[key], isDiff)}`) + .map( + (key) => `${key}: ${getShortTypeString(data[key], isDiff) as string}` + ) .concat(keys.length > 3 ? ['…'] : []) .join(', '); @@ -55,27 +59,27 @@ function getText(type, data, isWideLayout, isDiff) { const str = data .slice(0, 4) - .map((val) => getShortTypeString(val, isDiff)) + .map((val: any) => getShortTypeString(val, isDiff)) .concat(data.length > 4 ? ['…'] : []) .join(', '); - return `[${str}]`; + return `[${str as string}]`; } else { return type; } } const getItemString = ( - styling, - type, - data, - dataTypeKey, - isWideLayout, - isDiff + styling: StylingFunction, + type: string, + data: any, + dataTypeKey: string | undefined, + isWideLayout: boolean, + isDiff?: boolean ) => ( {data[IS_IMMUTABLE_KEY] ? 'Immutable' : ''} - {dataTypeKey && data[dataTypeKey] ? data[dataTypeKey] + ' ' : ''} + {dataTypeKey && data[dataTypeKey] ? `${data[dataTypeKey] as string} ` : ''} {getText(type, data, isWideLayout, isDiff)} ); diff --git a/packages/redux-devtools-inspector/src/tabs/getJsonTreeTheme.js b/packages/redux-devtools-inspector/src/tabs/getJsonTreeTheme.ts similarity index 65% rename from packages/redux-devtools-inspector/src/tabs/getJsonTreeTheme.js rename to packages/redux-devtools-inspector/src/tabs/getJsonTreeTheme.ts index e936f291..ff4f3c0d 100644 --- a/packages/redux-devtools-inspector/src/tabs/getJsonTreeTheme.js +++ b/packages/redux-devtools-inspector/src/tabs/getJsonTreeTheme.ts @@ -1,4 +1,9 @@ -export default function getJsonTreeTheme(base16Theme) { +import { Base16Theme } from 'redux-devtools-themes'; +import { StylingConfig } from 'react-base16-styling'; + +export default function getJsonTreeTheme( + base16Theme: Base16Theme +): StylingConfig { return { extend: base16Theme, nestedNode: ({ style }, keyPath, nodeType, expanded) => ({ diff --git a/packages/redux-devtools-inspector/src/themes/index.js b/packages/redux-devtools-inspector/src/themes/index.ts similarity index 100% rename from packages/redux-devtools-inspector/src/themes/index.js rename to packages/redux-devtools-inspector/src/themes/index.ts diff --git a/packages/redux-devtools-inspector/src/themes/inspector.js b/packages/redux-devtools-inspector/src/themes/inspector.ts similarity index 100% rename from packages/redux-devtools-inspector/src/themes/inspector.js rename to packages/redux-devtools-inspector/src/themes/inspector.ts diff --git a/packages/redux-devtools-inspector/src/utils/createStylingFromTheme.js b/packages/redux-devtools-inspector/src/utils/createStylingFromTheme.ts similarity index 95% rename from packages/redux-devtools-inspector/src/utils/createStylingFromTheme.js rename to packages/redux-devtools-inspector/src/utils/createStylingFromTheme.ts index 0af17dcb..e1db41f8 100644 --- a/packages/redux-devtools-inspector/src/utils/createStylingFromTheme.js +++ b/packages/redux-devtools-inspector/src/utils/createStylingFromTheme.ts @@ -1,14 +1,15 @@ -import jss from 'jss'; +import jss, { Styles, StyleSheet } from 'jss'; import preset from 'jss-preset-default'; import { createStyling } from 'react-base16-styling'; import rgba from 'hex-rgba'; +import { Base16Theme } from 'redux-devtools-themes'; import inspector from '../themes/inspector'; import * as reduxThemes from 'redux-devtools-themes'; import * as inspectorThemes from '../themes'; jss.setup(preset()); -const colorMap = (theme) => ({ +const colorMap = (theme: Base16Theme) => ({ TEXT_COLOR: theme.base06, TEXT_PLACEHOLDER_COLOR: rgba(theme.base06, 60), BACKGROUND_COLOR: theme.base00, @@ -34,7 +35,12 @@ const colorMap = (theme) => ({ ERROR_COLOR: theme.base08, }); -const getSheetFromColorMap = (map) => ({ +type Color = keyof ReturnType; +type ColorMap = { + [color in Color]: string; +}; + +const getSheetFromColorMap = (map: ColorMap) => ({ inspector: { display: 'flex', 'flex-direction': 'column', @@ -384,9 +390,9 @@ const getSheetFromColorMap = (map) => ({ }, }); -let themeSheet; +let themeSheet: StyleSheet; -const getDefaultThemeStyling = (theme) => { +const getDefaultThemeStyling = (theme: Base16Theme) => { if (themeSheet) { themeSheet.detach(); } diff --git a/packages/redux-devtools-inspector/src/utils/deepMap.js b/packages/redux-devtools-inspector/src/utils/deepMap.js deleted file mode 100644 index b76e1217..00000000 --- a/packages/redux-devtools-inspector/src/utils/deepMap.js +++ /dev/null @@ -1,30 +0,0 @@ -function deepMapCached(obj, f, ctx, cache) { - cache.push(obj); - if (Array.isArray(obj)) { - return obj.map(function (val, key) { - val = f.call(ctx, val, key); - return typeof val === 'object' && cache.indexOf(val) === -1 - ? deepMapCached(val, f, ctx, cache) - : val; - }); - } else if (typeof obj === 'object') { - const res = {}; - for (const key in obj) { - let val = obj[key]; - if (val && typeof val === 'object') { - val = f.call(ctx, val, key); - res[key] = - cache.indexOf(val) === -1 ? deepMapCached(val, f, ctx, cache) : val; - } else { - res[key] = f.call(ctx, val, key); - } - } - return res; - } else { - return obj; - } -} - -export default function deepMap(obj, f, ctx) { - return deepMapCached(obj, f, ctx, []); -} diff --git a/packages/redux-devtools-inspector/src/utils/getInspectedState.js b/packages/redux-devtools-inspector/src/utils/getInspectedState.ts similarity index 61% rename from packages/redux-devtools-inspector/src/utils/getInspectedState.js rename to packages/redux-devtools-inspector/src/utils/getInspectedState.ts index dd62c471..09fa708b 100644 --- a/packages/redux-devtools-inspector/src/utils/getInspectedState.js +++ b/packages/redux-devtools-inspector/src/utils/getInspectedState.ts @@ -1,10 +1,10 @@ -import { Iterable, fromJS } from 'immutable'; +import { fromJS, isAssociative } from 'immutable'; import isIterable from './isIterable'; -function iterateToKey(obj, key) { +function iterateToKey(obj: any, key: string | number) { // maybe there's a better way, dunno let idx = 0; - for (let entry of obj) { + for (const entry of obj) { if (Array.isArray(entry)) { if (entry[0] === key) return entry[1]; } else { @@ -15,24 +15,28 @@ function iterateToKey(obj, key) { } } -export default function getInspectedState(state, path, convertImmutable) { +export default function getInspectedState( + state: S, + path: (string | number)[], + convertImmutable: boolean +): S { state = path && path.length - ? { - [path[path.length - 1]]: path.reduce((s, key) => { + ? ({ + [path[path.length - 1]]: path.reduce((s: any, key) => { if (!s) { return s; } - if (Iterable.isAssociative(s)) { - return s.get(key); + if (isAssociative(s)) { + return s.get(key as number); } else if (isIterable(s)) { return iterateToKey(s, key); } return s[key]; }, state), - } + } as S) : state; if (convertImmutable) { diff --git a/packages/redux-devtools-inspector/src/utils/isIterable.js b/packages/redux-devtools-inspector/src/utils/isIterable.ts similarity index 76% rename from packages/redux-devtools-inspector/src/utils/isIterable.js rename to packages/redux-devtools-inspector/src/utils/isIterable.ts index 45f33b64..a7226ad0 100644 --- a/packages/redux-devtools-inspector/src/utils/isIterable.js +++ b/packages/redux-devtools-inspector/src/utils/isIterable.ts @@ -1,4 +1,4 @@ -export default function isIterable(obj) { +export default function isIterable(obj: any) { return ( obj !== null && typeof obj === 'object' && diff --git a/packages/redux-devtools-inspector/tsconfig.json b/packages/redux-devtools-inspector/tsconfig.json new file mode 100644 index 00000000..5c73f98c --- /dev/null +++ b/packages/redux-devtools-inspector/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.react.base.json", + "compilerOptions": { + "outDir": "lib", + "resolveJsonModule": true + }, + "include": ["src"] +} diff --git a/yarn.lock b/yarn.lock index 91b29d61..e7f61054 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,7 +25,7 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== @@ -1224,7 +1224,7 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== @@ -3082,6 +3082,16 @@ dependencies: "@types/node" "*" +"@types/dateformat@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/dateformat/-/dateformat-3.0.1.tgz#98d747a2e5e9a56070c6bf14e27bff56204e34cc" + integrity sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g== + +"@types/dragula@*", "@types/dragula@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@types/dragula/-/dragula-3.7.0.tgz#62178f21c3896ab9823a33d08ed844ab9af496af" + integrity sha512-Scr3lQ7pDmwic+I4qrzDEIfPVGUhc/qo8S0VJJ9v5pzTyIIJzAXrnFajjsMSL8J84VERIkZUh7wH6wYEisY+TA== + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" @@ -3121,6 +3131,16 @@ dependencies: "@types/node" "*" +"@types/hex-rgba@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/hex-rgba/-/hex-rgba-1.0.0.tgz#b2aed2aa9fdd6152b7f0ac5e3733b974d4eba35a" + integrity sha512-u3AGV8fjRsDBqY4wOvVWhVCgKDfh2b0h3mux7KPKU1cm/6mJp14OWBINLgBypeBTM89Nm2j+eKQqIoIe7150DA== + +"@types/history@*", "@types/history@^4.7.7": + version "4.7.7" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.7.tgz#613957d900fab9ff84c8dfb24fa3eef0c2a40896" + integrity sha512-2xtoL22/3Mv6a70i4+4RB7VgbDDORoWwjcqeNysojZA0R7NK17RbY5Gof/2QiFfJgX+KkWghbwJ+d/2SB8Ndzg== + "@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.0": version "3.3.1" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" @@ -3195,7 +3215,7 @@ resolved "https://registry.yarnpkg.com/@types/jsan/-/jsan-3.1.0.tgz#128fdb14a102134ede764b11682e795d1b380c43" integrity sha512-V5wfm0++TqM92D0ZkAhl9MDQHPTi88fXhMNVin5LV/Y3RnuU/FUv6wML4Vt/amZmPN9WaFTmDhKW+h58kAFmIg== -"@types/json-schema@^7.0.3", "@types/json-schema@^7.0.4": +"@types/json-schema@^7.0.3", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5": version "7.0.5" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== @@ -3214,6 +3234,13 @@ dependencies: "@types/lodash" "*" +"@types/lodash.shuffle@^4.2.6": + version "4.2.6" + resolved "https://registry.yarnpkg.com/@types/lodash.shuffle/-/lodash.shuffle-4.2.6.tgz#191b0fc66699214558352123811d1657d9ed8930" + integrity sha512-ucI9VswlV9jOZiIh43Nd0tJ4Z8pfXy3PbQ9cB6Re1gPds8gLbOdmB0l3UkVI2crZjnQB95bhyNZVEDH8DgglYA== + dependencies: + "@types/lodash" "*" + "@types/lodash@*", "@types/lodash@^4.14.159": version "4.14.159" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.159.tgz#61089719dc6fdd9c5cb46efc827f2571d1517065" @@ -3296,6 +3323,13 @@ dependencies: "@types/react" "*" +"@types/react-dragula@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@types/react-dragula/-/react-dragula-1.1.0.tgz#c7a6840891c52aa5007a8f8b87b31985fbc3c5b2" + integrity sha512-wgRIVV2jo/Gria1PK3K26II7gfRD3VTcMfPYhL0CuIApSeon7xjBTj8Xs8Ln+Vbb/FuRKWfUaJXmF4R3KUGntA== + dependencies: + "@types/dragula" "*" + "@types/react-native@*": version "0.63.8" resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.63.8.tgz#73ec087122c64c309eeaf150b565b8d755f0fb1f" @@ -3313,6 +3347,14 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" +"@types/react-router@^5.1.8": + version "5.1.8" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.8.tgz#4614e5ba7559657438e17766bb95ef6ed6acc3fa" + integrity sha512-HzOyJb+wFmyEhyfp4D4NYrumi+LQgQL/68HvJO+q6XtuHSDvw6Aqov7sCAhjbNq3bUPgPqbdvjXC5HeB2oEAPg== + dependencies: + "@types/history" "*" + "@types/react" "*" + "@types/react-test-renderer@^16.9.3": version "16.9.3" resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.9.3.tgz#96bab1860904366f4e848b739ba0e2f67bcae87e" @@ -3342,6 +3384,13 @@ dependencies: "@types/base16" "*" +"@types/redux-logger@^3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/redux-logger/-/redux-logger-3.0.8.tgz#1fb6d26917bb198792bb1cf57feb31cae1532c5d" + integrity sha512-zM+cxiSw6nZtRbxpVp9SE3x/X77Z7e7YAfHD1NkxJyJbAGSXJGF0E9aqajZfPOa/sTYnuwutmlCldveExuCeLw== + dependencies: + redux "^4.0.0" + "@types/serve-static@*": version "1.13.5" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53" @@ -4270,6 +4319,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + atoa@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/atoa/-/atoa-1.0.0.tgz#0cc0e91a480e738f923ebc103676471779b34a49" @@ -7886,6 +7940,23 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +fork-ts-checker-webpack-plugin@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.1.0.tgz#586fbee24aeea950c53bab529e32017f543e71cf" + integrity sha512-vuKyEjSLGbhQbEr5bifXXOkr9iV73L6n72mHoHIv7okvrf7O7z6RKeplM6C6ATPsukoQivij+Ba1vcptL60Z2g== + dependencies: + "@babel/code-frame" "^7.8.3" + "@types/json-schema" "^7.0.5" + chalk "^4.1.0" + cosmiconfig "^6.0.0" + deepmerge "^4.2.2" + fs-extra "^9.0.0" + memfs "^3.1.2" + minimatch "^3.0.4" + schema-utils "2.7.0" + semver "^7.3.2" + tapable "^1.0.0" + form-data@^2.3.1: version "2.5.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" @@ -7972,6 +8043,16 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" + integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^1.0.0" + fs-minipass@^1.2.5: version "1.2.7" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" @@ -7979,6 +8060,11 @@ fs-minipass@^1.2.5: dependencies: minipass "^2.6.0" +fs-monkey@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.1.tgz#4a82f36944365e619f4454d9fff106553067b781" + integrity sha512-fcSa+wyTqZa46iWweI7/ZiUfegOZl0SG8+dltIwFXo7+zYU9J9kpS3NB6pZcSlJdhvIwp81Adx2XhZorncxiaA== + fs-readdir-recursive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -10248,6 +10334,15 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179" + integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg== + dependencies: + universalify "^1.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -10866,7 +10961,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.0.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1, lodash@^4.8.0: +lodash@^4.0.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.8.0: version "4.17.19" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== @@ -11106,6 +11201,13 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +memfs@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.2.0.tgz#f9438e622b5acd1daa8a4ae160c496fdd1325b26" + integrity sha512-f/xxz2TpdKv6uDn6GtHee8ivFyxwxmPuXatBb1FBwxYNuVpbM3k/Y1Z+vC0mH/dIXXrukYfe3qe5J32Dfjg93A== + dependencies: + fs-monkey "1.0.1" + memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -13238,11 +13340,6 @@ react-color@^2.14.1: reactcss "^1.2.0" tinycolor2 "^1.4.1" -react-deep-force-update@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-1.1.2.tgz#3d2ae45c2c9040cbb1772be52f8ea1ade6ca2ee1" - integrity sha512-WUSQJ4P/wWcusaH+zZmbECOk7H5N2pOIl0vzheeornkIMhu+qrNdGFm0bDZLCb0hSF0jf/kH1SgkNGfBdTc4wA== - react-dev-utils@^6.1.0: version "6.1.1" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-6.1.1.tgz#a07e3e8923c4609d9f27e5af5207e3ca20724895" @@ -13404,14 +13501,6 @@ react-overlays@^4.1.0: uncontrollable "^7.0.0" warning "^4.0.3" -react-proxy@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-1.1.8.tgz#9dbfd9d927528c3aa9f444e4558c37830ab8c26a" - integrity sha1-nb/Z2SdSjDqp9ETkVYw3gwq4wmo= - dependencies: - lodash "^4.6.1" - react-deep-force-update "^1.0.0" - react-pure-render@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/react-pure-render/-/react-pure-render-1.0.2.tgz#9d8a928c7f2c37513c2d064e57b3e3c356e9fabb" @@ -13487,14 +13576,6 @@ react-textarea-autosize@^7.0.4: "@babel/runtime" "^7.1.2" prop-types "^15.6.0" -react-transform-hmr@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/react-transform-hmr/-/react-transform-hmr-1.0.4.tgz#e1a40bd0aaefc72e8dfd7a7cda09af85066397bb" - integrity sha1-4aQL0Krvxy6N/Xp82gmvhQZjl7s= - dependencies: - global "^4.3.0" - react-proxy "^1.1.7" - react-transition-group@^2.0.0: version "2.9.0" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d" @@ -14322,6 +14403,15 @@ scheduler@^0.19.1: loose-envify "^1.1.0" object-assign "^4.1.1" +schema-utils@2.7.0, schema-utils@^2.6.5, schema-utils@^2.6.6, schema-utils@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" + integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== + dependencies: + "@types/json-schema" "^7.0.4" + ajv "^6.12.2" + ajv-keywords "^3.4.1" + schema-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" @@ -14331,15 +14421,6 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.6.5, schema-utils@^2.6.6, schema-utils@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" - integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== - dependencies: - "@types/json-schema" "^7.0.4" - ajv "^6.12.2" - ajv-keywords "^3.4.1" - seamless-immutable@^7.1.4: version "7.1.4" resolved "https://registry.yarnpkg.com/seamless-immutable/-/seamless-immutable-7.1.4.tgz#6e9536def083ddc4dea0207d722e0e80d0f372f8" @@ -16132,6 +16213,11 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" + integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"