Merge branch 'master' into update-UNSAFE_componentWillReceiveProps-react-json-tree

This commit is contained in:
Bruno Fenzl 2020-09-25 11:02:16 +02:00 committed by GitHub
commit f21d5902ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 4340 additions and 3829 deletions

View File

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

View File

@ -0,0 +1,3 @@
examples
lib
dist

View File

@ -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'],
},
},
],
};

View File

@ -2,8 +2,17 @@
"name": "d3-state-visualizer-tree-example", "name": "d3-state-visualizer-tree-example",
"version": "0.0.2", "version": "0.0.2",
"description": "Visualize your app state as a tree", "description": "Visualize your app state as a tree",
"private": true, "keywords": [
"main": "index.js", "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": { "scripts": {
"start": "webpack-dev-server --open" "start": "webpack-dev-server --open"
}, },
@ -11,25 +20,9 @@
"type": "git", "type": "git",
"url": "https://github.com/reduxjs/redux-devtools.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": { "dependencies": {
"d3-state-visualizer": "^1.3.4", "d3-state-visualizer": "^1.3.4",
"map2tree": "^1.4.2" "map2tree": "^1.4.2"
}, },
"devDependencies": { "private": true
"@babel/core": "^7.11.1",
"babel-loader": "^8.1.0",
"webpack": "^4.44.1",
"webpack-dev-server": "^3.11.0"
}
} }

View File

@ -1,9 +1,8 @@
var path = require('path'); import * as path from 'path';
var webpack = require('webpack'); import * as webpack from 'webpack';
module.exports = { export default {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
devtool: 'eval-source-map',
entry: [ entry: [
'webpack-dev-server/client?http://localhost:3000', 'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server', 'webpack/hot/only-dev-server',
@ -14,23 +13,24 @@ module.exports = {
filename: 'bundle.js', filename: 'bundle.js',
publicPath: '/static/', publicPath: '/static/',
}, },
plugins: [new webpack.HotModuleReplacementPlugin()],
resolve: {
extensions: ['.js'],
},
module: { module: {
rules: [ rules: [
{ {
test: /\.js$/, test: /\.(js|ts)$/,
loaders: ['babel-loader'], loaders: 'babel-loader',
exclude: /node_modules/, exclude: /node_modules/,
include: __dirname, include: __dirname,
}, },
], ],
}, },
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
plugins: [new webpack.HotModuleReplacementPlugin()],
devServer: { devServer: {
historyApiFallback: true, historyApiFallback: true,
hot: true, hot: true,
port: 3000, port: 3000,
}, },
devtool: 'eval-source-map',
}; };

View File

@ -2,24 +2,6 @@
"name": "d3-state-visualizer", "name": "d3-state-visualizer",
"version": "1.3.4", "version": "1.3.4",
"description": "Visualize your app state with a range of reusable charts", "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": [ "keywords": [
"d3", "d3",
"state", "state",
@ -27,27 +9,46 @@
"tree", "tree",
"visualization" "visualization"
], ],
"author": "romseguy", "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/d3-state-visualizer",
"license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/reduxjs/redux-devtools/issues" "url": "https://github.com/reduxjs/redux-devtools/issues"
}, },
"homepage": "https://github.com/reduxjs/redux-devtools", "license": "MIT",
"devDependencies": { "author": "romseguy",
"@babel/cli": "^7.10.5", "files": [
"@babel/core": "^7.11.1", "dist",
"@babel/plugin-proposal-class-properties": "^7.10.4", "lib",
"@babel/plugin-proposal-export-default-from": "^7.10.4", "src"
"@babel/preset-env": "^7.11.0", ],
"babel-loader": "^8.1.0", "main": "lib/index.js",
"rimraf": "^3.0.2", "types": "lib/index.d.ts",
"webpack": "^4.44.1" "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": { "dependencies": {
"@types/d3": "^3.5.43",
"d3": "^3.5.17", "d3": "^3.5.17",
"d3tooltip": "^1.2.3", "d3tooltip": "^1.2.3",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"map2tree": "^1.4.2", "map2tree": "^1.4.2",
"ramda": "^0.27.1" "ramda": "^0.27.1"
},
"devDependencies": {
"@types/ramda": "^0.27.17"
} }
} }

View File

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

View File

@ -0,0 +1 @@
export { default as tree } from './tree/tree';

View File

