From f9f15a41defab9c9ce6ba7491f75a7ce69aae152 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Sat, 19 Sep 2020 19:24:18 -0400 Subject: [PATCH 1/6] fix(redux-devtools-test-generator): fix devui's Select component (#637) * Stash * Fix stuff * Unused * Update snapshot --- packages/devui/package.json | 1 - packages/devui/src/Select/Select.tsx | 5 + .../devui/src/utils/createThemedComponent.tsx | 40 +- .../tests/__snapshots__/Select.test.tsx.snap | 6497 +++++++++-------- .../src/TestGenerator.tsx | 1 - .../src/index.tsx | 17 +- yarn.lock | 2 +- 7 files changed, 3303 insertions(+), 3260 deletions(-) diff --git a/packages/devui/package.json b/packages/devui/package.json index ad161345..e1322af3 100755 --- a/packages/devui/package.json +++ b/packages/devui/package.json @@ -47,7 +47,6 @@ "base16": "^1.0.0", "codemirror": "^5.56.0", "color": "^3.1.2", - "hoist-non-react-statics": "^3.3.2", "prop-types": "^15.7.2", "react-icons": "^3.10.0", "react-jsonschema-form": "^1.8.1", diff --git a/packages/devui/src/Select/Select.tsx b/packages/devui/src/Select/Select.tsx index 75324b63..465ccb52 100644 --- a/packages/devui/src/Select/Select.tsx +++ b/packages/devui/src/Select/Select.tsx @@ -38,6 +38,11 @@ export class Select extends (PureComponent || Component) { neutral60: this.props.theme.base06, neutral80: this.props.theme.base07, }, + spacing: { + ...theme.spacing, + baseUnit: 2, + controlHeight: this.props.theme.inputHeight, + }, })} /> ); diff --git a/packages/devui/src/utils/createThemedComponent.tsx b/packages/devui/src/utils/createThemedComponent.tsx index 82205f62..e630cdc3 100644 --- a/packages/devui/src/utils/createThemedComponent.tsx +++ b/packages/devui/src/utils/createThemedComponent.tsx @@ -1,5 +1,4 @@ -import React, { ComponentType } from 'react'; -import hoistNonReactStatics from 'hoist-non-react-statics'; +import React from 'react'; import getDefaultTheme, { Theme } from '../themes/default'; import { withTheme } from 'styled-components'; import { Base16Theme } from 'base16'; @@ -9,33 +8,16 @@ export default >( ? C : never ) => { - const ThemedComponent = React.forwardRef>( - (props, ref) => { - // eslint-disable-next-line react/prop-types - if (props.theme && props.theme.type) { - const ThemedComponent = withTheme( - UnthemedComponent as ComponentType<{ theme?: Theme }> - ); - return ; - } - const UnthemedComponentAny = UnthemedComponent as any; - return ( - - ); - } - ); - - hoistNonReactStatics(ThemedComponent, UnthemedComponent); - - ThemedComponent.displayName = `ThemedComponent(${ - UnthemedComponent.displayName ?? 'Component' - })`; - - return ThemedComponent; + return withTheme((props) => { + return props.theme && props.theme.type ? ( + + ) : ( + + ); + }); }; // TODO: memoize it? diff --git a/packages/devui/tests/__snapshots__/Select.test.tsx.snap b/packages/devui/tests/__snapshots__/Select.test.tsx.snap index f7fdbcc7..994a9c71 100644 --- a/packages/devui/tests/__snapshots__/Select.test.tsx.snap +++ b/packages/devui/tests/__snapshots__/Select.test.tsx.snap @@ -5,18 +5,18 @@ exports[`Select renders correctly 1`] = ` class=" css-2b097c-container" >
Select...
+ + + + + + + `; diff --git a/packages/redux-devtools-test-generator/src/TestGenerator.tsx b/packages/redux-devtools-test-generator/src/TestGenerator.tsx index d8b240f4..24b4b84c 100644 --- a/packages/redux-devtools-test-generator/src/TestGenerator.tsx +++ b/packages/redux-devtools-test-generator/src/TestGenerator.tsx @@ -1,5 +1,4 @@ import React, { PureComponent, Component, ReactNode } from 'react'; -import PropTypes from 'prop-types'; import { stringify } from 'javascript-stringify'; import objectPath from 'object-path'; import jsan from 'jsan'; diff --git a/packages/redux-devtools-test-generator/src/index.tsx b/packages/redux-devtools-test-generator/src/index.tsx index 011946df..da9151f4 100644 --- a/packages/redux-devtools-test-generator/src/index.tsx +++ b/packages/redux-devtools-test-generator/src/index.tsx @@ -130,14 +130,15 @@ export default class TestTab> extends Component< return ( - template.name} + getOptionLabel={(template: Template) => template.name} + value={templates.filter((template) => template.name === name)} + onChange={this.handleSelectTemplate} + /> +
diff --git a/yarn.lock b/yarn.lock index ceeea8f7..8b678689 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9357,7 +9357,7 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== From 3b027f400e0e326596eedc2ee17ab45a8383080d Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Sat, 19 Sep 2020 19:56:40 -0400 Subject: [PATCH 2/6] feat(map2tree): convert to TypeScript (#638) * map2tree * Fix build --- packages/map2tree/.babelrc | 3 +- packages/map2tree/.eslintignore | 3 + packages/map2tree/.eslintrc.js | 29 ++++++ packages/map2tree/jest.config.js | 3 + packages/map2tree/package.json | 71 ++++++------- packages/map2tree/src/index.js | 79 --------------- packages/map2tree/src/index.ts | 99 +++++++++++++++++++ .../{map2tree.spec.js => map2tree.spec.ts} | 4 +- packages/map2tree/test/tsconfig.json | 4 + packages/map2tree/tsconfig.json | 7 ++ packages/map2tree/tsconfig.webpack.json | 4 + ...ck.config.umd.js => webpack.config.umd.ts} | 11 ++- 12 files changed, 191 insertions(+), 126 deletions(-) create mode 100644 packages/map2tree/.eslintignore create mode 100644 packages/map2tree/.eslintrc.js create mode 100644 packages/map2tree/jest.config.js delete mode 100755 packages/map2tree/src/index.js create mode 100644 packages/map2tree/src/index.ts rename packages/map2tree/test/{map2tree.spec.js => map2tree.spec.ts} (97%) mode change 100755 => 100644 create mode 100644 packages/map2tree/test/tsconfig.json create mode 100644 packages/map2tree/tsconfig.json create mode 100644 packages/map2tree/tsconfig.webpack.json rename packages/map2tree/{webpack.config.umd.js => webpack.config.umd.ts} (63%) diff --git a/packages/map2tree/.babelrc b/packages/map2tree/.babelrc index 1320b9a3..5259cd24 100755 --- a/packages/map2tree/.babelrc +++ b/packages/map2tree/.babelrc @@ -1,3 +1,4 @@ { - "presets": ["@babel/preset-env"] + "presets": ["@babel/preset-env", "@babel/preset-typescript"], + "plugins": ["@babel/plugin-proposal-class-properties"] } diff --git a/packages/map2tree/.eslintignore b/packages/map2tree/.eslintignore new file mode 100644 index 00000000..1d149abd --- /dev/null +++ b/packages/map2tree/.eslintignore @@ -0,0 +1,3 @@ +examples +lib +dist diff --git a/packages/map2tree/.eslintrc.js b/packages/map2tree/.eslintrc.js new file mode 100644 index 00000000..88327738 --- /dev/null +++ b/packages/map2tree/.eslintrc.js @@ -0,0 +1,29 @@ +module.exports = { + extends: '../../.eslintrc', + overrides: [ + { + files: ['*.ts'], + extends: '../../eslintrc.ts.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + }, + { + files: ['test/*.ts'], + extends: '../../eslintrc.ts.jest.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./test/tsconfig.json'], + }, + }, + { + files: ['webpack.config.umd.ts'], + extends: '../../eslintrc.ts.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.webpack.json'], + }, + }, + ], +}; diff --git a/packages/map2tree/jest.config.js b/packages/map2tree/jest.config.js new file mode 100644 index 00000000..8824c114 --- /dev/null +++ b/packages/map2tree/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: 'ts-jest', +}; diff --git a/packages/map2tree/package.json b/packages/map2tree/package.json index ee8d4cf3..04d1eb48 100755 --- a/packages/map2tree/package.json +++ b/packages/map2tree/package.json @@ -2,20 +2,6 @@ "name": "map2tree", "version": "1.4.2", "description": "Utility for mapping maps to trees", - "main": "lib/index.js", - "scripts": { - "clean": "rimraf lib dist", - "build": "babel src --out-dir lib", - "build:umd": "webpack --progress --config webpack.config.umd.js", - "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.js", - "test": "jest", - "prepare": "npm run build && npm run build:umd", - "prepublishOnly": "npm run test && npm run clean && npm run build && npm run build:umd && npm run build:umd:min" - }, - "repository": { - "type": "git", - "url": "https://github.com/reduxjs/redux-devtools.git" - }, "keywords": [ "map2tree", "map-to-tree", @@ -23,38 +9,43 @@ "map", "tree" ], - "author": "romseguy", - "license": "MIT", + "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/map2tree", "bugs": { "url": "https://github.com/reduxjs/redux-devtools/issues" }, - "homepage": "https://github.com/reduxjs/redux-devtools", - "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.11.1", - "@babel/preset-env": "^7.11.0", - "babel-loader": "^8.1.0", - "immutable": "^4.0.0-rc.12", - "jest": "^26.2.2", - "rimraf": "^3.0.2", - "webpack": "^4.44.1", - "webpack-cli": "^3.3.12" - }, - "dependencies": { - "lodash": "^4.17.19" - }, - "npmName": "map2tree", + "license": "MIT", + "author": "romseguy", "files": [ "lib", "dist", "src" ], - "npmFileMap": [ - { - "basePath": "/dist/", - "files": [ - "*.js" - ] - } - ] + "main": "lib/index.js", + "types": "lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/reduxjs/redux-devtools.git" + }, + "scripts": { + "build": "npm run build:types && npm run build:js && npm run build:umd && npm run build:umd:min", + "build:types": "tsc --emitDeclarationOnly", + "build:js": "babel src --out-dir lib --extensions \".ts\" --source-maps inline", + "build:umd": "webpack --progress --config webpack.config.umd.ts", + "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.ts", + "clean": "rimraf lib dist", + "test": "jest", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --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": { + "lodash": "^4.17.19" + }, + "devDependencies": { + "@types/lodash": "^4.14.159", + "immutable": "^4.0.0-rc.12" + } } diff --git a/packages/map2tree/src/index.js b/packages/map2tree/src/index.js deleted file mode 100755 index 4e43da70..00000000 --- a/packages/map2tree/src/index.js +++ /dev/null @@ -1,79 +0,0 @@ -import isArray from 'lodash/isArray'; -import isPlainObject from 'lodash/isPlainObject'; -import mapValues from 'lodash/mapValues'; - -function visit(parent, visitFn, childrenFn) { - if (!parent) return; - - visitFn(parent); - - const children = childrenFn(parent); - if (children) { - const count = children.length; - for (let i = 0; i < count; i++) { - visit(children[i], visitFn, childrenFn); - } - } -} - -function getNode(tree, key) { - let node = null; - - visit( - tree, - (d) => { - if (d.name === key) { - node = d; - } - }, - (d) => d.children - ); - - return node; -} - -export default function map2tree( - root, - options = {}, - tree = { name: options.key || 'state', children: [] } -) { - if (!isPlainObject(root) && root && !root.toJS) { - return {}; - } - - const { key: rootNodeKey = 'state', pushMethod = 'push' } = options; - const currentNode = getNode(tree, rootNodeKey); - - if (currentNode === null) { - return {}; - } - - mapValues(root && root.toJS ? root.toJS() : root, (maybeImmutable, key) => { - const value = - maybeImmutable && maybeImmutable.toJS - ? maybeImmutable.toJS() - : maybeImmutable; - let newNode = { name: key }; - - if (isArray(value)) { - newNode.children = []; - - for (let i = 0; i < value.length; i++) { - newNode.children[pushMethod]({ - name: `${key}[${i}]`, - [isPlainObject(value[i]) ? 'object' : 'value']: value[i], - }); - } - } else if (isPlainObject(value)) { - newNode.children = []; - } else { - newNode.value = value; - } - - currentNode.children[pushMethod](newNode); - - map2tree(value, { key, pushMethod }, tree); - }); - - return tree; -} diff --git a/packages/map2tree/src/index.ts b/packages/map2tree/src/index.ts new file mode 100644 index 00000000..958eef3d --- /dev/null +++ b/packages/map2tree/src/index.ts @@ -0,0 +1,99 @@ +import isArray from 'lodash/isArray'; +import isPlainObject from 'lodash/isPlainObject'; +import mapValues from 'lodash/mapValues'; + +interface Node { + name: string; + children?: Node[]; + value?: unknown; +} + +function visit( + parent: Node, + visitFn: (parent: Node) => void, + childrenFn: (parent: Node) => Node[] | undefined +) { + if (!parent) return; + + visitFn(parent); + + const children = childrenFn(parent); + if (children) { + const count = children.length; + for (let i = 0; i < count; i++) { + visit(children[i], visitFn, childrenFn); + } + } +} + +function getNode(tree: Node, key: string): Node | null { + let node = null; + + visit( + tree, + (d) => { + if (d.name === key) { + node = d; + } + }, + (d) => d.children + ); + + return node; +} + +export default function map2tree( + // eslint-disable-next-line @typescript-eslint/ban-types + root: {}, + options: { key?: string; pushMethod?: 'push' | 'unshift' } = {}, + tree: Node = { name: options.key || 'state', children: [] } +): Node { + // eslint-disable-next-line @typescript-eslint/ban-types + if (!isPlainObject(root) && root && !(root as { toJS: () => {} }).toJS) { + return {} as Node; + } + + const { key: rootNodeKey = 'state', pushMethod = 'push' } = options; + const currentNode = getNode(tree, rootNodeKey); + + if (currentNode === null) { + return {} as Node; + } + + mapValues( + // eslint-disable-next-line @typescript-eslint/ban-types + root && (root as { toJS: () => {} }).toJS + ? // eslint-disable-next-line @typescript-eslint/ban-types + (root as { toJS: () => {} }).toJS() + : root, + // eslint-disable-next-line @typescript-eslint/ban-types + (maybeImmutable: { toJS?: () => {} }, key) => { + const value = + maybeImmutable && maybeImmutable.toJS + ? maybeImmutable.toJS() + : maybeImmutable; + const newNode: Node = { name: key }; + + if (isArray(value)) { + newNode.children = []; + + for (let i = 0; i < value.length; i++) { + newNode.children[pushMethod]({ + name: `${key}[${i}]`, + [isPlainObject(value[i]) ? 'object' : 'value']: value[i], + }); + } + } else if (isPlainObject(value)) { + newNode.children = []; + } else { + newNode.value = value; + } + + currentNode.children![pushMethod](newNode); + + map2tree(value, { key, pushMethod }, tree); + } + ); + + return tree; +} diff --git a/packages/map2tree/test/map2tree.spec.js b/packages/map2tree/test/map2tree.spec.ts old mode 100755 new mode 100644 similarity index 97% rename from packages/map2tree/test/map2tree.spec.js rename to packages/map2tree/test/map2tree.spec.ts index 7114a16e..e1cc3787 --- a/packages/map2tree/test/map2tree.spec.js +++ b/packages/map2tree/test/map2tree.spec.ts @@ -1,5 +1,5 @@ import map2tree from '../src'; -import immutable from 'immutable'; +import * as immutable from 'immutable'; test('# rootNodeKey', () => { const map = {}; @@ -151,7 +151,7 @@ describe('# array map', () => { }); test('## unshift', () => { - const options = { pushMethod: 'unshift' }; + const options = { pushMethod: 'unshift' as const }; const expected = { name: 'state', children: [ diff --git a/packages/map2tree/test/tsconfig.json b/packages/map2tree/test/tsconfig.json new file mode 100644 index 00000000..b55532d2 --- /dev/null +++ b/packages/map2tree/test/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["../src", "."] +} diff --git a/packages/map2tree/tsconfig.json b/packages/map2tree/tsconfig.json new file mode 100644 index 00000000..7b7d1492 --- /dev/null +++ b/packages/map2tree/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.react.base.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["src"] +} diff --git a/packages/map2tree/tsconfig.webpack.json b/packages/map2tree/tsconfig.webpack.json new file mode 100644 index 00000000..655c4644 --- /dev/null +++ b/packages/map2tree/tsconfig.webpack.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["webpack.config.umd.ts"] +} diff --git a/packages/map2tree/webpack.config.umd.js b/packages/map2tree/webpack.config.umd.ts similarity index 63% rename from packages/map2tree/webpack.config.umd.js rename to packages/map2tree/webpack.config.umd.ts index fe011338..6bb5dabc 100644 --- a/packages/map2tree/webpack.config.umd.js +++ b/packages/map2tree/webpack.config.umd.ts @@ -1,9 +1,9 @@ -const path = require('path'); +import * as path from 'path'; -module.exports = (env = {}) => ({ +module.exports = (env: { production?: boolean } = {}) => ({ mode: env.production ? 'production' : 'development', entry: { - app: ['./src/index.js'], + app: ['./src/index'], }, output: { library: 'd3tooltip', @@ -14,10 +14,13 @@ module.exports = (env = {}) => ({ module: { rules: [ { - test: /\.js$/, + test: /\.(js|ts)$/, loader: 'babel-loader', exclude: /node_modules/, }, ], }, + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, }); From 3b580dad4cb36abc395f9be139b2c3f94e872d87 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Sun, 20 Sep 2020 14:21:59 -0400 Subject: [PATCH 3/6] feat(d3tooltip): convert to TypeScript (#639) * start d3tooltip * finish d3tooltip --- packages/d3tooltip/.babelrc | 3 +- packages/d3tooltip/.eslintignore | 3 + packages/d3tooltip/.eslintrc.js | 21 ++++ packages/d3tooltip/package.json | 56 ++++----- packages/d3tooltip/src/index.js | 78 ------------ packages/d3tooltip/src/index.ts | 115 ++++++++++++++++++ packages/d3tooltip/src/utils/functor.js | 5 - packages/d3tooltip/src/utils/functor.ts | 20 +++ .../src/utils/{index.js => index.ts} | 0 packages/d3tooltip/src/utils/prependClass.js | 20 --- packages/d3tooltip/src/utils/prependClass.ts | 28 +++++ packages/d3tooltip/tsconfig.json | 7 ++ packages/d3tooltip/tsconfig.webpack.json | 4 + ...ck.config.umd.js => webpack.config.umd.ts} | 11 +- packages/map2tree/package.json | 2 +- packages/map2tree/webpack.config.umd.ts | 2 +- yarn.lock | 17 +++ 17 files changed, 254 insertions(+), 138 deletions(-) create mode 100644 packages/d3tooltip/.eslintignore create mode 100644 packages/d3tooltip/.eslintrc.js delete mode 100644 packages/d3tooltip/src/index.js create mode 100644 packages/d3tooltip/src/index.ts delete mode 100644 packages/d3tooltip/src/utils/functor.js create mode 100644 packages/d3tooltip/src/utils/functor.ts rename packages/d3tooltip/src/utils/{index.js => index.ts} (100%) delete mode 100644 packages/d3tooltip/src/utils/prependClass.js create mode 100644 packages/d3tooltip/src/utils/prependClass.ts create mode 100644 packages/d3tooltip/tsconfig.json create mode 100644 packages/d3tooltip/tsconfig.webpack.json rename packages/d3tooltip/{webpack.config.umd.js => webpack.config.umd.ts} (64%) diff --git a/packages/d3tooltip/.babelrc b/packages/d3tooltip/.babelrc index 1320b9a3..5259cd24 100644 --- a/packages/d3tooltip/.babelrc +++ b/packages/d3tooltip/.babelrc @@ -1,3 +1,4 @@ { - "presets": ["@babel/preset-env"] + "presets": ["@babel/preset-env", "@babel/preset-typescript"], + "plugins": ["@babel/plugin-proposal-class-properties"] } diff --git a/packages/d3tooltip/.eslintignore b/packages/d3tooltip/.eslintignore new file mode 100644 index 00000000..1d149abd --- /dev/null +++ b/packages/d3tooltip/.eslintignore @@ -0,0 +1,3 @@ +examples +lib +dist diff --git a/packages/d3tooltip/.eslintrc.js b/packages/d3tooltip/.eslintrc.js new file mode 100644 index 00000000..f815f2cb --- /dev/null +++ b/packages/d3tooltip/.eslintrc.js @@ -0,0 +1,21 @@ +module.exports = { + extends: '../../.eslintrc', + overrides: [ + { + files: ['*.ts'], + extends: '../../eslintrc.ts.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + }, + { + files: ['webpack.config.umd.ts'], + extends: '../../eslintrc.ts.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.webpack.json'], + }, + }, + ], +}; diff --git a/packages/d3tooltip/package.json b/packages/d3tooltip/package.json index 1ac1190a..67355f4d 100644 --- a/packages/d3tooltip/package.json +++ b/packages/d3tooltip/package.json @@ -2,46 +2,46 @@ "name": "d3tooltip", "version": "1.2.3", "description": "A highly configurable tooltip for d3", - "main": "lib/index.js", - "scripts": { - "clean": "rimraf lib dist", - "build": "babel src --out-dir lib", - "build:umd": "webpack --progress --config webpack.config.umd.js", - "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.js", - "version": "npm run build", - "postversion": "git push && git push --tags && npm run clean", - "prepare": "npm run clean && npm run build", - "prepublishOnly": "npm run clean && npm run build && npm run build:umd && npm run build:umd:min" + "keywords": [ + "d3", + "tooltip" + ], + "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip", + "bugs": { + "url": "https://github.com/reduxjs/redux-devtools/issues" }, + "license": "MIT", + "author": "romseguy", "files": [ "lib", "dist", "src" ], + "main": "lib/index.js", + "types": "lib/index.d.ts", "repository": { "type": "git", "url": "https://github.com/reduxjs/redux-devtools.git" }, - "keywords": [ - "d3", - "tooltip" - ], - "author": "romseguy", - "license": "MIT", - "bugs": { - "url": "https://github.com/reduxjs/redux-devtools/issues" - }, - "homepage": "https://github.com/reduxjs/redux-devtools", - "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.11.1", - "@babel/preset-env": "^7.11.0", - "babel-loader": "^8.1.0", - "rimraf": "^3.0.2", - "webpack": "^4.44.1", - "webpack-cli": "^3.3.12" + "scripts": { + "build": "npm run build:types && npm run build:js && npm run build:umd && npm run build:umd:min", + "build:types": "tsc --emitDeclarationOnly", + "build:js": "babel src --out-dir lib --extensions \".ts\" --source-maps inline", + "build:umd": "webpack --progress --config webpack.config.umd.ts", + "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.ts", + "clean": "rimraf lib dist", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --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": { "ramda": "^0.27.1" + }, + "devDependencies": { + "@types/d3": "^3.5.43", + "@types/ramda": "^0.27.17" } } diff --git a/packages/d3tooltip/src/index.js b/packages/d3tooltip/src/index.js deleted file mode 100644 index 19d84255..00000000 --- a/packages/d3tooltip/src/index.js +++ /dev/null @@ -1,78 +0,0 @@ -import { is } from 'ramda'; -import utils from './utils'; -const { prependClass, functor } = utils.default || utils; - -const defaultOptions = { - left: undefined, // mouseX - top: undefined, // mouseY - offset: { left: 0, top: 0 }, - root: undefined, -}; - -export default function tooltip(d3, className = 'tooltip', options = {}) { - const { left, top, offset, root } = { ...defaultOptions, ...options }; - - let attrs = { class: className }; - let text = () => ''; - let styles = {}; - - let el; - const anchor = root || d3.select('body'); - const rootNode = anchor.node(); - - function tip(selection) { - selection.on({ - 'mouseover.tip': (node) => { - let [mouseX, mouseY] = d3.mouse(rootNode); - let [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top]; - - anchor.selectAll(`div.${className}`).remove(); - - el = anchor - .append('div') - .attr(prependClass(className)(attrs)) - .style({ - position: 'absolute', - 'z-index': 1001, - left: x + 'px', - top: y + 'px', - ...styles, - }) - .html(() => text(node)); - }, - - 'mousemove.tip': (node) => { - let [mouseX, mouseY] = d3.mouse(rootNode); - let [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top]; - - el.style({ - left: x + 'px', - top: y + 'px', - }).html(() => text(node)); - }, - - 'mouseout.tip': () => el.remove(), - }); - } - - tip.attr = function setAttr(d) { - if (is(Object, d)) { - attrs = { ...attrs, ...d }; - } - return this; - }; - - tip.style = function setStyle(d) { - if (is(Object, d)) { - styles = { ...styles, ...d }; - } - return this; - }; - - tip.text = function setText(d) { - text = functor(d); - return this; - }; - - return tip; -} diff --git a/packages/d3tooltip/src/index.ts b/packages/d3tooltip/src/index.ts new file mode 100644 index 00000000..13cac544 --- /dev/null +++ b/packages/d3tooltip/src/index.ts @@ -0,0 +1,115 @@ +import d3Package, { Primitive, Selection } from 'd3'; +import { is } from 'ramda'; +import utils from './utils'; +const { prependClass, functor } = utils; + +const defaultOptions = { + left: undefined, // mouseX + top: undefined, // mouseY + offset: { left: 0, top: 0 }, + root: undefined, +}; + +export default function tooltip( + d3: typeof d3Package, + className = 'tooltip', + options = {} +) { + const { left, top, offset, root } = { ...defaultOptions, ...options }; + + let attrs = { class: className }; + let text: (datum: Datum, index?: number, outerIndex?: number) => string = ( + node: Datum + ) => ''; + let styles = {}; + + let el: Selection; + const anchor = root || d3.select('body'); + const rootNode = anchor.node(); + + function tip(selection: Selection) { + selection.on('mouseover.tip', (node) => { + const [mouseX, mouseY] = d3.mouse(rootNode); + const [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top]; + + anchor.selectAll(`div.${className}`).remove(); + + el = anchor + .append('div') + .attr(prependClass(className)(attrs)) + .style({ + position: 'absolute', + 'z-index': 1001, + left: `${x}px`, + top: `${y}px`, + ...styles, + }) + .html(() => text(node)); + }); + + selection.on('mousemove.tip', (node) => { + const [mouseX, mouseY] = d3.mouse(rootNode); + const [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top]; + + el.style({ + left: `${x}px`, + top: `${y}px`, + }).html(() => text(node)); + }); + + selection.on('mouseout.tip', () => el.remove()); + } + + tip.attr = function setAttr( + d: + | string + | { + [key: string]: + | Primitive + | ((datum: Datum, index: number, outerIndex: number) => Primitive); + } + ) { + if (is(Object, d)) { + attrs = { + ...attrs, + ...(d as { + [key: string]: + | Primitive + | ((datum: Datum, index: number, outerIndex: number) => Primitive); + }), + }; + } + return this; + }; + + tip.style = function setStyle( + d: + | string + | { + [key: string]: + | Primitive + | ((datum: Datum, index: number, outerIndex: number) => Primitive); + } + ) { + if (is(Object, d)) { + styles = { + ...styles, + ...(d as { + [key: string]: + | Primitive + | ((datum: Datum, index: number, outerIndex: number) => Primitive); + }), + }; + } + return this; + }; + + tip.text = function setText( + d: string | ((datum: Datum, index?: number, outerIndex?: number) => string) + ) { + text = functor(d); + return this; + }; + + return tip; +} diff --git a/packages/d3tooltip/src/utils/functor.js b/packages/d3tooltip/src/utils/functor.js deleted file mode 100644 index 007885d3..00000000 --- a/packages/d3tooltip/src/utils/functor.js +++ /dev/null @@ -1,5 +0,0 @@ -import { is } from 'ramda'; - -export default function functor(v) { - return is(Function, v) ? v : () => v; -} diff --git a/packages/d3tooltip/src/utils/functor.ts b/packages/d3tooltip/src/utils/functor.ts new file mode 100644 index 00000000..b0ba2146 --- /dev/null +++ b/packages/d3tooltip/src/utils/functor.ts @@ -0,0 +1,20 @@ +import { is } from 'ramda'; +import { Primitive } from 'd3'; + +export default function functor( + v: string | ((datum: Datum, index?: number, outerIndex?: number) => string) +): (datum: Datum, index?: number, outerIndex?: number) => string; +export default function functor( + v: + | Primitive + | ((datum: Datum, index: number, outerIndex?: number) => Primitive) +): (datum: Datum, index?: number, outerIndex?: number) => Primitive; +export default function functor( + v: + | Primitive + | ((datum: Datum, index: number, outerIndex?: number) => Primitive) +): (datum: Datum, index: number, outerIndex?: number) => Primitive { + return is(Function, v) + ? (v as (datum: Datum, index: number, outerIndex?: number) => Primitive) + : () => v as Primitive; +} diff --git a/packages/d3tooltip/src/utils/index.js b/packages/d3tooltip/src/utils/index.ts similarity index 100% rename from packages/d3tooltip/src/utils/index.js rename to packages/d3tooltip/src/utils/index.ts diff --git a/packages/d3tooltip/src/utils/prependClass.js b/packages/d3tooltip/src/utils/prependClass.js deleted file mode 100644 index 2194f865..00000000 --- a/packages/d3tooltip/src/utils/prependClass.js +++ /dev/null @@ -1,20 +0,0 @@ -import { mapObjIndexed, join } from 'ramda'; -import functor from './functor'; - -export default function prependClass(className) { - return mapObjIndexed((value, key) => { - if (key === 'class') { - const fn = functor(value); - - return (d, i) => { - const classNames = fn(d, i); - if (classNames !== className) { - return join(' ', [className, classNames]); - } - return classNames; - }; - } - - return value; - }); -} diff --git a/packages/d3tooltip/src/utils/prependClass.ts b/packages/d3tooltip/src/utils/prependClass.ts new file mode 100644 index 00000000..cc9bf058 --- /dev/null +++ b/packages/d3tooltip/src/utils/prependClass.ts @@ -0,0 +1,28 @@ +import { mapObjIndexed, join } from 'ramda'; +import functor from './functor'; +import { Primitive } from 'd3'; + +export default function prependClass(className: string) { + return mapObjIndexed( + ( + value: + | Primitive + | ((datum: Datum, index: number, outerIndex?: number) => Primitive), + key + ) => { + if (key === 'class') { + const fn = functor(value); + + return (d: Datum, i: number) => { + const classNames = fn(d, i); + if (classNames !== className) { + return join(' ', [className, classNames]); + } + return classNames; + }; + } + + return value; + } + ); +} diff --git a/packages/d3tooltip/tsconfig.json b/packages/d3tooltip/tsconfig.json new file mode 100644 index 00000000..7b7d1492 --- /dev/null +++ b/packages/d3tooltip/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.react.base.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["src"] +} diff --git a/packages/d3tooltip/tsconfig.webpack.json b/packages/d3tooltip/tsconfig.webpack.json new file mode 100644 index 00000000..655c4644 --- /dev/null +++ b/packages/d3tooltip/tsconfig.webpack.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["webpack.config.umd.ts"] +} diff --git a/packages/d3tooltip/webpack.config.umd.js b/packages/d3tooltip/webpack.config.umd.ts similarity index 64% rename from packages/d3tooltip/webpack.config.umd.js rename to packages/d3tooltip/webpack.config.umd.ts index 37a3178a..9913c7f5 100644 --- a/packages/d3tooltip/webpack.config.umd.js +++ b/packages/d3tooltip/webpack.config.umd.ts @@ -1,9 +1,9 @@ -const path = require('path'); +import * as path from 'path'; -module.exports = (env = {}) => ({ +module.exports = (env: { production?: boolean } = {}) => ({ mode: env.production ? 'production' : 'development', entry: { - app: ['./src/index.js'], + app: ['./src/index'], }, output: { library: 'd3tooltip', @@ -14,10 +14,13 @@ module.exports = (env = {}) => ({ module: { rules: [ { - test: /\.js$/, + test: /\.(js|ts)$/, loader: 'babel-loader', exclude: /node_modules/, }, ], }, + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, }); diff --git a/packages/map2tree/package.json b/packages/map2tree/package.json index 04d1eb48..516f5da6 100755 --- a/packages/map2tree/package.json +++ b/packages/map2tree/package.json @@ -38,7 +38,7 @@ "lint:fix": "eslint . --ext .ts --fix", "type-check": "tsc --noEmit", "type-check:watch": "npm run type-check -- --watch", - "preversion": "npm run type-check && npm run lint && npm run test", + "preversion": "npm run type-check && npm run lint", "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { diff --git a/packages/map2tree/webpack.config.umd.ts b/packages/map2tree/webpack.config.umd.ts index 6bb5dabc..37e91464 100644 --- a/packages/map2tree/webpack.config.umd.ts +++ b/packages/map2tree/webpack.config.umd.ts @@ -6,7 +6,7 @@ module.exports = (env: { production?: boolean } = {}) => ({ app: ['./src/index'], }, output: { - library: 'd3tooltip', + library: 'map2tree', libraryTarget: 'umd', path: path.resolve(__dirname, 'dist'), filename: env.production ? 'map2tree.min.js' : 'map2tree.js', diff --git a/yarn.lock b/yarn.lock index 8b678689..58a70246 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3355,6 +3355,11 @@ dependencies: "@types/node" "*" +"@types/d3@^3.5.43": + version "3.5.43" + resolved "https://registry.yarnpkg.com/@types/d3/-/d3-3.5.43.tgz#e9b4992817e0b6c5efaa7d6e5bb2cee4d73eab58" + integrity sha512-t9ZmXOcpVxywRw86YtIC54g7M9puRh8hFedRvVfHKf5YyOP6pSxA0TvpXpfseXSCInoW4P7bggTrSDiUOs4g5w== + "@types/dateformat@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/dateformat/-/dateformat-3.0.1.tgz#98d747a2e5e9a56070c6bf14e27bff56204e34cc" @@ -3675,6 +3680,13 @@ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a" integrity sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ== +"@types/ramda@^0.27.17": + version "0.27.17" + resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.27.17.tgz#b4359d29614994dbb4c70e504b268bd9f0388bb0" + integrity sha512-AHVwr1YdFdxeabfC1g34ZuJ61dKOcfdXlG+sqGUweD+5VrD6A9emwmc2OZY+N8CdEKdwl29hwvtTMSJ6ZVVsiQ== + dependencies: + ts-toolbelt "^6.3.3" + "@types/range-parser@*": version "1.2.3" resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" @@ -16929,6 +16941,11 @@ ts-pnp@^1.1.6: resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== +ts-toolbelt@^6.3.3: + version "6.15.5" + resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz#cb3b43ed725cb63644782c64fbcad7d8f28c0a83" + integrity sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A== + tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" From 0c78a5a9a76ee7eff37dcd8e39272d98c03e0869 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Sun, 20 Sep 2020 19:05:37 -0400 Subject: [PATCH 4/6] feat(d3-state-visualizer): convert to TypeScript (#640) * feat(d3-state-visualizer): convert to TypeScript * dep * Odd --- packages/d3-state-visualizer/.babelrc | 7 +- packages/d3-state-visualizer/.eslintignore | 3 + packages/d3-state-visualizer/.eslintrc.js | 21 ++ packages/d3-state-visualizer/package.json | 61 ++--- .../d3-state-visualizer/src/charts/index.js | 1 - .../d3-state-visualizer/src/charts/index.ts | 1 + ...ortAndSerialize.js => sortAndSerialize.ts} | 8 +- .../src/charts/tree/{tree.js => tree.ts} | 245 +++++++++++++----- .../src/charts/tree/{utils.js => utils.ts} | 40 ++- .../src/{index.js => index.ts} | 0 packages/d3-state-visualizer/tsconfig.json | 7 + .../d3-state-visualizer/tsconfig.webpack.json | 4 + .../webpack.config.base.js | 17 -- .../webpack.config.development.js | 14 - .../webpack.config.production.js | 14 - .../d3-state-visualizer/webpack.config.umd.ts | 28 ++ packages/d3tooltip/package.json | 7 +- packages/d3tooltip/src/index.ts | 21 +- packages/d3tooltip/webpack.config.umd.ts | 2 +- packages/map2tree/package.json | 2 +- packages/map2tree/src/index.ts | 13 +- packages/map2tree/test/map2tree.spec.ts | 4 +- packages/map2tree/webpack.config.umd.ts | 2 +- .../src/LogMonitor.tsx | 10 +- 24 files changed, 340 insertions(+), 192 deletions(-) create mode 100644 packages/d3-state-visualizer/.eslintignore create mode 100644 packages/d3-state-visualizer/.eslintrc.js delete mode 100644 packages/d3-state-visualizer/src/charts/index.js create mode 100644 packages/d3-state-visualizer/src/charts/index.ts rename packages/d3-state-visualizer/src/charts/tree/{sortAndSerialize.js => sortAndSerialize.ts} (57%) rename packages/d3-state-visualizer/src/charts/tree/{tree.js => tree.ts} (64%) rename packages/d3-state-visualizer/src/charts/tree/{utils.js => utils.ts} (57%) rename packages/d3-state-visualizer/src/{index.js => index.ts} (100%) create mode 100644 packages/d3-state-visualizer/tsconfig.json create mode 100644 packages/d3-state-visualizer/tsconfig.webpack.json delete mode 100644 packages/d3-state-visualizer/webpack.config.base.js delete mode 100644 packages/d3-state-visualizer/webpack.config.development.js delete mode 100644 packages/d3-state-visualizer/webpack.config.production.js create mode 100644 packages/d3-state-visualizer/webpack.config.umd.ts diff --git a/packages/d3-state-visualizer/.babelrc b/packages/d3-state-visualizer/.babelrc index 06050b00..5259cd24 100644 --- a/packages/d3-state-visualizer/.babelrc +++ b/packages/d3-state-visualizer/.babelrc @@ -1,7 +1,4 @@ { - "presets": ["@babel/preset-env"], - "plugins": [ - "@babel/plugin-proposal-class-properties", - "@babel/plugin-proposal-export-default-from" - ] + "presets": ["@babel/preset-env", "@babel/preset-typescript"], + "plugins": ["@babel/plugin-proposal-class-properties"] } diff --git a/packages/d3-state-visualizer/.eslintignore b/packages/d3-state-visualizer/.eslintignore new file mode 100644 index 00000000..1d149abd --- /dev/null +++ b/packages/d3-state-visualizer/.eslintignore @@ -0,0 +1,3 @@ +examples +lib +dist diff --git a/packages/d3-state-visualizer/.eslintrc.js b/packages/d3-state-visualizer/.eslintrc.js new file mode 100644 index 00000000..f815f2cb --- /dev/null +++ b/packages/d3-state-visualizer/.eslintrc.js @@ -0,0 +1,21 @@ +module.exports = { + extends: '../../.eslintrc', + overrides: [ + { + files: ['*.ts'], + extends: '../../eslintrc.ts.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + }, + { + files: ['webpack.config.umd.ts'], + extends: '../../eslintrc.ts.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.webpack.json'], + }, + }, + ], +}; diff --git a/packages/d3-state-visualizer/package.json b/packages/d3-state-visualizer/package.json index 589db98a..4ab6245f 100644 --- a/packages/d3-state-visualizer/package.json +++ b/packages/d3-state-visualizer/package.json @@ -2,24 +2,6 @@ "name": "d3-state-visualizer", "version": "1.3.4", "description": "Visualize your app state with a range of reusable charts", - "main": "lib/index.js", - "files": [ - "dist", - "lib", - "src" - ], - "scripts": { - "clean": "rimraf lib dist", - "build": "babel src --out-dir lib", - "build:umd": "webpack src/index.js -o dist/d3-state-visualizer.js --config webpack.config.development.js", - "build:umd:min": "webpack src/index.js -o dist/d3-state-visualizer.min.js --config webpack.config.production.js", - "prepare": "npm run build", - "prepublishOnly": "npm run clean && npm run build && npm run build:umd && npm run build:umd:min" - }, - "repository": { - "type": "git", - "url": "https://github.com/reduxjs/redux-devtools.git" - }, "keywords": [ "d3", "state", @@ -27,27 +9,46 @@ "tree", "visualization" ], - "author": "romseguy", - "license": "MIT", + "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/d3-state-visualizer", "bugs": { "url": "https://github.com/reduxjs/redux-devtools/issues" }, - "homepage": "https://github.com/reduxjs/redux-devtools", - "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.11.1", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/plugin-proposal-export-default-from": "^7.10.4", - "@babel/preset-env": "^7.11.0", - "babel-loader": "^8.1.0", - "rimraf": "^3.0.2", - "webpack": "^4.44.1" + "license": "MIT", + "author": "romseguy", + "files": [ + "dist", + "lib", + "src" + ], + "main": "lib/index.js", + "types": "lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/reduxjs/redux-devtools.git" + }, + "scripts": { + "build": "npm run build:types && npm run build:js && npm run build:umd && npm run build:umd:min", + "build:types": "tsc --emitDeclarationOnly", + "build:js": "babel src --out-dir lib --extensions \".ts\" --source-maps inline", + "build:umd": "webpack --env.production --progress --config webpack.config.umd.ts", + "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.ts", + "clean": "rimraf lib dist", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "type-check": "tsc --noEmit", + "type-check:watch": "npm run type-check -- --watch", + "preversion": "npm run type-check && npm run lint", + "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { + "@types/d3": "^3.5.43", "d3": "^3.5.17", "d3tooltip": "^1.2.3", "deepmerge": "^4.2.2", "map2tree": "^1.4.2", "ramda": "^0.27.1" + }, + "devDependencies": { + "@types/ramda": "^0.27.17" } } diff --git a/packages/d3-state-visualizer/src/charts/index.js b/packages/d3-state-visualizer/src/charts/index.js deleted file mode 100644 index d2f1835e..00000000 --- a/packages/d3-state-visualizer/src/charts/index.js +++ /dev/null @@ -1 +0,0 @@ -export tree from './tree/tree'; diff --git a/packages/d3-state-visualizer/src/charts/index.ts b/packages/d3-state-visualizer/src/charts/index.ts new file mode 100644 index 00000000..33abb024 --- /dev/null +++ b/packages/d3-state-visualizer/src/charts/index.ts @@ -0,0 +1 @@ +export { default as tree } from './tree/tree'; diff --git a/packages/d3-state-visualizer/src/charts/tree/sortAndSerialize.js b/packages/d3-state-visualizer/src/charts/tree/sortAndSerialize.ts similarity index 57% rename from packages/d3-state-visualizer/src/charts/tree/sortAndSerialize.js rename to packages/d3-state-visualizer/src/charts/tree/sortAndSerialize.ts index ff36ef6f..270eab40 100644 --- a/packages/d3-state-visualizer/src/charts/tree/sortAndSerialize.js +++ b/packages/d3-state-visualizer/src/charts/tree/sortAndSerialize.ts @@ -1,4 +1,4 @@ -function sortObject(obj, strict) { +function sortObject(obj: unknown, strict?: boolean) { if (obj instanceof Array) { let ary; if (strict) { @@ -10,16 +10,16 @@ function sortObject(obj, strict) { } if (obj && typeof obj === 'object') { - const tObj = {}; + const tObj: { [key: string]: unknown } = {}; Object.keys(obj) .sort() - .forEach((key) => (tObj[key] = sortObject(obj[key]))); + .forEach((key) => (tObj[key] = sortObject(obj[key as keyof typeof obj]))); return tObj; } return obj; } -export default function sortAndSerialize(obj) { +export default function sortAndSerialize(obj: unknown) { return JSON.stringify(sortObject(obj, true), undefined, 2); } diff --git a/packages/d3-state-visualizer/src/charts/tree/tree.js b/packages/d3-state-visualizer/src/charts/tree/tree.ts similarity index 64% rename from packages/d3-state-visualizer/src/charts/tree/tree.js rename to packages/d3-state-visualizer/src/charts/tree/tree.ts index 5c97a6b1..246d2df8 100644 --- a/packages/d3-state-visualizer/src/charts/tree/tree.js +++ b/packages/d3-state-visualizer/src/charts/tree/tree.ts @@ -1,4 +1,4 @@ -import d3 from 'd3'; +import d3, { ZoomEvent, Primitive } from 'd3'; import { isEmpty } from 'ramda'; import map2tree from 'map2tree'; import deepmerge from 'deepmerge'; @@ -10,7 +10,63 @@ import { } from './utils'; import d3tooltip from 'd3tooltip'; -const defaultOptions = { +interface Options { + // eslint-disable-next-line @typescript-eslint/ban-types + state?: {}; + // eslint-disable-next-line @typescript-eslint/ban-types + tree?: NodeWithId | {}; + + rootKeyName: string; + pushMethod: 'push' | 'unshift'; + id: string; + style: { + node: { + colors: { + default: string; + collapsed: string; + parent: string; + }; + radius: number; + }; + text: { + colors: { + default: string; + hover: string; + }; + }; + link: { + stroke: string; + fill: string; + }; + }; + size: number; + aspectRatio: number; + initialZoom: number; + margin: { + top: number; + right: number; + bottom: number; + left: number; + }; + isSorted: boolean; + heightBetweenNodesCoeff: number; + widthBetweenNodesCoeff: number; + transitionDuration: number; + blinkDuration: number; + onClickText: () => void; + tooltipOptions: { + disabled: boolean; + left: number | undefined; + top: number | undefined; + offset: { + left: number; + top: number; + }; + style: { [key: string]: Primitive } | undefined; + }; +} + +const defaultOptions: Options = { state: undefined, rootKeyName: 'state', pushMethod: 'push', @@ -50,11 +106,13 @@ const defaultOptions = { widthBetweenNodesCoeff: 1, transitionDuration: 750, blinkDuration: 100, - onClickText: () => {}, + onClickText: () => { + // noop + }, tooltipOptions: { disabled: false, left: undefined, - right: undefined, + top: undefined, offset: { left: 0, top: 0, @@ -63,7 +121,27 @@ const defaultOptions = { }, }; -export default function (DOMNode, options = {}) { +export interface NodeWithId { + name: string; + children?: NodeWithId[] | null; + _children?: NodeWithId[] | null; + value?: unknown; + id: string; + + parent?: NodeWithId; + depth?: number; + x?: number; + y?: number; +} + +interface NodePosition { + parentId: string | null | undefined; + id: string; + x: number | undefined; + y: number | undefined; +} + +export default function (DOMNode: HTMLElement, options: Partial = {}) { const { id, style, @@ -89,16 +167,19 @@ export default function (DOMNode, options = {}) { const fullWidth = size; const fullHeight = size * aspectRatio; - const attr = { + const attr: { [key: string]: Primitive } = { id, preserveAspectRatio: 'xMinYMin slice', }; - if (!style.width) { + if (!((style as unknown) as { [key: string]: Primitive }).width) { attr.width = fullWidth; } - if (!style.width || !style.height) { + if ( + !((style as unknown) as { [key: string]: Primitive }).width || + !((style as unknown) as { [key: string]: Primitive }).height + ) { attr.viewBox = `0 0 ${fullWidth} ${fullHeight}`; } @@ -107,11 +188,16 @@ export default function (DOMNode, options = {}) { const vis = root .append('svg') .attr(attr) - .style({ cursor: '-webkit-grab', ...style }) + .style(({ cursor: '-webkit-grab', ...style } as unknown) as { + [key: string]: Primitive; + }) .call( zoom.on('zoom', () => { - const { translate, scale } = d3.event; - vis.attr('transform', `translate(${translate})scale(${scale})`); + const { translate, scale } = d3.event as ZoomEvent; + vis.attr( + 'transform', + `translate(${translate.toString()})scale(${scale})` + ); }) ) .append('g') @@ -122,18 +208,21 @@ export default function (DOMNode, options = {}) { }); let layout = d3.layout.tree().size([width, height]); - let data; + let data: NodeWithId; if (isSorted) { layout.sort((a, b) => - b.name.toLowerCase() < a.name.toLowerCase() ? 1 : -1 + (b as NodeWithId).name.toLowerCase() < + (a as NodeWithId).name.toLowerCase() + ? 1 + : -1 ); } // previousNodePositionsById stores node x and y // as well as hierarchy (id / parentId); // helps animating transitions - let previousNodePositionsById = { + let previousNodePositionsById: { [nodeId: string]: NodePosition } = { root: { id: 'root', parentId: null, @@ -145,10 +234,14 @@ export default function (DOMNode, options = {}) { // traverses a map with node positions by going through the chain // of parent ids; once a parent that matches the given filter is found, // the parent position gets returned - function findParentNodePosition(nodePositionsById, nodeId, filter) { + function findParentNodePosition( + nodePositionsById: { [nodeId: string]: NodePosition }, + nodeId: string, + filter: (nodePosition: NodePosition) => boolean + ) { let currentPosition = nodePositionsById[nodeId]; while (currentPosition) { - currentPosition = nodePositionsById[currentPosition.parentId]; + currentPosition = nodePositionsById[currentPosition.parentId!]; if (!currentPosition) { return null; } @@ -160,14 +253,18 @@ export default function (DOMNode, options = {}) { return function renderChart(nextState = tree || state) { data = !tree - ? map2tree(nextState, { key: rootKeyName, pushMethod }) - : nextState; + ? // eslint-disable-next-line @typescript-eslint/ban-types + (map2tree(nextState as {}, { + key: rootKeyName, + pushMethod, + }) as NodeWithId) + : (nextState as NodeWithId); if (isEmpty(data) || !data.name) { - data = { + data = ({ name: 'error', message: 'Please provide a state map or a tree structure', - }; + } as unknown) as NodeWithId; } let nodeIndex = 0; @@ -191,13 +288,13 @@ export default function (DOMNode, options = {}) { : null ); - /*eslint-disable*/ update(); - /*eslint-enable*/ function update() { // path generator for links - const diagonal = d3.svg.diagonal().projection((d) => [d.y, d.x]); + const diagonal = d3.svg + .diagonal() + .projection((d) => [d.y!, d.x!]); // set tree dimensions and spacing between branches and nodes const maxNodeCountByLevel = Math.max(...getNodeGroupByDepthCount(data)); @@ -206,12 +303,12 @@ export default function (DOMNode, options = {}) { width, ]); - let nodes = layout.nodes(data); - let links = layout.links(nodes); + const nodes = layout.nodes(data as d3.layout.tree.Node) as NodeWithId[]; + const links = layout.links(nodes as d3.layout.tree.Node[]); nodes.forEach( (node) => - (node.y = node.depth * (maxLabelLength * 7 * widthBetweenNodesCoeff)) + (node.y = node.depth! * (maxLabelLength * 7 * widthBetweenNodesCoeff)) ); const nodePositions = nodes.map((n) => ({ @@ -220,15 +317,18 @@ export default function (DOMNode, options = {}) { x: n.x, y: n.y, })); - const nodePositionsById = {}; + const nodePositionsById: { [nodeId: string]: NodePosition } = {}; nodePositions.forEach((node) => (nodePositionsById[node.id] = node)); // process the node selection - let node = vis + const node = vis .selectAll('g.node') - .property('__oldData__', (d) => d) - .data(nodes, (d) => d.id || (d.id = ++nodeIndex)); - let nodeEnter = node + .property('__oldData__', (d: NodeWithId) => d) + .data( + nodes, + (d) => d.id || (d.id = (++nodeIndex as unknown) as string) + ); + const nodeEnter = node .enter() .append('g') .attr({ @@ -237,35 +337,39 @@ export default function (DOMNode, options = {}) { const position = findParentNodePosition( nodePositionsById, d.id, - (n) => previousNodePositionsById[n.id] + (n) => !!previousNodePositionsById[n.id] ); const previousPosition = (position && previousNodePositionsById[position.id]) || previousNodePositionsById.root; - return `translate(${previousPosition.y},${previousPosition.x})`; + return `translate(${previousPosition.y!},${previousPosition.x!})`; }, }) .style({ fill: style.text.colors.default, cursor: 'pointer', }) - .on({ - mouseover: function mouseover() { - d3.select(this).style({ - fill: style.text.colors.hover, - }); - }, - mouseout: function mouseout() { - d3.select(this).style({ - fill: style.text.colors.default, - }); - }, + .on('mouseover', function mouseover(this: any) { + d3.select(this).style({ + fill: style.text.colors.hover, + }); + }) + .on('mouseout', function mouseout(this: any) { + d3.select(this).style({ + fill: style.text.colors.default, + }); }); if (!tooltipOptions.disabled) { nodeEnter.call( d3tooltip(d3, 'tooltip', { ...tooltipOptions, root }) - .text((d, i) => getTooltipString(d, i, tooltipOptions)) + .text((d, i) => + getTooltipString( + d, + i, + (tooltipOptions as unknown) as { indentationSize: number } + ) + ) .style(tooltipOptions.style) ); } @@ -279,12 +383,10 @@ export default function (DOMNode, options = {}) { class: 'nodeCircle', r: 0, }) - .on({ - click: (clickedNode) => { - if (d3.event.defaultPrevented) return; - toggleChildren(clickedNode); - update(); - }, + .on('click', (clickedNode) => { + if ((d3.event as Event).defaultPrevented) return; + toggleChildren(clickedNode); + update(); }); nodeEnterInnerGroup @@ -299,9 +401,7 @@ export default function (DOMNode, options = {}) { 'fill-opacity': 0, }) .text((d) => d.name) - .on({ - click: onClickText, - }); + .on('click', onClickText); // update the text to reflect whether node has children or not node.select('text').text((d) => d.name); @@ -319,11 +419,11 @@ export default function (DOMNode, options = {}) { }); // transition nodes to their new position - let nodeUpdate = node + const nodeUpdate = node .transition() .duration(transitionDuration) .attr({ - transform: (d) => `translate(${d.y},${d.x})`, + transform: (d) => `translate(${d.y!},${d.x!})`, }); // ensure circle radius is correct @@ -334,7 +434,7 @@ export default function (DOMNode, options = {}) { .select('text') .style('fill-opacity', 1) .attr({ - transform: function transform(d) { + transform: function transform(this: SVGGraphicsElement, d) { const x = (d.children || d._children ? -1 : 1) * (this.getBBox().width / 2 + style.node.radius + 5); @@ -344,7 +444,7 @@ export default function (DOMNode, options = {}) { // blink updated nodes node - .filter(function flick(d) { + .filter(function flick(this: any, d) { // test whether the relevant properties of d match // the equivalent property of the oldData // also test whether the old data exists, @@ -358,7 +458,7 @@ export default function (DOMNode, options = {}) { .style('opacity', '1'); // transition exiting nodes to the parent's new position - let nodeExit = node + const nodeExit = node .exit() .transition() .duration(transitionDuration) @@ -367,12 +467,12 @@ export default function (DOMNode, options = {}) { const position = findParentNodePosition( previousNodePositionsById, d.id, - (n) => nodePositionsById[n.id] + (n) => !!nodePositionsById[n.id] ); const futurePosition = (position && nodePositionsById[position.id]) || nodePositionsById.root; - return `translate(${futurePosition.y},${futurePosition.x})`; + return `translate(${futurePosition.y!},${futurePosition.x!})`; }, }) .remove(); @@ -382,7 +482,9 @@ export default function (DOMNode, options = {}) { nodeExit.select('text').style('fill-opacity', 0); // update the links - let link = vis.selectAll('path.link').data(links, (d) => d.target.id); + const link = vis + .selectAll('path.link') + .data(links, (d) => (d.target as NodeWithId).id); // enter any new links at the parent's previous position link @@ -393,8 +495,8 @@ export default function (DOMNode, options = {}) { d: (d) => { const position = findParentNodePosition( nodePositionsById, - d.target.id, - (n) => previousNodePositionsById[n.id] + (d.target as NodeWithId).id, + (n) => !!previousNodePositionsById[n.id] ); const previousPosition = (position && previousNodePositionsById[position.id]) || @@ -402,15 +504,18 @@ export default function (DOMNode, options = {}) { return diagonal({ source: previousPosition, target: previousPosition, - }); + } as d3.svg.diagonal.Link); }, }) .style(style.link); // transition links to their new position - link.transition().duration(transitionDuration).attr({ - d: diagonal, - }); + link + .transition() + .duration(transitionDuration) + .attr({ + d: (diagonal as unknown) as Primitive, + }); // transition exiting nodes to the parent's new position link @@ -421,8 +526,8 @@ export default function (DOMNode, options = {}) { d: (d) => { const position = findParentNodePosition( previousNodePositionsById, - d.target.id, - (n) => nodePositionsById[n.id] + (d.target as NodeWithId).id, + (n) => !!nodePositionsById[n.id] ); const futurePosition = (position && nodePositionsById[position.id]) || diff --git a/packages/d3-state-visualizer/src/charts/tree/utils.js b/packages/d3-state-visualizer/src/charts/tree/utils.ts similarity index 57% rename from packages/d3-state-visualizer/src/charts/tree/utils.js rename to packages/d3-state-visualizer/src/charts/tree/utils.ts index 7b76058d..dcd4a82c 100644 --- a/packages/d3-state-visualizer/src/charts/tree/utils.js +++ b/packages/d3-state-visualizer/src/charts/tree/utils.ts @@ -1,7 +1,8 @@ import { is, join, pipe, replace } from 'ramda'; import sortAndSerialize from './sortAndSerialize'; +import { NodeWithId } from './tree'; -export function collapseChildren(node) { +export function collapseChildren(node: NodeWithId) { if (node.children) { node._children = node.children; node._children.forEach(collapseChildren); @@ -9,7 +10,7 @@ export function collapseChildren(node) { } } -export function expandChildren(node) { +export function expandChildren(node: NodeWithId) { if (node._children) { node.children = node._children; node.children.forEach(expandChildren); @@ -17,7 +18,7 @@ export function expandChildren(node) { } } -export function toggleChildren(node) { +export function toggleChildren(node: NodeWithId) { if (node.children) { node._children = node.children; node.children = null; @@ -28,16 +29,20 @@ export function toggleChildren(node) { return node; } -export function visit(parent, visitFn, childrenFn) { +export function visit( + parent: NodeWithId, + visitFn: (parent: NodeWithId) => void, + childrenFn: (parent: NodeWithId) => NodeWithId[] | null | undefined +) { if (!parent) { return; } visitFn(parent); - let children = childrenFn(parent); + const children = childrenFn(parent); if (children) { - let count = children.length; + const count = children.length; for (let i = 0; i < count; i++) { visit(children[i], visitFn, childrenFn); @@ -45,10 +50,10 @@ export function visit(parent, visitFn, childrenFn) { } } -export function getNodeGroupByDepthCount(rootNode) { - let nodeGroupByDepthCount = [1]; +export function getNodeGroupByDepthCount(rootNode: NodeWithId) { + const nodeGroupByDepthCount = [1]; - const traverseFrom = function traverseFrom(node, depth = 0) { + const traverseFrom = function traverseFrom(node: NodeWithId, depth = 0) { if (!node.children || node.children.length === 0) { return 0; } @@ -68,7 +73,11 @@ export function getNodeGroupByDepthCount(rootNode) { return nodeGroupByDepthCount; } -export function getTooltipString(node, i, { indentationSize = 4 }) { +export function getTooltipString( + node: unknown, + i: number | undefined, + { indentationSize = 4 } +) { if (!is(Object, node)) return ''; const spacer = join('  '); @@ -76,10 +85,13 @@ export function getTooltipString(node, i, { indentationSize = 4 }) { const spaces2nbsp = replace(/\s{2}/g, spacer(new Array(indentationSize))); const json2html = pipe(sortAndSerialize, cr2br, spaces2nbsp); - const children = node.children || node._children; + const children = (node as any).children || (node as any)._children; - if (typeof node.value !== 'undefined') return json2html(node.value); - if (typeof node.object !== 'undefined') return json2html(node.object); - if (children && children.length) return 'childrenCount: ' + children.length; + if (typeof (node as any).value !== 'undefined') + return json2html((node as any).value); + if (typeof (node as any).object !== 'undefined') + return json2html((node as any).object); + if (children && children.length) + return `childrenCount: ${(children as unknown[]).length}`; return 'empty'; } diff --git a/packages/d3-state-visualizer/src/index.js b/packages/d3-state-visualizer/src/index.ts similarity index 100% rename from packages/d3-state-visualizer/src/index.js rename to packages/d3-state-visualizer/src/index.ts diff --git a/packages/d3-state-visualizer/tsconfig.json b/packages/d3-state-visualizer/tsconfig.json new file mode 100644 index 00000000..7b7d1492 --- /dev/null +++ b/packages/d3-state-visualizer/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.react.base.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["src"] +} diff --git a/packages/d3-state-visualizer/tsconfig.webpack.json b/packages/d3-state-visualizer/tsconfig.webpack.json new file mode 100644 index 00000000..655c4644 --- /dev/null +++ b/packages/d3-state-visualizer/tsconfig.webpack.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["webpack.config.umd.ts"] +} diff --git a/packages/d3-state-visualizer/webpack.config.base.js b/packages/d3-state-visualizer/webpack.config.base.js deleted file mode 100644 index f7ac921b..00000000 --- a/packages/d3-state-visualizer/webpack.config.base.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -module.exports = { - module: { - rules: [ - { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }, - ], - }, - output: { - library: 'd3-state-visualizer', - libraryExport: 'default', - libraryTarget: 'umd', - }, - resolve: { - extensions: ['.js'], - }, -}; diff --git a/packages/d3-state-visualizer/webpack.config.development.js b/packages/d3-state-visualizer/webpack.config.development.js deleted file mode 100644 index aa9d02ee..00000000 --- a/packages/d3-state-visualizer/webpack.config.development.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -var webpack = require('webpack'); -var baseConfig = require('./webpack.config.base'); - -var config = Object.assign({}, baseConfig); -config.mode = 'development'; -config.plugins = [ - new webpack.DefinePlugin({ - 'process.env.NODE_ENV': JSON.stringify('development'), - }), -]; - -module.exports = config; diff --git a/packages/d3-state-visualizer/webpack.config.production.js b/packages/d3-state-visualizer/webpack.config.production.js deleted file mode 100644 index b5310704..00000000 --- a/packages/d3-state-visualizer/webpack.config.production.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -var webpack = require('webpack'); -var baseConfig = require('./webpack.config.base'); - -var config = Object.assign({}, baseConfig); -config.mode = 'production'; -config.plugins = [ - new webpack.DefinePlugin({ - 'process.env.NODE_ENV': JSON.stringify('production'), - }), -]; - -module.exports = config; diff --git a/packages/d3-state-visualizer/webpack.config.umd.ts b/packages/d3-state-visualizer/webpack.config.umd.ts new file mode 100644 index 00000000..a9643899 --- /dev/null +++ b/packages/d3-state-visualizer/webpack.config.umd.ts @@ -0,0 +1,28 @@ +import * as path from 'path'; + +export default (env: { production?: boolean } = {}) => ({ + mode: env.production ? 'production' : 'development', + entry: { + app: ['./src/index'], + }, + output: { + library: 'd3-state-visualizer', + libraryTarget: 'umd', + path: path.resolve(__dirname, 'dist'), + filename: env.production + ? 'd3-state-visualizer.min.js' + : 'd3-state-visualizer.js', + }, + module: { + rules: [ + { + test: /\.(js|ts)$/, + loader: 'babel-loader', + exclude: /node_modules/, + }, + ], + }, + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, +}); diff --git a/packages/d3tooltip/package.json b/packages/d3tooltip/package.json index 67355f4d..27791a44 100644 --- a/packages/d3tooltip/package.json +++ b/packages/d3tooltip/package.json @@ -34,14 +34,17 @@ "lint:fix": "eslint . --ext .ts --fix", "type-check": "tsc --noEmit", "type-check:watch": "npm run type-check -- --watch", - "preversion": "npm run type-check && npm run lint && npm run test", + "preversion": "npm run type-check && npm run lint", "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { "ramda": "^0.27.1" }, "devDependencies": { - "@types/d3": "^3.5.43", "@types/ramda": "^0.27.17" + }, + "peerDependencies": { + "@types/d3": "^3.5.43", + "d3": "^3.5.17" } } diff --git a/packages/d3tooltip/src/index.ts b/packages/d3tooltip/src/index.ts index 13cac544..2f093242 100644 --- a/packages/d3tooltip/src/index.ts +++ b/packages/d3tooltip/src/index.ts @@ -3,7 +3,17 @@ import { is } from 'ramda'; import utils from './utils'; const { prependClass, functor } = utils; -const defaultOptions = { +interface Options { + left: number | undefined; + top: number | undefined; + offset: { + left: number; + top: number; + }; + root: Selection | undefined; +} + +const defaultOptions: Options = { left: undefined, // mouseX top: undefined, // mouseY offset: { left: 0, top: 0 }, @@ -13,9 +23,12 @@ const defaultOptions = { export default function tooltip( d3: typeof d3Package, className = 'tooltip', - options = {} + options: Partial> = {} ) { - const { left, top, offset, root } = { ...defaultOptions, ...options }; + const { left, top, offset, root } = { + ...defaultOptions, + ...options, + } as Options; let attrs = { class: className }; let text: (datum: Datum, index?: number, outerIndex?: number) => string = ( @@ -44,7 +57,7 @@ export default function tooltip( top: `${y}px`, ...styles, }) - .html(() => text(node)); + .html(() => text(node)) as Selection; }); selection.on('mousemove.tip', (node) => { diff --git a/packages/d3tooltip/webpack.config.umd.ts b/packages/d3tooltip/webpack.config.umd.ts index 9913c7f5..e52a1b34 100644 --- a/packages/d3tooltip/webpack.config.umd.ts +++ b/packages/d3tooltip/webpack.config.umd.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -module.exports = (env: { production?: boolean } = {}) => ({ +export default (env: { production?: boolean } = {}) => ({ mode: env.production ? 'production' : 'development', entry: { app: ['./src/index'], diff --git a/packages/map2tree/package.json b/packages/map2tree/package.json index 516f5da6..04d1eb48 100755 --- a/packages/map2tree/package.json +++ b/packages/map2tree/package.json @@ -38,7 +38,7 @@ "lint:fix": "eslint . --ext .ts --fix", "type-check": "tsc --noEmit", "type-check:watch": "npm run type-check -- --watch", - "preversion": "npm run type-check && npm run lint", + "preversion": "npm run type-check && npm run lint && npm run test", "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { diff --git a/packages/map2tree/src/index.ts b/packages/map2tree/src/index.ts index 958eef3d..4239fdb6 100644 --- a/packages/map2tree/src/index.ts +++ b/packages/map2tree/src/index.ts @@ -2,16 +2,16 @@ import isArray from 'lodash/isArray'; import isPlainObject from 'lodash/isPlainObject'; import mapValues from 'lodash/mapValues'; -interface Node { +export interface Node { name: string; - children?: Node[]; + children?: Node[] | null; value?: unknown; } function visit( parent: Node, visitFn: (parent: Node) => void, - childrenFn: (parent: Node) => Node[] | undefined + childrenFn: (parent: Node) => Node[] | undefined | null ) { if (!parent) return; @@ -47,17 +47,18 @@ export default function map2tree( root: {}, options: { key?: string; pushMethod?: 'push' | 'unshift' } = {}, tree: Node = { name: options.key || 'state', children: [] } -): Node { + // eslint-disable-next-line @typescript-eslint/ban-types +): Node | {} { // eslint-disable-next-line @typescript-eslint/ban-types if (!isPlainObject(root) && root && !(root as { toJS: () => {} }).toJS) { - return {} as Node; + return {}; } const { key: rootNodeKey = 'state', pushMethod = 'push' } = options; const currentNode = getNode(tree, rootNodeKey); if (currentNode === null) { - return {} as Node; + return {}; } mapValues( diff --git a/packages/map2tree/test/map2tree.spec.ts b/packages/map2tree/test/map2tree.spec.ts index e1cc3787..2a3cc7af 100644 --- a/packages/map2tree/test/map2tree.spec.ts +++ b/packages/map2tree/test/map2tree.spec.ts @@ -1,11 +1,11 @@ -import map2tree from '../src'; +import map2tree, { Node } from '../src'; import * as immutable from 'immutable'; test('# rootNodeKey', () => { const map = {}; const options = { key: 'foo' }; - expect(map2tree(map, options).name).toBe('foo'); + expect((map2tree(map, options) as Node).name).toBe('foo'); }); describe('# shallow map', () => { diff --git a/packages/map2tree/webpack.config.umd.ts b/packages/map2tree/webpack.config.umd.ts index 37e91464..86adef24 100644 --- a/packages/map2tree/webpack.config.umd.ts +++ b/packages/map2tree/webpack.config.umd.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -module.exports = (env: { production?: boolean } = {}) => ({ +export default (env: { production?: boolean } = {}) => ({ mode: env.production ? 'production' : 'development', entry: { app: ['./src/index'], diff --git a/packages/redux-devtools-log-monitor/src/LogMonitor.tsx b/packages/redux-devtools-log-monitor/src/LogMonitor.tsx index f224987a..b0d1f538 100644 --- a/packages/redux-devtools-log-monitor/src/LogMonitor.tsx +++ b/packages/redux-devtools-log-monitor/src/LogMonitor.tsx @@ -4,6 +4,7 @@ import { Action, Dispatch } from 'redux'; import * as themes from 'redux-devtools-themes'; import { Base16Theme } from 'redux-devtools-themes'; import { ActionCreators, LiftedAction, LiftedState } from 'redux-devtools'; +import debounce from 'lodash.debounce'; import { updateScrollTop, startConsecutiveToggle, @@ -12,9 +13,6 @@ import { import reducer, { LogMonitorState } from './reducers'; import LogMonitorButtonBar from './LogMonitorButtonBar'; import LogMonitorEntryList from './LogMonitorEntryList'; -import debounce from 'lodash.debounce'; -import { DockMonitorState } from 'redux-devtools-dock-monitor/lib/reducers'; -import { DockMonitorAction } from 'redux-devtools-dock-monitor/lib/actions'; // eslint-disable-next-line @typescript-eslint/unbound-method const { toggleAction, setActionsActive } = ActionCreators; @@ -276,8 +274,8 @@ export default (LogMonitor as unknown) as React.ComponentType< > & { update( monitorProps: ExternalProps>, - state: DockMonitorState | undefined, - action: DockMonitorAction - ): DockMonitorState; + state: LogMonitorState | undefined, + action: LogMonitorAction + ): LogMonitorState; defaultProps: DefaultProps; }; From 300b60a8b1f92a6d7c78510a1bea304490aa23be Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Sun, 20 Sep 2020 19:29:13 -0400 Subject: [PATCH 5/6] feat(d3-state-visualizer): convert example to TypeScript (#641) --- .../examples/tree/{index.js => index.ts} | 0 .../examples/tree/package.json | 31 +++++------ .../{webpack.config.js => webpack.config.ts} | 20 +++---- .../src/charts/tree/tree.ts | 54 +++++++++++++++---- 4 files changed, 67 insertions(+), 38 deletions(-) rename packages/d3-state-visualizer/examples/tree/{index.js => index.ts} (100%) rename packages/d3-state-visualizer/examples/tree/{webpack.config.js => webpack.config.ts} (76%) diff --git a/packages/d3-state-visualizer/examples/tree/index.js b/packages/d3-state-visualizer/examples/tree/index.ts similarity index 100% rename from packages/d3-state-visualizer/examples/tree/index.js rename to packages/d3-state-visualizer/examples/tree/index.ts diff --git a/packages/d3-state-visualizer/examples/tree/package.json b/packages/d3-state-visualizer/examples/tree/package.json index 43a24992..56170c6b 100644 --- a/packages/d3-state-visualizer/examples/tree/package.json +++ b/packages/d3-state-visualizer/examples/tree/package.json @@ -2,8 +2,17 @@ "name": "d3-state-visualizer-tree-example", "version": "0.0.2", "description": "Visualize your app state as a tree", - "private": true, - "main": "index.js", + "keywords": [ + "d3", + "state", + "store", + "visualization" + ], + "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/d3-state-visualizer/examples/tree", + "bugs": { + "url": "https://github.com/reduxjs/redux-devtools/issues" + }, + "license": "MIT", "scripts": { "start": "webpack-dev-server --open" }, @@ -11,25 +20,9 @@ "type": "git", "url": "https://github.com/reduxjs/redux-devtools.git" }, - "keywords": [ - "d3", - "state", - "store", - "visualization" - ], - "license": "MIT", - "bugs": { - "url": "https://github.com/reduxjs/redux-devtools/issues" - }, - "homepage": "https://github.com/reduxjs/redux-devtools", "dependencies": { "d3-state-visualizer": "^1.3.4", "map2tree": "^1.4.2" }, - "devDependencies": { - "@babel/core": "^7.11.1", - "babel-loader": "^8.1.0", - "webpack": "^4.44.1", - "webpack-dev-server": "^3.11.0" - } + "private": true } diff --git a/packages/d3-state-visualizer/examples/tree/webpack.config.js b/packages/d3-state-visualizer/examples/tree/webpack.config.ts similarity index 76% rename from packages/d3-state-visualizer/examples/tree/webpack.config.js rename to packages/d3-state-visualizer/examples/tree/webpack.config.ts index 9c710375..54df34db 100644 --- a/packages/d3-state-visualizer/examples/tree/webpack.config.js +++ b/packages/d3-state-visualizer/examples/tree/webpack.config.ts @@ -1,9 +1,8 @@ -var path = require('path'); -var webpack = require('webpack'); +import * as path from 'path'; +import * as webpack from 'webpack'; -module.exports = { +export default { mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', - devtool: 'eval-source-map', entry: [ 'webpack-dev-server/client?http://localhost:3000', 'webpack/hot/only-dev-server', @@ -14,23 +13,24 @@ module.exports = { filename: 'bundle.js', publicPath: '/static/', }, - plugins: [new webpack.HotModuleReplacementPlugin()], - resolve: { - extensions: ['.js'], - }, module: { rules: [ { - test: /\.js$/, - loaders: ['babel-loader'], + test: /\.(js|ts)$/, + loaders: 'babel-loader', exclude: /node_modules/, include: __dirname, }, ], }, + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + plugins: [new webpack.HotModuleReplacementPlugin()], devServer: { historyApiFallback: true, hot: true, port: 3000, }, + devtool: 'eval-source-map', }; diff --git a/packages/d3-state-visualizer/src/charts/tree/tree.ts b/packages/d3-state-visualizer/src/charts/tree/tree.ts index 246d2df8..e7eb7ac5 100644 --- a/packages/d3-state-visualizer/src/charts/tree/tree.ts +++ b/packages/d3-state-visualizer/src/charts/tree/tree.ts @@ -10,6 +10,44 @@ import { } from './utils'; import d3tooltip from 'd3tooltip'; +interface InputOptions { + // eslint-disable-next-line @typescript-eslint/ban-types + state?: {}; + // eslint-disable-next-line @typescript-eslint/ban-types + tree?: NodeWithId | {}; + + rootKeyName: string; + pushMethod: 'push' | 'unshift'; + id: string; + style: { [key: string]: Primitive }; + size: number; + aspectRatio: number; + initialZoom: number; + margin: { + top: number; + right: number; + bottom: number; + left: number; + }; + isSorted: boolean; + heightBetweenNodesCoeff: number; + widthBetweenNodesCoeff: number; + transitionDuration: number; + blinkDuration: number; + onClickText: () => void; + tooltipOptions: { + disabled?: boolean; + left?: number | undefined; + top?: number | undefined; + offset?: { + left: number; + top: number; + }; + style?: { [key: string]: Primitive } | undefined; + indentationSize?: number; + }; +} + interface Options { // eslint-disable-next-line @typescript-eslint/ban-types state?: {}; @@ -63,6 +101,7 @@ interface Options { top: number; }; style: { [key: string]: Primitive } | undefined; + indentationSize?: number; }; } @@ -141,7 +180,10 @@ interface NodePosition { y: number | undefined; } -export default function (DOMNode: HTMLElement, options: Partial = {}) { +export default function ( + DOMNode: HTMLElement, + options: Partial = {} +) { const { id, style, @@ -160,7 +202,7 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { tree, tooltipOptions, onClickText, - } = deepmerge(defaultOptions, options); + } = deepmerge(defaultOptions, options) as Options; const width = size - margin.left - margin.right; const height = size * aspectRatio - margin.top - margin.bottom; @@ -363,13 +405,7 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { if (!tooltipOptions.disabled) { nodeEnter.call( d3tooltip(d3, 'tooltip', { ...tooltipOptions, root }) - .text((d, i) => - getTooltipString( - d, - i, - (tooltipOptions as unknown) as { indentationSize: number } - ) - ) + .text((d, i) => getTooltipString(d, i, tooltipOptions)) .style(tooltipOptions.style) ); } From 761baba0aa0f4dc672f8771f4b12bed3863557f7 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Mon, 21 Sep 2020 21:23:38 -0400 Subject: [PATCH 6/6] feat(redux-devtools-chart-monitor): convert to TypeScript (#642) * chart-monitor * and that --- .../src/charts/tree/tree.ts | 4 +- .../redux-devtools-chart-monitor/.babelrc | 11 +- .../.eslintignore | 1 + .../redux-devtools-chart-monitor/.eslintrc.js | 13 +++ .../redux-devtools-chart-monitor/package.json | 69 ++++++------ .../src/{Chart.js => Chart.tsx} | 47 ++++++-- .../src/{ChartMonitor.js => ChartMonitor.tsx} | 100 ++++++++++++------ .../src/actions.js | 2 - .../src/actions.ts | 6 ++ .../redux-devtools-chart-monitor/src/index.js | 1 - .../redux-devtools-chart-monitor/src/index.ts | 1 + .../src/reducers.js | 19 ---- .../src/reducers.ts | 33 ++++++ .../tsconfig.json | 7 ++ 14 files changed, 212 insertions(+), 102 deletions(-) create mode 100644 packages/redux-devtools-chart-monitor/.eslintignore create mode 100644 packages/redux-devtools-chart-monitor/.eslintrc.js rename packages/redux-devtools-chart-monitor/src/{Chart.js => Chart.tsx} (55%) rename packages/redux-devtools-chart-monitor/src/{ChartMonitor.js => ChartMonitor.tsx} (62%) delete mode 100644 packages/redux-devtools-chart-monitor/src/actions.js create mode 100644 packages/redux-devtools-chart-monitor/src/actions.ts delete mode 100644 packages/redux-devtools-chart-monitor/src/index.js create mode 100644 packages/redux-devtools-chart-monitor/src/index.ts delete mode 100644 packages/redux-devtools-chart-monitor/src/reducers.js create mode 100644 packages/redux-devtools-chart-monitor/src/reducers.ts create mode 100644 packages/redux-devtools-chart-monitor/tsconfig.json diff --git a/packages/d3-state-visualizer/src/charts/tree/tree.ts b/packages/d3-state-visualizer/src/charts/tree/tree.ts index e7eb7ac5..894eceb4 100644 --- a/packages/d3-state-visualizer/src/charts/tree/tree.ts +++ b/packages/d3-state-visualizer/src/charts/tree/tree.ts @@ -12,7 +12,7 @@ import d3tooltip from 'd3tooltip'; interface InputOptions { // eslint-disable-next-line @typescript-eslint/ban-types - state?: {}; + state?: {} | null; // eslint-disable-next-line @typescript-eslint/ban-types tree?: NodeWithId | {}; @@ -50,7 +50,7 @@ interface InputOptions { interface Options { // eslint-disable-next-line @typescript-eslint/ban-types - state?: {}; + state?: {} | null; // eslint-disable-next-line @typescript-eslint/ban-types tree?: NodeWithId | {}; diff --git a/packages/redux-devtools-chart-monitor/.babelrc b/packages/redux-devtools-chart-monitor/.babelrc index 2d8ea82b..0d42ef44 100644 --- a/packages/redux-devtools-chart-monitor/.babelrc +++ b/packages/redux-devtools-chart-monitor/.babelrc @@ -1,7 +1,8 @@ { - "presets": ["@babel/preset-env", "@babel/preset-react"], - "plugins": [ - "@babel/plugin-proposal-class-properties", - "@babel/plugin-proposal-export-default-from" - ] + "presets": [ + "@babel/preset-env", + "@babel/preset-react", + "@babel/preset-typescript" + ], + "plugins": ["@babel/plugin-proposal-class-properties"] } diff --git a/packages/redux-devtools-chart-monitor/.eslintignore b/packages/redux-devtools-chart-monitor/.eslintignore new file mode 100644 index 00000000..a65b4177 --- /dev/null +++ b/packages/redux-devtools-chart-monitor/.eslintignore @@ -0,0 +1 @@ +lib diff --git a/packages/redux-devtools-chart-monitor/.eslintrc.js b/packages/redux-devtools-chart-monitor/.eslintrc.js new file mode 100644 index 00000000..e98ddf18 --- /dev/null +++ b/packages/redux-devtools-chart-monitor/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + extends: '../../.eslintrc', + overrides: [ + { + files: ['*.ts', '*.tsx'], + extends: '../../eslintrc.ts.react.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + }, + ], +}; diff --git a/packages/redux-devtools-chart-monitor/package.json b/packages/redux-devtools-chart-monitor/package.json index 37e9a9c1..291d3a0f 100644 --- a/packages/redux-devtools-chart-monitor/package.json +++ b/packages/redux-devtools-chart-monitor/package.json @@ -2,21 +2,6 @@ "name": "redux-devtools-chart-monitor", "version": "1.7.2", "description": "Chart monitor for Redux DevTools", - "main": "lib/index.js", - "scripts": { - "clean": "rimraf lib", - "build": "babel src --out-dir lib", - "prepare": "npm run build", - "prepublishOnly": "npm run clean && npm run build" - }, - "files": [ - "lib", - "src" - ], - "repository": { - "type": "git", - "url": "https://github.com/reduxjs/redux-devtools.git" - }, "keywords": [ "redux", "devtools", @@ -24,32 +9,52 @@ "react", "chart" ], - "author": "romseguy", - "license": "MIT", + "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-chart-monitor", "bugs": { "url": "https://github.com/reduxjs/redux-devtools/issues" }, - "homepage": "https://github.com/reduxjs/redux-devtools", - "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.11.1", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/plugin-proposal-export-default-from": "^7.10.4", - "@babel/preset-env": "^7.11.0", - "@babel/preset-react": "^7.10.4", - "babel-loader": "^8.1.0", - "rimraf": "^3.0.2" + "license": "MIT", + "author": "romseguy", + "files": [ + "lib", + "src" + ], + "main": "lib/index.js", + "types": "lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/reduxjs/redux-devtools.git" }, - "peerDependencies": { - "react": "^16.3.0", - "react-dom": "^16.3.0", - "redux-devtools": "^3.0.0" + "scripts": { + "build": "npm run build:types && npm run build:js", + "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", + "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { + "@types/prop-types": "^15.7.3", + "@types/redux-devtools-themes": "^1.0.0", "d3-state-visualizer": "^1.3.4", "deepmerge": "^4.2.2", "prop-types": "^15.7.2", - "react-pure-render": "^1.0.2", "redux-devtools-themes": "^1.0.0" + }, + "devDependencies": { + "@types/react": "^16.9.46", + "react": "^16.13.1", + "redux": "^4.0.5", + "redux-devtools": "^3.7.0" + }, + "peerDependencies": { + "@types/react": "^16.3.18", + "react": "^16.3.0", + "redux": "^3.4.0 || ^4.0.0", + "redux-devtools": "^3.0.0" } } diff --git a/packages/redux-devtools-chart-monitor/src/Chart.js b/packages/redux-devtools-chart-monitor/src/Chart.tsx similarity index 55% rename from packages/redux-devtools-chart-monitor/src/Chart.js rename to packages/redux-devtools-chart-monitor/src/Chart.tsx index 5cfac370..8b646f58 100644 --- a/packages/redux-devtools-chart-monitor/src/Chart.js +++ b/packages/redux-devtools-chart-monitor/src/Chart.tsx @@ -1,13 +1,44 @@ import React, { Component, createRef } from 'react'; import PropTypes from 'prop-types'; import { tree } from 'd3-state-visualizer'; +import { Action, Dispatch } from 'redux'; +import { LiftedAction, LiftedState } from 'redux-devtools-instrument'; +import * as themes from 'redux-devtools-themes'; +import { Base16Theme } from 'react-base16-styling'; +import { ChartMonitorState } from './reducers'; +import { Primitive } from 'd3'; const wrapperStyle = { width: '100%', height: '100%', }; -class Chart extends Component { +export interface Props> + extends LiftedState { + dispatch: Dispatch>; + preserveScrollTop: boolean; + select: (state: S) => unknown; + theme: keyof typeof themes | Base16Theme; + invertTheme: boolean; + + state: S | null; + isSorted: boolean; + heightBetweenNodesCoeff: number; + widthBetweenNodesCoeff: number; + tooltipOptions: { + disabled: boolean; + offset: { + left: number; + top: number; + }; + indentationSize: number; + style: { [key: string]: Primitive } | undefined; + }; + style: { [key: string]: Primitive } | undefined; + defaultIsVisible?: boolean; +} + +class Chart> extends Component> { static propTypes = { state: PropTypes.object, rootKeyName: PropTypes.string, @@ -60,21 +91,25 @@ class Chart extends Component { }), }; - divRef = createRef(); + divRef = createRef(); + // eslint-disable-next-line @typescript-eslint/ban-types + renderChart?: (state?: {} | null | undefined) => void; componentDidMount() { const { select, state, defaultIsVisible } = this.props; - this.renderChart = tree(this.divRef.current, this.props); + this.renderChart = tree(this.divRef.current!, this.props); if (defaultIsVisible) { - this.renderChart(select(state)); + // eslint-disable-next-line @typescript-eslint/ban-types + this.renderChart(select(state!) as {} | null | undefined); } } - UNSAFE_componentWillReceiveProps(nextProps) { + UNSAFE_componentWillReceiveProps(nextProps: Props) { const { state, select, monitorState } = nextProps; if (monitorState.isVisible !== false) { - this.renderChart(select(state)); + // eslint-disable-next-line @typescript-eslint/ban-types + this.renderChart!(select(state!) as {} | null | undefined); } } diff --git a/packages/redux-devtools-chart-monitor/src/ChartMonitor.js b/packages/redux-devtools-chart-monitor/src/ChartMonitor.tsx similarity index 62% rename from packages/redux-devtools-chart-monitor/src/ChartMonitor.js rename to packages/redux-devtools-chart-monitor/src/ChartMonitor.tsx index df45d93c..8fe44c64 100644 --- a/packages/redux-devtools-chart-monitor/src/ChartMonitor.js +++ b/packages/redux-devtools-chart-monitor/src/ChartMonitor.tsx @@ -1,15 +1,18 @@ -import React, { Component } from 'react'; +import React, { CSSProperties, PureComponent } from 'react'; import PropTypes from 'prop-types'; -import shouldPureComponentUpdate from 'react-pure-render/function'; import * as themes from 'redux-devtools-themes'; -import { ActionCreators } from 'redux-devtools'; +import { ActionCreators, LiftedAction, LiftedState } from 'redux-devtools'; import deepmerge from 'deepmerge'; +import { Action, Dispatch } from 'redux'; +import { Base16Theme } from 'react-base16-styling'; -import reducer from './reducers'; -import Chart from './Chart'; +import reducer, { ChartMonitorState } from './reducers'; +import Chart, { Props } from './Chart'; +import { Primitive } from 'd3'; +// eslint-disable-next-line @typescript-eslint/unbound-method const { reset, rollback, commit, sweep, toggleAction } = ActionCreators; -const styles = { +const styles: { container: CSSProperties } = { container: { fontFamily: 'monaco, Consolas, Lucida Console, monospace', position: 'relative', @@ -20,7 +23,7 @@ const styles = { }, }; -function invertColors(theme) { +function invertColors(theme: Base16Theme) { return { ...theme, base00: theme.base07, @@ -34,7 +37,43 @@ function invertColors(theme) { }; } -class ChartMonitor extends Component { +export interface ChartMonitorProps> + extends LiftedState { + dispatch: Dispatch>; + preserveScrollTop: boolean; + select: (state: S) => unknown; + theme: keyof typeof themes | Base16Theme; + invertTheme: boolean; + + state: S | null; + isSorted: boolean; + heightBetweenNodesCoeff: number; + widthBetweenNodesCoeff: number; + tooltipOptions: unknown; + style: { + width: number; + height: number; + node: { + colors: { + default: string; + collapsed: string; + parent: string; + }; + radius: number; + }; + text: { + colors: { + default: string; + hover: string; + }; + }; + }; + defaultIsVisible?: boolean; +} + +class ChartMonitor> extends PureComponent< + ChartMonitorProps +> { static update = reducer; static propTypes = { @@ -55,45 +94,34 @@ class ChartMonitor extends Component { }; static defaultProps = { - select: (state) => state, + select: (state: unknown) => state, theme: 'nicinabox', preserveScrollTop: true, invertTheme: false, }; - shouldComponentUpdate = shouldPureComponentUpdate; - - constructor(props) { - super(props); - this.handleToggleAction = this.handleToggleAction.bind(this); - 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() { + handleRollback = () => { this.props.dispatch(rollback()); - } + }; - handleSweep() { + handleSweep = () => { this.props.dispatch(sweep()); - } + }; - handleCommit() { + handleCommit = () => { this.props.dispatch(commit()); - } + }; - handleToggleAction(id) { + handleToggleAction = (id: number) => { this.props.dispatch(toggleAction(id)); - } + }; - handleReset() { + handleReset = () => { this.props.dispatch(reset()); - } + }; getTheme() { - let { theme, invertTheme } = this.props; + const { theme, invertTheme } = this.props; if (typeof theme !== 'string') { return invertTheme ? invertColors(theme) : theme; } @@ -102,7 +130,6 @@ class ChartMonitor extends Component { return invertTheme ? invertColors(themes[theme]) : themes[theme]; } - // eslint-disable-next-line no-console console.warn( 'DevTools theme ' + theme + ' not found, defaulting to nicinabox' ); @@ -132,7 +159,7 @@ class ChartMonitor extends Component { }; } - getChartOptions(props = this.props) { + getChartOptions(props = this.props): Props { const { computedStates } = props; const theme = this.getTheme(); @@ -156,7 +183,9 @@ class ChartMonitor extends Component { heightBetweenNodesCoeff: 1, widthBetweenNodesCoeff: 1.3, tooltipOptions, - style: this.getChartStyle(), + style: (this.getChartStyle() as unknown) as + | { [key: string]: Primitive } + | undefined, }; return deepmerge(defaultOptions, props); @@ -165,9 +194,10 @@ class ChartMonitor extends Component { render() { const theme = this.getTheme(); + const ChartAsAny = Chart as any; return (
- +
); } diff --git a/packages/redux-devtools-chart-monitor/src/actions.js b/packages/redux-devtools-chart-monitor/src/actions.js deleted file mode 100644 index 0eefa3a9..00000000 --- a/packages/redux-devtools-chart-monitor/src/actions.js +++ /dev/null @@ -1,2 +0,0 @@ -export const TOGGLE_VISIBILITY = - '@@redux-devtools-log-monitor/TOGGLE_VISIBILITY'; diff --git a/packages/redux-devtools-chart-monitor/src/actions.ts b/packages/redux-devtools-chart-monitor/src/actions.ts new file mode 100644 index 00000000..062215ed --- /dev/null +++ b/packages/redux-devtools-chart-monitor/src/actions.ts @@ -0,0 +1,6 @@ +export const TOGGLE_VISIBILITY = + '@@redux-devtools-log-monitor/TOGGLE_VISIBILITY'; +interface ToggleVisibilityAction { + type: typeof TOGGLE_VISIBILITY; +} +export type ChartMonitorAction = ToggleVisibilityAction; diff --git a/packages/redux-devtools-chart-monitor/src/index.js b/packages/redux-devtools-chart-monitor/src/index.js deleted file mode 100644 index 47f35f02..00000000 --- a/packages/redux-devtools-chart-monitor/src/index.js +++ /dev/null @@ -1 +0,0 @@ -export default from './ChartMonitor'; diff --git a/packages/redux-devtools-chart-monitor/src/index.ts b/packages/redux-devtools-chart-monitor/src/index.ts new file mode 100644 index 00000000..c1fa1959 --- /dev/null +++ b/packages/redux-devtools-chart-monitor/src/index.ts @@ -0,0 +1 @@ +export { default } from './ChartMonitor'; diff --git a/packages/redux-devtools-chart-monitor/src/reducers.js b/packages/redux-devtools-chart-monitor/src/reducers.js deleted file mode 100644 index 93479d63..00000000 --- a/packages/redux-devtools-chart-monitor/src/reducers.js +++ /dev/null @@ -1,19 +0,0 @@ -import { TOGGLE_VISIBILITY } from './actions'; - -function toggleVisibility(props, state = props.defaultIsVisible, action) { - if (action.type === TOGGLE_VISIBILITY) { - return !state; - } - - if (props.defaultIsVisible !== undefined) { - return props.defaultIsVisible; - } - - return true; -} - -export default function reducer(props, state = {}, action) { - return { - isVisible: toggleVisibility(props, state.isVisible, action), - }; -} diff --git a/packages/redux-devtools-chart-monitor/src/reducers.ts b/packages/redux-devtools-chart-monitor/src/reducers.ts new file mode 100644 index 00000000..d335beb6 --- /dev/null +++ b/packages/redux-devtools-chart-monitor/src/reducers.ts @@ -0,0 +1,33 @@ +import { Action } from 'redux'; +import { ChartMonitorAction, TOGGLE_VISIBILITY } from './actions'; +import { ChartMonitorProps } from './ChartMonitor'; + +function toggleVisibility>( + props: ChartMonitorProps, + state = props.defaultIsVisible, + action: ChartMonitorAction +): boolean { + if (action.type === TOGGLE_VISIBILITY) { + return !state; + } + + if (props.defaultIsVisible !== undefined) { + return props.defaultIsVisible; + } + + return true; +} + +export interface ChartMonitorState { + isVisible?: boolean; +} + +export default function reducer>( + props: ChartMonitorProps, + state: ChartMonitorState | undefined = {}, + action: ChartMonitorAction +) { + return { + isVisible: toggleVisibility(props, state.isVisible, action), + }; +} diff --git a/packages/redux-devtools-chart-monitor/tsconfig.json b/packages/redux-devtools-chart-monitor/tsconfig.json new file mode 100644 index 00000000..7b7d1492 --- /dev/null +++ b/packages/redux-devtools-chart-monitor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.react.base.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["src"] +}