force-graph 1.42.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +228 -0
- package/dist/force-graph.common.js +1754 -0
- package/dist/force-graph.d.ts +195 -0
- package/dist/force-graph.js +12168 -0
- package/dist/force-graph.js.map +1 -0
- package/dist/force-graph.min.js +5 -0
- package/dist/force-graph.module.js +1743 -0
- package/example/auto-colored/index.html +34 -0
- package/example/basic/index.html +29 -0
- package/example/build-a-graph/index.html +108 -0
- package/example/click-to-focus/index.html +28 -0
- package/example/collision-detection/index.html +50 -0
- package/example/curved-links/index.html +37 -0
- package/example/curved-links-computed-curvature/index.html +76 -0
- package/example/custom-node-shape/index.html +44 -0
- package/example/dag-yarn/index.html +96 -0
- package/example/dagre/index.html +119 -0
- package/example/dash-odd-links/index.html +47 -0
- package/example/datasets/blocks.json +1 -0
- package/example/datasets/d3-dependencies.csv +464 -0
- package/example/datasets/miserables.json +337 -0
- package/example/datasets/mplate.mtx +74090 -0
- package/example/directional-links-arrows/index.html +29 -0
- package/example/directional-links-particles/index.html +22 -0
- package/example/dynamic/index.html +42 -0
- package/example/emit-particles/index.html +50 -0
- package/example/expandable-nodes/index.html +66 -0
- package/example/expandable-tree/index.html +85 -0
- package/example/fit-to-canvas/index.html +34 -0
- package/example/fix-dragged-nodes/index.html +24 -0
- package/example/highlight/index.html +84 -0
- package/example/huge-1M/index.html +37 -0
- package/example/img-nodes/imgs/cat.jpg +0 -0
- package/example/img-nodes/imgs/dog.jpg +0 -0
- package/example/img-nodes/imgs/eagle.jpg +0 -0
- package/example/img-nodes/imgs/elephant.jpg +0 -0
- package/example/img-nodes/imgs/grasshopper.jpg +0 -0
- package/example/img-nodes/imgs/octopus.jpg +0 -0
- package/example/img-nodes/imgs/owl.jpg +0 -0
- package/example/img-nodes/imgs/panda.jpg +0 -0
- package/example/img-nodes/imgs/squirrel.jpg +0 -0
- package/example/img-nodes/imgs/tiger.jpg +0 -0
- package/example/img-nodes/imgs/whale.jpg +0 -0
- package/example/img-nodes/index.html +43 -0
- package/example/large-graph/index.html +41 -0
- package/example/load-json/index.html +24 -0
- package/example/medium-graph/index.html +26 -0
- package/example/medium-graph/preview.png +0 -0
- package/example/move-viewport/index.html +42 -0
- package/example/multi-selection/index.html +57 -0
- package/example/responsive/index.html +37 -0
- package/example/text-links/index.html +69 -0
- package/example/text-nodes/index.html +42 -0
- package/example/tree/index.html +71 -0
- package/package.json +72 -0
- package/src/canvas-force-graph.js +544 -0
- package/src/color-utils.js +17 -0
- package/src/dagDepths.js +51 -0
- package/src/force-graph.css +35 -0
- package/src/force-graph.js +644 -0
- package/src/index.d.ts +195 -0
- package/src/index.js +3 -0
- package/src/kapsule-link.js +34 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
// Random tree
|
|
13
|
+
const N = 300;
|
|
14
|
+
const gData = {
|
|
15
|
+
nodes: [...Array(N).keys()].map(i => ({ id: i })),
|
|
16
|
+
links: [...Array(N).keys()]
|
|
17
|
+
.filter(id => id)
|
|
18
|
+
.map(id => ({
|
|
19
|
+
source: id,
|
|
20
|
+
target: Math.round(Math.random() * (id-1))
|
|
21
|
+
}))
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const Graph = ForceGraph()
|
|
25
|
+
(document.getElementById('graph'))
|
|
26
|
+
.graphData(gData);
|
|
27
|
+
|
|
28
|
+
let k = 0, angle = 0, radius = 300;
|
|
29
|
+
setInterval(() => {
|
|
30
|
+
// zoom in
|
|
31
|
+
Graph.zoom(k);
|
|
32
|
+
k += 0.001;
|
|
33
|
+
|
|
34
|
+
// pan around
|
|
35
|
+
Graph.centerAt(
|
|
36
|
+
radius * Math.cos(angle),
|
|
37
|
+
radius * Math.sin(angle)
|
|
38
|
+
);
|
|
39
|
+
angle += Math.PI / 300;
|
|
40
|
+
}, 10);
|
|
41
|
+
</script>
|
|
42
|
+
</body>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!-- <script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
// Random tree
|
|
13
|
+
const N = 30;
|
|
14
|
+
const gData = {
|
|
15
|
+
nodes: [...Array(N).keys()].map(i => ({ id: i })),
|
|
16
|
+
links: [...Array(N).keys()]
|
|
17
|
+
.filter(id => id)
|
|
18
|
+
.map(id => ({
|
|
19
|
+
source: id,
|
|
20
|
+
target: Math.round(Math.random() * (id-1))
|
|
21
|
+
}))
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
let selectedNodes = new Set();
|
|
25
|
+
|
|
26
|
+
const Graph = ForceGraph()
|
|
27
|
+
(document.getElementById('graph'))
|
|
28
|
+
.graphData(gData)
|
|
29
|
+
.nodeRelSize(7)
|
|
30
|
+
.nodeColor(node => selectedNodes.has(node) ? 'darkorange' : 'grey')
|
|
31
|
+
.onNodeClick((node, event) => {
|
|
32
|
+
if (event.ctrlKey || event.shiftKey || event.altKey) { // multi-selection
|
|
33
|
+
selectedNodes.has(node) ? selectedNodes.delete(node) : selectedNodes.add(node);
|
|
34
|
+
} else { // single-selection
|
|
35
|
+
const untoggle = selectedNodes.has(node) && selectedNodes.size === 1;
|
|
36
|
+
selectedNodes.clear();
|
|
37
|
+
!untoggle && selectedNodes.add(node);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Graph.nodeColor(Graph.nodeColor()); // update color of selected nodes
|
|
41
|
+
})
|
|
42
|
+
.onNodeDrag((node, translate) => {
|
|
43
|
+
if (selectedNodes.has(node)) { // moving a selected node
|
|
44
|
+
[...selectedNodes]
|
|
45
|
+
.filter(selNode => selNode !== node) // don't touch node being dragged
|
|
46
|
+
.forEach(node => ['x', 'y'].forEach(coord => node[`f${coord}`] = node[coord] + translate[coord])); // translate other nodes by same amount
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
.onNodeDragEnd(node => {
|
|
50
|
+
if (selectedNodes.has(node)) { // finished moving a selected node
|
|
51
|
+
[...selectedNodes]
|
|
52
|
+
.filter(selNode => selNode !== node) // don't touch node being dragged
|
|
53
|
+
.forEach(node => ['x', 'y'].forEach(coord => node[`f${coord}`] = undefined)); // unfix controlled nodes
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
</script>
|
|
57
|
+
</body>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 30px; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/element-resize-detector/dist/element-resize-detector.min.js"></script>
|
|
5
|
+
|
|
6
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
7
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
8
|
+
</head>
|
|
9
|
+
|
|
10
|
+
<body>
|
|
11
|
+
<div id="graph"></div>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
// Random tree
|
|
15
|
+
const N = 200;
|
|
16
|
+
const gData = {
|
|
17
|
+
nodes: [...Array(N).keys()].map(i => ({ id: i })),
|
|
18
|
+
links: [...Array(N).keys()]
|
|
19
|
+
.filter(id => id)
|
|
20
|
+
.map(id => ({
|
|
21
|
+
source: id,
|
|
22
|
+
target: Math.round(Math.random() * (id-1))
|
|
23
|
+
}))
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const Graph = ForceGraph()
|
|
27
|
+
(document.getElementById('graph'))
|
|
28
|
+
.backgroundColor('#F5F5FF')
|
|
29
|
+
.height(window.innerHeight - 60)
|
|
30
|
+
.graphData(gData);
|
|
31
|
+
|
|
32
|
+
elementResizeDetectorMaker().listenTo(
|
|
33
|
+
document.getElementById('graph'),
|
|
34
|
+
el => Graph.width(el.offsetWidth)
|
|
35
|
+
);
|
|
36
|
+
</script>
|
|
37
|
+
</body>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
fetch('../datasets/miserables.json').then(res => res.json()).then(data => {
|
|
13
|
+
const Graph = ForceGraph()
|
|
14
|
+
(document.getElementById('graph'))
|
|
15
|
+
.graphData(data)
|
|
16
|
+
.nodeId('id')
|
|
17
|
+
.nodeLabel('id')
|
|
18
|
+
.nodeAutoColorBy('group')
|
|
19
|
+
.linkCanvasObjectMode(() => 'after')
|
|
20
|
+
.linkCanvasObject((link, ctx) => {
|
|
21
|
+
const MAX_FONT_SIZE = 4;
|
|
22
|
+
const LABEL_NODE_MARGIN = Graph.nodeRelSize() * 1.5;
|
|
23
|
+
|
|
24
|
+
const start = link.source;
|
|
25
|
+
const end = link.target;
|
|
26
|
+
|
|
27
|
+
// ignore unbound links
|
|
28
|
+
if (typeof start !== 'object' || typeof end !== 'object') return;
|
|
29
|
+
|
|
30
|
+
// calculate label positioning
|
|
31
|
+
const textPos = Object.assign(...['x', 'y'].map(c => ({
|
|
32
|
+
[c]: start[c] + (end[c] - start[c]) / 2 // calc middle point
|
|
33
|
+
})));
|
|
34
|
+
|
|
35
|
+
const relLink = { x: end.x - start.x, y: end.y - start.y };
|
|
36
|
+
|
|
37
|
+
const maxTextLength = Math.sqrt(Math.pow(relLink.x, 2) + Math.pow(relLink.y, 2)) - LABEL_NODE_MARGIN * 2;
|
|
38
|
+
|
|
39
|
+
let textAngle = Math.atan2(relLink.y, relLink.x);
|
|
40
|
+
// maintain label vertical orientation for legibility
|
|
41
|
+
if (textAngle > Math.PI / 2) textAngle = -(Math.PI - textAngle);
|
|
42
|
+
if (textAngle < -Math.PI / 2) textAngle = -(-Math.PI - textAngle);
|
|
43
|
+
|
|
44
|
+
const label = `${link.source.id} > ${link.target.id}`;
|
|
45
|
+
|
|
46
|
+
// estimate fontSize to fit in link length
|
|
47
|
+
ctx.font = '1px Sans-Serif';
|
|
48
|
+
const fontSize = Math.min(MAX_FONT_SIZE, maxTextLength / ctx.measureText(label).width);
|
|
49
|
+
ctx.font = `${fontSize}px Sans-Serif`;
|
|
50
|
+
const textWidth = ctx.measureText(label).width;
|
|
51
|
+
const bckgDimensions = [textWidth, fontSize].map(n => n + fontSize * 0.2); // some padding
|
|
52
|
+
|
|
53
|
+
// draw text label (with background rect)
|
|
54
|
+
ctx.save();
|
|
55
|
+
ctx.translate(textPos.x, textPos.y);
|
|
56
|
+
ctx.rotate(textAngle);
|
|
57
|
+
|
|
58
|
+
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
|
|
59
|
+
ctx.fillRect(- bckgDimensions[0] / 2, - bckgDimensions[1] / 2, ...bckgDimensions);
|
|
60
|
+
|
|
61
|
+
ctx.textAlign = 'center';
|
|
62
|
+
ctx.textBaseline = 'middle';
|
|
63
|
+
ctx.fillStyle = 'darkgrey';
|
|
64
|
+
ctx.fillText(label, 0, 0);
|
|
65
|
+
ctx.restore();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
</script>
|
|
69
|
+
</body>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
fetch('../datasets/miserables.json').then(res => res.json()).then(data => {
|
|
13
|
+
const Graph = ForceGraph()
|
|
14
|
+
(document.getElementById('graph'))
|
|
15
|
+
.graphData(data)
|
|
16
|
+
.nodeId('id')
|
|
17
|
+
.nodeAutoColorBy('group')
|
|
18
|
+
.nodeCanvasObject((node, ctx, globalScale) => {
|
|
19
|
+
const label = node.id;
|
|
20
|
+
const fontSize = 12/globalScale;
|
|
21
|
+
ctx.font = `${fontSize}px Sans-Serif`;
|
|
22
|
+
const textWidth = ctx.measureText(label).width;
|
|
23
|
+
const bckgDimensions = [textWidth, fontSize].map(n => n + fontSize * 0.2); // some padding
|
|
24
|
+
|
|
25
|
+
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
|
|
26
|
+
ctx.fillRect(node.x - bckgDimensions[0] / 2, node.y - bckgDimensions[1] / 2, ...bckgDimensions);
|
|
27
|
+
|
|
28
|
+
ctx.textAlign = 'center';
|
|
29
|
+
ctx.textBaseline = 'middle';
|
|
30
|
+
ctx.fillStyle = node.color;
|
|
31
|
+
ctx.fillText(label, node.x, node.y);
|
|
32
|
+
|
|
33
|
+
node.__bckgDimensions = bckgDimensions; // to re-use in nodePointerAreaPaint
|
|
34
|
+
})
|
|
35
|
+
.nodePointerAreaPaint((node, color, ctx) => {
|
|
36
|
+
ctx.fillStyle = color;
|
|
37
|
+
const bckgDimensions = node.__bckgDimensions;
|
|
38
|
+
bckgDimensions && ctx.fillRect(node.x - bckgDimensions[0] / 2, node.y - bckgDimensions[1] / 2, ...bckgDimensions);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
</script>
|
|
42
|
+
</body>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/d3-dsv"></script>
|
|
5
|
+
<script src="//unpkg.com/dat.gui"></script>
|
|
6
|
+
<script src="//unpkg.com/d3-quadtree"></script>
|
|
7
|
+
<script src="//unpkg.com/d3-force"></script>
|
|
8
|
+
|
|
9
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
10
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
11
|
+
</head>
|
|
12
|
+
|
|
13
|
+
<body>
|
|
14
|
+
<div id="graph"></div>
|
|
15
|
+
|
|
16
|
+
<script>
|
|
17
|
+
// controls
|
|
18
|
+
const controls = { 'DAG Orientation': 'td'};
|
|
19
|
+
const gui = new dat.GUI();
|
|
20
|
+
gui.add(controls, 'DAG Orientation', ['td', 'bu', 'lr', 'rl', 'radialout', 'radialin', null])
|
|
21
|
+
.onChange(orientation => graph && graph.dagMode(orientation));
|
|
22
|
+
|
|
23
|
+
// graph config
|
|
24
|
+
const NODE_REL_SIZE = 1;
|
|
25
|
+
const graph = ForceGraph()
|
|
26
|
+
.dagMode('td')
|
|
27
|
+
.dagLevelDistance(300)
|
|
28
|
+
.backgroundColor('#101020')
|
|
29
|
+
.linkColor(() => 'rgba(255,255,255,0.2)')
|
|
30
|
+
.nodeRelSize(NODE_REL_SIZE)
|
|
31
|
+
.nodeId('path')
|
|
32
|
+
.nodeVal(node => 100 / (node.level + 1))
|
|
33
|
+
.nodeLabel('path')
|
|
34
|
+
.nodeAutoColorBy('module')
|
|
35
|
+
.linkDirectionalParticles(2)
|
|
36
|
+
.linkDirectionalParticleWidth(2)
|
|
37
|
+
.d3Force('collision', d3.forceCollide(node => Math.sqrt(100 / (node.level + 1)) * NODE_REL_SIZE))
|
|
38
|
+
.d3VelocityDecay(0.3);
|
|
39
|
+
|
|
40
|
+
fetch('../datasets/d3-dependencies.csv')
|
|
41
|
+
.then(r => r.text())
|
|
42
|
+
.then(d3.csvParse)
|
|
43
|
+
.then(data => {
|
|
44
|
+
const nodes = [], links = [];
|
|
45
|
+
data.forEach(({ size, path }) => {
|
|
46
|
+
const levels = path.split('/'),
|
|
47
|
+
level = levels.length - 1,
|
|
48
|
+
module = level > 0 ? levels[1] : null,
|
|
49
|
+
leaf = levels.pop(),
|
|
50
|
+
parent = levels.join('/');
|
|
51
|
+
|
|
52
|
+
const node = {
|
|
53
|
+
path,
|
|
54
|
+
leaf,
|
|
55
|
+
module,
|
|
56
|
+
size: +size || 20,
|
|
57
|
+
level
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
nodes.push(node);
|
|
61
|
+
|
|
62
|
+
if (parent) {
|
|
63
|
+
links.push({source: parent, target: path, targetNode: node});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
graph(document.getElementById('graph'))
|
|
68
|
+
.graphData({ nodes, links });
|
|
69
|
+
});
|
|
70
|
+
</script>
|
|
71
|
+
</body>
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "force-graph",
|
|
3
|
+
"version": "1.42.3",
|
|
4
|
+
"description": "2D force-directed graph rendered on HTML5 canvas",
|
|
5
|
+
"unpkg": "dist/force-graph.min.js",
|
|
6
|
+
"main": "dist/force-graph.common.js",
|
|
7
|
+
"module": "dist/force-graph.module.js",
|
|
8
|
+
"types": "src/index.d.ts",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/vasturiano/force-graph.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/vasturiano/force-graph",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"2d",
|
|
16
|
+
"force",
|
|
17
|
+
"simulation",
|
|
18
|
+
"graph",
|
|
19
|
+
"canvas",
|
|
20
|
+
"d3"
|
|
21
|
+
],
|
|
22
|
+
"author": {
|
|
23
|
+
"name": "Vasco Asturiano",
|
|
24
|
+
"url": "http://bl.ocks.org/vasturiano"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/vasturiano/force-graph/issues"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "rimraf dist && rollup -c",
|
|
32
|
+
"dev": "rollup -w -c rollup.config.dev.js",
|
|
33
|
+
"prepare": "npm run build"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist/**/*",
|
|
37
|
+
"example/**/*",
|
|
38
|
+
"src/**/*"
|
|
39
|
+
],
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@tweenjs/tween.js": "18",
|
|
42
|
+
"accessor-fn": "1",
|
|
43
|
+
"bezier-js": "3 - 4",
|
|
44
|
+
"canvas-color-tracker": "1",
|
|
45
|
+
"d3-array": "1 - 3",
|
|
46
|
+
"d3-drag": "2 - 3",
|
|
47
|
+
"d3-force-3d": "2 - 3",
|
|
48
|
+
"d3-scale": "1 - 4",
|
|
49
|
+
"d3-scale-chromatic": "1 - 3",
|
|
50
|
+
"d3-selection": "2 - 3",
|
|
51
|
+
"d3-zoom": "2 - 3",
|
|
52
|
+
"index-array-by": "1",
|
|
53
|
+
"kapsule": "^1.13",
|
|
54
|
+
"lodash.throttle": "4"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@babel/core": "^7.15.5",
|
|
58
|
+
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
|
59
|
+
"@babel/plugin-proposal-object-rest-spread": "^7.15.6",
|
|
60
|
+
"@babel/preset-env": "^7.15.6",
|
|
61
|
+
"@rollup/plugin-babel": "^5.3.0",
|
|
62
|
+
"@rollup/plugin-commonjs": "^21.0.0",
|
|
63
|
+
"@rollup/plugin-node-resolve": "^13.0.5",
|
|
64
|
+
"postcss": "^8.3.8",
|
|
65
|
+
"rimraf": "^3.0.2",
|
|
66
|
+
"rollup": "^2.58.0",
|
|
67
|
+
"rollup-plugin-dts": "^4.0.0",
|
|
68
|
+
"rollup-plugin-postcss": "^4.0.1",
|
|
69
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
70
|
+
"typescript": "^4.4.3"
|
|
71
|
+
}
|
|
72
|
+
}
|