@ -1,4 +1,4 @@
function sortObject(obj, strict) { function sortObject(obj: unknown, strict?: boolean) {
if (obj instanceof Array) { if (obj instanceof Array) {
let ary; let ary;
if (strict) { if (strict) {
@ -10,16 +10,16 @@ function sortObject(obj, strict) {
} }
if (obj && typeof obj === 'object') { if (obj && typeof obj === 'object') {
const tObj = {}; const tObj: { [key: string]: unknown } = {};
Object.keys(obj) Object.keys(obj)
.sort() .sort()
.forEach((key) => (tObj[key] = sortObject(obj[key]))); .forEach((key) => (tObj[key] = sortObject(obj[key as keyof typeof obj])));
return tObj; return tObj;
} }
return obj; return obj;
} }
export default function sortAndSerialize(obj) { export default function sortAndSerialize(obj: unknown) {
return JSON.stringify(sortObject(obj, true), undefined, 2); return JSON.stringify(sortObject(obj, true), undefined, 2);
} }

View File

@ -1,4 +1,4 @@
import d3 from 'd3'; import d3, { ZoomEvent, Primitive } from 'd3';
import { isEmpty } from 'ramda'; import { isEmpty } from 'ramda';
import map2tree from 'map2tree'; import map2tree from 'map2tree';
import deepmerge from 'deepmerge'; import deepmerge from 'deepmerge';
@ -10,7 +10,102 @@ import {
} from './utils'; } from './utils';
import d3tooltip from 'd3tooltip'; import d3tooltip from 'd3tooltip';
const defaultOptions = { interface InputOptions {
// eslint-disable-next-line @typescript-eslint/ban-types
state?: {} | null;
// 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?: {} | null;
// 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;
indentationSize?: number;
};
}
const defaultOptions: Options = {
state: undefined, state: undefined,
rootKeyName: 'state', rootKeyName: 'state',
pushMethod: 'push', pushMethod: 'push',
@ -50,11 +145,13 @@ const defaultOptions = {
widthBetweenNodesCoeff: 1, widthBetweenNodesCoeff: 1,
transitionDuration: 750, transitionDuration: 750,
blinkDuration: 100, blinkDuration: 100,
onClickText: () => {}, onClickText: () => {
// noop
},
tooltipOptions: { tooltipOptions: {
disabled: false, disabled: false,
left: undefined, left: undefined,
right: undefined, top: undefined,
offset: { offset: {
left: 0, left: 0,
top: 0, top: 0,
@ -63,7 +160,30 @@ 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<InputOptions> = {}
) {
const { const {
id, id,
style, style,
@ -82,23 +202,26 @@ export default function (DOMNode, options = {}) {
tree, tree,
tooltipOptions, tooltipOptions,
onClickText, onClickText,
} = deepmerge(defaultOptions, options); } = deepmerge(defaultOptions, options) as Options;
const width = size - margin.left - margin.right; const width = size - margin.left - margin.right;
const height = size * aspectRatio - margin.top - margin.bottom; const height = size * aspectRatio - margin.top - margin.bottom;
const fullWidth = size; const fullWidth = size;
const fullHeight = size * aspectRatio; const fullHeight = size * aspectRatio;
const attr = { const attr: { [key: string]: Primitive } = {
id, id,
preserveAspectRatio: 'xMinYMin slice', preserveAspectRatio: 'xMinYMin slice',
}; };
if (!style.width) { if (!((style as unknown) as { [key: string]: Primitive }).width) {
attr.width = fullWidth; 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}`; attr.viewBox = `0 0 ${fullWidth} ${fullHeight}`;
} }
@ -107,11 +230,16 @@ export default function (DOMNode, options = {}) {
const vis = root const vis = root
.append('svg') .append('svg')
.attr(attr) .attr(attr)
.style({ cursor: '-webkit-grab', ...style }) .style(({ cursor: '-webkit-grab', ...style } as unknown) as {
[key: string]: Primitive;
})
.call( .call(
zoom.on('zoom', () => { zoom.on('zoom', () => {
const { translate, scale } = d3.event; const { translate, scale } = d3.event as ZoomEvent;
vis.attr('transform', `translate(${translate})scale(${scale})`); vis.attr(
'transform',
`translate(${translate.toString()})scale(${scale})`
);
}) })
) )
.append('g') .append('g')
@ -122,18 +250,21 @@ export default function (DOMNode, options = {}) {
}); });
let layout = d3.layout.tree().size([width, height]); let layout = d3.layout.tree().size([width, height]);
let data; let data: NodeWithId;
if (isSorted) { if (isSorted) {
layout.sort((a, b) => 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 // previousNodePositionsById stores node x and y
// as well as hierarchy (id / parentId); // as well as hierarchy (id / parentId);
// helps animating transitions // helps animating transitions
let previousNodePositionsById = { let previousNodePositionsById: { [nodeId: string]: NodePosition } = {
root: { root: {
id: 'root', id: 'root',
parentId: null, parentId: null,
@ -145,10 +276,14 @@ export default function (DOMNode, options = {}) {
// traverses a map with node positions by going through the chain // traverses a map with node positions by going through the chain
// of parent ids; once a parent that matches the given filter is found, // of parent ids; once a parent that matches the given filter is found,
// the parent position gets returned // 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]; let currentPosition = nodePositionsById[nodeId];
while (currentPosition) { while (currentPosition) {
currentPosition = nodePositionsById[currentPosition.parentId]; currentPosition = nodePositionsById[currentPosition.parentId!];
if (!currentPosition) { if (!currentPosition) {
return null; return null;
} }
@ -160,14 +295,18 @@ export default function (DOMNode, options = {}) {
return function renderChart(nextState = tree || state) { return function renderChart(nextState = tree || state) {
data = !tree data = !tree
? map2tree(nextState, { key: rootKeyName, pushMethod }) ? // eslint-disable-next-line @typescript-eslint/ban-types
: nextState; (map2tree(nextState as {}, {
key: rootKeyName,
pushMethod,
}) as NodeWithId)
: (nextState as NodeWithId);
if (isEmpty(data) || !data.name) { if (isEmpty(data) || !data.name) {
data = { data = ({
name: 'error', name: 'error',
message: 'Please provide a state map or a tree structure', message: 'Please provide a state map or a tree structure',
}; } as unknown) as NodeWithId;
} }
let nodeIndex = 0; let nodeIndex = 0;
@ -191,13 +330,13 @@ export default function (DOMNode, options = {}) {
: null : null
); );
/*eslint-disable*/
update(); update();
/*eslint-enable*/
function update() { function update() {
// path generator for links // path generator for links
const diagonal = d3.svg.diagonal().projection((d) => [d.y, d.x]); const diagonal = d3.svg
.diagonal<NodePosition>()
.projection((d) => [d.y!, d.x!]);
// set tree dimensions and spacing between branches and nodes // set tree dimensions and spacing between branches and nodes
const maxNodeCountByLevel = Math.max(...getNodeGroupByDepthCount(data)); const maxNodeCountByLevel = Math.max(...getNodeGroupByDepthCount(data));
@ -206,12 +345,12 @@ export default function (DOMNode, options = {}) {
width, width,
]); ]);
let nodes = layout.nodes(data); const nodes = layout.nodes(data as d3.layout.tree.Node) as NodeWithId[];
let links = layout.links(nodes); const links = layout.links(nodes as d3.layout.tree.Node[]);
nodes.forEach( nodes.forEach(
(node) => (node) =>
(node.y = node.depth * (maxLabelLength * 7 * widthBetweenNodesCoeff)) (node.y = node.depth! * (maxLabelLength * 7 * widthBetweenNodesCoeff))
); );
const nodePositions = nodes.map((n) => ({ const nodePositions = nodes.map((n) => ({
@ -220,15 +359,18 @@ export default function (DOMNode, options = {}) {
x: n.x, x: n.x,
y: n.y, y: n.y,
})); }));
const nodePositionsById = {}; const nodePositionsById: { [nodeId: string]: NodePosition } = {};
nodePositions.forEach((node) => (nodePositionsById[node.id] = node)); nodePositions.forEach((node) => (nodePositionsById[node.id] = node));
// process the node selection // process the node selection
let node = vis const node = vis
.selectAll('g.node') .selectAll('g.node')
.property('__oldData__', (d) => d) .property('__oldData__', (d: NodeWithId) => d)
.data(nodes, (d) => d.id || (d.id = ++nodeIndex)); .data(
let nodeEnter = node nodes,
(d) => d.id || (d.id = (++nodeIndex as unknown) as string)
);
const nodeEnter = node
.enter() .enter()
.append('g') .append('g')
.attr({ .attr({
@ -237,29 +379,27 @@ export default function (DOMNode, options = {}) {
const position = findParentNodePosition( const position = findParentNodePosition(
nodePositionsById, nodePositionsById,
d.id, d.id,
(n) => previousNodePositionsById[n.id] (n) => !!previousNodePositionsById[n.id]
); );
const previousPosition = const previousPosition =
(position && previousNodePositionsById[position.id]) || (position && previousNodePositionsById[position.id]) ||
previousNodePositionsById.root; previousNodePositionsById.root;
return `translate(${previousPosition.y},${previousPosition.x})`; return `translate(${previousPosition.y!},${previousPosition.x!})`;
}, },
}) })
.style({ .style({
fill: style.text.colors.default, fill: style.text.colors.default,
cursor: 'pointer', cursor: 'pointer',
}) })
.on({ .on('mouseover', function mouseover(this: any) {
mouseover: function mouseover() { d3.select(this).style({
d3.select(this).style({ fill: style.text.colors.hover,
fill: style.text.colors.hover, });
}); })
}, .on('mouseout', function mouseout(this: any) {
mouseout: function mouseout() { d3.select(this).style({
d3.select(this).style({ fill: style.text.colors.default,
fill: style.text.colors.default, });
});
},
}); });
if (!tooltipOptions.disabled) { if (!tooltipOptions.disabled) {
@ -279,12 +419,10 @@ export default function (DOMNode, options = {}) {
class: 'nodeCircle', class: 'nodeCircle',
r: 0, r: 0,
}) })
.on({ .on('click', (clickedNode) => {
click: (clickedNode) => { if ((d3.event as Event).defaultPrevented) return;
if (d3.event.defaultPrevented) return; toggleChildren(clickedNode);
toggleChildren(clickedNode); update();
update();
},
}); });
nodeEnterInnerGroup nodeEnterInnerGroup
@ -299,9 +437,7 @@ export default function (DOMNode, options = {}) {
'fill-opacity': 0, 'fill-opacity': 0,
}) })
.text((d) => d.name) .text((d) => d.name)
.on({ .on('click', onClickText);
click: onClickText,
});
// update the text to reflect whether node has children or not // update the text to reflect whether node has children or not
node.select('text').text((d) => d.name); node.select('text').text((d) => d.name);
@ -319,11 +455,11 @@ export default function (DOMNode, options = {}) {
}); });
// transition nodes to their new position // transition nodes to their new position
let nodeUpdate = node const nodeUpdate = node
.transition() .transition()
.duration(transitionDuration) .duration(transitionDuration)
.attr({ .attr({
transform: (d) => `translate(${d.y},${d.x})`, transform: (d) => `translate(${d.y!},${d.x!})`,
}); });
// ensure circle radius is correct // ensure circle radius is correct
@ -334,7 +470,7 @@ export default function (DOMNode, options = {}) {
.select('text') .select('text')
.style('fill-opacity', 1) .style('fill-opacity', 1)
.attr({ .attr({
transform: function transform(d) { transform: function transform(this: SVGGraphicsElement, d) {
const x = const x =
(d.children || d._children ? -1 : 1) * (d.children || d._children ? -1 : 1) *
(this.getBBox().width / 2 + style.node.radius + 5); (this.getBBox().width / 2 + style.node.radius + 5);
@ -344,7 +480,7 @@ export default function (DOMNode, options = {}) {
// blink updated nodes // blink updated nodes
node node
.filter(function flick(d) { .filter(function flick(this: any, d) {
// test whether the relevant properties of d match // test whether the relevant properties of d match
// the equivalent property of the oldData // the equivalent property of the oldData
// also test whether the old data exists, // also test whether the old data exists,
@ -358,7 +494,7 @@ export default function (DOMNode, options = {}) {
.style('opacity', '1'); .style('opacity', '1');
// transition exiting nodes to the parent's new position // transition exiting nodes to the parent's new position
let nodeExit = node const nodeExit = node
.exit() .exit()
.transition() .transition()
.duration(transitionDuration) .duration(transitionDuration)
@ -367,12 +503,12 @@ export default function (DOMNode, options = {}) {
const position = findParentNodePosition( const position = findParentNodePosition(
previousNodePositionsById, previousNodePositionsById,
d.id, d.id,
(n) => nodePositionsById[n.id] (n) => !!nodePositionsById[n.id]
); );
const futurePosition = const futurePosition =
(position && nodePositionsById[position.id]) || (position && nodePositionsById[position.id]) ||
nodePositionsById.root; nodePositionsById.root;
return `translate(${futurePosition.y},${futurePosition.x})`; return `translate(${futurePosition.y!},${futurePosition.x!})`;
}, },
}) })
.remove(); .remove();
@ -382,7 +518,9 @@ export default function (DOMNode, options = {}) {
nodeExit.select('text').style('fill-opacity', 0); nodeExit.select('text').style('fill-opacity', 0);
// update the links // 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 // enter any new links at the parent's previous position
link link
@ -393,8 +531,8 @@ export default function (DOMNode, options = {}) {
d: (d) => { d: (d) => {
const position = findParentNodePosition( const position = findParentNodePosition(
nodePositionsById, nodePositionsById,
d.target.id, (d.target as NodeWithId).id,
(n) => previousNodePositionsById[n.id] (n) => !!previousNodePositionsById[n.id]
); );
const previousPosition = const previousPosition =
(position && previousNodePositionsById[position.id]) || (position && previousNodePositionsById[position.id]) ||
@ -402,15 +540,18 @@ export default function (DOMNode, options = {}) {
return diagonal({ return diagonal({
source: previousPosition, source: previousPosition,
target: previousPosition, target: previousPosition,
}); } as d3.svg.diagonal.Link<NodePosition>);
}, },
}) })
.style(style.link); .style(style.link);
// transition links to their new position // transition links to their new position
link.transition().duration(transitionDuration).attr({ link
d: diagonal, .transition()
}); .duration(transitionDuration)
.attr({
d: (diagonal as unknown) as Primitive,
});
// transition exiting nodes to the parent's new position // transition exiting nodes to the parent's new position
link link
@ -421,8 +562,8 @@ export default function (DOMNode, options = {}) {
d: (d) => { d: (d) => {
const position = findParentNodePosition( const position = findParentNodePosition(
previousNodePositionsById, previousNodePositionsById,
d.target.id, (d.target as NodeWithId).id,
(n) => nodePositionsById[n.id] (n) => !!nodePositionsById[n.id]
); );
const futurePosition = const futurePosition =
(position && nodePositionsById[position.id]) || (position && nodePositionsById[position.id]) ||

View File

@ -1,7 +1,8 @@
import { is, join, pipe, replace } from 'ramda'; import { is, join, pipe, replace } from 'ramda';
import sortAndSerialize from './sortAndSerialize'; import sortAndSerialize from './sortAndSerialize';
import { NodeWithId } from './tree';
export function collapseChildren(node) { export function collapseChildren(node: NodeWithId) {
if (node.children) { if (node.children) {
node._children = node.children; node._children = node.children;
node._children.forEach(collapseChildren); node._children.forEach(collapseChildren);
@ -9,7 +10,7 @@ export function collapseChildren(node) {
} }
} }
export function expandChildren(node) { export function expandChildren(node: NodeWithId) {
if (node._children) { if (node._children) {
node.children = node._children; node.children = node._children;
node.children.forEach(expandChildren); node.children.forEach(expandChildren);
@ -17,7 +18,7 @@ export function expandChildren(node) {
} }
} }
export function toggleChildren(node) { export function toggleChildren(node: NodeWithId) {
if (node.children) { if (node.children) {
node._children = node.children; node._children = node.children;
node.children = null; node.children = null;
@ -28,16 +29,20 @@ export function toggleChildren(node) {
return 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) { if (!parent) {
return; return;
} }
visitFn(parent); visitFn(parent);
let children = childrenFn(parent); const children = childrenFn(parent);
if (children) { if (children) {
let count = children.length; const count = children.length;
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
visit(children[i], visitFn, childrenFn); visit(children[i], visitFn, childrenFn);
@ -45,10 +50,10 @@ export function visit(parent, visitFn, childrenFn) {
} }
} }
export function getNodeGroupByDepthCount(rootNode) { export function getNodeGroupByDepthCount(rootNode: NodeWithId) {
let nodeGroupByDepthCount = [1]; 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) { if (!node.children || node.children.length === 0) {
return 0; return 0;
} }
@ -68,7 +73,11 @@ export function getNodeGroupByDepthCount(rootNode) {
return nodeGroupByDepthCount; return nodeGroupByDepthCount;
} }
export function getTooltipString(node, i, { indentationSize = 4 }) { export function getTooltipString(
node: unknown,
i: number | undefined,
{ indentationSize = 4 }
) {
if (!is(Object, node)) return ''; if (!is(Object, node)) return '';
const spacer = join('&nbsp;&nbsp;'); const spacer = join('&nbsp;&nbsp;');
@ -76,10 +85,13 @@ export function getTooltipString(node, i, { indentationSize = 4 }) {
const spaces2nbsp = replace(/\s{2}/g, spacer(new Array(indentationSize))); const spaces2nbsp = replace(/\s{2}/g, spacer(new Array(indentationSize)));
const json2html = pipe(sortAndSerialize, cr2br, spaces2nbsp); 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 as any).value !== 'undefined')
if (typeof node.object !== 'undefined') return json2html(node.object); return json2html((node as any).value);
if (children && children.length) return 'childrenCount: ' + children.length; 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'; return 'empty';
} }

View File

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

View File

@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.base.json",
"include": ["webpack.config.umd.ts"]
}

View File

@ -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'],
},
};

View File

@ -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;

View File

@ -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;

View File

@ -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'],
},
});

View File

@ -1,3 +1,4 @@
{ {
"presets": ["@babel/preset-env"] "presets": ["@babel/preset-env", "@babel/preset-typescript"],
"plugins": ["@babel/plugin-proposal-class-properties"]
} }

View File

@ -0,0 +1,3 @@
examples
lib
dist

View File

@ -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'],
},
},
],
};

View File

@ -2,46 +2,49 @@
"name": "d3tooltip", "name": "d3tooltip",
"version": "1.2.3", "version": "1.2.3",
"description": "A highly configurable tooltip for d3", "description": "A highly configurable tooltip for d3",
"main": "lib/index.js", "keywords": [
"scripts": { "d3",
"clean": "rimraf lib dist", "tooltip"
"build": "babel src --out-dir lib", ],
"build:umd": "webpack --progress --config webpack.config.umd.js", "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip",
"build:umd:min": "webpack --env.production --progress --config webpack.config.umd.js", "bugs": {
"version": "npm run build", "url": "https://github.com/reduxjs/redux-devtools/issues"
"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"
}, },
"license": "MIT",
"author": "romseguy",
"files": [ "files": [
"lib", "lib",
"dist", "dist",
"src" "src"
], ],
"main": "lib/index.js",
"types": "lib/index.d.ts",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/reduxjs/redux-devtools.git" "url": "https://github.com/reduxjs/redux-devtools.git"
}, },
"keywords": [ "scripts": {
"d3", "build": "npm run build:types && npm run build:js && npm run build:umd && npm run build:umd:min",
"tooltip" "build:types": "tsc --emitDeclarationOnly",
], "build:js": "babel src --out-dir lib --extensions \".ts\" --source-maps inline",
"author": "romseguy", "build:umd": "webpack --progress --config webpack.config.umd.ts",
"license": "MIT", "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.ts",
"bugs": { "clean": "rimraf lib dist",
"url": "https://github.com/reduxjs/redux-devtools/issues" "lint": "eslint . --ext .ts",
}, "lint:fix": "eslint . --ext .ts --fix",
"homepage": "https://github.com/reduxjs/redux-devtools", "type-check": "tsc --noEmit",
"devDependencies": { "type-check:watch": "npm run type-check -- --watch",
"@babel/cli": "^7.10.5", "preversion": "npm run type-check && npm run lint",
"@babel/core": "^7.11.1", "prepublishOnly": "npm run clean && npm run build"
"@babel/preset-env": "^7.11.0",
"babel-loader": "^8.1.0",
"rimraf": "^3.0.2",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12"
}, },
"dependencies": { "dependencies": {
"ramda": "^0.27.1" "ramda": "^0.27.1"
},
"devDependencies": {
"@types/ramda": "^0.27.17"
},
"peerDependencies": {
"@types/d3": "^3.5.43",
"d3": "^3.5.17"
} }
} }

View File

@ -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;
}

View File

@ -0,0 +1,128 @@
import d3Package, { Primitive, Selection } from 'd3';
import { is } from 'ramda';
import utils from './utils';
const { prependClass, functor } = utils;
interface Options<Datum> {
left: number | undefined;
top: number | undefined;
offset: {
left: number;
top: number;
};
root: Selection<Datum> | undefined;
}
const defaultOptions: Options<unknown> = {
left: undefined, // mouseX
top: undefined, // mouseY
offset: { left: 0, top: 0 },
root: undefined,
};
export default function tooltip<Datum>(
d3: typeof d3Package,
className = 'tooltip',
options: Partial<Options<Datum>> = {}
) {
const { left, top, offset, root } = {
...defaultOptions,
...options,
} as Options<Datum>;
let attrs = { class: className };
let text: (datum: Datum, index?: number, outerIndex?: number) => string = (
node: Datum
) => '';
let styles = {};
let el: Selection<Datum>;
const anchor = root || d3.select('body');
const rootNode = anchor.node();
function tip(selection: Selection<Datum>) {
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)) as Selection<Datum>;
});
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;
}

View File

@ -1,5 +0,0 @@
import { is } from 'ramda';
export default function functor(v) {
return is(Function, v) ? v : () => v;
}

View File

@ -0,0 +1,20 @@
import { is } from 'ramda';
import { Primitive } from 'd3';
export default function functor<Datum>(
v: string | ((datum: Datum, index?: number, outerIndex?: number) => string)
): (datum: Datum, index?: number, outerIndex?: number) => string;
export default function functor<Datum>(
v:
| Primitive
| ((datum: Datum, index: number, outerIndex?: number) => Primitive)
): (datum: Datum, index?: number, outerIndex?: number) => Primitive;
export default function functor<Datum>(
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;
}

View File

@ -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;
});
}

View File

@ -0,0 +1,28 @@
import { mapObjIndexed, join } from 'ramda';
import functor from './functor';
import { Primitive } from 'd3';
export default function prependClass<Datum>(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;
}
);
}

View File

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

View File

@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.base.json",
"include": ["webpack.config.umd.ts"]
}

View File

@ -1,9 +1,9 @@
const path = require('path'); import * as path from 'path';
module.exports = (env = {}) => ({ export default (env: { production?: boolean } = {}) => ({
mode: env.production ? 'production' : 'development', mode: env.production ? 'production' : 'development',
entry: { entry: {
app: ['./src/index.js'], app: ['./src/index'],
}, },
output: { output: {
library: 'd3tooltip', library: 'd3tooltip',
@ -14,10 +14,13 @@ module.exports = (env = {}) => ({
module: { module: {
rules: [ rules: [
{ {
test: /\.js$/, test: /\.(js|ts)$/,
loader: 'babel-loader', loader: 'babel-loader',
exclude: /node_modules/, exclude: /node_modules/,
}, },
], ],
}, },
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
}); });

View File

@ -47,7 +47,6 @@
"base16": "^1.0.0", "base16": "^1.0.0",
"codemirror": "^5.56.0", "codemirror": "^5.56.0",
"color": "^3.1.2", "color": "^3.1.2",
"hoist-non-react-statics": "^3.3.2",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react-icons": "^3.10.0", "react-icons": "^3.10.0",
"react-jsonschema-form": "^1.8.1", "react-jsonschema-form": "^1.8.1",

View File

@ -38,6 +38,11 @@ export class Select extends (PureComponent || Component)<SelectProps> {
neutral60: this.props.theme.base06, neutral60: this.props.theme.base06,
neutral80: this.props.theme.base07, neutral80: this.props.theme.base07,
}, },
spacing: {
...theme.spacing,
baseUnit: 2,
controlHeight: this.props.theme.inputHeight,
},
})} })}
/> />
); );

View File

@ -1,5 +1,4 @@
import React, { ComponentType } from 'react'; import React from 'react';
import hoistNonReactStatics from 'hoist-non-react-statics';
import getDefaultTheme, { Theme } from '../themes/default'; import getDefaultTheme, { Theme } from '../themes/default';
import { withTheme } from 'styled-components'; import { withTheme } from 'styled-components';
import { Base16Theme } from 'base16'; import { Base16Theme } from 'base16';
@ -9,33 +8,16 @@ export default <C extends React.ComponentType<any>>(
? C ? C
: never : never
) => { ) => {
const ThemedComponent = React.forwardRef<C, React.ComponentProps<C>>( return withTheme((props) => {
(props, ref) => { return props.theme && props.theme.type ? (
// eslint-disable-next-line react/prop-types <UnthemedComponent {...props} />
if (props.theme && props.theme.type) { ) : (
const ThemedComponent = withTheme( <UnthemedComponent
UnthemedComponent as ComponentType<{ theme?: Theme }> {...props}
); theme={getDefaultTheme((props.theme ?? {}) as Base16Theme)}
return <ThemedComponent {...props} ref={ref} />; />
} );
const UnthemedComponentAny = UnthemedComponent as any; });
return (
<UnthemedComponentAny
{...props}
ref={ref}
theme={getDefaultTheme({} as Base16Theme)}
/>
);
}
);
hoistNonReactStatics(ThemedComponent, UnthemedComponent);
ThemedComponent.displayName = `ThemedComponent(${
UnthemedComponent.displayName ?? 'Component'
})`;
return ThemedComponent;
}; };
// TODO: memoize it? // TODO: memoize it?

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,4 @@
{ {
"presets": ["@babel/preset-env"] "presets": ["@babel/preset-env", "@babel/preset-typescript"],
"plugins": ["@babel/plugin-proposal-class-properties"]
} }

View File

@ -0,0 +1,3 @@
examples
lib
dist

View File

@ -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'],
},
},
],
};

View File

@ -0,0 +1,3 @@
module.exports = {
preset: 'ts-jest',
};

View File

@ -2,20 +2,6 @@
"name": "map2tree", "name": "map2tree",
"version": "1.4.2", "version": "1.4.2",
"description": "Utility for mapping maps to trees", "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": [ "keywords": [
"map2tree", "map2tree",
"map-to-tree", "map-to-tree",
@ -23,38 +9,43 @@
"map", "map",
"tree" "tree"
], ],
"author": "romseguy", "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/map2tree",
"license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/reduxjs/redux-devtools/issues" "url": "https://github.com/reduxjs/redux-devtools/issues"
}, },
"homepage": "https://github.com/reduxjs/redux-devtools", "license": "MIT",
"devDependencies": { "author": "romseguy",
"@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",
"files": [ "files": [
"lib", "lib",
"dist", "dist",
"src" "src"
], ],
"npmFileMap": [ "main": "lib/index.js",
{ "types": "lib/index.d.ts",
"basePath": "/dist/", "repository": {
"files": [ "type": "git",
"*.js" "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"
}
} }

View File

@ -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;
}

View File

@ -0,0 +1,100 @@
import isArray from 'lodash/isArray';
import isPlainObject from 'lodash/isPlainObject';
import mapValues from 'lodash/mapValues';
export interface Node {
name: string;
children?: Node[] | null;
value?: unknown;
}
function visit(
parent: Node,
visitFn: (parent: Node) => void,
childrenFn: (parent: Node) => Node[] | undefined | null
) {
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: [] }
// 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 {};
}
const { key: rootNodeKey = 'state', pushMethod = 'push' } = options;
const currentNode = getNode(tree, rootNodeKey);
if (currentNode === null) {
return {};
}
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;
}

View File

@ -1,11 +1,11 @@
import map2tree from '../src'; import map2tree, { Node } from '../src';
import immutable from 'immutable'; import * as immutable from 'immutable';
test('# rootNodeKey', () => { test('# rootNodeKey', () => {
const map = {}; const map = {};
const options = { key: 'foo' }; const options = { key: 'foo' };
expect(map2tree(map, options).name).toBe('foo'); expect((map2tree(map, options) as Node).name).toBe('foo');
}); });
describe('# shallow map', () => { describe('# shallow map', () => {
@ -151,7 +151,7 @@ describe('# array map', () => {
}); });
test('## unshift', () => { test('## unshift', () => {
const options = { pushMethod: 'unshift' }; const options = { pushMethod: 'unshift' as const };
const expected = { const expected = {
name: 'state', name: 'state',
children: [ children: [

View File

@ -0,0 +1,4 @@
{
"extends": "../../../tsconfig.base.json",
"include": ["../src", "."]
}

View File

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

View File

@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.base.json",
"include": ["webpack.config.umd.ts"]
}

View File

@ -1,12 +1,12 @@
const path = require('path'); import * as path from 'path';
module.exports = (env = {}) => ({ export default (env: { production?: boolean } = {}) => ({
mode: env.production ? 'production' : 'development', mode: env.production ? 'production' : 'development',
entry: { entry: {
app: ['./src/index.js'], app: ['./src/index'],
}, },
output: { output: {
library: 'd3tooltip', library: 'map2tree',
libraryTarget: 'umd', libraryTarget: 'umd',
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
filename: env.production ? 'map2tree.min.js' : 'map2tree.js', filename: env.production ? 'map2tree.min.js' : 'map2tree.js',
@ -14,10 +14,13 @@ module.exports = (env = {}) => ({
module: { module: {
rules: [ rules: [
{ {
test: /\.js$/, test: /\.(js|ts)$/,
loader: 'babel-loader', loader: 'babel-loader',
exclude: /node_modules/, exclude: /node_modules/,
}, },
], ],
}, },
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
}); });

View File

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

View File

@ -0,0 +1 @@
lib

View File

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

View File

@ -2,21 +2,6 @@
"name": "redux-devtools-chart-monitor", "name": "redux-devtools-chart-monitor",
"version": "1.7.2", "version": "1.7.2",
"description": "Chart monitor for Redux DevTools", "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": [ "keywords": [
"redux", "redux",
"devtools", "devtools",
@ -24,32 +9,52 @@
"react", "react",
"chart" "chart"
], ],
"author": "romseguy", "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-chart-monitor",
"license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/reduxjs/redux-devtools/issues" "url": "https://github.com/reduxjs/redux-devtools/issues"
}, },
"homepage": "https://github.com/reduxjs/redux-devtools", "license": "MIT",
"devDependencies": { "author": "romseguy",
"@babel/cli": "^7.10.5", "files": [
"@babel/core": "^7.11.1", "lib",
"@babel/plugin-proposal-class-properties": "^7.10.4", "src"
"@babel/plugin-proposal-export-default-from": "^7.10.4", ],
"@babel/preset-env": "^7.11.0", "main": "lib/index.js",
"@babel/preset-react": "^7.10.4", "types": "lib/index.d.ts",
"babel-loader": "^8.1.0", "repository": {
"rimraf": "^3.0.2" "type": "git",
"url": "https://github.com/reduxjs/redux-devtools.git"
}, },
"peerDependencies": { "scripts": {
"react": "^16.3.0", "build": "npm run build:types && npm run build:js",
"react-dom": "^16.3.0", "build:types": "tsc --emitDeclarationOnly",
"redux-devtools": "^3.0.0" "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": { "dependencies": {
"@types/prop-types": "^15.7.3",
"@types/redux-devtools-themes": "^1.0.0",
"d3-state-visualizer": "^1.3.4", "d3-state-visualizer": "^1.3.4",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react-pure-render": "^1.0.2",
"redux-devtools-themes": "^1.0.0" "redux-devtools-themes": "^1.0.0"
},
"devDependencies": {
"@types/react": "^16.9.46",
"react": "^16.13.1",
"redux": "^4.0.5",
"redux-devtools": "^3.7.0"
},
"peerDependencies": {
"@types/react": "^16.3.18",
"react": "^16.3.0",
"redux": "^3.4.0 || ^4.0.0",
"redux-devtools": "^3.0.0"
} }
} }

View File

@ -1,13 +1,44 @@
import React, { Component, createRef } from 'react'; import React, { Component, createRef } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { tree } from 'd3-state-visualizer'; 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 = { const wrapperStyle = {
width: '100%', width: '100%',
height: '100%', height: '100%',
}; };
class Chart extends Component { export interface Props<S, A extends Action<unknown>>
extends LiftedState<S, A, ChartMonitorState> {
dispatch: Dispatch<LiftedAction<S, A, ChartMonitorState>>;
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<S, A extends Action<unknown>> extends Component<Props<S, A>> {
static propTypes = { static propTypes = {
state: PropTypes.object, state: PropTypes.object,
rootKeyName: PropTypes.string, rootKeyName: PropTypes.string,
@ -60,21 +91,25 @@ class Chart extends Component {
}), }),
}; };
divRef = createRef(); divRef = createRef<HTMLDivElement>();
// eslint-disable-next-line @typescript-eslint/ban-types
renderChart?: (state?: {} | null | undefined) => void;
componentDidMount() { componentDidMount() {
const { select, state, defaultIsVisible } = this.props; const { select, state, defaultIsVisible } = this.props;
this.renderChart = tree(this.divRef.current, this.props); this.renderChart = tree(this.divRef.current!, this.props);
if (defaultIsVisible) { 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<S, A>) {
const { state, select, monitorState } = nextProps; const { state, select, monitorState } = nextProps;
if (monitorState.isVisible !== false) { if (monitorState.isVisible !== false) {
this.renderChart(select(state)); // eslint-disable-next-line @typescript-eslint/ban-types
this.renderChart!(select(state!) as {} | null | undefined);
} }
} }

View File

@ -1,15 +1,18 @@
import React, { Component } from 'react'; import React, { CSSProperties, PureComponent } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import shouldPureComponentUpdate from 'react-pure-render/function';
import * as themes from 'redux-devtools-themes'; import * as themes from 'redux-devtools-themes';
import { ActionCreators } from 'redux-devtools'; import { ActionCreators, LiftedAction, LiftedState } from 'redux-devtools';
import deepmerge from 'deepmerge'; import deepmerge from 'deepmerge';
import { Action, Dispatch } from 'redux';
import { Base16Theme } from 'react-base16-styling';
import reducer from './reducers'; import reducer, { ChartMonitorState } from './reducers';
import Chart from './Chart'; 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 { reset, rollback, commit, sweep, toggleAction } = ActionCreators;
const styles = { const styles: { container: CSSProperties } = {
container: { container: {
fontFamily: 'monaco, Consolas, Lucida Console, monospace', fontFamily: 'monaco, Consolas, Lucida Console, monospace',
position: 'relative', position: 'relative',
@ -20,7 +23,7 @@ const styles = {
}, },
}; };
function invertColors(theme) { function invertColors(theme: Base16Theme) {
return { return {
...theme, ...theme,
base00: theme.base07, base00: theme.base07,
@ -34,7 +37,43 @@ function invertColors(theme) {
}; };
} }
class ChartMonitor extends Component { export interface ChartMonitorProps<S, A extends Action<unknown>>
extends LiftedState<S, A, ChartMonitorState> {
dispatch: Dispatch<LiftedAction<S, A, ChartMonitorState>>;
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<S, A extends Action<unknown>> extends PureComponent<
ChartMonitorProps<S, A>
> {
static update = reducer; static update = reducer;
static propTypes = { static propTypes = {
@ -55,45 +94,34 @@ class ChartMonitor extends Component {
}; };
static defaultProps = { static defaultProps = {
select: (state) => state, select: (state: unknown) => state,
theme: 'nicinabox', theme: 'nicinabox',
preserveScrollTop: true, preserveScrollTop: true,
invertTheme: false, invertTheme: false,
}; };
shouldComponentUpdate = shouldPureComponentUpdate; handleRollback = () => {
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() {
this.props.dispatch(rollback()); this.props.dispatch(rollback());
} };
handleSweep() { handleSweep = () => {
this.props.dispatch(sweep()); this.props.dispatch(sweep());
} };
handleCommit() { handleCommit = () => {
this.props.dispatch(commit()); this.props.dispatch(commit());
} };
handleToggleAction(id) { handleToggleAction = (id: number) => {
this.props.dispatch(toggleAction(id)); this.props.dispatch(toggleAction(id));
} };
handleReset() { handleReset = () => {
this.props.dispatch(reset()); this.props.dispatch(reset());
} };
getTheme() { getTheme() {
let { theme, invertTheme } = this.props; const { theme, invertTheme } = this.props;
if (typeof theme !== 'string') { if (typeof theme !== 'string') {
return invertTheme ? invertColors(theme) : theme; return invertTheme ? invertColors(theme) : theme;
} }
@ -102,7 +130,6 @@ class ChartMonitor extends Component {
return invertTheme ? invertColors(themes[theme]) : themes[theme]; return invertTheme ? invertColors(themes[theme]) : themes[theme];
} }
// eslint-disable-next-line no-console
console.warn( console.warn(
'DevTools theme ' + theme + ' not found, defaulting to nicinabox' '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<S, A> {
const { computedStates } = props; const { computedStates } = props;
const theme = this.getTheme(); const theme = this.getTheme();
@ -156,7 +183,9 @@ class ChartMonitor extends Component {
heightBetweenNodesCoeff: 1, heightBetweenNodesCoeff: 1,
widthBetweenNodesCoeff: 1.3, widthBetweenNodesCoeff: 1.3,
tooltipOptions, tooltipOptions,
style: this.getChartStyle(), style: (this.getChartStyle() as unknown) as
| { [key: string]: Primitive }
| undefined,
}; };
return deepmerge(defaultOptions, props); return deepmerge(defaultOptions, props);
@ -165,9 +194,10 @@ class ChartMonitor extends Component {
render() { render() {
const theme = this.getTheme(); const theme = this.getTheme();
const ChartAsAny = Chart as any;
return ( return (
<div style={{ ...styles.container, backgroundColor: theme.base07 }}> <div style={{ ...styles.container, backgroundColor: theme.base07 }}>
<Chart {...this.getChartOptions()} /> <ChartAsAny {...this.getChartOptions()} />
</div> </div>
); );
} }

View File

@ -1,2 +0,0 @@
export const TOGGLE_VISIBILITY =
'@@redux-devtools-log-monitor/TOGGLE_VISIBILITY';

View File

@ -0,0 +1,6 @@
export const TOGGLE_VISIBILITY =
'@@redux-devtools-log-monitor/TOGGLE_VISIBILITY';
interface ToggleVisibilityAction {
type: typeof TOGGLE_VISIBILITY;
}
export type ChartMonitorAction = ToggleVisibilityAction;

View File

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

View File

@ -0,0 +1 @@
export { default } from './ChartMonitor';

View File

@ -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),
};
}

View File

@ -0,0 +1,33 @@
import { Action } from 'redux';
import { ChartMonitorAction, TOGGLE_VISIBILITY } from './actions';
import { ChartMonitorProps } from './ChartMonitor';
function toggleVisibility<S, A extends Action<unknown>>(
props: ChartMonitorProps<S, A>,
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<S, A extends Action<unknown>>(
props: ChartMonitorProps<S, A>,
state: ChartMonitorState | undefined = {},
action: ChartMonitorAction
) {
return {
isVisible: toggleVisibility(props, state.isVisible, action),
};
}

View File

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

View File

@ -4,6 +4,7 @@ import { Action, Dispatch } from 'redux';
import * as themes from 'redux-devtools-themes'; import * as themes from 'redux-devtools-themes';
import { Base16Theme } from 'redux-devtools-themes'; import { Base16Theme } from 'redux-devtools-themes';
import { ActionCreators, LiftedAction, LiftedState } from 'redux-devtools'; import { ActionCreators, LiftedAction, LiftedState } from 'redux-devtools';
import debounce from 'lodash.debounce';
import { import {
updateScrollTop, updateScrollTop,
startConsecutiveToggle, startConsecutiveToggle,
@ -12,9 +13,6 @@ import {
import reducer, { LogMonitorState } from './reducers'; import reducer, { LogMonitorState } from './reducers';
import LogMonitorButtonBar from './LogMonitorButtonBar'; import LogMonitorButtonBar from './LogMonitorButtonBar';
import LogMonitorEntryList from './LogMonitorEntryList'; import LogMonitorEntryList from './LogMonitorEntryList';
import debounce from 'lodash.debounce';
import { 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 // eslint-disable-next-line @typescript-eslint/unbound-method
const { toggleAction, setActionsActive } = ActionCreators; const { toggleAction, setActionsActive } = ActionCreators;
@ -276,8 +274,8 @@ export default (LogMonitor as unknown) as React.ComponentType<
> & { > & {
update( update(
monitorProps: ExternalProps<unknown, Action<unknown>>, monitorProps: ExternalProps<unknown, Action<unknown>>,
state: DockMonitorState | undefined, state: LogMonitorState | undefined,
action: DockMonitorAction action: LogMonitorAction
): DockMonitorState; ): LogMonitorState;
defaultProps: DefaultProps<unknown>; defaultProps: DefaultProps<unknown>;
}; };

View File

@ -1,5 +1,4 @@
import React, { PureComponent, Component, ReactNode } from 'react'; import React, { PureComponent, Component, ReactNode } from 'react';
import PropTypes from 'prop-types';
import { stringify } from 'javascript-stringify'; import { stringify } from 'javascript-stringify';
import objectPath from 'object-path'; import objectPath from 'object-path';
import jsan from 'jsan'; import jsan from 'jsan';

View File

@ -130,14 +130,15 @@ export default class TestTab<S, A extends Action<unknown>> extends Component<
return ( return (
<Container> <Container>
<Toolbar> <Toolbar>
<Select <div style={{ flexGrow: 1, zIndex: 100 }}>
options={templates} <Select
valueKey="name" options={templates}
labelKey="name" getOptionValue={(template: Template) => template.name}
value={name} getOptionLabel={(template: Template) => template.name}
simpleValue={false} value={templates.filter((template) => template.name === name)}
onChange={this.handleSelectTemplate} onChange={this.handleSelectTemplate}
/> />
</div>
<Button onClick={this.editTemplate}> <Button onClick={this.editTemplate}>
<MdEdit /> <MdEdit />
</Button> </Button>

View File

@ -3355,6 +3355,11 @@
dependencies: dependencies:
"@types/node" "*" "@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": "@types/dateformat@^3.0.1":
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/dateformat/-/dateformat-3.0.1.tgz#98d747a2e5e9a56070c6bf14e27bff56204e34cc" 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" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a"
integrity sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ== 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@*": "@types/range-parser@*":
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
@ -9357,7 +9369,7 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0" minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1" 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" version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@ -16929,6 +16941,11 @@ ts-pnp@^1.1.6:
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== 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: tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.13.0" version "1.13.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"