
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@mind-wired/core
Advanced tools
Javascript based mindmap library. It provides dragging, aligment, styling(node, edge) and editing functionality.
mind-wired is javascript library to build mindmap.
npm install @mind-wired/core@0.2.0-alpha.3
The example code in this document was generated using Vite(Vanilla + TS).
[PROJECT]
+- assets
+- src
+- api.ts
+- main.ts
+- index.html
The library needs a placeholder for mindmap
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MindWired Demo</title>
</head>
<body>
<div id="mmap-root"><!-- viewport generated here--></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
#mmap-root - placeholder for mindmap(You can name it freely)It is a minimal initialization code for an instance of mind-wired
/* src/main.ts */
import type { MindWired, NodeSpec, UISetting } from "@mind-wired/core";
import { initMindWired } from "@mind-wired/core";
import "@mind-wired/core/mind-wired.css";
import "@mind-wired/core/mind-wired-form.scss";
import { loadFromServer } from "./api";
window.onload = async () => {
const mapData: { node: NodeSpec } = await loadFromServer();
const el = document.querySelector<HTMLDivElement>("#mmap-root")!;
const mwd: MindWired = await initMindWired({
el,
ui: {
width: "100%",
height: 500,
} as UISetting,
});
mwd.nodes(mapData.node);
};
el - placeholder for mindmap.ui - size, scale, class namings and snap layout etc.@mind-wired/core/mind-wired.css - minimal css style for mindmap. You can add or modify style for your own css(scss). See section 3. Style@mind-wired/core/mind-wired-form.scss - style for default editing form.loadFromServer - fetch mindmap data(nodes, ui, and schema) from your serverYou might fetch mindmap data from server like this.
/* src/api.ts */
export const loadFromServer = (): Promise<{
node: NodeSpec;
}> => {
// using axis(...) or fetch(...) in production code
return Promise.resolve({
node: {
model: { text: "Countries\nand\nCities" },
view: {
x: 0,
y: 0,
},
subs: [
{
model: { text: "Canada" },
view: { x: -100, y: 0 },
subs: [
{ model: { text: "Toronto" }, view: { x: -90, y: 0 } },
{ model: { text: "Quebec City" }, view: { x: -10, y: -40 } },
],
},
{
model: { text: "Spain" },
view: { x: 100, y: 0 },
subs: [
{ model: { text: "Madrid" }, view: { x: 90, y: 90 } },
{ model: { text: "Barcelona" }, view: { x: 100, y: 0 } },
{ model: { text: "Valencia" }, view: { x: 90, y: 45 } },
],
},
],
},
});
};
view: {x:0, y:0}NodeSpec has three key properties
NodeSpec[].For examples,
Spain(100, 0) is positioned to the right of the root node.Madrid, Barcelona, Valencia are also positioned to the right of the parent node Spainmind-wired generates base structure.
<div id="mmap-root">
<!-- generated automatically by mind-wired -->
<div data-mind-wired-viewport>
<canvas></canvas>
<div class="mwd-selection-area"></div>
<div class="mwd-nodes"></div>
</div>
</div>
[data-mind-wired-viewport] - reserved data attribute meaning root element of mindmap<canvas></canvas> - placeholer for edges.mwd-selection-area - used to highlight selected nodes.mwd-nodes - placeholder for node structureTo define your node styles, create a css(scss) file
[PROJECT]
+- assets
+- mindmap.css (+)
+- src
+- main.ts
+- index.html
assets/mindmap.css - you can name it as you wantThen, import the (s)css file
/* /src/main.ts */
...
import "@mind-wired/core/mind-wired.css";
import "@mind-wired/core/mind-wired-form.scss";
...
import "./assets/mindmap.css"
window.onload = async () => {
...
};
MindWired supports snap to node, which helps node alignment while dragging.
initinitMindWired({
el,
ui: {
...
snap: { # optional
limit: 4, # within 4 pixels
width: 0.4, # snap line width
dash: [6, 2], # dashed line style
color: "red", # line color
},
})
<canvas/>You can disable it by setting false
initinitMindWired({
el,
ui: {
...
snap: false,
})
// or
ui: {
snap: { # optional
limit: 4, # within 4 pixels
width: 0.4, # snap line width
dash: [6, 2], # dashed line style
color: "red", # line color
enabled: false # disable snap
},
}
All nodes are placed in the .mwd-nodes with tree structure(recursively)
<div id="mmap-root">
<div data-mind-wired-viewport>
...
<div class="mwd-nodes">
<!-- root node -->
<div class="mwd-node">
<div class="mwd-body"></div>
<div class="mwd-subs">
<!--child nodes -->
<div class="mwd-node">..Canada..</div>
<div class="mwd-node">..Spain..</div>
</div>
</div>
</div>
</div>
</div>
Each node is assigned level number, 0 for root node, 1 for sub nodes of the root.
[TOP]
+- [Left]
|
+- [Right]
|
+--[Cat]
TOP - class="level-0"Left - class="level-1"Right - class="level-1"Cat - class="level-2"<div class="mwd-nodes">
<div class="mwd-node">
<div class="mwd-body level-0">..TOP..</div>
<div class="mwd-subs">
<div class="mwd-node">
<div class="mwd-body level-1">..LEFT..</div>
</div>
<div class="mwd-node">
<div class="mwd-body level-1">..RIGHT..</div>
<div class="mwd-subs">
<div class="mwd-node">
<div class="mwd-body level-2">..Cat..</div>
</div>
</div>
</div>
</div>
</div>
</div>
level-x) is attached at .mwd-bodyFor example, here is css to assign rounded border with bigger text to root node,
/* assets/mindmap.css */
[data-mind-wired-viewport] .mwd-body.level-0 {
border: 1px solid #444;
border-radius: 8px;
font-size: 1.5rem;
}
.node-body together to override default css styleStyle for level-1(Left, Right)
/* assets/mindmap.css */
[data-mind-wired-viewport] .mwd-body.level-1 {
color: 'red'
font-size: 1.25rem;
}
A group of nodes(Canada, Spain) need to have same style(border, background and font style etc) regardless of level.
Schema can be specified in each node
{
node: {
model: { text: "Countries\nand\nCities" },
view: {...},
subs: [
{
model: { text: "Canada", schema: 'country' },
view: {...},
subs: [...],
},
{
model: { text: "Spain", schema: 'country' },
view: {...},
subs: [...],
},
],
},
}
// schemas
const schema = [{
name: 'country',
style: { // optional
fontSize: '1rem',
border: '1px solid #2323FF',
color: '#2323FF',
borderRadius: '6px'
}
}]
model.schema in each NodeSpecstringIf you have your schema, pass them to
initMindWiredconst yourSchemap: [...] initMindWired({ el: mapEl!, ui, schema: yourSchema }) .then((mwd: MindWired) => { ... });
It is rendered as class value
<div class="mwd-nodes">
<div class="mwd-node">
<div class="mwd-body level-0">..Countries...</div>
<div class="mwd-subs">
<div class="mwd-node country">
<div class="mwd-body country level-1">..Canada..</div>
</div>
<div class="mwd-node country">
<div class="mwd-body country level-1">..Span..</div>
...
</div>
</div>
</div>
</div>
city(schema) is assigned at .mwd-node and .mwd-body<style>...</style> for schemas are injected into <head/>If schema has property style defined, <style>...</style> for each schema is created in <head/>
<!-- automatically created from property schema.style -->
<head>
<style id="...">
[data-mind-wired-viewport] .mwd-node.country > .mwd-body {
font-size: 1rem;
border: 1px dashed #2323ff;
color: #2323ff;
border-radius: 6px;
}
</style>
</head>
You can define style for schema without property style.
const yourSchema = [
{name: 'coutnry', style: {...}},
{name: 'city'}
]
city has no style.Nodes with schema city can be styled like this
/* assets/mindmap.css */
[data-mind-wired-viewport] .mwd-node.city > .mwd-body.city {
color: #777;
box-shadow: 0 0 8px #0000002d, 0 0 2px #00000041;
}
.parent > .child) should be used.You can define separate CSS styles for each node, which add or override styles defined by level and schema.
return Promise.resolve({
node: {
model: { text: "Countries\nand\nCities" },
view: {...},
subs: [
{
model: { text: "Canada", schema: 'country'},
...
},
{
model: { text: "Spain", schema: 'country' },
view: { x: 100, y: 0,
style: {
backgroundColor: '#9a7baf',
color: 'white',
border:'none'
}
},
},
{
model: { text: "South Korea", schema: 'country' },
...
},
],
},
schema : [{
name: 'country',
style: {...}
}]
});
country.Spain has additional style at view.style, which override background(#9a7baf), font color(white) and border(none)Edges are rendered on
<canvas/>
node: {
model { ... },
view: {
x: ...,
y: ...,
layout: ...,
edge: {
name: 'line', # name of edge renderer
color: 'blue', # edge color
width: 4 # edge width
}
}
}
view.edge of NodeSpecline, natural_curve, mustache_lr and mustache_tb) are available.For example, mustache_lr edge on the root node
export const loadFromServer = () => {
return Promise.resolve({
node: {
model: { text: "Countries\nand\nCities" },
view: {
x: 0,
y: 0,
edge: { name: "mustache_lr", color: "#2378ff", width: 2 },
},
subs: [...],
},
});
};
view.edge (typeof EdgeSpec)#acdeff)EdgeSpec from the root node, if they has no one.1. line
// for line edge
view: {
x: ..., y: ...,
edge: {
name: 'line',
color: ...,
width: ...
}
}
2. mustache_lr (bottom)
// for mustach_lr bottom edge
view: {
x: ...,
y: ...,
edge: {
name: 'mustache_lr',
option: {
valign: "bottom",
},
color: ...,
width: ...
}
}
3. mustache_lr(center)
// for mustach_lr center edge
view: {
x: ...,
y: ...,
edge: {
name: 'mustache_lr',
// option: {
// valign: "center",
// },
color: ...,
width: ...
}
}
center is default4. mustache_tb
// for mustach_lr center edge
view: {
x: ...,
y: ...,
edge: {
name: 'mustache_tb',
color: ...,
width: ...
}
}
5. natural_curve
// for natural_curve center edge
view: {
x: ...,
y: ...,
edge: {
name: 'natural_curve',
color: ...,
width: ...
}
}
When you drag node Right to the left side of the root node, child nodes cat and Dog keep their side, which results in annoying troublesome(have to move all sub nodes to the left of the parent Right).

Layout can help moving all descendant nodes to the opposite side when a node moves.
4 layouts are predefined.
[A]
|
[B] | [B`]
[C] [D] | [D`] [C`]
B moves to the opposite side B', node C, D also moves to D', C'Let's install X-AXIS on the root node
export const loadFromServer = () => {
return Promise.resolve({
node: {
model: { text: "Countries\nand\nCities" },
view: {
x: 0,
y: 0,
edge: {...},
layout: {type: 'X-AXIS'},
},
subs: [...],
},
});
};
view.layout of NodeSpecRight to the opposite side makes Cat and Dog change their sides. [C] [D]
[B]
---------------[A]---------------
[B']
[C'][D']
X-AXIS + Y-AXISIf root node has no layout, layout DEFAULT is assign, which does nothing.
| event name | description |
|---|---|
node.selected | nodes are selected |
node.clicked | a node is clicked |
node.created | nodes are created |
node.updated | nodes are updated(model, pos, path) |
node.deleted | nodes are deleted |
triggered when nodes have been selected(activate sate).
import {..., type NodeEventArg} from "@mind-wired/core";
window.onload = async () => {
...
mwd.listen("node.selected", async (e: NodeEventArg) => {
const {type, nodes} = e;
console.log(type, nodes);
})
};
node.selected always preoceds node.clickedtriggered when a node has been clicked.
window.onload = async () => {
...
mwd.listen("node.clicked", async (e: NodeEventArg) => {
const {type, nodes} = e;
console.log(type, nodes);
})
};
triggered when nodes have been created(for example Enter, or Shift+Enter)
window.onload = async () => {
...
mwd.listen("node.created", (e: NodeEventArg) => {
const {type, nodes} = e;
console.log(type, nodes);
})
};
triggered when nodes have been updated by
'pos')'path')'model')schema)folding)window.onload = async () => {
...
mwd.listen("node.updated", (e: NodeEventArg) => {
const {type, nodes} = e; // type: 'pos' | 'path' | 'model' | 'schema' | 'folding'
console.log(type, nodes);
})
};
path, pos, model, schema, foldingtype have one of five values.
path - means the nodes have changed parent(by dragging control icon).pos - means the nodes move by draggingmodel - content has updated(text, icon, etc)schema - a schema has been (un)bounded to nodefolding - folding state has been changed of nodetriggered when nodes have been deleted(pressing delete key, fn+delete in mac)
window.onload = async () => {
...
mwd.listen("node.deleted", (e: NodeDeletionArg) => {
const { type, nodes, updated } = e; // type: 'delete'
console.log(type, nodes, updated);
})
};
node[] of deleted node P are attached to parent of node P, keeping their position on viewport. NodeDeletionArg.updated references children node[]If deleted node has children, they are moved to node.parent, which triggers node.updated event
| event name | description |
|---|---|
schema.created | new schema(s) is(are) created |
schema.updated | schemas are updated |
schema.deleted | schemas are deleted |
triggered when new schemas are created.
window.onload = async () => {
...
mwd.listen("schema.created", (e: SchemaEventArg) => {
const { type, schemas } = e; // type: 'create'
console.log(type, schemas);
})
};
// or
import { EVENT } from '@mind-wired/core'
mwd.listenStrict(EVENT.SCHEMA.CREATED, (e: SchemaEventArg) => {
const { type, schemas } = e; // type: 'create'
console.log(type, schemas);
});
triggered when schemas are updated.
window.onload = async () => {
...
mwd.listen("schema.updated", (e: SchemaEventArg) => {
const { type, schemas } = e; // type: 'create'
console.log(type, schemas);
})
};
// or
mwd.listenStrict(EVENT.SCHEMA.UPDATED, (e: SchemaEventArg) => {
const { type, schemas } = e; // type: 'update'
console.log(type, schemas);
});
triggered when schemas are updated.
window.onload = async () => {
...
mwd.listen("schema.deleted", (e: SchemaEventArg) => {
const { type, schemas } = e; // type: 'delete'
console.log(type, schemas);
})
};
// or
mwd.listenStrict(EVENT.SCHEMA.DELETED, (e: SchemaEventArg) => {
const { type, schemas } = e; // type: 'update'
console.log(type, schemas);
});
| Ctrl | Alt | Shift | KEY | description |
|---|---|---|---|---|
| none |
| Ctrl | Alt | Shift | Click | description |
|---|---|---|---|---|
click | make node active | |||
shift | click | add node to active state |
| Ctrl | Alt | Shift | KEY | description |
|---|---|---|---|---|
Enter | insert sinbling of active node enter | |||
shift | Enter | insert child on active node shift+enter | ||
Delete | delete active node(s), fn+delete in mac | |||
Space | start editing state of active node |
| Ctrl | Alt | Shift | KEY | description |
|---|---|---|---|---|
Enter | save data and finish editing | |||
esc | finish editing state without save |
Calling MindWired.exportWith() exports current state of mindmap.
/* /src/main.ts */
import type {..., NodeEventArg } from "@mind-wired/core";
...
const sendToBackend = (data: ExportResponse) => {
console.log(data)
}
window.onload = async () => {
...
const mwd: MindWired = await initMindWired({...});
mwd.nodes(mapData.node);
mwd
.listen("node.updated", async (e: NodeEventArg) => {
const data = await mwd.exportWith();
sendToBackend(data)
}).listen("node.created", async (e: NodeEventArg) => {
const data = await mwd.exportWith();
sendToBackend(data)
}).listen("node.deleted", async (e: NodeDeletionArg) => {
const data = await mwd.exportWith();
sendToBackend(data)
});
};
You could provide, for example, <button/> to export current state of mindmap
<body>
<nav id="controls">
<button data-export>EXPORT</button>
</nav>
<div id="mmap-root">...</div>
</body>
window.onload = async () => {
const mwd: MindWired = await initMindWired({...});
...
const btnExport = document.querySelector<HTMLButtonElement>('#controls > [data-export]')
btnExport!.addEventListener('click', async () => {
const data = await mwd.exportWith();
sendToBackend(data)
}, false)
};
FAQs
Javascript based mindmap library. It provides dragging, aligment, styling(node, edge) and editing functionality.
We found that @mind-wired/core demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.