Thank you for your interest in contributing to JointJS! This document provides guidelines and instructions for contributing.
- Node.js 22.14.0 (managed via Volta)
- Yarn 4.18.0
git clone https://github.com/clientIO/joint.git
cd joint
yarn install# Build distribution files
yarn dist
# Build all packages
yarn build# Run all tests
yarn test
# Run specific test types
yarn test-server # Server-side tests (Node.js/Mocha)
yarn test-client # Client-side tests (Browser/Karma/QUnit)
yarn test-ts # TypeScript type definition tests
yarn test-e2e # End-to-end tests (Puppeteer)# Check for linting errors
yarn lint
# Auto-fix linting errors
yarn lint-fixThis is a Yarn workspace monorepo. Main packages:
packages/joint-core- The main diagramming librarypackages/joint-react- React bindingspackages/joint-layout-directed-graph- Graph layout algorithmspackages/joint-layout-msagl- MSAGL layout integration
Before submitting a PR, please verify:
- Code is up-to-date with the
masterbranch - You've successfully run
yarn testlocally - If applicable, there are new or updated unit tests validating the change
- If applicable, there are new or updated @types
- If applicable, documentation has been updated
- If the change is releasable, you've added a changeset (
yarn changeset)
We use conventional commits. Format: type(scope): description
Examples:
fix(dia.Graph): correct batch event optionsfeat(dia.Paper): add new zoom featuredocs: update contributing guide
Types: feat, fix, style, refactor, test, chore, example
Versions and changelogs are managed by Changesets.
Every package keeps its own CHANGELOG.md. Most packages are versioned
independently; the exception is @joint/core, @joint/layout-directed-graph
and @joint/layout-msagl, which are linked - whenever two or more of them
are released in the same run, they all land on one shared version number.
Linking only applies to the packages actually being released, so the three do
drift apart between releases. See Releasing for the
details.
If your PR changes releasable code, add a changeset:
yarn changesetPick the affected package and the bump type (patch, minor, major), then
write the summary as described in Changeset format below.
Commit the generated .changeset/*.md file with your PR.
CI runs changeset status --since=origin/master and fails a PR that changes
releasable code in a public package without a changeset. Test-, docs-, demo- and
build-config-only changes are exempt - the exact list can be found in
changedFilePatterns in .changeset/config.json. If a
PR touches releasable files but should not trigger a release, add an empty
changeset:
yarn changeset add --emptyA changeset is a Markdown file in .changeset/ with YAML
frontmatter. The frontmatter says which packages the change releases; the
body is the changelog entry that gets written into each of those packages'
CHANGELOG.md:
---
"@joint/core": minor
---
dia.Paper - add `originX` and `originY` options to `getFitToContentArea()`Keep the body to a single line - one changeset produces exactly one changelog
bullet. Only the body's first line receives the - marker; any further lines
are indented beneath it and render as continuation text of that same bullet
rather than as entries of their own. So do not write your own -/* bullets or
Markdown headings in the body, and add another changeset file for every
additional changelog line you need. Most often that happens because a PR touches
several packages - see Frontmatter below.
Each key is a package name, each value is the bump type (patch, minor,
major). Listing more than one package in a single changeset should be
rare - the body is copied unchanged into every listed package's changelog,
which is only correct when the exact same sentence is right for all of them.
When one commit touches several packages, write a separate changeset per
package, each with a body phrased for that package's users.
Follow the changelog style already used in the packages' CHANGELOG.md files:
a scope, - (space-hyphen-space), then a short description.
Scope. Most commonly namespace.Class:
dia.Paper - add `getCellView()` method for strict view lookup
mvc.View - add `classNamePrefix` instance property to override the `joint-` CSS class prefix
elementTools.Control - respect the `padding` option when computing the handle position
layout.DirectedGraph - add `rankSep` optionFor @joint/react, the scope is the exported component or hook - components
written as JSX tags, hooks by name:
<Paper /> - fix the visual grid to redraw reactively when `drawGrid` changes
useCells - fix ghost cells reported after `resetCells()`Less commonly, a bare namespace when the change applies to everything in it
and repeating it per class would be noise:
anchors - add `rotate` option to all built-in anchors
connectionPoints - fix stroke-width handling on transformed elementsLeast commonly, no scope at all for overarching or architectural changes
that affect the whole package - then the body is just the description, with no
scope and no leading -:
drop support for Internet Explorer 11
publish native ESM alongside the UMD bundleThe one fixed exception is a brand-new package, which uses the literal scope
new package:
new package - idiomatic React components and hooks for JointJS, built directly on the core engineDescription. Keep it to less than ~100 characters. Start lowercase, no
trailing period. Lead with a verb (add, fix, deprecate, remove,
support); a bug fix reads naturally as fix <what> or fix to <do what>.
Code artifacts mentioned in the description - and most descriptions mention
at least one - go in backticks: `changeId`, `batch:start`,
`initializeUnmounted: true`, `drawGrid`. Function and method names
always carry trailing parentheses:
| Write | Not |
|---|---|
of `layout()` |
of the layout function |
of `layout()` |
of `layout()` function |
fix `toJSON()` to honor the option |
fix toJSON to honor the option |
Releasing is automated by
.github/workflows/release.yml, which runs on
every push to master:
- Version - while there are pending changesets, the workflow keeps a
changeset-release/masterPR ("Version Packages") up to date. That PR applies the version bumps, writes the per-packageCHANGELOG.mdentries and deletes the consumed changesets. - Publish - merging that PR is the release. The workflow then builds the
workspace, runs
changeset publish(which publishes throughyarn npm publish), and creates a git tag plus a GitHub Release for every published package.
Notes:
- Private packages are never versioned or published.
- A package is only dragged into a release by a dependency when the new version
falls outside its declared range, and only through a runtime dependency -
a
devDependenciesentry never causes one.workspace:~expands to~<core's current version>, so@joint/layout-directed-graphand@joint/layout-msaglget an automatic patch release on a@joint/coreminor or major, but not on a@joint/corepatch -4.3.2still satisfies~4.3.1.@joint/decoratorsand@joint/reactuseworkspace:^, so they only ride along on a@joint/coremajor. @joint/core,@joint/layout-directed-graphand@joint/layout-msaglare linked, so any of them released together share one version (the highest bump type in the run, applied to the group's highest current version). Linking only covers the packages in that run - a linked package with nothing to release keeps its current version, which is how@joint/corecan sit at4.3.1while both layout packages are still at4.3.0. Every other package versions independently.- Prereleases use the standard changesets pre mode:
yarn changeset pre enter betaonmaster, release as usual, thenyarn changeset pre exit. - Snapshot releases:
yarn changeset version --snapshot+yarn changeset publish --tag.
- TypeScript strict mode is enabled; its settings are per package, not repo-wide
- ESLint flat config (v9) via
@joint/eslint-config - Run
yarn lint-fixbefore committing
- Open an issue on GitHub
- Visit jointjs.com for documentation