Skip to content

Repository files navigation

d3-polytree (v2 monorepo)

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 SimpleNetwork viewer) is preserved on the v1 branch. main is this modernized, TypeScript monorepo. See ROADMAP.md for 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.

Packages

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.

Install

# 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-drag

Quick start

import { 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 .pfdn

JSON documents (typed + validated)

Besides .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.

Theming

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.

Extending

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> (UMD) usage

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

Monorepo / toolchain

  • 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 from main)
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 bump

Releases

Versioning 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.

License

MIT

About

Simple directed node networks with D3js

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages