Monorepo for the @d3-polytree/* v2 ecosystem — an interactive
polytree / process-flow diagram toolkit built on slim,
modular D3 v7. TypeScript, ESM-first, published to npm.
v1 (the legacy
SimpleNetworkviewer) is preserved on thev1branch.mainis this modernized, TypeScript monorepo. SeeROADMAP.mdfor the full modernization plan and the decisions log (O1–O10).
▶ Live Storybook — interactive demos of every component
(viewer, interactive-viewer, editor, canvas, icon pack) and the Guides/Kitchensink worked example,
published from main via GitHub Pages.
| Package | Role |
|---|---|
@d3-polytree/canvas |
Base SVG canvas toolbox (Canvas, ElementRegistry, ElementBuilder, SVG export). |
@d3-polytree/pfdn-moddle |
Read/write the .pfdn (Process Flow Diagram Notation) XML model. |
@d3-polytree/core |
The engine: draw + features + modelling, on modular D3 v7 peer deps. |
@d3-polytree/layout |
Framework-free layered (Sugiyama) auto-layout solver (pure + Web-Worker); composes into core. |
@d3-polytree/viewer |
Static, read-only viewer. |
@d3-polytree/interactive-viewer |
Viewer + pan/zoom, selection, side-tabs & search panels. |
@d3-polytree/editor |
Full editor — create/modify diagrams, palette, properties panel. |
@d3-polytree/icons-amazon |
AWS icon pack + the reference icon-pack convention. |
@d3-polytree/element |
<d3-polytree-editor> custom element — shadow DOM, form-associated (ElementInternals). |
@d3-polytree/react |
React wrapper (<PolytreeEditor>) bridging the event bus via useSyncExternalStore. |
@d3-polytree/ssr |
Server-side rendering: deterministic .pfdn → static SVG in Node (no browser). |
@d3-polytree/diff |
Pure structural diff of two .pfdn documents → an ordered DiffOp[] (add/remove/move/retype/reattach/modify). |
Every package ships ESM + CJS + .d.ts; the three components (viewer, interactive-viewer,
editor) and the @d3-polytree/element custom element also ship a self-contained UMD bundle
with D3 inlined for a plain <script> drop-in.
# a component pulls in @d3-polytree/core; add the D3 v7 slices it peers on:
pnpm add @d3-polytree/editor d3-selection d3-zoom d3-transition d3-scale d3-axis d3-dragimport { Editor } from '@d3-polytree/editor';
import '@d3-polytree/interactive-viewer/style.css'; // side-tabs + search panels
import '@d3-polytree/editor/style.css'; // properties panel
const editor = new Editor({ container: document.getElementById('app')! });
await editor.createDiagram(); // or: await editor.importDiagram(pfdnXml)
const node = editor.createNode({ type: 'default', position: { x: 80, y: 80 } });
editor.select(node);
const xml = editor.exportDiagram(); // serialize back to .pfdnBesides .pfdn XML, the model round-trips through plain, typed JSON over the same moddle
model — so you can produce, validate, and load documents without touching XML:
import { toJson, fromJson, validate, type PfdnDocument } from '@d3-polytree/pfdn-moddle';
import { loadModelFromJson } from '@d3-polytree/core';
const doc = toJson(editor.get('d3polytree').definitions); // typed PfdnDocument (refs as ids, defaults omitted)
const result = validate(doc); // strict, collects ALL errors as a Result
if (!result.ok) console.error(result.errors); // each with a JSON-Pointer instancePath
const host = await loadModelFromJson(doc); // JSON twin of loadModel — throws on invalid input
// host: { definitions, moddle } — a normalised ModelHost (ensureSettings + routeLinks applied)The validator and the document types are generated from the schema (pfdn.json) — zero runtime
dependencies. Pass { lax: true } to fromJson/loadModelFromJson to drop unresolvable references
instead of rejecting them.
The panel/toolbar chrome is themed with --pfd-color-* CSS custom properties. A dark scheme
follows the OS prefers-color-scheme automatically; force one per instance with a data-pfd-theme
attribute, and re-theme by overriding the tokens:
/* force dark on a container (or the <d3-polytree-editor> element) */
.my-editor[data-pfd-theme='dark'] {
}
/* or re-brand the chrome */
:root {
--pfd-color-accent-ink: #6c5ce7;
--pfd-color-surface: #faf7ff;
}High-contrast (forced-colors) maps the selection outline and focus rings to system colours. The
diagram content (nodes, links, zones, labels) keeps the colours authored in the document — it is your
data, not chrome, so it renders the same in every theme, and exported SVG is theme-invariant.
Compose your own didi modules through the modules option — they layer over the component's own,
last definition wins (no subclassing):
import { Editor } from '@d3-polytree/editor';
import { awsIconsModule } from '@d3-polytree/icons-amazon';
// a custom feature reacting to the event bus
const auditModule = {
__init__: ['audit'],
audit: [
'type',
class Audit {
static $inject = ['eventBus'];
constructor(bus) {
bus.on('selection.changed', (_p, next) => console.log(next.length, 'selected'));
}
}
]
};
new Editor({ container, modules: [awsIconsModule, auditModule] });The Storybook Guides/Kitchensink story shows a custom feature module, a custom node-type drawer, and the programmatic API end to end.
<script src="https://cdn.jsdelivr.net/npm/@d3-polytree/editor/dist/editor.umd.js"></script>
<script>
const editor = new d3PolytreeEditor.Editor({ container: document.body });
editor.createDiagram();
</script>- pnpm workspaces · Turborepo task graph · Changesets releases
- TypeScript (strict) · tsup builds (ESM + CJS +
.d.ts, plus UMD for the components) - Vitest (jsdom) · ESLint (flat) + Prettier · dart-sass for panel CSS
- Storybook (
@storybook/html-vite) — dev harness, visual-regression baseline, and the published docs site (GitHub Pages, deployed frommain)
pnpm install
pnpm build # turbo run build
pnpm test # turbo run test (vitest)
pnpm typecheck # turbo run typecheck (tsc --noEmit)
pnpm lint # eslint .
pnpm storybook # Storybook dev server
pnpm build-storybook # static Storybook build
pnpm changeset # record a version bumpVersioning and publishing are automated with Changesets + the Release GitHub Actions workflow.
Publishing is tokenless via npm Trusted Publishing (OIDC) — no long-lived npm token. Merge a
changeset to main, merge the generated Version Packages PR, and the changed packages publish
themselves.
MIT