Upgrade D3 to v4 (#1307)

* Update packages

* Fix after update

* Update some types

* Remove attr

* Finish d3tooltip

* Update style option

* Updates

* Zoom

* Update

* Update

* Update

* Fix

* Update

* Update

* Update

* Update

* Update

* Fixes

* Update id type

* Fix enter + update selections

* Use this

* Fix stringifying

* Remove InputOptions

* Use data.value

* Updates

* Remove UMD builds

* Fix exit

* No need to re-assign

* Simplify d3tooltip API

* Update redux-devtools-chart-monitor

* Update redux-devtools-app

* Update

* Update

* Remove @types/prop-types

* Update prop types

* Update d3tooltip docs

* Update d3-state-visualizer docs

* Update chart-monitor docs

* Create weak-kings-brake.md

* Create spicy-olives-compete.md

* Create friendly-coats-trade.md

* Create slimy-elephants-flash.md

* Fix empty arrays
This commit is contained in:
Nathan Bierema 2023-01-02 14:19:13 -05:00 committed by GitHub
parent 40b024a308
commit b323f77d31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 825 additions and 1050 deletions

View File

@ -0,0 +1,8 @@
---
'd3-state-visualizer': major
---
- Remove UMD build.
- Split `style` option into `chartStyles`, `nodeStyleOptions`, `textStyleOptions`, and `linkStyles`.
- The shape of the argument passed to the option `onClickText` has been updated to match the d3 v4 node.
- Rename `InputOptions` to `Options`, `Primitive` to `StyleValue`, and `NodeWithId` to `HierarchyPointNode<Node>`.

View File

@ -0,0 +1,6 @@
---
'@redux-devtools/chart-monitor': major
---
- Split `style` option into `chartStyles`, `nodeStyleOptions`, `textStyleOptions`, and `linkStyles`.
- The shape of the argument passed to the option `onClickText` has been updated to match the d3 v4 node.

View File

@ -0,0 +1,10 @@
---
'd3tooltip': major
---
- Remove UMD build.
- Upgrade d3 peer dependency from v3 to v4.
- Remove `attr` configuration method.
- Rename `style` configuration method to `styles` and move to options.
- Move `text` configuration method to options.
- Remove d3 parameter as first parameter for `tooltip`.

View File

@ -0,0 +1,5 @@
---
'map2tree': major
---
- Remove UMD build.

View File

@ -35,7 +35,7 @@ const render = tree(document.getElementById('root'), {
isSorted: false,
widthBetweenNodesCoeff: 1.5,
heightBetweenNodesCoeff: 2,
style: { border: '1px solid black' },
chartStyles: { border: '1px solid black' },
tooltipOptions: { offset: { left: 30, top: 10 }, indentationSize: 2 },
});
@ -61,7 +61,7 @@ Other options are listed below and have reasonable default values if you want to
| Option | Type | Default | Description |
| ------------------------- | ------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | String | `'d3svg'` | Sets the identifier of the SVG element —i.e your chart— that will be added to the DOM element you passed as first argument |
| `style` | Object | `{}` | Sets the CSS style of the chart |
| `chartStyles` | Object | `{}` | Sets the CSS style of the chart |
| `size` | Number | `500` | Sets size of the chart in pixels |
| `aspectRatio` | Float | `1.0` | Sets the chart height to `size * aspectRatio` and [viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox) in order to preserve the aspect ratio of the chart. [Great video](https://www.youtube.com/watch?v=FCOeMy7HrBc) if you want to learn more about how SVG works |
| `widthBetweenNodesCoeff` | Float | `1.0` | Alters the horizontal space between each node |
@ -74,12 +74,6 @@ Other options are listed below and have reasonable default values if you want to
More to come...
## Bindings
### React
[example](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3-state-visualizer/examples/react-tree) implementation.
## Roadmap
- Threshold for large arrays so only a single node is displayed instead of all the children. That single node would be exclude from searching until selected.

View File

@ -28,7 +28,7 @@ const render = tree(document.getElementById('root')!, {
isSorted: false,
widthBetweenNodesCoeff: 1.5,
heightBetweenNodesCoeff: 2,
style: { border: '1px solid black' },
chartStyles: { border: '1px solid black' },
tooltipOptions: { offset: { left: 30, top: 10 }, indentationSize: 2 },
});

View File

@ -23,18 +23,16 @@
"main": "lib/cjs/index.js",
"module": "lib/esm/index.js",
"types": "lib/types/index.d.ts",
"unpkg": "dist/d3-state-visualizer.umd.js",
"sideEffects": false,
"repository": {
"type": "git",
"url": "https://github.com/reduxjs/redux-devtools.git"
},
"scripts": {
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types && pnpm run build:umd",
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types",
"build:cjs": "babel src --extensions \".ts\" --out-dir lib/cjs",
"build:esm": "babel src --config-file ./babel.config.esm.json --extensions \".ts\" --out-dir lib/esm",
"build:types": "tsc --emitDeclarationOnly",
"build:umd": "rollup -c",
"clean": "rimraf lib",
"lint": "eslint . --ext .ts",
"type-check": "tsc --noEmit",
@ -43,8 +41,8 @@
},
"dependencies": {
"@babel/runtime": "^7.20.6",
"@types/d3": "^3.5.47",
"d3": "^3.5.17",
"@types/d3": "^4.13.12",
"d3": "^4.13.0",
"d3tooltip": "^2.1.0",
"deepmerge": "^4.2.2",
"map2tree": "^2.1.0",
@ -54,23 +52,14 @@
"@babel/cli": "^7.19.3",
"@babel/core": "^7.20.5",
"@babel/eslint-parser": "^7.19.1",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.18.6",
"@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-commonjs": "^24.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-terser": "^0.2.1",
"@types/node": "^18.11.17",
"@types/ramda": "^0.28.20",
"@typescript-eslint/eslint-plugin": "^5.47.0",
"@typescript-eslint/parser": "^5.47.0",
"eslint": "^8.30.0",
"eslint-config-prettier": "^8.5.0",
"rimraf": "^3.0.2",
"rollup": "^3.7.5",
"rollup-plugin-typescript2": "^0.34.1",
"tslib": "^2.4.1",
"typescript": "~4.9.4"
}
}

View File

@ -1,51 +0,0 @@
import typescript from 'rollup-plugin-typescript2';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';
const config = [
{
input: 'src/index.ts',
output: {
name: 'd3-state-visualizer',
file: 'lib/umd/d3-state-visualizer.js',
format: 'umd',
},
plugins: [
typescript({
tsconfigOverride: { compilerOptions: { declaration: false } },
}),
resolve(),
commonjs(),
babel({
babelHelpers: 'runtime',
extensions: ['.ts'],
plugins: ['@babel/plugin-transform-runtime'],
}),
],
},
{
input: 'src/index.ts',
output: {
name: 'd3-state-visualizer',
file: 'lib/umd/d3-state-visualizer.min.js',
format: 'umd',
},
plugins: [
typescript({
tsconfigOverride: { compilerOptions: { declaration: false } },
}),
resolve(),
commonjs(),
babel({
babelHelpers: 'runtime',
extensions: ['.ts'],
plugins: ['@babel/plugin-transform-runtime'],
}),
terser(),
],
},
];
export default config;

View File

@ -1,2 +1,4 @@
export type { HierarchyPointNode } from 'd3';
export type { StyleValue } from 'd3tooltip';
export { default as tree } from './tree/tree';
export type { InputOptions, NodeWithId, Primitive } from './tree/tree';
export type { Node, Options } from './tree/tree';

View File

@ -1,6 +1,8 @@
import d3, { ZoomEvent, Primitive } from 'd3';
import * as d3 from 'd3';
import type { D3ZoomEvent, HierarchyPointLink, HierarchyPointNode } from 'd3';
import { isEmpty } from 'ramda';
import { map2tree } from 'map2tree';
import type { Node } from 'map2tree';
import deepmerge from 'deepmerge';
import {
getTooltipString,
@ -9,17 +11,33 @@ import {
getNodeGroupByDepthCount,
} from './utils';
import { tooltip } from 'd3tooltip';
import type { StyleValue } from 'd3tooltip';
export interface InputOptions {
export interface Options {
// eslint-disable-next-line @typescript-eslint/ban-types
state?: {} | null;
// eslint-disable-next-line @typescript-eslint/ban-types
tree?: NodeWithId | {};
tree?: Node | {};
rootKeyName: string;
pushMethod: 'push' | 'unshift';
id: string;
style: { [key: string]: Primitive };
chartStyles: { [key: string]: StyleValue };
nodeStyleOptions: {
colors: {
default: string;
collapsed: string;
parent: string;
};
radius: number;
};
textStyleOptions: {
colors: {
default: string;
hover: string;
};
};
linkStyles: { [key: string]: StyleValue };
size: number;
aspectRatio: number;
initialZoom: number;
@ -34,7 +52,7 @@ export interface InputOptions {
widthBetweenNodesCoeff: number;
transitionDuration: number;
blinkDuration: number;
onClickText: (datum: NodeWithId) => void;
onClickText: (datum: HierarchyPointNode<Node>) => void;
tooltipOptions: {
disabled?: boolean;
left?: number | undefined;
@ -43,64 +61,7 @@ export interface InputOptions {
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;
styles?: { [key: string]: StyleValue } | undefined;
indentationSize?: number;
};
}
@ -111,26 +72,25 @@ const defaultOptions: Options = {
pushMethod: 'push',
tree: undefined,
id: 'd3svg',
style: {
node: {
colors: {
default: '#ccc',
collapsed: 'lightsteelblue',
parent: 'white',
},
radius: 7,
chartStyles: {},
nodeStyleOptions: {
colors: {
default: '#ccc',
collapsed: 'lightsteelblue',
parent: 'white',
},
text: {
colors: {
default: 'black',
hover: 'skyblue',
},
},
link: {
stroke: '#000',
fill: 'none',
radius: 7,
},
textStyleOptions: {
colors: {
default: 'black',
hover: 'skyblue',
},
},
linkStyles: {
stroke: '#000',
fill: 'none',
},
size: 500,
aspectRatio: 1.0,
initialZoom: 1,
@ -156,37 +116,29 @@ const defaultOptions: Options = {
left: 0,
top: 0,
},
style: undefined,
styles: undefined,
},
};
} satisfies Options;
export interface NodeWithId {
name: string;
children?: NodeWithId[] | null;
_children?: NodeWithId[] | null;
value?: unknown;
id: string;
parent?: NodeWithId;
depth?: number;
x?: number;
y?: number;
export interface InternalNode extends Node {
_children?: this[] | undefined;
id: string | number;
}
interface NodePosition {
parentId: string | null | undefined;
id: string;
x: number | undefined;
y: number | undefined;
parentId: string | number | null;
id: string | number;
x: number;
y: number;
}
export default function (
DOMNode: HTMLElement,
options: Partial<InputOptions> = {}
) {
export default function (DOMNode: HTMLElement, options: Partial<Options> = {}) {
const {
id,
style,
chartStyles,
nodeStyleOptions,
textStyleOptions,
linkStyles,
size,
aspectRatio,
initialZoom,
@ -202,64 +154,50 @@ export default function (
tree,
tooltipOptions,
onClickText,
} = deepmerge(defaultOptions, options) as Options;
} = deepmerge(defaultOptions, options);
const width = size - margin.left - margin.right;
const height = size * aspectRatio - margin.top - margin.bottom;
const fullWidth = size;
const fullHeight = size * aspectRatio;
const attr: { [key: string]: Primitive } = {
id,
preserveAspectRatio: 'xMinYMin slice',
};
if (!(style as unknown as { [key: string]: Primitive }).width) {
attr.width = fullWidth;
}
if (
!(style as unknown as { [key: string]: Primitive }).width ||
!(style as unknown as { [key: string]: Primitive }).height
) {
attr.viewBox = `0 0 ${fullWidth} ${fullHeight}`;
}
const root = d3.select(DOMNode);
const zoom = d3.behavior.zoom().scaleExtent([0.1, 3]).scale(initialZoom);
const vis = root
const zoom = d3.zoom<SVGSVGElement, unknown>().scaleExtent([0.1, 3]);
const svgElement = root
.append('svg')
.attr(attr)
.style({ cursor: '-webkit-grab', ...style } as unknown as {
[key: string]: Primitive;
})
.attr('id', id)
.attr('preserveAspectRatio', 'xMinYMin slice')
.style('cursor', '-webkit-grab');
if (!chartStyles.width) {
svgElement.attr('width', fullWidth);
}
if (!chartStyles.width || !chartStyles.height) {
svgElement.attr('viewBox', `0 0 ${fullWidth} ${fullHeight}`);
}
for (const [key, value] of Object.entries(chartStyles)) {
svgElement.style(key, value);
}
const vis = svgElement
// eslint-disable-next-line @typescript-eslint/unbound-method
.call(zoom.scaleTo, initialZoom)
.call(
zoom.on('zoom', () => {
const { translate, scale } = d3.event as ZoomEvent;
vis.attr(
'transform',
`translate(${translate.toString()})scale(${scale})`
);
const { transform } = d3.event as D3ZoomEvent<SVGSVGElement, unknown>;
vis.attr('transform', transform.toString());
})
)
.append('g')
.attr({
transform: `translate(${margin.left + style.node.radius}, ${
.attr(
'transform',
`translate(${margin.left + nodeStyleOptions.radius}, ${
margin.top
}) scale(${initialZoom})`,
});
let layout = d3.layout.tree().size([width, height]);
let data: NodeWithId;
if (isSorted) {
layout.sort((a, b) =>
(b as NodeWithId).name.toLowerCase() <
(a as NodeWithId).name.toLowerCase()
? 1
: -1
}) scale(${initialZoom})`
);
}
// previousNodePositionsById stores node x and y
// as well as hierarchy (id / parentId);
@ -277,8 +215,8 @@ export default function (
// of parent ids; once a parent that matches the given filter is found,
// the parent position gets returned
function findParentNodePosition(
nodePositionsById: { [nodeId: string]: NodePosition },
nodeId: string,
nodePositionsById: { [nodeId: string | number]: NodePosition },
nodeId: string | number,
filter: (nodePosition: NodePosition) => boolean
) {
let currentPosition = nodePositionsById[nodeId];
@ -294,19 +232,18 @@ export default function (
}
return function renderChart(nextState = tree || state) {
data = !tree
? // eslint-disable-next-line @typescript-eslint/ban-types
(map2tree(nextState as {}, {
let data = !tree
? (map2tree(nextState, {
key: rootKeyName,
pushMethod,
}) as NodeWithId)
: (nextState as NodeWithId);
}) as InternalNode)
: (nextState as InternalNode);
if (isEmpty(data) || !data.name) {
data = {
name: 'error',
message: 'Please provide a state map or a tree structure',
} as unknown as NodeWithId;
} as unknown as InternalNode;
}
let nodeIndex = 0;
@ -334,76 +271,94 @@ export default function (
function update() {
// path generator for links
const diagonal = d3.svg
.diagonal<NodePosition>()
.projection((d) => [d.y!, d.x!]);
const linkHorizontal = d3
.linkHorizontal<
{
source: { x: number; y: number };
target: { x: number; y: number };
},
{ x: number; y: number }
>()
.x((d) => d.y)
.y((d) => d.x);
// set tree dimensions and spacing between branches and nodes
const maxNodeCountByLevel = Math.max(...getNodeGroupByDepthCount(data));
layout = layout.size([
maxNodeCountByLevel * 25 * heightBetweenNodesCoeff,
width,
]);
const layout = d3
.tree<InternalNode>()
.size([maxNodeCountByLevel * 25 * heightBetweenNodesCoeff, width]);
const nodes = layout.nodes(data as d3.layout.tree.Node) as NodeWithId[];
const links = layout.links(nodes as d3.layout.tree.Node[]);
const rootNode = d3.hierarchy(data);
if (isSorted) {
rootNode.sort((a, b) =>
b.data.name.toLowerCase() < a.data.name.toLowerCase() ? 1 : -1
);
}
nodes.forEach(
const rootPointNode = layout(rootNode);
const links = rootPointNode.links();
rootPointNode.each(
(node) =>
(node.y = node.depth! * (maxLabelLength * 7 * widthBetweenNodesCoeff))
(node.y = node.depth * (maxLabelLength * 7 * widthBetweenNodesCoeff))
);
const nodes = rootPointNode.descendants();
const nodePositions = nodes.map((n) => ({
parentId: n.parent && n.parent.id,
id: n.id,
parentId: n.parent && n.parent.data.id,
id: n.data.id,
x: n.x,
y: n.y,
}));
const nodePositionsById: { [nodeId: string]: NodePosition } = {};
const nodePositionsById: { [nodeId: string | number]: NodePosition } = {};
nodePositions.forEach((node) => (nodePositionsById[node.id] = node));
// process the node selection
const node = vis
.selectAll('g.node')
.property('__oldData__', (d: NodeWithId) => d)
.data(nodes, (d) => d.id || (d.id = ++nodeIndex as unknown as string));
.selectAll<SVGGElement, HierarchyPointNode<InternalNode>>('g.node')
.property('__oldData__', (d) => d)
.data(nodes, (d) => d.data.id || (d.data.id = ++nodeIndex));
const nodeEnter = node
.enter()
.append('g')
.attr({
class: 'node',
transform: (d) => {
const position = findParentNodePosition(
nodePositionsById,
d.id,
(n) => !!previousNodePositionsById[n.id]
);
const previousPosition =
(position && previousNodePositionsById[position.id]) ||
previousNodePositionsById.root;
return `translate(${previousPosition.y!},${previousPosition.x!})`;
},
.attr('class', 'node')
.attr('transform', (d) => {
const position = findParentNodePosition(
nodePositionsById,
d.data.id,
(n) => !!previousNodePositionsById[n.id]
);
const previousPosition =
(position && previousNodePositionsById[position.id]) ||
previousNodePositionsById.root;
return `translate(${previousPosition.y},${previousPosition.x})`;
})
.style({
fill: style.text.colors.default,
cursor: 'pointer',
.style('fill', textStyleOptions.colors.default)
.style('cursor', 'pointer')
.on('mouseover', function mouseover() {
d3.select(this).style('fill', textStyleOptions.colors.hover);
})
.on('mouseover', function mouseover(this: EventTarget) {
d3.select(this).style({
fill: style.text.colors.hover,
});
})
.on('mouseout', function mouseout(this: EventTarget) {
d3.select(this).style({
fill: style.text.colors.default,
});
.on('mouseout', function mouseout() {
d3.select(this).style('fill', textStyleOptions.colors.default);
});
if (!tooltipOptions.disabled) {
nodeEnter.call(
tooltip<NodeWithId>(d3, 'tooltip', { ...tooltipOptions, root })
.text((d, i) => getTooltipString(d, i, tooltipOptions))
.style(tooltipOptions.style)
tooltip<
SVGGElement,
HierarchyPointNode<InternalNode>,
SVGGElement,
unknown,
HTMLElement,
unknown,
null,
undefined
>('tooltip', {
...tooltipOptions,
root,
text: (d) => getTooltipString(d.data, tooltipOptions),
})
);
}
@ -412,77 +367,79 @@ export default function (
const nodeEnterInnerGroup = nodeEnter.append('g');
nodeEnterInnerGroup
.append('circle')
.attr({
class: 'nodeCircle',
r: 0,
})
.attr('class', 'nodeCircle')
.attr('r', 0)
.on('click', (clickedNode) => {
if ((d3.event as Event).defaultPrevented) return;
toggleChildren(clickedNode);
if (d3.event.defaultPrevented) return;
toggleChildren(clickedNode.data);
update();
});
nodeEnterInnerGroup
.append('text')
.attr({
class: 'nodeText',
'text-anchor': 'middle',
transform: 'translate(0,0)',
dy: '.35em',
})
.style({
'fill-opacity': 0,
})
.text((d) => d.name)
.attr('class', 'nodeText')
.attr('text-anchor', 'middle')
.attr('transform', 'translate(0,0)')
.attr('dy', '.35em')
.style('fill-opacity', 0)
.text((d) => d.data.name)
.on('click', onClickText);
const nodeEnterAndUpdate = nodeEnter.merge(node);
// update the text to reflect whether node has children or not
node.select('text').text((d) => d.name);
nodeEnterAndUpdate.select('text').text((d) => d.data.name);
// change the circle fill depending on whether it has children and is collapsed
node.select('circle').style({
stroke: 'black',
'stroke-width': '1.5px',
fill: (d) =>
d._children
? style.node.colors.collapsed
: d.children
? style.node.colors.parent
: style.node.colors.default,
});
nodeEnterAndUpdate
.select('circle')
.style('stroke', 'black')
.style('stroke-width', '1.5px')
.style('fill', (d) =>
d.data._children && d.data._children.length > 0
? nodeStyleOptions.colors.collapsed
: d.data.children && d.data.children.length > 0
? nodeStyleOptions.colors.parent
: nodeStyleOptions.colors.default
);
// transition nodes to their new position
const nodeUpdate = node
const nodeUpdate = nodeEnterAndUpdate
.transition()
.duration(transitionDuration)
.attr({
transform: (d) => `translate(${d.y!},${d.x!})`,
});
.attr('transform', (d) => `translate(${d.y},${d.x})`);
// ensure circle radius is correct
nodeUpdate.select('circle').attr('r', style.node.radius);
nodeUpdate.select('circle').attr('r', nodeStyleOptions.radius);
// fade the text in and align it
nodeUpdate
.select('text')
.select<SVGTextElement>('text')
.style('fill-opacity', 1)
.attr({
transform: function transform(this: SVGGraphicsElement, d) {
const x =
(d.children || d._children ? -1 : 1) *
(this.getBBox().width / 2 + style.node.radius + 5);
return `translate(${x},0)`;
},
.attr('transform', function transform(d) {
const x =
(((d.data.children ?? d.data._children)?.length ?? 0) > 0
? -1
: 1) *
(this.getBBox().width / 2 + nodeStyleOptions.radius + 5);
return `translate(${x},0)`;
});
// blink updated nodes
node
.filter(function flick(this: any, d) {
nodeEnterAndUpdate
.filter(function flick(
this: SVGGElement & {
__oldData__?: HierarchyPointNode<InternalNode>;
},
d
) {
// test whether the relevant properties of d match
// the equivalent property of the oldData
// also test whether the old data exists,
// to catch the entering elements!
return this.__oldData__ && d.value !== this.__oldData__.value;
return (
!!this.__oldData__ && d.data.value !== this.__oldData__.data.value
);
})
.select('g')
.style('opacity', '0.3')
@ -492,21 +449,19 @@ export default function (
// transition exiting nodes to the parent's new position
const nodeExit = node
.exit()
.exit<HierarchyPointNode<InternalNode>>()
.transition()
.duration(transitionDuration)
.attr({
transform: (d) => {
const position = findParentNodePosition(
previousNodePositionsById,
d.id,
(n) => !!nodePositionsById[n.id]
);
const futurePosition =
(position && nodePositionsById[position.id]) ||
nodePositionsById.root;
return `translate(${futurePosition.y!},${futurePosition.x!})`;
},
.attr('transform', (d) => {
const position = findParentNodePosition(
previousNodePositionsById,
d.data.id,
(n) => !!nodePositionsById[n.id]
);
const futurePosition =
(position && nodePositionsById[position.id]) ||
nodePositionsById.root;
return `translate(${futurePosition.y},${futurePosition.x})`;
})
.remove();
@ -516,65 +471,66 @@ export default function (
// update the links
const link = vis
.selectAll('path.link')
.data(links, (d) => (d.target as NodeWithId).id);
.selectAll<SVGPathElement, HierarchyPointLink<InternalNode>>(
'path.link'
)
.data(links, (d) => d.target.data.id);
// enter any new links at the parent's previous position
link
const linkEnter = link
.enter()
.insert('path', 'g')
.attr({
class: 'link',
d: (d) => {
const position = findParentNodePosition(
nodePositionsById,
(d.target as NodeWithId).id,
(n) => !!previousNodePositionsById[n.id]
);
const previousPosition =
(position && previousNodePositionsById[position.id]) ||
previousNodePositionsById.root;
return diagonal({
source: previousPosition,
target: previousPosition,
} as d3.svg.diagonal.Link<NodePosition>);
},
})
.style(style.link);
.attr('class', 'link')
.attr('d', (d) => {
const position = findParentNodePosition(
nodePositionsById,
d.target.data.id,
(n) => !!previousNodePositionsById[n.id]
);
const previousPosition =
(position && previousNodePositionsById[position.id]) ||
previousNodePositionsById.root;
return linkHorizontal({
source: previousPosition,
target: previousPosition,
});
});
for (const [key, value] of Object.entries(linkStyles)) {
linkEnter.style(key, value);
}
const linkEnterAndUpdate = linkEnter.merge(link);
// transition links to their new position
link
linkEnterAndUpdate
.transition()
.duration(transitionDuration)
.attr({
d: diagonal as unknown as Primitive,
});
.attr('d', linkHorizontal);
// transition exiting nodes to the parent's new position
link
.exit()
.exit<HierarchyPointLink<InternalNode>>()
.transition()
.duration(transitionDuration)
.attr({
d: (d) => {
const position = findParentNodePosition(
previousNodePositionsById,
(d.target as NodeWithId).id,
(n) => !!nodePositionsById[n.id]
);
const futurePosition =
(position && nodePositionsById[position.id]) ||
nodePositionsById.root;
return diagonal({
source: futurePosition,
target: futurePosition,
});
},
.attr('d', (d) => {
const position = findParentNodePosition(
previousNodePositionsById,
d.target.data.id,
(n) => !!nodePositionsById[n.id]
);
const futurePosition =
(position && nodePositionsById[position.id]) ||
nodePositionsById.root;
return linkHorizontal({
source: futurePosition,
target: futurePosition,
});
})
.remove();
// delete the old data once it's no longer needed
node.property('__oldData__', null);
nodeEnterAndUpdate.property('__oldData__', null);
// stash the old positions for transition
previousNodePositionsById = nodePositionsById;
@ -582,4 +538,4 @@ export default function (
};
}
export { Primitive };
export type { Node };

View File

@ -1,38 +1,38 @@
import { is, join, pipe, replace } from 'ramda';
import sortAndSerialize from './sortAndSerialize';
import { NodeWithId } from './tree';
import type { InternalNode } from './tree';
export function collapseChildren(node: NodeWithId) {
export function collapseChildren(node: InternalNode) {
if (node.children) {
node._children = node.children;
node._children.forEach(collapseChildren);
node.children = null;
node.children = undefined;
}
}
export function expandChildren(node: NodeWithId) {
export function expandChildren(node: InternalNode) {
if (node._children) {
node.children = node._children;
node.children.forEach(expandChildren);
node._children = null;
node._children = undefined;
}
}
export function toggleChildren(node: NodeWithId) {
export function toggleChildren(node: InternalNode) {
if (node.children) {
node._children = node.children;
node.children = null;
node.children = undefined;
} else if (node._children) {
node.children = node._children;
node._children = null;
node._children = undefined;
}
return node;
}
export function visit(
parent: NodeWithId,
visitFn: (parent: NodeWithId) => void,
childrenFn: (parent: NodeWithId) => NodeWithId[] | null | undefined
parent: InternalNode,
visitFn: (parent: InternalNode) => void,
childrenFn: (parent: InternalNode) => InternalNode[] | null | undefined
) {
if (!parent) {
return;
@ -50,10 +50,10 @@ export function visit(
}
}
export function getNodeGroupByDepthCount(rootNode: NodeWithId) {
export function getNodeGroupByDepthCount(rootNode: InternalNode) {
const nodeGroupByDepthCount = [1];
const traverseFrom = function traverseFrom(node: NodeWithId, depth = 0) {
const traverseFrom = function traverseFrom(node: InternalNode, depth = 0) {
if (!node.children || node.children.length === 0) {
return 0;
}
@ -73,11 +73,7 @@ export function getNodeGroupByDepthCount(rootNode: NodeWithId) {
return nodeGroupByDepthCount;
}
export function getTooltipString(
node: unknown,
i: number | undefined,
{ indentationSize = 4 }
) {
export function getTooltipString(node: InternalNode, { indentationSize = 4 }) {
if (!is(Object, node)) return '';
const spacer = join('&nbsp;&nbsp;');
@ -89,7 +85,6 @@ export function getTooltipString(
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 as unknown[]).length}`;
if (children && children.length) return `childrenCount: ${children.length}`;
return 'empty';
}

View File

@ -1,2 +1,2 @@
export { tree } from './charts';
export type { InputOptions, NodeWithId, Primitive } from './charts';
export type { HierarchyPointNode, Node, Options, StyleValue } from './charts';

View File

@ -10,45 +10,45 @@ It was created by [@romseguy](https://github.com/romseguy) and merged from [`rom
## Quick usage
```javascript
import d3 from 'd3';
import * as d3 from 'd3';
import { tooltip } from 'd3tooltip';
const DOMNode = document.getElementById('chart');
const root = d3.select(DOMNode);
const vis = root.append('svg');
let options = {
offset: {left: 30, top: 10}
const options = {
offset: { left: 30, top: 10 },
styles: { 'min-width': '50px', 'border-radius': '5px' },
};
vis.selectAll('circle').data(someData).enter()
vis
.selectAll('circle')
.data(someData)
.enter()
.append('circle')
.attr('r', 10)
.call(
d3tooltip(d3, 'tooltipClassName', options)
.text((d, i) => toStringOrHtml(d))
.attr({ 'class': 'anotherClassName' })
.style({ 'min-width': '50px', 'border-radius: 5px' })
d3tooltip('tooltipClassName', {
...options,
text: (d) => toStringOrHtml(d),
})
)
.on({
mouseover(d, i) {
d3.select(this).style({
fill: 'skyblue'
});
},
mouseout(d, i) {
d3.select(this).style({
fill: 'black'
});
}
.on('mouseover', function () {
d3.select(this).style('fill', 'skyblue');
})
.on('mouseout', function () {
d3.select(this).style('fill', 'black');
});
```
## API
| Option | Type | Default | Description |
| -------- | ----------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `root` | DOM.Element | `body` | The tooltip will be added as a child of that element. You can also use a D3 [selection](https://github.com/mbostock/d3/wiki/Selections#d3_select) |
| `left` | Number | `undefined` | Sets the tooltip `x` absolute position instead of the mouse `x` position, relative to the `root` element |
| `top` | Number | `undefined` | Sets the tooltip `y` absolute position instead of the mouse `y` position, relative to the `root` element |
| `offset` | Object | `{left: 0, top: 0}` | Sets the distance, starting from the cursor position, until the tooltip is rendered. **Warning**: only applicable if you don't provide a `left` or `top` option |
| Option | Type | Default | Description |
| -------- | ------------------ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `root` | DOM.Element | `body` | The tooltip will be added as a child of that element. You can also use a D3 [selection](https://github.com/mbostock/d3/wiki/Selections#d3_select). |
| `left` | Number | `undefined` | Sets the tooltip `x` absolute position instead of the mouse `x` position, relative to the `root` element. |
| `top` | Number | `undefined` | Sets the tooltip `y` absolute position instead of the mouse `y` position, relative to the `root` element. |
| `offset` | Object | `{left: 0, top: 0}` | Sets the distance, starting from the cursor position, until the tooltip is rendered. **Warning**: only applicable if you don't provide a `left` or `top` option. |
| `styles` | Object | `{}` | Sets the styles of the tooltip element. |
| `text` | String or Function | `''` | Sets the text of the tooltip. Can be a constant `string` or a function that takes the datum and returns a `string`. |

View File

@ -19,18 +19,16 @@
"main": "lib/cjs/index.js",
"module": "lib/esm/index.js",
"types": "lib/types/index.d.ts",
"unpkg": "lib/umd/d3tooltip.umd.js",
"sideEffects": false,
"repository": {
"type": "git",
"url": "https://github.com/reduxjs/redux-devtools.git"
},
"scripts": {
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types && pnpm run build:umd",
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types",
"build:cjs": "babel src --extensions \".ts\" --out-dir lib/cjs",
"build:esm": "babel src --config-file ./babel.config.esm.json --extensions \".ts\" --out-dir lib/esm",
"build:types": "tsc --emitDeclarationOnly",
"build:umd": "rollup -c",
"clean": "rimraf lib",
"lint": "eslint . --ext .ts",
"type-check": "tsc --noEmit",
@ -38,36 +36,25 @@
"prepublish": "pnpm run type-check && pnpm run lint"
},
"dependencies": {
"@babel/runtime": "^7.20.6",
"ramda": "^0.28.0"
"@babel/runtime": "^7.20.6"
},
"devDependencies": {
"@babel/cli": "^7.19.3",
"@babel/core": "^7.20.5",
"@babel/eslint-parser": "^7.19.1",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.18.6",
"@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-commonjs": "^24.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-terser": "^0.2.1",
"@types/d3": "^3.5.47",
"@types/node": "^18.11.17",
"@types/ramda": "^0.28.20",
"@types/d3": "^4.13.12",
"@typescript-eslint/eslint-plugin": "^5.47.0",
"@typescript-eslint/parser": "^5.47.0",
"d3": "^3.5.17",
"d3": "^4.13.0",
"eslint": "^8.30.0",
"eslint-config-prettier": "^8.5.0",
"rimraf": "^3.0.2",
"rollup": "^3.7.5",
"rollup-plugin-typescript2": "^0.34.1",
"tslib": "^2.4.1",
"typescript": "~4.9.4"
},
"peerDependencies": {
"@types/d3": "^3.5.47",
"d3": "^3.5.17"
"@types/d3": "^4.13.12",
"d3": "^4.13.0"
}
}

View File

@ -1,51 +0,0 @@
import typescript from 'rollup-plugin-typescript2';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';
const config = [
{
input: 'src/index.ts',
output: {
name: 'd3tooltip',
file: 'lib/umd/d3tooltip.js',
format: 'umd',
},
plugins: [
typescript({
tsconfigOverride: { compilerOptions: { declaration: false } },
}),
resolve(),
commonjs(),
babel({
babelHelpers: 'runtime',
extensions: ['.ts'],
plugins: ['@babel/plugin-transform-runtime'],
}),
],
},
{
input: 'src/index.ts',
output: {
name: 'd3tooltip',
file: 'lib/umd/d3tooltip.min.js',
format: 'umd',
},
plugins: [
typescript({
tsconfigOverride: { compilerOptions: { declaration: false } },
}),
resolve(),
commonjs(),
babel({
babelHelpers: 'runtime',
extensions: ['.ts'],
plugins: ['@babel/plugin-transform-runtime'],
}),
terser(),
],
},
];
export default config;

View File

@ -1,75 +1,73 @@
import d3Package, { Primitive, Selection } from 'd3';
import { is } from 'ramda';
import utils from './utils';
const { prependClass, functor } = utils;
import * as d3 from 'd3';
import type { BaseType, ContainerElement, Selection } from 'd3';
interface Options<Datum> {
export type StyleValue = string | number | boolean;
interface Options<
Datum,
RootGElement extends ContainerElement,
RootDatum,
RootPElement extends BaseType,
RootPDatum
> {
left: number | undefined;
top: number | undefined;
offset: {
left: number;
top: number;
};
root: Selection<Datum> | undefined;
root:
| Selection<RootGElement, RootDatum, RootPElement, RootPDatum>
| undefined;
styles: { [key: string]: StyleValue };
text: string | ((datum: Datum) => string);
}
const defaultOptions: Options<unknown> = {
const defaultOptions: Options<
unknown,
ContainerElement,
unknown,
BaseType,
unknown
> = {
left: undefined, // mouseX
top: undefined, // mouseY
offset: { left: 0, top: 0 },
root: undefined,
styles: {},
text: '',
};
interface Tip<Datum> {
(selection: Selection<Datum>): void;
attr: (
this: this,
d:
| string
| {
[key: string]:
| Primitive
| ((datum: Datum, index: number, outerIndex: number) => Primitive);
}
) => this;
style: (
this: this,
d:
| string
| {
[key: string]:
| Primitive
| ((datum: Datum, index: number, outerIndex: number) => Primitive);
}
| undefined
) => this;
text: (
this: this,
d: string | ((datum: Datum, index?: number, outerIndex?: number) => string)
) => this;
}
export function tooltip<Datum>(
d3: typeof d3Package,
export function tooltip<
GElement extends BaseType,
Datum,
PElement extends BaseType,
PDatum,
RootGElement extends ContainerElement,
RootDatum,
RootPElement extends BaseType,
RootPDatum
>(
className = 'tooltip',
options: Partial<Options<Datum>> = {}
): Tip<Datum> {
const { left, top, offset, root } = {
options: Partial<
Options<Datum, RootGElement, RootDatum, RootPElement, RootPDatum>
> = {}
) {
const { left, top, offset, root, styles, text } = {
...defaultOptions,
...options,
} as Options<Datum>;
} as Options<Datum, RootGElement, RootDatum, RootPElement, RootPDatum>;
let attrs = { class: className };
let text: (datum: Datum, index?: number, outerIndex?: number) => string = (
node: Datum
) => '';
let styles = {};
let el: Selection<HTMLDivElement, RootDatum, BaseType, unknown>;
const anchor: Selection<
RootGElement,
RootDatum,
RootPElement | HTMLElement,
RootPDatum
> = root || d3.select<RootGElement, RootDatum>('body');
const rootNode = anchor.node()!;
let el: Selection<Datum>;
const anchor = root || d3.select('body');
const rootNode = anchor.node();
function tip(selection: Selection<Datum>) {
return function tip(selection: Selection<GElement, Datum, PElement, PDatum>) {
selection.on('mouseover.tip', (node) => {
const [mouseX, mouseY] = d3.mouse(rootNode);
const [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top];
@ -78,84 +76,27 @@ export function tooltip<Datum>(
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>;
.attr('class', className)
.style('position', 'absolute')
.style('z-index', 1001)
.style('left', `${x}px`)
.style('top', `${y}px`)
.html(typeof text === 'function' ? () => text(node) : () => text);
for (const [key, value] of Object.entries(styles)) {
el.style(key, value);
}
});
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));
el.style('left', `${x}px`)
.style('top', `${y}px`)
.html(typeof text === 'function' ? () => text(node) : () => text);
});
selection.on('mouseout.tip', () => el.remove());
}
tip.attr = function setAttr(
this: typeof tip,
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(
this: typeof tip,
d:
| string
| {
[key: string]:
| Primitive
| ((datum: Datum, index: number, outerIndex: number) => Primitive);
}
| undefined
) {
if (is(Object, d)) {
styles = {
...styles,
...(d as {
[key: string]:
| Primitive
| ((datum: Datum, index: number, outerIndex: number) => Primitive);
}),
};
}
return this;
};
tip.text = function setText(
this: typeof tip,
d: string | ((datum: Datum, index?: number, outerIndex?: number) => string)
) {
text = functor(d);
return this;
};
return tip;
}

View File

@ -1,20 +0,0 @@
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;
}

View File

@ -1,7 +0,0 @@
import prependClass from './prependClass';
import functor from './functor';
export default {
prependClass,
functor,
};

View File

@ -1,28 +0,0 @@
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

@ -22,18 +22,16 @@
"main": "lib/cjs/index.js",
"module": "lib/esm/index.js",
"types": "lib/types/index.d.ts",
"unpkg": "lib/umd/map2tree.umd.js",
"sideEffects": false,
"repository": {
"type": "git",
"url": "https://github.com/reduxjs/redux-devtools.git"
},
"scripts": {
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types && pnpm run build:umd",
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types",
"build:cjs": "babel src --extensions \".ts\" --out-dir lib/cjs",
"build:esm": "babel src --config-file ./babel.config.esm.json --extensions \".ts\" --out-dir lib/esm",
"build:types": "tsc --emitDeclarationOnly",
"build:umd": "rollup -c",
"clean": "rimraf lib",
"test": "jest",
"lint": "eslint . --ext .ts",
@ -49,16 +47,10 @@
"@babel/cli": "^7.19.3",
"@babel/core": "^7.20.5",
"@babel/eslint-parser": "^7.19.1",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.18.6",
"@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-commonjs": "^24.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-terser": "^0.2.1",
"@types/jest": "^29.2.4",
"@types/lodash": "^4.14.191",
"@types/node": "^18.11.17",
"@typescript-eslint/eslint-plugin": "^5.47.0",
"@typescript-eslint/parser": "^5.47.0",
"eslint": "^8.30.0",
@ -67,10 +59,7 @@
"immutable": "^4.1.0",
"jest": "^29.3.1",
"rimraf": "^3.0.2",
"rollup": "^3.7.5",
"rollup-plugin-typescript2": "^0.34.1",
"ts-jest": "^29.0.3",
"tslib": "^2.4.1",
"typescript": "~4.9.4"
}
}

View File

@ -1,51 +0,0 @@
import typescript from 'rollup-plugin-typescript2';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';
const config = [
{
input: 'src/index.ts',
output: {
name: 'map2tree',
file: 'lib/umd/map2tree.js',
format: 'umd',
},
plugins: [
typescript({
tsconfigOverride: { compilerOptions: { declaration: false } },
}),
resolve(),
commonjs(),
babel({
babelHelpers: 'runtime',
extensions: ['.ts'],
plugins: ['@babel/plugin-transform-runtime'],
}),
],
},
{
input: 'src/index.ts',
output: {
name: 'map2tree',
file: 'lib/umd/map2tree.min.js',
format: 'umd',
},
plugins: [
typescript({
tsconfigOverride: { compilerOptions: { declaration: false } },
}),
resolve(),
commonjs(),
babel({
babelHelpers: 'runtime',
extensions: ['.ts'],
plugins: ['@babel/plugin-transform-runtime'],
}),
terser(),
],
},
];
export default config;

View File

@ -4,7 +4,8 @@ import mapValues from 'lodash/mapValues';
export interface Node {
name: string;
children?: Node[] | null;
children?: this[];
object?: unknown;
value?: unknown;
}
@ -43,7 +44,6 @@ function getNode(tree: Node, key: string): Node | null {
}
export function map2tree(
// eslint-disable-next-line @typescript-eslint/ban-types
root: unknown,
options: { key?: string; pushMethod?: 'push' | 'unshift' } = {},
tree: Node = { name: options.key || 'state', children: [] }

View File

@ -1,14 +1,17 @@
import React, { Component } from 'react';
import { connect, ResolveThunks } from 'react-redux';
import { ChartMonitor } from '@redux-devtools/chart-monitor';
import { NodeWithId } from 'd3-state-visualizer';
import type { HierarchyPointNode, Node } from 'd3-state-visualizer';
import { selectMonitorWithState } from '../../actions';
export function getPath(obj: NodeWithId, inspectedStatePath: string[]) {
export function getPath(
obj: HierarchyPointNode<Node>,
inspectedStatePath: string[]
) {
const parent = obj.parent;
if (!parent) return;
getPath(parent, inspectedStatePath);
let name = obj.name;
let name = obj.data.name;
const item = /.+\[(\d+)]/.exec(name);
if (item) name = item[1];
inspectedStatePath.push(name);
@ -20,7 +23,7 @@ type Props = DispatchProps;
class ChartMonitorWrapper extends Component<Props> {
static update = ChartMonitor.update;
onClickText = (data: NodeWithId) => {
onClickText = (data: HierarchyPointNode<Node>) => {
const inspectedStatePath: string[] = [];
getPath(data, inspectedStatePath);
this.props.selectMonitorWithState('InspectorMonitor', {

View File

@ -1,7 +1,8 @@
import React, { Component, RefCallback } from 'react';
import { connect, ResolveThunks } from 'react-redux';
import { withTheme } from 'styled-components';
import { InputOptions, NodeWithId, tree } from 'd3-state-visualizer';
import { tree } from 'd3-state-visualizer';
import type { HierarchyPointNode, Node, Options } from 'd3-state-visualizer';
import { getPath } from '../ChartMonitorWrapper';
import { updateMonitorState } from '../../../actions';
import { ThemeFromProvider } from '@redux-devtools/ui';
@ -54,12 +55,12 @@ class ChartTab extends Component<Props> {
this.renderChart(props.data as {} | null | undefined);
}
getChartTheme(theme: ThemeFromProvider): Partial<InputOptions> {
getChartTheme(theme: ThemeFromProvider): Partial<Options> {
return {
heightBetweenNodesCoeff: 1,
widthBetweenNodesCoeff: 1.3,
tooltipOptions: {
style: {
styles: {
color: theme.base06,
'background-color': theme.base01,
opacity: '0.9',
@ -69,29 +70,29 @@ class ChartTab extends Component<Props> {
offset: { left: 30, top: 10 },
indentationSize: 2,
},
style: {
chartStyles: {
width: '100%',
height: '100%',
node: {
colors: {
default: theme.base0B,
collapsed: theme.base0B,
parent: theme.base0E,
},
radius: 7,
} as unknown as string,
text: {
colors: {
default: theme.base0D,
hover: theme.base06,
},
} as unknown as string,
},
nodeStyleOptions: {
colors: {
default: theme.base0B,
collapsed: theme.base0B,
parent: theme.base0E,
},
radius: 7,
},
textStyleOptions: {
colors: {
default: theme.base0D,
hover: theme.base06,
},
},
onClickText: this.onClickText,
};
}
onClickText = (data: NodeWithId) => {
onClickText = (data: HierarchyPointNode<Node>) => {
const inspectedStatePath: string[] = [];
getPath(data, inspectedStatePath);
this.props.updateMonitorState({

View File

@ -47,16 +47,18 @@ Consult the [`DockMonitor` README](https://github.com/reduxjs/redux-devtools/tre
You can read the React component [propTypes](https://github.com/reduxjs/redux-devtools/blob/master/packages/redux-devtools-chart-monitor/src/Chart.js#L11) in addition to the details below:
| Name | Description |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultIsVisible` | By default, set to `true`. |
| `transitionDuration` | By default, set to `750`, in milliseconds. |
| `heightBetweenNodesCoeff` | By default, set to `1`. |
| `widthBetweenNodesCoeff` | By default, set to `1.3`. |
| `isSorted` | By default, set to `false`. |
| `style` | {<br>&nbsp;&nbsp;width: '100%', height: '100%', // i.e fullscreen for [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor)<br>&nbsp;&nbsp;text: {<br>&nbsp;&nbsp;&nbsp;&nbsp;colors: {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'default': `theme.base0D`,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hover: `theme.base06`<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;},<br>&nbsp;&nbsp;node: {<br>&nbsp;&nbsp;&nbsp;&nbsp;colors: {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'default': `theme.base0B`,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;collapsed: `theme.base0B`,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parent: `theme.base0E`<br>&nbsp;&nbsp;&nbsp;&nbsp;},<br>&nbsp;&nbsp;&nbsp;&nbsp;radius: 7<br>&nbsp;&nbsp;}<br>} |
| `onClickText` | Function called with a reference to the clicked node as first argument when clicking on the text next to a node. |
| `tooltipOptions` | {<br>&nbsp;&nbsp;disabled: false,<br>&nbsp;&nbsp;indentationSize: 2,<br>&nbsp;&nbsp;style: {<br>&nbsp;&nbsp;&nbsp;&nbsp;'background-color': `theme.base06`,<br>&nbsp;&nbsp;&nbsp;&nbsp;'opacity': '0.7',<br>&nbsp;&nbsp;&nbsp;&nbsp;'border-radius': '5px',<br>&nbsp;&nbsp;&nbsp;&nbsp;'padding': '5px'<br>&nbsp;&nbsp;}<br>}<br>[More info](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip#api). |
| Name | Description |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `defaultIsVisible` | By default, set to `true`. |
| `transitionDuration` | By default, set to `750`, in milliseconds. |
| `heightBetweenNodesCoeff` | By default, set to `1`. |
| `widthBetweenNodesCoeff` | By default, set to `1.3`. |
| `isSorted` | By default, set to `false`. |
| `chartStyles` | {<br>&nbsp;&nbsp;width: '100%', height: '100%', // i.e fullscreen for [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor)<br>} |
| `textStyleOptions` | {<br>&nbsp;&nbsp;colors: {<br>&nbsp;&nbsp;&nbsp;&nbsp;default: `theme.base0D`,<br>&nbsp;&nbsp;&nbsp;&nbsp;hover: `theme.base06`,<br>&nbsp;&nbsp;},<br>} |
| `nodeStyleOptions` | {<br>&nbsp;&nbsp;colors: {<br>&nbsp;&nbsp;&nbsp;&nbsp;default: `theme.base0B`,<br>&nbsp;&nbsp;&nbsp;&nbsp;collapsed: `theme.base0B`,<br>&nbsp;&nbsp;&nbsp;&nbsp;parent: `theme.base0E`,<br>&nbsp;&nbsp;},<br>&nbsp;&nbsp;radius: 7,<br>} |
| `onClickText` | Function called with a reference to the clicked node as first argument when clicking on the text next to a node. |
| `tooltipOptions` | {<br>&nbsp;&nbsp;disabled: false,<br>&nbsp;&nbsp;indentationSize: 2,<br>&nbsp;&nbsp;styles: {<br>&nbsp;&nbsp;&nbsp;&nbsp;'background-color': `theme.base06`,<br>&nbsp;&nbsp;&nbsp;&nbsp;'opacity': '0.7',<br>&nbsp;&nbsp;&nbsp;&nbsp;'border-radius': '5px',<br>&nbsp;&nbsp;&nbsp;&nbsp;'padding': '5px',<br>&nbsp;&nbsp;},<br>}<br>[More info](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip#api). |
#### Redux DevTools props

View File

@ -40,11 +40,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.6",
"@types/prop-types": "^15.7.5",
"@types/redux-devtools-themes": "^1.0.0",
"d3-state-visualizer": "^1.6.0",
"deepmerge": "^4.2.2",
"prop-types": "^15.8.1",
"redux-devtools-themes": "^1.0.0"
},
"devDependencies": {

View File

@ -1,6 +1,6 @@
import React, { Component, createRef } from 'react';
import PropTypes from 'prop-types';
import { tree, NodeWithId, Primitive } from 'd3-state-visualizer';
import { tree } from 'd3-state-visualizer';
import type { Options } from 'd3-state-visualizer';
import { Action, Dispatch } from 'redux';
import { LiftedAction, LiftedState } from '@redux-devtools/core';
import * as themes from 'redux-devtools-themes';
@ -12,7 +12,8 @@ const wrapperStyle = {
};
export interface Props<S, A extends Action<unknown>>
extends LiftedState<S, A, ChartMonitorState> {
extends LiftedState<S, A, ChartMonitorState>,
Options {
dispatch: Dispatch<LiftedAction<S, A, ChartMonitorState>>;
preserveScrollTop: boolean;
select: (state: S) => unknown;
@ -20,76 +21,10 @@ export interface Props<S, A extends Action<unknown>>
invertTheme: boolean;
state: S | null;
isSorted: boolean;
heightBetweenNodesCoeff: number;
widthBetweenNodesCoeff: number;
onClickText: (datum: NodeWithId) => void;
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 = {
state: PropTypes.object,
rootKeyName: PropTypes.string,
pushMethod: PropTypes.oneOf(['push', 'unshift']),
tree: PropTypes.shape({
name: PropTypes.string,
children: PropTypes.array,
}),
id: PropTypes.string,
style: PropTypes.shape({
node: PropTypes.shape({
colors: PropTypes.shape({
default: PropTypes.string,
parent: PropTypes.string,
collapsed: PropTypes.string,
}),
radius: PropTypes.number,
}),
text: PropTypes.shape({
colors: PropTypes.shape({
default: PropTypes.string,
hover: PropTypes.string,
}),
}),
link: PropTypes.object,
}),
size: PropTypes.number,
aspectRatio: PropTypes.number,
margin: PropTypes.shape({
top: PropTypes.number,
right: PropTypes.number,
bottom: PropTypes.number,
left: PropTypes.number,
}),
isSorted: PropTypes.bool,
heightBetweenNodesCoeff: PropTypes.number,
widthBetweenNodesCoeff: PropTypes.number,
transitionDuration: PropTypes.number,
onClickText: PropTypes.func,
tooltipOptions: PropTypes.shape({
disabled: PropTypes.bool,
left: PropTypes.number,
top: PropTypes.number,
offset: PropTypes.shape({
left: PropTypes.number,
top: PropTypes.number,
}),
indentationSize: PropTypes.number,
style: PropTypes.object,
}),
};
divRef = createRef<HTMLDivElement>();
// eslint-disable-next-line @typescript-eslint/ban-types
renderChart?: (state?: {} | null | undefined) => void;

View File

@ -1,5 +1,4 @@
import React, { CSSProperties, PureComponent } from 'react';
import PropTypes from 'prop-types';
import * as themes from 'redux-devtools-themes';
import {
ActionCreators,
@ -8,7 +7,7 @@ import {
} from '@redux-devtools/core';
import deepmerge from 'deepmerge';
import { Action, Dispatch } from 'redux';
import { NodeWithId, Primitive } from 'd3-state-visualizer';
import type { Options } from 'd3-state-visualizer';
import reducer, { ChartMonitorState } from './reducers';
import Chart, { Props } from './Chart';
@ -41,37 +40,14 @@ function invertColors(theme: themes.Base16Theme) {
}
export interface ChartMonitorProps<S, A extends Action<unknown>>
extends LiftedState<S, A, ChartMonitorState> {
extends LiftedState<S, A, ChartMonitorState>,
Options {
dispatch: Dispatch<LiftedAction<S, A, ChartMonitorState>>;
preserveScrollTop: boolean;
select: (state: S) => unknown;
theme: keyof typeof themes | themes.Base16Theme;
invertTheme: boolean;
state: S | null;
isSorted: boolean;
heightBetweenNodesCoeff: number;
widthBetweenNodesCoeff: number;
onClickText: (datum: NodeWithId) => void;
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;
}
@ -80,23 +56,6 @@ class ChartMonitor<S, A extends Action<unknown>> extends PureComponent<
> {
static update = reducer;
static propTypes = {
dispatch: PropTypes.func,
computedStates: PropTypes.array,
currentStateIndex: PropTypes.number,
actionsById: PropTypes.object,
stagedActionIds: PropTypes.array,
skippedActionIds: PropTypes.array,
monitorState: PropTypes.shape({
initialScrollTop: PropTypes.number,
}),
preserveScrollTop: PropTypes.bool,
select: PropTypes.func.isRequired,
theme: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
invertTheme: PropTypes.bool,
};
static defaultProps = {
select: (state: unknown) => state,
theme: 'nicinabox',
@ -140,45 +99,10 @@ class ChartMonitor<S, A extends Action<unknown>> extends PureComponent<
return invertTheme ? invertColors(themes.nicinabox) : themes.nicinabox;
}
getChartStyle() {
const theme = this.getTheme();
return {
width: '100%',
height: '100%',
node: {
colors: {
default: theme.base0B,
collapsed: theme.base0B,
parent: theme.base0E,
},
radius: 7,
},
text: {
colors: {
default: theme.base0D,
hover: theme.base06,
},
},
};
}
getChartOptions(props = this.props): Props<S, A> {
const { computedStates } = props;
const theme = this.getTheme();
const tooltipOptions = {
disabled: false,
offset: { left: 30, top: 10 },
indentationSize: 2,
style: {
'background-color': theme.base06,
opacity: '0.7',
'border-radius': '5px',
padding: '5px',
},
};
const defaultOptions = {
state: computedStates.length
? computedStates[props.currentStateIndex].state
@ -186,10 +110,35 @@ class ChartMonitor<S, A extends Action<unknown>> extends PureComponent<
isSorted: false,
heightBetweenNodesCoeff: 1,
widthBetweenNodesCoeff: 1.3,
tooltipOptions,
style: this.getChartStyle() as unknown as
| { [key: string]: Primitive }
| undefined,
tooltipOptions: {
disabled: false,
offset: { left: 30, top: 10 },
indentationSize: 2,
styles: {
'background-color': theme.base06,
opacity: '0.7',
'border-radius': '5px',
padding: '5px',
},
},
chartStyles: {
width: '100%',
height: '100%',
},
nodeStyleOptions: {
colors: {
default: theme.base0B,
collapsed: theme.base0B,
parent: theme.base0E,
},
radius: 7,
},
textStyleOptions: {
colors: {
default: theme.base0D,
hover: theme.base06,
},
},
};
return deepmerge(defaultOptions, props);
@ -198,10 +147,9 @@ class ChartMonitor<S, A extends Action<unknown>> extends PureComponent<
render() {
const theme = this.getTheme();
const ChartAsAny = Chart as any;
return (
<div style={{ ...styles.container, backgroundColor: theme.base07 }}>
<ChartAsAny {...this.getChartOptions()} />
<Chart {...this.getChartOptions()} />
</div>
);
}

View File

@ -1,39 +0,0 @@
import typescript from 'rollup-plugin-typescript2';
import babel from '@rollup/plugin-babel';
import nodePolyfills from 'rollup-plugin-node-polyfills';
const config = [
{
input: 'src/StackTraceTab.tsx',
output: [
{
file: 'dist/redux-devtools-inspector-monitor-trace-tab.cjs.js',
format: 'cjs',
},
{
file: 'dist/redux-devtools-inspector-monitor-trace-tab.esm.js',
format: 'esm',
},
],
plugins: [
typescript(),
babel({
babelHelpers: 'runtime',
extensions: ['.ts', '.tsx'],
plugins: ['@babel/plugin-transform-runtime'],
}),
nodePolyfills(),
],
external: [
/@babel\/runtime/,
'react',
'redux-devtools-themes',
'source-map',
'@babel/code-frame',
'anser',
'html-entities',
],
},
];
export default config;

View File

@ -43,12 +43,10 @@
"@babel/cli": "^7.19.3",
"@babel/core": "^7.20.5",
"@babel/eslint-parser": "^7.19.1",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@redux-devtools/core": "^3.13.1",
"@rollup/plugin-babel": "^6.0.3",
"@types/node": "^18.11.17",
"@types/react": "^18.0.26",
"@typescript-eslint/eslint-plugin": "^5.47.0",
@ -60,9 +58,6 @@
"react": "^18.2.0",
"redux": "^4.2.0",
"rimraf": "^3.0.2",
"rollup": "^3.7.5",
"rollup-plugin-typescript2": "^0.34.1",
"tslib": "^2.4.1",
"typescript": "~4.9.4"
},
"peerDependencies": {

View File

@ -175,20 +175,14 @@ importers:
'@babel/cli': ^7.19.3
'@babel/core': ^7.20.5
'@babel/eslint-parser': ^7.19.1
'@babel/plugin-transform-runtime': ^7.19.6
'@babel/preset-env': ^7.20.2
'@babel/preset-typescript': ^7.18.6
'@babel/runtime': ^7.20.6
'@rollup/plugin-babel': ^6.0.3
'@rollup/plugin-commonjs': ^24.0.0
'@rollup/plugin-node-resolve': ^15.0.1
'@rollup/plugin-terser': ^0.2.1
'@types/d3': ^3.5.47
'@types/node': ^18.11.17
'@types/d3': ^4.13.12
'@types/ramda': ^0.28.20
'@typescript-eslint/eslint-plugin': ^5.47.0
'@typescript-eslint/parser': ^5.47.0
d3: ^3.5.17
d3: ^4.13.0
d3tooltip: ^2.1.0
deepmerge: ^4.2.2
eslint: ^8.30.0
@ -196,14 +190,11 @@ importers:
map2tree: ^2.1.0
ramda: ^0.28.0
rimraf: ^3.0.2
rollup: ^3.7.5
rollup-plugin-typescript2: ^0.34.1
tslib: ^2.4.1
typescript: ~4.9.4
dependencies:
'@babel/runtime': 7.20.6
'@types/d3': 3.5.47
d3: 3.5.17
'@types/d3': 4.13.12
d3: 4.13.0
d3tooltip: link:../d3tooltip
deepmerge: 4.2.2
map2tree: link:../map2tree
@ -212,23 +203,14 @@ importers:
'@babel/cli': 7.19.3_@babel+core@7.20.5
'@babel/core': 7.20.5
'@babel/eslint-parser': 7.19.1_ak4stjm4k2uvd2drmeegtfb5ly
'@babel/plugin-transform-runtime': 7.19.6_@babel+core@7.20.5
'@babel/preset-env': 7.20.2_@babel+core@7.20.5
'@babel/preset-typescript': 7.18.6_@babel+core@7.20.5
'@rollup/plugin-babel': 6.0.3_zrxplyvfi52whpdwd6wkjjeo5q
'@rollup/plugin-commonjs': 24.0.0_rollup@3.7.5
'@rollup/plugin-node-resolve': 15.0.1_rollup@3.7.5
'@rollup/plugin-terser': 0.2.1_rollup@3.7.5
'@types/node': 18.11.17
'@types/ramda': 0.28.20
'@typescript-eslint/eslint-plugin': 5.47.0_ncmi6noazr3nzas7jxykisekym
'@typescript-eslint/parser': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa
eslint: 8.30.0
eslint-config-prettier: 8.5.0_eslint@8.30.0
rimraf: 3.0.2
rollup: 3.7.5
rollup-plugin-typescript2: 0.34.1_oj4jlwi3mkekxo3vucumcwebnq
tslib: 2.4.1
typescript: 4.9.4
packages/d3-state-visualizer/examples/tree:
@ -279,54 +261,32 @@ importers:
'@babel/cli': ^7.19.3
'@babel/core': ^7.20.5
'@babel/eslint-parser': ^7.19.1
'@babel/plugin-transform-runtime': ^7.19.6
'@babel/preset-env': ^7.20.2
'@babel/preset-typescript': ^7.18.6
'@babel/runtime': ^7.20.6
'@rollup/plugin-babel': ^6.0.3
'@rollup/plugin-commonjs': ^24.0.0
'@rollup/plugin-node-resolve': ^15.0.1
'@rollup/plugin-terser': ^0.2.1
'@types/d3': ^3.5.47
'@types/node': ^18.11.17
'@types/ramda': ^0.28.20
'@types/d3': ^4.13.12
'@typescript-eslint/eslint-plugin': ^5.47.0
'@typescript-eslint/parser': ^5.47.0
d3: ^3.5.17
d3: ^4.13.0
eslint: ^8.30.0
eslint-config-prettier: ^8.5.0
ramda: ^0.28.0
rimraf: ^3.0.2
rollup: ^3.7.5
rollup-plugin-typescript2: ^0.34.1
tslib: ^2.4.1
typescript: ~4.9.4
dependencies:
'@babel/runtime': 7.20.6
ramda: 0.28.0
devDependencies:
'@babel/cli': 7.19.3_@babel+core@7.20.5
'@babel/core': 7.20.5
'@babel/eslint-parser': 7.19.1_ak4stjm4k2uvd2drmeegtfb5ly
'@babel/plugin-transform-runtime': 7.19.6_@babel+core@7.20.5
'@babel/preset-env': 7.20.2_@babel+core@7.20.5
'@babel/preset-typescript': 7.18.6_@babel+core@7.20.5
'@rollup/plugin-babel': 6.0.3_zrxplyvfi52whpdwd6wkjjeo5q
'@rollup/plugin-commonjs': 24.0.0_rollup@3.7.5
'@rollup/plugin-node-resolve': 15.0.1_rollup@3.7.5
'@rollup/plugin-terser': 0.2.1_rollup@3.7.5
'@types/d3': 3.5.47
'@types/node': 18.11.17
'@types/ramda': 0.28.20
'@types/d3': 4.13.12
'@typescript-eslint/eslint-plugin': 5.47.0_ncmi6noazr3nzas7jxykisekym
'@typescript-eslint/parser': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa
d3: 3.5.17
d3: 4.13.0
eslint: 8.30.0
eslint-config-prettier: 8.5.0_eslint@8.30.0
rimraf: 3.0.2
rollup: 3.7.5
rollup-plugin-typescript2: 0.34.1_oj4jlwi3mkekxo3vucumcwebnq
tslib: 2.4.1
typescript: 4.9.4
packages/map2tree:
@ -334,17 +294,11 @@ importers:
'@babel/cli': ^7.19.3
'@babel/core': ^7.20.5
'@babel/eslint-parser': ^7.19.1
'@babel/plugin-transform-runtime': ^7.19.6
'@babel/preset-env': ^7.20.2
'@babel/preset-typescript': ^7.18.6
'@babel/runtime': ^7.20.6
'@rollup/plugin-babel': ^6.0.3
'@rollup/plugin-commonjs': ^24.0.0
'@rollup/plugin-node-resolve': ^15.0.1
'@rollup/plugin-terser': ^0.2.1
'@types/jest': ^29.2.4
'@types/lodash': ^4.14.191
'@types/node': ^18.11.17
'@typescript-eslint/eslint-plugin': ^5.47.0
'@typescript-eslint/parser': ^5.47.0
eslint: ^8.30.0
@ -354,10 +308,7 @@ importers:
jest: ^29.3.1
lodash: ^4.17.21
rimraf: ^3.0.2
rollup: ^3.7.5
rollup-plugin-typescript2: ^0.34.1
ts-jest: ^29.0.3
tslib: ^2.4.1
typescript: ~4.9.4
dependencies:
'@babel/runtime': 7.20.6
@ -366,28 +317,19 @@ importers:
'@babel/cli': 7.19.3_@babel+core@7.20.5
'@babel/core': 7.20.5
'@babel/eslint-parser': 7.19.1_ak4stjm4k2uvd2drmeegtfb5ly
'@babel/plugin-transform-runtime': 7.19.6_@babel+core@7.20.5
'@babel/preset-env': 7.20.2_@babel+core@7.20.5
'@babel/preset-typescript': 7.18.6_@babel+core@7.20.5
'@rollup/plugin-babel': 6.0.3_zrxplyvfi52whpdwd6wkjjeo5q
'@rollup/plugin-commonjs': 24.0.0_rollup@3.7.5
'@rollup/plugin-node-resolve': 15.0.1_rollup@3.7.5
'@rollup/plugin-terser': 0.2.1_rollup@3.7.5
'@types/jest': 29.2.4
'@types/lodash': 4.14.191
'@types/node': 18.11.17
'@typescript-eslint/eslint-plugin': 5.47.0_ncmi6noazr3nzas7jxykisekym
'@typescript-eslint/parser': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa
eslint: 8.30.0
eslint-config-prettier: 8.5.0_eslint@8.30.0
eslint-plugin-jest: 27.1.7_ynswt5pvagzyqki5w7w75b3qvm
immutable: 4.1.0
jest: 29.3.1_@types+node@18.11.17
jest: 29.3.1
rimraf: 3.0.2
rollup: 3.7.5
rollup-plugin-typescript2: 0.34.1_oj4jlwi3mkekxo3vucumcwebnq
ts-jest: 29.0.3_orsjflytm5zjweotzi5qijesea
tslib: 2.4.1
typescript: 4.9.4
packages/react-base16-styling:
@ -940,7 +882,6 @@ importers:
'@babel/preset-typescript': ^7.18.6
'@babel/runtime': ^7.20.6
'@redux-devtools/core': ^3.13.1
'@types/prop-types': ^15.7.5
'@types/react': ^18.0.26
'@types/redux-devtools-themes': ^1.0.0
'@typescript-eslint/eslint-plugin': ^5.47.0
@ -951,7 +892,6 @@ importers:
eslint-config-prettier: ^8.5.0
eslint-plugin-react: ^7.31.11
eslint-plugin-react-hooks: ^4.6.0
prop-types: ^15.8.1
react: ^18.2.0
redux: ^4.2.0
redux-devtools-themes: ^1.0.0
@ -959,11 +899,9 @@ importers:
typescript: ~4.9.4
dependencies:
'@babel/runtime': 7.20.6
'@types/prop-types': 15.7.5
'@types/redux-devtools-themes': 1.0.0
d3-state-visualizer: link:../d3-state-visualizer
deepmerge: 4.2.2
prop-types: 15.8.1
redux-devtools-themes: 1.0.0
devDependencies:
'@babel/cli': 7.19.3_@babel+core@7.20.5
@ -2025,14 +1963,12 @@ importers:
'@babel/cli': ^7.19.3
'@babel/core': ^7.20.5
'@babel/eslint-parser': ^7.19.1
'@babel/plugin-transform-runtime': ^7.19.6
'@babel/preset-env': ^7.20.2
'@babel/preset-react': ^7.18.6
'@babel/preset-typescript': ^7.18.6
'@babel/runtime': ^7.20.6
'@redux-devtools/core': ^3.13.1
'@redux-devtools/ui': ^1.3.0
'@rollup/plugin-babel': ^6.0.3
'@types/node': ^18.11.17
'@types/prop-types': ^15.7.5
'@types/react': ^18.0.26
@ -2048,9 +1984,6 @@ importers:
redux: ^4.2.0
redux-devtools-themes: ^1.0.0
rimraf: ^3.0.2
rollup: ^3.7.5
rollup-plugin-typescript2: ^0.34.1
tslib: ^2.4.1
typescript: ~4.9.4
dependencies:
'@babel/runtime': 7.20.6
@ -2063,12 +1996,10 @@ importers:
'@babel/cli': 7.19.3_@babel+core@7.20.5
'@babel/core': 7.20.5
'@babel/eslint-parser': 7.19.1_ak4stjm4k2uvd2drmeegtfb5ly
'@babel/plugin-transform-runtime': 7.19.6_@babel+core@7.20.5
'@babel/preset-env': 7.20.2_@babel+core@7.20.5
'@babel/preset-react': 7.18.6_@babel+core@7.20.5
'@babel/preset-typescript': 7.18.6_@babel+core@7.20.5
'@redux-devtools/core': link:../redux-devtools
'@rollup/plugin-babel': 6.0.3_zrxplyvfi52whpdwd6wkjjeo5q
'@types/node': 18.11.17
'@types/react': 18.0.26
'@typescript-eslint/eslint-plugin': 5.47.0_ncmi6noazr3nzas7jxykisekym
@ -2080,9 +2011,6 @@ importers:
react: 18.2.0
redux: 4.2.0
rimraf: 3.0.2
rollup: 3.7.5
rollup-plugin-typescript2: 0.34.1_oj4jlwi3mkekxo3vucumcwebnq
tslib: 2.4.1
typescript: 4.9.4
packages/redux-devtools-slider-monitor/examples/todomvc:
@ -8249,8 +8177,150 @@ packages:
'@types/node': 18.11.17
dev: true
/@types/d3/3.5.47:
resolution: {integrity: sha512-VkWIQoZXLFdcBGe5pdBKJmTU3fmpXvo/KV6ixvTzOMl1yJ2hbTXpfvsziag0kcaerPDwas2T0vxojwQG3YwivQ==}
/@types/d3-array/1.2.9:
resolution: {integrity: sha512-E/7RgPr2ylT5dWG0CswMi9NpFcjIEDqLcUSBgNHe/EMahfqYaTx4zhcggG3khqoEB/leY4Vl6nTSbwLUPjXceA==}
/@types/d3-axis/1.0.16:
resolution: {integrity: sha512-p7085weOmo4W+DzlRRVC/7OI/jugaKbVa6WMQGCQscaMylcbuaVEGk7abJLNyGVFLeCBNrHTdDiqRGnzvL0nXQ==}
dependencies:
'@types/d3-selection': 1.4.3
/@types/d3-brush/1.1.5:
resolution: {integrity: sha512-4zGkBafJf5zCsBtLtvDj/pNMo5X9+Ii/1hUz0GvQ+wEwelUBm2AbIDAzJnp2hLDFF307o0fhxmmocHclhXC+tw==}
dependencies:
'@types/d3-selection': 1.4.3
/@types/d3-chord/1.0.11:
resolution: {integrity: sha512-0DdfJ//bxyW3G9Nefwq/LDgazSKNN8NU0lBT3Cza6uVuInC2awMNsAcv1oKyRFLn9z7kXClH5XjwpveZjuz2eg==}
/@types/d3-collection/1.0.10:
resolution: {integrity: sha512-54Fdv8u5JbuXymtmXm2SYzi1x/Svt+jfWBU5junkhrCewL92VjqtCBDn97coBRVwVFmYNnVTNDyV8gQyPYfm+A==}
/@types/d3-color/1.4.2:
resolution: {integrity: sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA==}
/@types/d3-dispatch/1.0.9:
resolution: {integrity: sha512-zJ44YgjqALmyps+II7b1mZLhrtfV/FOxw9owT87mrweGWcg+WK5oiJX2M3SYJ0XUAExBduarysfgbR11YxzojQ==}
/@types/d3-drag/1.2.5:
resolution: {integrity: sha512-7NeTnfolst1Js3Vs7myctBkmJWu6DMI3k597AaHUX98saHjHWJ6vouT83UrpE+xfbSceHV+8A0JgxuwgqgmqWw==}
dependencies:
'@types/d3-selection': 1.4.3
/@types/d3-dsv/1.2.1:
resolution: {integrity: sha512-LLmJmjiqp/fTNEdij5bIwUJ6P6TVNk5hKM9/uk5RPO2YNgEu9XvKO0dJ7Iqd3psEdmZN1m7gB1bOsjr4HmO2BA==}
/@types/d3-ease/1.0.11:
resolution: {integrity: sha512-wUigPL0kleGZ9u3RhzBP07lxxkMcUjL5IODP42mN/05UNL+JJCDnpEPpFbJiPvLcTeRKGIRpBBJyP/1BNwYsVA==}
/@types/d3-force/1.2.4:
resolution: {integrity: sha512-fkorLTKvt6AQbFBQwn4aq7h9rJ4c7ZVcPMGB8X6eFFveAyMZcv7t7m6wgF4Eg93rkPgPORU7sAho1QSHNcZu6w==}
/@types/d3-format/1.4.2:
resolution: {integrity: sha512-WeGCHAs7PHdZYq6lwl/+jsl+Nfc1J2W1kNcMeIMYzQsT6mtBDBgtJ/rcdjZ0k0rVIvqEZqhhuD5TK/v3P2gFHQ==}
/@types/d3-geo/1.12.3:
resolution: {integrity: sha512-yZbPb7/5DyL/pXkeOmZ7L5ySpuGr4H48t1cuALjnJy5sXQqmSSAYBiwa6Ya/XpWKX2rJqGDDubmh3nOaopOpeA==}
dependencies:
'@types/geojson': 7946.0.10
/@types/d3-hierarchy/1.1.8:
resolution: {integrity: sha512-AbStKxNyWiMDQPGDguG2Kuhlq1Sv539pZSxYbx4UZeYkutpPwXCcgyiRrlV4YH64nIOsKx7XVnOMy9O7rJsXkg==}
/@types/d3-interpolate/1.4.2:
resolution: {integrity: sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg==}
dependencies:
'@types/d3-color': 1.4.2
/@types/d3-path/1.0.9:
resolution: {integrity: sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==}
/@types/d3-polygon/1.0.8:
resolution: {integrity: sha512-1TOJPXCBJC9V3+K3tGbTqD/CsqLyv/YkTXAcwdsZzxqw5cvpdnCuDl42M4Dvi8XzMxZNCT9pL4ibrK2n4VmAcw==}
/@types/d3-quadtree/1.0.9:
resolution: {integrity: sha512-5E0OJJn2QVavITFEc1AQlI8gLcIoDZcTKOD3feKFckQVmFV4CXhqRFt83tYNVNIN4ZzRkjlAMavJa1ldMhf5rA==}
/@types/d3-queue/3.0.8:
resolution: {integrity: sha512-1FWOiI/MYwS5Z1Sa9EvS1Xet3isiVIIX5ozD6iGnwHonGcqL+RcC1eThXN5VfDmAiYt9Me9EWNEv/9J9k9RIKQ==}
/@types/d3-random/1.1.3:
resolution: {integrity: sha512-XXR+ZbFCoOd4peXSMYJzwk0/elP37WWAzS/DG+90eilzVbUSsgKhBcWqylGWe+lA2ubgr7afWAOBaBxRgMUrBQ==}
/@types/d3-request/1.0.6:
resolution: {integrity: sha512-4nRKDUBg3EBx8VowpMvM3NAVMiMMI1qFUOYv3OJsclGjHX6xjtu09nsWhRQ0fvSUla3MEjb5Ch4IeaYarMEi1w==}
dependencies:
'@types/d3-dsv': 1.2.1
/@types/d3-scale/1.0.17:
resolution: {integrity: sha512-baIP5/gw+PS8Axs1lfZCeIjcOXen/jxQmgFEjbYThwaj2drvivOIrJMh2Ig4MeenrogCH6zkhiOxCPRkvN1scA==}
dependencies:
'@types/d3-time': 1.1.1
/@types/d3-selection/1.4.3:
resolution: {integrity: sha512-GjKQWVZO6Sa96HiKO6R93VBE8DUW+DDkFpIMf9vpY5S78qZTlRRSNUsHr/afDpF7TvLDV7VxrUFOWW7vdIlYkA==}
/@types/d3-shape/1.3.8:
resolution: {integrity: sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==}
dependencies:
'@types/d3-path': 1.0.9
/@types/d3-time-format/2.3.1:
resolution: {integrity: sha512-fck0Z9RGfIQn3GJIEKVrp15h9m6Vlg0d5XXeiE/6+CQiBmMDZxfR21XtjEPuDeg7gC3bBM0SdieA5XF3GW1wKA==}
/@types/d3-time/1.1.1:
resolution: {integrity: sha512-ULX7LoqXTCYtM+tLYOaeAJK7IwCT+4Gxlm2MaH0ErKLi07R5lh8NHCAyWcDkCCmx1AfRcBEV6H9QE9R25uP7jw==}
/@types/d3-timer/1.0.10:
resolution: {integrity: sha512-ZnAbquVqy+4ZjdW0cY6URp+qF/AzTVNda2jYyOzpR2cPT35FTXl78s15Bomph9+ckOiI1TtkljnWkwbIGAb6rg==}
/@types/d3-transition/1.3.2:
resolution: {integrity: sha512-J+a3SuF/E7wXbOSN19p8ZieQSFIm5hU2Egqtndbc54LXaAEOpLfDx4sBu/PKAKzHOdgKK1wkMhINKqNh4aoZAg==}
dependencies:
'@types/d3-selection': 1.4.3
/@types/d3-voronoi/1.1.9:
resolution: {integrity: sha512-DExNQkaHd1F3dFPvGA/Aw2NGyjMln6E9QzsiqOcBgnE+VInYnFBHBBySbZQts6z6xD+5jTfKCP7M4OqMyVjdwQ==}
/@types/d3-zoom/1.8.3:
resolution: {integrity: sha512-3kHkL6sPiDdbfGhzlp5gIHyu3kULhtnHTTAl3UBZVtWB1PzcLL8vdmz5mTx7plLiUqOA2Y+yT2GKjt/TdA2p7Q==}
dependencies:
'@types/d3-interpolate': 1.4.2
'@types/d3-selection': 1.4.3
/@types/d3/4.13.12:
resolution: {integrity: sha512-/bbFtkOBc04gGGN8N9rMG5ps3T0eIj5I8bnYe9iIyeM5qoOrydPCbFYlEPUnj2h9ibc2i+QZfDam9jY5XTrTxQ==}
dependencies:
'@types/d3-array': 1.2.9
'@types/d3-axis': 1.0.16
'@types/d3-brush': 1.1.5
'@types/d3-chord': 1.0.11
'@types/d3-collection': 1.0.10
'@types/d3-color': 1.4.2
'@types/d3-dispatch': 1.0.9
'@types/d3-drag': 1.2.5
'@types/d3-dsv': 1.2.1
'@types/d3-ease': 1.0.11
'@types/d3-force': 1.2.4
'@types/d3-format': 1.4.2
'@types/d3-geo': 1.12.3
'@types/d3-hierarchy': 1.1.8
'@types/d3-interpolate': 1.4.2
'@types/d3-path': 1.0.9
'@types/d3-polygon': 1.0.8
'@types/d3-quadtree': 1.0.9
'@types/d3-queue': 3.0.8
'@types/d3-random': 1.1.3
'@types/d3-request': 1.0.6
'@types/d3-scale': 1.0.17
'@types/d3-selection': 1.4.3
'@types/d3-shape': 1.3.8
'@types/d3-time': 1.1.1
'@types/d3-time-format': 2.3.1
'@types/d3-timer': 1.0.10
'@types/d3-transition': 1.3.2
'@types/d3-voronoi': 1.1.9
'@types/d3-zoom': 1.8.3
/@types/dateformat/3.0.1:
resolution: {integrity: sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g==}
@ -8323,6 +8393,9 @@ packages:
/@types/filewriter/0.0.29:
resolution: {integrity: sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ==}
/@types/geojson/7946.0.10:
resolution: {integrity: sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==}
/@types/get-params/0.1.0:
resolution: {integrity: sha512-dlrC7vGuNvUCD4UXLTPqNSdSFHDa+n6wHmyKWP2OJXwtgY1A3Lttn5Dx7gmo00fg/xuuLILTuzI/1isDV/1V2Q==}
dev: false
@ -11844,8 +11917,185 @@ packages:
resolution: {integrity: sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==}
dev: true
/d3/3.5.17:
resolution: {integrity: sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==}
/d3-array/1.2.1:
resolution: {integrity: sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==}
/d3-axis/1.0.8:
resolution: {integrity: sha512-K0djTb26iQ6AsuD2d6Ka08wBHf4V30awIxV4XFuB/iLzYtTqqJlE/nIN0DBJJCX7lbOqbt2/oeX3r+sU5k2veg==}
/d3-brush/1.0.4:
resolution: {integrity: sha512-nUFueDzOlvwFvuOBynGSyJM7Wt1H9fKgJeoWFSg3ScS4c7FJBch92FKUJKum4xtgPYHdgH2C3bRg3GzSVltCJQ==}
dependencies:
d3-dispatch: 1.0.3
d3-drag: 1.2.1
d3-interpolate: 1.1.6
d3-selection: 1.3.0
d3-transition: 1.1.1
/d3-chord/1.0.4:
resolution: {integrity: sha512-o0ExexkK1N0KikUakKrQwttP5Flu8AYD6iBUh3AdPJqnTh6xlvcX5wFRuuo29sLOAr9+T4yZPUH1S3CCQJ1SlQ==}
dependencies:
d3-array: 1.2.1
d3-path: 1.0.5
/d3-collection/1.0.4:
resolution: {integrity: sha512-+TPxaBFzbzfpLF3Hjz8JPeuStNmJnyWAufu8VUfpDCDn5RieIgY+OQDjhKMDorf2naLgAjjZXLUQN7XFp/kgog==}
/d3-color/1.0.3:
resolution: {integrity: sha512-t+rSOrshj6m2AUOe8kHvTwfUQ5TFoInEkBfmsHHAHPof58dmbRXNpicB7XAyPbMQbcC7i09p2BxeCEdgBd8xmw==}
/d3-dispatch/1.0.3:
resolution: {integrity: sha512-Qh2DR3neW3lq/ug4oymXHYoIsA91nYt47ERb+fPKjRg6zLij06aP7KqHHl2NyziK9ASxrR3GLkHCtZvXe/jMVg==}
/d3-drag/1.2.1:
resolution: {integrity: sha512-Cg8/K2rTtzxzrb0fmnYOUeZHvwa4PHzwXOLZZPwtEs2SKLLKLXeYwZKBB+DlOxUvFmarOnmt//cU4+3US2lyyQ==}
dependencies:
d3-dispatch: 1.0.3
d3-selection: 1.3.0
/d3-dsv/1.0.8:
resolution: {integrity: sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==}
hasBin: true
dependencies:
commander: 2.20.3
iconv-lite: 0.4.24
rw: 1.3.3
/d3-ease/1.0.3:
resolution: {integrity: sha512-io3QwOJwVPAxRF2UXpKpCdz2wm/7VLFCQQ1yy+GzX6YCtt3vi2BGnimI8agSF5jyUrHsADyF303d2S+ps7zU8w==}
/d3-force/1.1.0:
resolution: {integrity: sha512-2HVQz3/VCQs0QeRNZTYb7GxoUCeb6bOzMp/cGcLa87awY9ZsPvXOGeZm0iaGBjXic6I1ysKwMn+g+5jSAdzwcg==}
dependencies:
d3-collection: 1.0.4
d3-dispatch: 1.0.3
d3-quadtree: 1.0.3
d3-timer: 1.0.7
/d3-format/1.2.2:
resolution: {integrity: sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==}
/d3-geo/1.9.1:
resolution: {integrity: sha512-l9wL/cEQkyZQYXw3xbmLsH3eQ5ij+icNfo4r0GrLa5rOCZR/e/3am45IQ0FvQ5uMsv+77zBRunLc9ufTWSQYFA==}
dependencies:
d3-array: 1.2.1
/d3-hierarchy/1.1.5:
resolution: {integrity: sha512-PcsLIhThc60mWnxlojIOH7Sc0tQ2DgLWfEwEAyzCtej5f3H9wSsRmrg5pEhKZLrwiJnI2zyw/pznJxL9a/Eugw==}
/d3-interpolate/1.1.6:
resolution: {integrity: sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==}
dependencies:
d3-color: 1.0.3
/d3-path/1.0.5:
resolution: {integrity: sha512-eD76prgnTKYkLzHlY2UMyOEZXTpC+WOanCr1BLxo38w4fPPPq/LgCFqRQvqFU3AJngfZmmKR7rgKPZ4EGJ9Atw==}
/d3-polygon/1.0.3:
resolution: {integrity: sha512-2zP7GOvf4XOWTeQouK7fCO534yQxyhYYTw6GTqcXifIalHgA6qV/es+4GRQii9m6XxEPFcht4loobD/o2iEo1A==}
/d3-quadtree/1.0.3:
resolution: {integrity: sha512-U2Jc3jF3JOBGXIOnvWY9C4ekRwRX9hEVpMMmeduJyaxAwPmoe7t84iZFTLn1RwYOyrXxJF55H/Hrg186TFQQdw==}
/d3-queue/3.0.7:
resolution: {integrity: sha512-2rs+6pNFKkrJhqe1rg5znw7dKJ7KZr62j9aLZfhondkrnz6U7VRmJj1UGcbD8MRc46c7H8m4SWhab8EalBQrkw==}
/d3-random/1.1.0:
resolution: {integrity: sha512-XuMbjx3Jq4EWfJP4g6nR7zns/bZfaVbWHWfR8auDkEiWCzVbWifmasfszV1ZRN3xXK3nY4RUFL2nTIhceGZSFQ==}
/d3-request/1.0.6:
resolution: {integrity: sha512-FJj8ySY6GYuAJHZMaCQ83xEYE4KbkPkmxZ3Hu6zA1xxG2GD+z6P+Lyp+zjdsHf0xEbp2xcluDI50rCS855EQ6w==}
dependencies:
d3-collection: 1.0.4
d3-dispatch: 1.0.3
d3-dsv: 1.0.8
xmlhttprequest: 1.8.0
/d3-scale/1.0.7:
resolution: {integrity: sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==}
dependencies:
d3-array: 1.2.1
d3-collection: 1.0.4
d3-color: 1.0.3
d3-format: 1.2.2
d3-interpolate: 1.1.6
d3-time: 1.0.8
d3-time-format: 2.1.1
/d3-selection/1.3.0:
resolution: {integrity: sha512-qgpUOg9tl5CirdqESUAu0t9MU/t3O9klYfGfyKsXEmhyxyzLpzpeh08gaxBUTQw1uXIOkr/30Ut2YRjSSxlmHA==}
/d3-shape/1.2.0:
resolution: {integrity: sha512-LP48zJ9ykPKjCdd0vSu5k2l4s8v1vI6vvdDeJtmgtTa+L6Ery0lzvOaV7pMunFuLv11hwSRZQnSnlhFl801aiw==}
dependencies:
d3-path: 1.0.5
/d3-time-format/2.1.1:
resolution: {integrity: sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==}
dependencies:
d3-time: 1.0.8
/d3-time/1.0.8:
resolution: {integrity: sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==}
/d3-timer/1.0.7:
resolution: {integrity: sha512-vMZXR88XujmG/L5oB96NNKH5lCWwiLM/S2HyyAQLcjWJCloK5shxta4CwOFYLZoY3AWX73v8Lgv4cCAdWtRmOA==}
/d3-transition/1.1.1:
resolution: {integrity: sha512-xeg8oggyQ+y5eb4J13iDgKIjUcEfIOZs2BqV/eEmXm2twx80wTzJ4tB4vaZ5BKfz7XsI/DFmQL5me6O27/5ykQ==}
dependencies:
d3-color: 1.0.3
d3-dispatch: 1.0.3
d3-ease: 1.0.3
d3-interpolate: 1.1.6
d3-selection: 1.3.0
d3-timer: 1.0.7
/d3-voronoi/1.1.2:
resolution: {integrity: sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw==}
/d3-zoom/1.7.1:
resolution: {integrity: sha512-sZHQ55DGq5BZBFGnRshUT8tm2sfhPHFnOlmPbbwTkAoPeVdRTkB4Xsf9GCY0TSHrTD8PeJPZGmP/TpGicwJDJQ==}
dependencies:
d3-dispatch: 1.0.3
d3-drag: 1.2.1
d3-interpolate: 1.1.6
d3-selection: 1.3.0
d3-transition: 1.1.1
/d3/4.13.0:
resolution: {integrity: sha512-l8c4+0SldjVKLaE2WG++EQlqD7mh/dmQjvi2L2lKPadAVC+TbJC4ci7Uk9bRi+To0+ansgsS0iWfPjD7DBy+FQ==}
dependencies:
d3-array: 1.2.1
d3-axis: 1.0.8
d3-brush: 1.0.4
d3-chord: 1.0.4
d3-collection: 1.0.4
d3-color: 1.0.3
d3-dispatch: 1.0.3
d3-drag: 1.2.1
d3-dsv: 1.0.8
d3-ease: 1.0.3
d3-force: 1.1.0
d3-format: 1.2.2
d3-geo: 1.9.1
d3-hierarchy: 1.1.5
d3-interpolate: 1.1.6
d3-path: 1.0.5
d3-polygon: 1.0.3
d3-quadtree: 1.0.3
d3-queue: 3.0.7
d3-random: 1.1.0
d3-request: 1.0.6
d3-scale: 1.0.7
d3-selection: 1.3.0
d3-shape: 1.2.0
d3-time: 1.0.8
d3-time-format: 2.1.1
d3-timer: 1.0.7
d3-transition: 1.1.1
d3-voronoi: 1.1.2
d3-zoom: 1.7.1
/damerau-levenshtein/1.0.8:
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
@ -12718,7 +12968,7 @@ packages:
'@typescript-eslint/eslint-plugin': 5.47.0_ncmi6noazr3nzas7jxykisekym
'@typescript-eslint/utils': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa
eslint: 8.30.0
jest: 29.3.1_@types+node@18.11.17
jest: 29.3.1
transitivePeerDependencies:
- supports-color
- typescript
@ -16057,6 +16307,7 @@ packages:
chalk: 2.4.2
diff-match-patch: 1.0.5
dev: false
bundledDependencies: []
/jsonfile/4.0.0:
resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
@ -16587,7 +16838,7 @@ packages:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'}
dependencies:
chalk: 4.1.1
chalk: 4.1.2
is-unicode-supported: 0.1.0
dev: false
@ -19722,6 +19973,9 @@ packages:
aproba: 1.2.0
dev: true
/rw/1.3.3:
resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
/rxjs/7.8.0:
resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==}
dependencies:
@ -22573,6 +22827,10 @@ packages:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
dev: true
/xmlhttprequest/1.8.0:
resolution: {integrity: sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==}
engines: {node: '>=0.4.0'}
/xss/1.0.14:
resolution: {integrity: sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw==}
engines: {node: '>= 0.10.0'}