Merge branch 'develop' into knsv/5342-kanban

This commit is contained in:
Knut Sveidqvist 2024-10-25 14:56:46 +02:00
commit fb86e5c689
87 changed files with 4661 additions and 3568 deletions

View File

@ -1,3 +1,9 @@
export interface PackageOptions {
name: string;
packageName: string;
file: string;
}
/** /**
* Shared common options for both ESBuild and Vite * Shared common options for both ESBuild and Vite
*/ */
@ -27,4 +33,4 @@ export const packageOptions = {
packageName: 'mermaid-layout-elk', packageName: 'mermaid-layout-elk',
file: 'layouts.ts', file: 'layouts.ts',
}, },
} as const; } as const satisfies Record<string, PackageOptions>;

View File

@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: Jagged edge fix for icon shape

View File

@ -0,0 +1,5 @@
---
'mermaid': patch
---
Add missing TypeScript dependencies

View File

@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: Icon color fix for colored icons.

View File

@ -8,7 +8,10 @@ import { defaultOptions, getBuildConfig } from './util.js';
const shouldVisualize = process.argv.includes('--visualize'); const shouldVisualize = process.argv.includes('--visualize');
const buildPackage = async (entryName: keyof typeof packageOptions) => { const buildPackage = async (entryName: keyof typeof packageOptions) => {
const commonOptions: MermaidBuildOptions = { ...defaultOptions, entryName } as const; const commonOptions: MermaidBuildOptions = {
...defaultOptions,
options: packageOptions[entryName],
} as const;
const buildConfigs: MermaidBuildOptions[] = [ const buildConfigs: MermaidBuildOptions[] = [
// package.mjs // package.mjs
{ ...commonOptions }, { ...commonOptions },
@ -40,7 +43,7 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => {
continue; continue;
} }
const fileName = Object.keys(metafile.outputs) const fileName = Object.keys(metafile.outputs)
.find((file) => !file.includes('chunks') && file.endsWith('js')) .find((file) => !file.includes('chunks') && file.endsWith('js'))!
.replace('dist/', ''); .replace('dist/', '');
// Upload metafile into https://esbuild.github.io/analyze/ // Upload metafile into https://esbuild.github.io/analyze/
await writeFile(`stats/${fileName}.meta.json`, JSON.stringify(metafile)); await writeFile(`stats/${fileName}.meta.json`, JSON.stringify(metafile));

View File

@ -9,13 +9,18 @@ import { generateLangium } from '../.build/generateLangium.js';
import { defaultOptions, getBuildConfig } from './util.js'; import { defaultOptions, getBuildConfig } from './util.js';
const configs = Object.values(packageOptions).map(({ packageName }) => const configs = Object.values(packageOptions).map(({ packageName }) =>
getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: packageName }) getBuildConfig({
...defaultOptions,
minify: false,
core: false,
options: packageOptions[packageName],
})
); );
const mermaidIIFEConfig = getBuildConfig({ const mermaidIIFEConfig = getBuildConfig({
...defaultOptions, ...defaultOptions,
minify: false, minify: false,
core: false, core: false,
entryName: 'mermaid', options: packageOptions.mermaid,
format: 'iife', format: 'iife',
}); });
configs.push(mermaidIIFEConfig); configs.push(mermaidIIFEConfig);

View File

@ -3,7 +3,7 @@ import { fileURLToPath } from 'url';
import type { BuildOptions } from 'esbuild'; import type { BuildOptions } from 'esbuild';
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import jsonSchemaPlugin from './jsonSchemaPlugin.js'; import jsonSchemaPlugin from './jsonSchemaPlugin.js';
import { packageOptions } from '../.build/common.js'; import type { PackageOptions } from '../.build/common.js';
import { jisonPlugin } from './jisonPlugin.js'; import { jisonPlugin } from './jisonPlugin.js';
const __dirname = fileURLToPath(new URL('.', import.meta.url)); const __dirname = fileURLToPath(new URL('.', import.meta.url));
@ -13,10 +13,10 @@ export interface MermaidBuildOptions extends BuildOptions {
core: boolean; core: boolean;
metafile: boolean; metafile: boolean;
format: 'esm' | 'iife'; format: 'esm' | 'iife';
entryName: keyof typeof packageOptions; options: PackageOptions;
} }
export const defaultOptions: Omit<MermaidBuildOptions, 'entryName'> = { export const defaultOptions: Omit<MermaidBuildOptions, 'entryName' | 'options'> = {
minify: false, minify: false,
metafile: false, metafile: false,
core: false, core: false,
@ -52,9 +52,14 @@ const getFileName = (fileName: string, { core, format, minify }: MermaidBuildOpt
}; };
export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => { export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
const { core, entryName, metafile, format, minify } = options; const {
core,
metafile,
format,
minify,
options: { name, file, packageName },
} = options;
const external: string[] = ['require', 'fs', 'path']; const external: string[] = ['require', 'fs', 'path'];
const { name, file, packageName } = packageOptions[entryName];
const outFileName = getFileName(name, options); const outFileName = getFileName(name, options);
const output: BuildOptions = buildOptions({ const output: BuildOptions = buildOptions({
absWorkingDir: resolve(__dirname, `../packages/${packageName}`), absWorkingDir: resolve(__dirname, `../packages/${packageName}`),

View File

@ -19,7 +19,7 @@ jobs:
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
cache: pnpm cache: pnpm
node-version-file: '.node-version' node-version-file: '.node-version'

View File

@ -23,7 +23,7 @@ jobs:
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
cache: pnpm cache: pnpm
node-version-file: '.node-version' node-version-file: '.node-version'

View File

@ -36,7 +36,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
with: with:
config-file: ./.github/codeql/codeql-config.yml config-file: ./.github/codeql/codeql-config.yml
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
@ -48,7 +48,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 uses: github/codeql-action/autobuild@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@ -62,4 +62,4 @@ jobs:
# make release # make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12

View File

@ -38,7 +38,7 @@ jobs:
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'

53
.github/workflows/e2e-timings.yml vendored Normal file
View File

@ -0,0 +1,53 @@
name: E2E - Generate Timings
on:
# run this workflow every night at 3am
schedule:
- cron: '28 3 * * *'
# or when the user triggers it from GitHub Actions page
workflow_dispatch:
concurrency: ${{ github.workflow }}-${{ github.ref }}
permissions:
contents: write
jobs:
timings:
runs-on: ubuntu-latest
container:
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
options: --user 1001
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
- name: Setup Node.js
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with:
node-version-file: '.node-version'
- name: Install dependencies
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
with:
runTests: false
- name: Cypress run
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
id: cypress
with:
install: false
start: pnpm run dev:coverage
wait-on: 'http://localhost:9000'
browser: chrome
publish-summary: false
env:
VITEST_COVERAGE: true
CYPRESS_COMMIT: ${{ github.sha }}
SPLIT: 1
SPLIT_INDEX: 0
SPLIT_FILE: 'cypress/timings.json'
- name: Commit changes
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4
with:
add: 'cypress/timings.json'
author_name: 'github-actions[bot]'
author_email: '41898282+github-actions[bot]@users.noreply.github.com'
message: 'chore: update E2E timings'

View File

@ -28,7 +28,6 @@ env:
) || ) ||
github.event.before github.event.before
}} }}
shouldRunParallel: ${{ secrets.CYPRESS_RECORD_KEY != '' && !(github.event_name == 'push' && github.ref == 'refs/heads/develop') }}
jobs: jobs:
cache: cache:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -39,7 +38,7 @@ jobs:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
- name: Cache snapshots - name: Cache snapshots
@ -59,7 +58,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }} if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
uses: cypress-io/github-action@df7484c5ba85def7eef30db301afa688187bc378 # v6.7.2 uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
with: with:
# just perform install # just perform install
runTests: false runTests: false
@ -80,7 +79,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
containers: [1, 2, 3, 4] containers: [1, 2, 3, 4, 5]
steps: steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
@ -88,7 +87,7 @@ jobs:
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
@ -101,7 +100,7 @@ jobs:
key: ${{ runner.os }}-snapshots-${{ env.targetHash }} key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
- name: Install dependencies - name: Install dependencies
uses: cypress-io/github-action@df7484c5ba85def7eef30db301afa688187bc378 # v6.7.2 uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
with: with:
runTests: false runTests: false
@ -117,11 +116,8 @@ jobs:
# Install NPM dependencies, cache them correctly # Install NPM dependencies, cache them correctly
# and run all Cypress tests # and run all Cypress tests
- name: Cypress run - name: Cypress run
uses: cypress-io/github-action@df7484c5ba85def7eef30db301afa688187bc378 # v6.7.2 uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
id: cypress id: cypress
# If CYPRESS_RECORD_KEY is set, run in parallel on all containers
# Otherwise (e.g. if running from fork), we run on a single container only
if: ${{ env.shouldRunParallel == 'true' || ( matrix.containers == 1 ) }}
with: with:
install: false install: false
start: pnpm run dev:coverage start: pnpm run dev:coverage
@ -129,16 +125,18 @@ jobs:
browser: chrome browser: chrome
# Disable recording if we don't have an API key # Disable recording if we don't have an API key
# e.g. if this action was run from a fork # e.g. if this action was run from a fork
record: ${{ env.shouldRunParallel == 'true' }} record: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
parallel: ${{ env.shouldRunParallel == 'true' }}
env: env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
VITEST_COVERAGE: true VITEST_COVERAGE: true
CYPRESS_COMMIT: ${{ github.sha }} CYPRESS_COMMIT: ${{ github.sha }}
ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }} ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }}
ARGOS_PARALLEL: ${{ env.shouldRunParallel == 'true' }} ARGOS_PARALLEL: true
ARGOS_PARALLEL_TOTAL: 4 ARGOS_PARALLEL_TOTAL: ${{ strategy.job-total }}
ARGOS_PARALLEL_INDEX: ${{ matrix.containers }} ARGOS_PARALLEL_INDEX: ${{ matrix.containers }}
SPLIT: ${{ strategy.job-total }}
SPLIT_INDEX: ${{ strategy.job-index }}
SPLIT_FILE: 'cypress/timings.json'
- name: Upload Coverage to Codecov - name: Upload Coverage to Codecov
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0

View File

@ -29,7 +29,7 @@ jobs:
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
cache: pnpm cache: pnpm
node-version-file: '.node-version' node-version-file: '.node-version'

View File

@ -28,7 +28,7 @@ jobs:
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
cache: pnpm cache: pnpm
node-version-file: '.node-version' node-version-file: '.node-version'

View File

@ -16,7 +16,7 @@ jobs:
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
cache: pnpm cache: pnpm
node-version-file: '.node-version' node-version-file: '.node-version'

View File

@ -31,7 +31,7 @@ jobs:
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
cache: pnpm cache: pnpm
node-version-file: '.node-version' node-version-file: '.node-version'

View File

@ -26,7 +26,7 @@ jobs:
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
cache: pnpm cache: pnpm
node-version-file: '.node-version' node-version-file: '.node-version'
@ -36,7 +36,7 @@ jobs:
- name: Create Release Pull Request or Publish to npm - name: Create Release Pull Request or Publish to npm
id: changesets id: changesets
uses: changesets/action@aba318e9165b45b7948c60273e0b72fce0a64eb9 # v1.4.7 uses: changesets/action@3de3850952bec538fde60aac71731376e57b9b57 # v1.4.8
with: with:
version: pnpm changeset:version version: pnpm changeset:version
publish: pnpm changeset:publish publish: pnpm changeset:publish

View File

@ -16,11 +16,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with: with:
persist-credentials: false persist-credentials: false
- name: Run analysis - name: Run analysis
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
with: with:
results_file: results.sarif results_file: results.sarif
results_format: sarif results_format: sarif
@ -32,6 +32,6 @@ jobs:
path: results.sarif path: results.sarif
retention-days: 5 retention-days: 5
- name: Upload to code-scanning - name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@f0f3afee809481da311ca3a6ff1ff51d81dbeb24 # v3.26.4 uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
with: with:
sarif_file: results.sarif sarif_file: results.sarif

View File

@ -15,7 +15,7 @@ jobs:
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
with: with:
cache: pnpm cache: pnpm
node-version-file: '.node-version' node-version-file: '.node-version'

View File

@ -1,8 +1,9 @@
import { defineConfig } from 'cypress';
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';
import coverage from '@cypress/code-coverage/task';
import eyesPlugin from '@applitools/eyes-cypress'; import eyesPlugin from '@applitools/eyes-cypress';
import { registerArgosTask } from '@argos-ci/cypress/task'; import { registerArgosTask } from '@argos-ci/cypress/task';
import coverage from '@cypress/code-coverage/task';
import { defineConfig } from 'cypress';
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';
import cypressSplit from 'cypress-split';
export default eyesPlugin( export default eyesPlugin(
defineConfig({ defineConfig({
@ -13,6 +14,7 @@ export default eyesPlugin(
specPattern: 'cypress/integration/**/*.{js,ts}', specPattern: 'cypress/integration/**/*.{js,ts}',
setupNodeEvents(on, config) { setupNodeEvents(on, config) {
coverage(on, config); coverage(on, config);
cypressSplit(on, config);
on('before:browser:launch', (browser, launchOptions) => { on('before:browser:launch', (browser, launchOptions) => {
if (browser.name === 'chrome' && browser.isHeadless) { if (browser.name === 'chrome' && browser.isHeadless) {
launchOptions.args.push('--window-size=1440,1024', '--force-device-scale-factor=1'); launchOptions.args.push('--window-size=1440,1024', '--force-device-scale-factor=1');

View File

@ -124,3 +124,20 @@ describe('Test iconShape with different h', () => {
imgSnapshotTest(flowchartCode); imgSnapshotTest(flowchartCode);
}); });
}); });
describe('Test colored iconShape', () => {
it('with no styles', () => {
let flowchartCode = `flowchart TB\n`;
const icon = 'fluent-emoji:tropical-fish';
flowchartCode += ` nA --> nAA@{ icon: '${icon}', form: 'square', label: 'icon with color' }\n`;
imgSnapshotTest(flowchartCode);
});
it('with styles', () => {
let flowchartCode = `flowchart TB\n`;
const icon = 'fluent-emoji:tropical-fish';
flowchartCode += ` nA --> nAA@{ icon: '${icon}', form: 'square', label: 'icon with color' }\n`;
flowchartCode += ` style nAA fill:#f9f,stroke:#333,stroke-width:4px \n`;
imgSnapshotTest(flowchartCode);
});
});

File diff suppressed because one or more lines are too long

152
cypress/timings.json Normal file
View File

@ -0,0 +1,152 @@
{
"durations": [
{
"spec": "cypress/integration/other/configuration.spec.js",
"duration": 4989
},
{
"spec": "cypress/integration/other/external-diagrams.spec.js",
"duration": 1382
},
{
"spec": "cypress/integration/other/ghsa.spec.js",
"duration": 3178
},
{
"spec": "cypress/integration/other/iife.spec.js",
"duration": 1372
},
{
"spec": "cypress/integration/other/interaction.spec.js",
"duration": 8998
},
{
"spec": "cypress/integration/other/rerender.spec.js",
"duration": 1249
},
{
"spec": "cypress/integration/other/xss.spec.js",
"duration": 25664
},
{
"spec": "cypress/integration/rendering/appli.spec.js",
"duration": 1928
},
{
"spec": "cypress/integration/rendering/architecture.spec.ts",
"duration": 2330
},
{
"spec": "cypress/integration/rendering/block.spec.js",
"duration": 11156
},
{
"spec": "cypress/integration/rendering/c4.spec.js",
"duration": 3418
},
{
"spec": "cypress/integration/rendering/classDiagram-v2.spec.js",
"duration": 14866
},
{
"spec": "cypress/integration/rendering/classDiagram.spec.js",
"duration": 9894
},
{
"spec": "cypress/integration/rendering/conf-and-directives.spec.js",
"duration": 5778
},
{
"spec": "cypress/integration/rendering/current.spec.js",
"duration": 1690
},
{
"spec": "cypress/integration/rendering/erDiagram.spec.js",
"duration": 9144
},
{
"spec": "cypress/integration/rendering/errorDiagram.spec.js",
"duration": 1951
},
{
"spec": "cypress/integration/rendering/flowchart-elk.spec.js",
"duration": 2196
},
{
"spec": "cypress/integration/rendering/flowchart-handDrawn.spec.js",
"duration": 21029
},
{
"spec": "cypress/integration/rendering/flowchart-shape-alias.spec.ts",
"duration": 16087
},
{
"spec": "cypress/integration/rendering/flowchart-v2.spec.js",
"duration": 27465
},
{
"spec": "cypress/integration/rendering/flowchart.spec.js",
"duration": 20035
},
{
"spec": "cypress/integration/rendering/gantt.spec.js",
"duration": 11366
},
{
"spec": "cypress/integration/rendering/gitGraph.spec.js",
"duration": 34025
},
{
"spec": "cypress/integration/rendering/iconShape.spec.ts",
"duration": 185902
},
{
"spec": "cypress/integration/rendering/imageShape.spec.ts",
"duration": 41631
},
{
"spec": "cypress/integration/rendering/info.spec.ts",
"duration": 1736
},
{
"spec": "cypress/integration/rendering/journey.spec.js",
"duration": 2247
},
{
"spec": "cypress/integration/rendering/katex.spec.js",
"duration": 2144
},
{
"spec": "cypress/integration/rendering/marker_unique_id.spec.js",
"duration": 1646
},
{
"spec": "cypress/integration/rendering/mindmap.spec.ts",
"duration": 6406
},
{
"spec": "cypress/integration/rendering/newShapes.spec.ts",
"duration": 107219
},
{
"spec": "cypress/integration/rendering/stateDiagram.spec.js",
"duration": 15834
},
{
"spec": "cypress/integration/rendering/theme.spec.js",
"duration": 33240
},
{
"spec": "cypress/integration/rendering/timeline.spec.ts",
"duration": 7122
},
{
"spec": "cypress/integration/rendering/xyChart.spec.js",
"duration": 11127
},
{
"spec": "cypress/integration/rendering/zenuml.spec.js",
"duration": 2391
}
]
}

View File

@ -101,7 +101,7 @@ To add a new shape:
- **Example**: - **Example**:
```typescript ```typescript
import { Node, RenderOptions } from '../../types.d.ts'; import { Node, RenderOptions } from '../../types.ts';
export const myNewShape = async ( export const myNewShape = async (
parent: SVGAElement, parent: SVGAElement,
@ -117,7 +117,7 @@ To add a new shape:
### 2. Register the Shape ### 2. Register the Shape
- **Register the shape**: Add your shape to the `shapes` object in the main shapes module. This allows your shape to be recognized and used within the system. - **Register the shape**: Add your shape to the `shapes` object in the [main shapes module](../rendering-util/rendering-elements/shapes.ts). This allows your shape to be recognized and used within the system.
- **Example**: - **Example**:
@ -126,9 +126,14 @@ To add a new shape:
const shapes = { const shapes = {
..., ...,
'my-new-shape': myNewShape, {
// Shortened alias (if any). semanticName: 'My Shape',
'm-nsh': myNewShape name: 'Shape Name',
shortName: '<short-name>',
description: '<Description for the shape>',
aliases: ['<alias-one>', '<al-on>', '<alias-two>', '<al-two>'],
handler: myNewShape,
},
}; };
``` ```

55
docs/config/icons.md Normal file
View File

@ -0,0 +1,55 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/icons.md](../../packages/mermaid/src/docs/config/icons.md).
# Registering icon pack in mermaid
The icon packs available can be found at [icones.js.org](https://icones.js.org/).
We use the name defined when registering the icon pack, to override the prefix field of the iconify pack. This allows the user to use shorter names for the icons. It also allows us to load a particular pack only when it is used in a diagram.
Using JSON file directly from CDN:
```js
import mermaid from 'CDN/mermaid.esm.mjs';
mermaid.registerIconPacks([
{
name: 'logos',
loader: () =>
fetch('https://unpkg.com/@iconify-json/logos@1/icons.json').then((res) => res.json()),
},
]);
```
Using packages and a bundler:
```bash
npm install @iconify-json/logos@1
```
With lazy loading
```js
import mermaid from 'mermaid';
mermaid.registerIconPacks([
{
name: 'logos',
loader: () => import('@iconify-json/logos').then((module) => module.icons),
},
]);
```
Without lazy loading
```js
import mermaid from 'mermaid';
import { icons } from '@iconify-json/logos';
mermaid.registerIconPacks([
{
name: icons.prefix, // To use the prefix defined in the icon pack
icons,
},
]);
```

View File

@ -127,7 +127,7 @@ Error.prepareStackTrace
#### Defined in #### Defined in
node_modules/.pnpm/@types+node\@20.16.2/node_modules/@types/node/globals.d.ts:28 node_modules/.pnpm/@types+node\@20.16.11/node_modules/@types/node/globals.d.ts:98
--- ---
@ -141,7 +141,7 @@ Error.stackTraceLimit
#### Defined in #### Defined in
node_modules/.pnpm/@types+node\@20.16.2/node_modules/@types/node/globals.d.ts:30 node_modules/.pnpm/@types+node\@20.16.11/node_modules/@types/node/globals.d.ts:100
## Methods ## Methods
@ -168,4 +168,4 @@ Error.captureStackTrace
#### Defined in #### Defined in
node_modules/.pnpm/@types+node\@20.16.2/node_modules/@types/node/globals.d.ts:21 node_modules/.pnpm/@types+node\@20.16.11/node_modules/@types/node/globals.d.ts:91

View File

@ -200,15 +200,22 @@ Communication tools and platforms
- [Vim](https://www.vim.org) - [Vim](https://www.vim.org)
- [Vim Diagram Syntax](https://github.com/zhaozg/vim-diagram) - [Vim Diagram Syntax](https://github.com/zhaozg/vim-diagram)
- [Official Vim Syntax and ft plugin](https://github.com/craigmac/vim-mermaid) - [Official Vim Syntax and ft plugin](https://github.com/craigmac/vim-mermaid)
- [Zed](https://zed.dev)
- [zed-mermaid](https://github.com/gabeidx/zed-mermaid)
### Document Generation ### Document Generation
- [Astro](https://astro.build/)
- [Adding diagrams to your Astro site with MermaidJS and Playwright](https://agramont.net/blog/diagraming-with-mermaidjs-astro/)
- [Codedoc](https://codedoc.cc/) - [Codedoc](https://codedoc.cc/)
- [codedoc-mermaid-plugin](https://www.npmjs.com/package/codedoc-mermaid-plugin) - [codedoc-mermaid-plugin](https://www.npmjs.com/package/codedoc-mermaid-plugin)
- [Docsy Hugo Theme](https://www.docsy.dev/docs/adding-content/lookandfeel/#diagrams-with-mermaid) ✅ - [Docsy Hugo Theme](https://www.docsy.dev/docs/adding-content/lookandfeel/#diagrams-with-mermaid) ✅
- [Docusaurus](https://docusaurus.io/docs/markdown-features/diagrams) ✅ - [Docusaurus](https://docusaurus.io/docs/markdown-features/diagrams) ✅
- [Gatsby](https://www.gatsbyjs.com/) - [Gatsby](https://www.gatsbyjs.com/)
- [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid) - [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid)
- [Jekyll](https://jekyllrb.com/)
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
- [JSDoc](https://jsdoc.app/) - [JSDoc](https://jsdoc.app/)
- [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid) - [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid)
- [Madness](https://madness.dannyb.co/) - [Madness](https://madness.dannyb.co/)
@ -217,7 +224,7 @@ Communication tools and platforms
- [MkDocs](https://www.mkdocs.org) - [MkDocs](https://www.mkdocs.org)
- [mkdocs-mermaid2-plugin](https://github.com/fralau/mkdocs-mermaid2-plugin) - [mkdocs-mermaid2-plugin](https://github.com/fralau/mkdocs-mermaid2-plugin)
- [mkdocs-material](https://github.com/squidfunk/mkdocs-material), check the [docs](https://squidfunk.github.io/mkdocs-material/reference/diagrams/) - [mkdocs-material](https://github.com/squidfunk/mkdocs-material), check the [docs](https://squidfunk.github.io/mkdocs-material/reference/diagrams/)
- [Quarto](https://quarto.org/) - [Quarto](https://quarto.org/)
- [rehype](https://github.com/rehypejs/rehype) - [rehype](https://github.com/rehypejs/rehype)
- [rehype-mermaid](https://github.com/remcohaszing/rehype-mermaid) - [rehype-mermaid](https://github.com/remcohaszing/rehype-mermaid)
- [remark](https://remark.js.org/) - [remark](https://remark.js.org/)
@ -246,17 +253,12 @@ Communication tools and platforms
### Other ### Other
- [Astro](https://astro.build/)
- [Adding diagrams to your Astro site with MermaidJS and Playwright](https://agramont.net/blog/diagraming-with-mermaidjs-astro/)
- [Bisheng](https://www.npmjs.com/package/bisheng) - [Bisheng](https://www.npmjs.com/package/bisheng)
- [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid) - [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid)
- [Blazorade Mermaid: Render Mermaid diagrams in Blazor applications](https://github.com/Blazorade/Blazorade-Mermaid/wiki) - [Blazorade Mermaid: Render Mermaid diagrams in Blazor applications](https://github.com/Blazorade/Blazorade-Mermaid/wiki)
- [Codemia: A tool to practice system design problems](https://codemia.io) ✅ - [Codemia: A tool to practice system design problems](https://codemia.io) ✅
- [ExDoc](https://github.com/elixir-lang/ex_doc) - [ExDoc](https://github.com/elixir-lang/ex_doc)
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs) - [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
- [Jekyll](https://jekyllrb.com/)
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
- [MarkChart: Preview Mermaid diagrams on macOS](https://markchart.app/) - [MarkChart: Preview Mermaid diagrams on macOS](https://markchart.app/)
- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic) - [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic)
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server) - [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)

View File

@ -94,10 +94,8 @@ Mermaid offers a variety of styles or “looks” for your diagrams, allowing yo
**Available Looks:** **Available Looks:**
``` - Hand-Drawn Look: For a more personal, creative touch, the hand-drawn look brings a sketch-like quality to your diagrams. This style is perfect for informal settings or when you want to add a bit of personality to your diagrams.
• Hand-Drawn Look: For a more personal, creative touch, the hand-drawn look brings a sketch-like quality to your diagrams. This style is perfect for informal settings or when you want to add a bit of personality to your diagrams. - Classic Look: If you prefer the traditional Mermaid style, the classic look maintains the original appearance that many users are familiar with. Its great for consistency across projects or when you want to keep the familiar aesthetic.
• Classic Look: If you prefer the traditional Mermaid style, the classic look maintains the original appearance that many users are familiar with. Its great for consistency across projects or when you want to keep the familiar aesthetic.
```
**How to Select a Look:** **How to Select a Look:**
@ -133,10 +131,8 @@ In addition to customizing the look of your diagrams, Mermaid Chart now allows y
#### Supported Layout Algorithms: #### Supported Layout Algorithms:
``` - Dagre (default): This is the classic layout algorithm that has been used in Mermaid for a long time. It provides a good balance of simplicity and visual clarity, making it ideal for most diagrams.
• Dagre (default): This is the classic layout algorithm that has been used in Mermaid for a long time. It provides a good balance of simplicity and visual clarity, making it ideal for most diagrams. - ELK: For those who need more sophisticated layout capabilities, especially when working with large or intricate diagrams, the ELK (Eclipse Layout Kernel) layout offers advanced options. It provides a more optimized arrangement, potentially reducing overlapping and improving readability. This is not included out the box but needs to be added when integrating mermaid for sites/applications that want to have elk support.
• ELK: For those who need more sophisticated layout capabilities, especially when working with large or intricate diagrams, the ELK (Eclipse Layout Kernel) layout offers advanced options. It provides a more optimized arrangement, potentially reducing overlapping and improving readability. This is not included out the box but needs to be added when integrating mermaid for sites/applications that want to have elk support.
```
#### How to Select a Layout Algorithm: #### How to Select a Layout Algorithm:

View File

@ -79,15 +79,15 @@ service {service id}({icon name})[{title}] (in {parent id})?
Put together: Put together:
``` ```
service database(db)[Database] service database1(database)[My Database]
``` ```
creates the service identified as `database`, using the icon `db`, with the label `Database`. creates the service identified as `database1`, using the icon `database`, with the label `My Database`.
If the service belongs to a group, it can be placed inside it through the optional `in` keyword If the service belongs to a group, it can be placed inside it through the optional `in` keyword
``` ```
service database(db)[Database] in private_api service database1(database)[My Database] in private_api
``` ```
### Edges ### Edges
@ -194,55 +194,7 @@ architecture-beta
## Icons ## Icons
By default, architecture diagram supports the following icons: `cloud`, `database`, `disk`, `internet`, `server`. By default, architecture diagram supports the following icons: `cloud`, `database`, `disk`, `internet`, `server`.
Users can use any of the 200,000+ icons available in iconify.design, or add their own custom icons, by following the steps below. Users can use any of the 200,000+ icons available in iconify.design, or add their own custom icons, by following the steps [here](../config/icons.md).
The icon packs available can be found at [icones.js.org](https://icones.js.org/).
We use the name defined when registering the icon pack, to override the prefix field of the iconify pack. This allows the user to use shorter names for the icons. It also allows us to load a particular pack only when it is used in a diagram.
Using JSON file directly from CDN:
```js
import mermaid from 'CDN/mermaid.esm.mjs';
mermaid.registerIconPacks([
{
name: 'logos',
loader: () =>
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
},
]);
```
Using packages and a bundler:
```bash
npm install @iconify-json/logos
```
With lazy loading
```js
import mermaid from 'mermaid';
mermaid.registerIconPacks([
{
name: 'logos',
loader: () => import('@iconify-json/logos').then((module) => module.icons),
},
]);
```
Without lazy loading
```js
import mermaid from 'mermaid';
import { icons } from '@iconify-json/logos';
mermaid.registerIconPacks([
{
name: icons.prefix, // To use the prefix defined in the icon pack
icons,
},
]);
```
After the icons are installed, they can be used in the architecture diagram by using the format "name:icon-name", where name is the value used when registering the icon pack. After the icons are installed, they can be used in the architecture diagram by using the format "name:icon-name", where name is the value used when registering the icon pack.

View File

@ -141,7 +141,7 @@ block-beta
a["A label"] b:2 c:2 d a["A label"] b:2 c:2 d
``` ```
In this example, the block labeled "A wide one" spans two columns, while blocks 'b', 'c', and 'd' are allocated their own columns. This flexibility in block sizing is crucial for accurately representing systems with components of varying significance or size. In this example, the block labeled "A labels" spans one column, while blocks 'b', 'c' span 2 columns, and 'd' is again allocated its own column. This flexibility in block sizing is crucial for accurately representing systems with components of varying significance or size.
### Creating Composite Blocks ### Creating Composite Blocks

View File

@ -317,52 +317,53 @@ This syntax creates a node A as a rectangle. It renders in the same way as `A["A
Below is a comprehensive list of the newly introduced shapes and their corresponding semantic meanings, short names, and aliases: Below is a comprehensive list of the newly introduced shapes and their corresponding semantic meanings, short names, and aliases:
| **Semantic Name** | **Shape Name** | **Short Name** | **Description** | **Alias Supported** | | **Semantic Name** | **Shape Name** | **Short Name** | **Description** | **Alias Supported** |
| ------------------------------------- | ---------------------- | -------------- | ------------------------------ | -------------------------------------------------------------- | | --------------------------------- | ---------------------- | -------------- | ------------------------------ | ---------------------------------------------------------------- |
| **Process** | Rectangle | `rect` | Standard process shape | `proc`, `process`, `rectangle` | | Card | Notched Rectangle | `notch-rect` | Represents a card | `card`, `notched-rectangle` |
| **Event** | Rounded Rectangle | `rounded` | Represents an event | `event` | | Collate | Hourglass | `hourglass` | Represents a collate operation | `collate`, `hourglass` |
| **Terminal Point** | Stadium | `stadium` | Terminal point | `terminal`, `pill` | | Com Link | Lightning Bolt | `bolt` | Communication link | `com-link`, `lightning-bolt` |
| **Subprocess** | Framed Rectangle | `fr-rect` | Subprocess | `subprocess`,`subproc`, `framed-rectangle`, `subroutine` | | Comment | Curly Brace | `brace` | Adds a comment | `brace-l`, `comment` |
| **Database** | Cylinder | `cyl` | Database storage | `db`, `database`, `cylinder` | | Comment Right | Curly Brace | `brace-r` | Adds a comment | |
| **Start** | Circle | `circle` | Starting point | `circ` | | Comment with braces on both sides | Curly Braces | `braces` | Adds a comment | |
| **Odd** | Odd | `odd` | Odd shape | | | Data Input/Output | Lean Right | `lean-r` | Represents input or output | `in-out`, `lean-right` |
| **Decision** | Diamond | `diam` | Decision-making step | `decision`, `diamond` | | Data Input/Output | Lean Left | `lean-l` | Represents output or input | `lean-left`, `out-in` |
| **Prepare Conditional** | Hexagon | `hex` | Preparation or condition step | `hexagon`, `prepare` | | Database | Cylinder | `cyl` | Database storage | `cylinder`, `database`, `db` |
| **Data Input/Output** | Lean Right | `lean-r` | Represents input or output | `lean-right`, `in-out` | | Decision | Diamond | `diam` | Decision-making step | `decision`, `diamond`, `question` |
| **Data Input/Output** | Lean Left | `lean-l` | Represents output or input | `lean-left`, `out-in` | | Delay | Half-Rounded Rectangle | `delay` | Represents a delay | `half-rounded-rectangle` |
| **Priority Action** | Trapezoid Base Bottom | `trap-b` | Priority action | `priority`, `trapezoid-bottom` | | Direct Access Storage | Horizontal Cylinder | `h-cyl` | Direct access storage | `das`, `horizontal-cylinder` |
| **Manual Operation** | Trapezoid Base Top | `trap-t` | Represents a manual task | `manual`, `trapezoid-top` | | Disk Storage | Lined Cylinder | `lin-cyl` | Disk storage | `disk`, `lined-cylinder` |
| **Stop** | Double Circle | `dbl-circ` | Represents a stop point | `double-circle` | | Display | Curved Trapezoid | `curv-trap` | Represents a display | `curved-trapezoid`, `display` |
| **Text Block** | Text Block | `text` | Text block | - | | Divided Process | Divided Rectangle | `div-rect` | Divided process shape | `div-proc`, `divided-process`, `divided-rectangle` |
| **Card** | Notched Rectangle | `notch-rect` | Represents a card | `card`, `notched-rectangle` | | Document | Document | `doc` | Represents a document | `doc`, `document` |
| **Lined/Shaded Process** | Lined Rectangle | `lin-rect` | Lined process shape | `lined-rectangle`,`lined-process`, `lin-proc`,`shaded-process` | | Event | Rounded Rectangle | `rounded` | Represents an event | `event` |
| **Start** | Small Circle | `sm-circ` | Small starting point | `start`, `small-circle` | | Extract | Triangle | `tri` | Extraction process | `extract`, `triangle` |
| **Stop** | Framed Circle | `fr-circ` | Stop point | `stop`, `framed-circle` | | Fork/Join | Filled Rectangle | `fork` | Fork or join in process flow | `join` |
| **Fork/Join** | Filled Rectangle | `fork` | Fork or join in process flow | `join` | | Internal Storage | Window Pane | `win-pane` | Internal storage | `internal-storage`, `window-pane` |
| **Collate** | Hourglass | `hourglass` | Represents a collate operation | `hourglass` | | Junction | Filled Circle | `f-circ` | Junction point | `filled-circle`, `junction` |
| **Comment** | Curly Brace | `brace` | Adds a comment | `comment`, `brace-l` | | Kanban Item | Kanban Item | `kanbanItem` | Item on a kanban board | `kanban-item` |
| **Comment Right** | Curly Brace | `brace-r` | Adds a comment | - | | Lined Document | Lined Document | `lin-doc` | Lined document | `lined-document` |
| **Comment with braces on both sides** | Curly Braces | `braces` | Adds a comment | - | | Lined/Shaded Process | Lined Rectangle | `lin-rect` | Lined process shape | `lin-proc`, `lined-process`, `lined-rectangle`, `shaded-process` |
| **Com Link** | Lightning Bolt | `bolt` | Communication link | `com-link`, `lightning-bolt` | | Loop Limit | Trapezoidal Pentagon | `notch-pent` | Loop limit step | `loop-limit`, `notched-pentagon` |
| **Document** | Document | `doc` | Represents a document | `doc`, `document` | | Manual File | Flipped Triangle | `flip-tri` | Manual file operation | `flipped-triangle`, `manual-file` |
| **Delay** | Half-Rounded Rectangle | `delay` | Represents a delay | `half-rounded-rectangle` | | Manual Input | Sloped Rectangle | `sl-rect` | Manual input step | `manual-input`, `sloped-rectangle` |
| **Direct Access Storage** | Horizontal Cylinder | `h-cyl` | Direct access storage | `das`, `horizontal-cylinder` | | Manual Operation | Trapezoid Base Top | `trap-t` | Represents a manual task | `inv-trapezoid`, `manual`, `trapezoid-top` |
| **Disk Storage** | Lined Cylinder | `lin-cyl` | Disk storage | `disk`, `lined-cylinder` | | Multi-Document | Stacked Document | `docs` | Multiple documents | `documents`, `st-doc`, `stacked-document` |
| **Display** | Curved Trapezoid | `curv-trap` | Represents a display | `curved-trapezoid`, `display` | | Multi-Process | Stacked Rectangle | `st-rect` | Multiple processes | `processes`, `procs`, `stacked-rectangle` |
| **Divided Process** | Divided Rectangle | `div-rect` | Divided process shape | `div-proc`, `divided-rectangle`, `divided-process` | | Odd | Odd | `odd` | Odd shape | |
| **Extract** | Triangle | `tri` | Extraction process | `extract`, `triangle` | | Paper Tape | Flag | `flag` | Paper tape | `paper-tape` |
| **Internal Storage** | Window Pane | `win-pane` | Internal storage | `internal-storage`, `window-pane` | | Prepare Conditional | Hexagon | `hex` | Preparation or condition step | `hexagon`, `prepare` |
| **Junction** | Filled Circle | `f-circ` | Junction point | `junction`, `filled-circle` | | Priority Action | Trapezoid Base Bottom | `trap-b` | Priority action | `priority`, `trapezoid`, `trapezoid-bottom` |
| **Lined Document** | Lined Document | `lin-doc` | Lined document | `lined-document` | | Process | Rectangle | `rect` | Standard process shape | `proc`, `process`, `rectangle` |
| **Loop Limit** | Trapezoidal Pentagon | `notch-pent` | Loop limit step | `loop-limit`, `notched-pentagon` | | Start | Circle | `circle` | Starting point | `circ` |
| **Manual File** | Flipped Triangle | `flip-tri` | Manual file operation | `manual-file`, `flipped-triangle` | | Start | Small Circle | `sm-circ` | Small starting point | `small-circle`, `start` |
| **Manual Input** | Sloped Rectangle | `sl-rect` | Manual input step | `manual-input`, `sloped-rectangle` | | Stop | Double Circle | `dbl-circ` | Represents a stop point | `double-circle` |
| **Multi-Document** | Stacked Document | `docs` | Multiple documents | `documents`, `st-doc`, `stacked-document` | | Stop | Framed Circle | `fr-circ` | Stop point | `framed-circle`, `stop` |
| **Multi-Process** | Stacked Rectangle | `st-rect` | Multiple processes | `procs`, `processes`, `stacked-rectangle` | | Stored Data | Bow Tie Rectangle | `bow-rect` | Stored data | `bow-tie-rectangle`, `stored-data` |
| **Paper Tape** | Flag | `flag` | Paper tape | `paper-tape` | | Subprocess | Framed Rectangle | `fr-rect` | Subprocess | `framed-rectangle`, `subproc`, `subprocess`, `subroutine` |
| **Stored Data** | Bow Tie Rectangle | `bow-rect` | Stored data | `stored-data`, `bow-tie-rectangle` | | Summary | Crossed Circle | `cross-circ` | Summary | `crossed-circle`, `summary` |
| **Summary** | Crossed Circle | `cross-circ` | Summary | `summary`, `crossed-circle` | | Tagged Document | Tagged Document | `tag-doc` | Tagged document | `tag-doc`, `tagged-document` |
| **Tagged Document** | Tagged Document | `tag-doc` | Tagged document | `tag-doc`, `tagged-document` | | Tagged Process | Tagged Rectangle | `tag-rect` | Tagged process | `tag-proc`, `tagged-process`, `tagged-rectangle` |
| **Tagged Process** | Tagged Rectangle | `tag-rect` | Tagged process | `tagged-rectangle`,`tag-proc`, `tagged-process` | | Terminal Point | Stadium | `stadium` | Terminal point | `pill`, `terminal` |
| Text Block | Text Block | `text` | Text block | |
### Example Flowchart with New Shapes ### Example Flowchart with New Shapes
@ -926,6 +927,66 @@ flowchart TD
A@{ shape: tag-rect, label: "Tagged process" } A@{ shape: tag-rect, label: "Tagged process" }
``` ```
## Special shapes in Mermaid Flowcharts (v11.3.0+)
Mermaid also introduces 2 special shapes to enhance your flowcharts: **icon** and **image**. These shapes allow you to include icons and images directly within your flowcharts, providing more visual context and clarity.
### Icon Shape
You can use the `icon` shape to include an icon in your flowchart. To use icons, you need to register the icon pack first. Follow the instructions provided [here](../config/icons.md). The syntax for defining an icon shape is as follows:
```mermaid-example
flowchart TD
A@{ icon: "fa:user", form: "square", label: "User Icon", pos: "t", h: 60 }
```
```mermaid
flowchart TD
A@{ icon: "fa:user", form: "square", label: "User Icon", pos: "t", h: 60 }
```
### Parameters
- **icon**: The name of the icon from the registered icon pack.
- **form**: Specifies the background shape of the icon. If not defined there will be no background to icon. Options include:
- `square`
- `circle`
- `rounded`
- **label**: The text label associated with the icon. This can be any string. If not defined, no label will be displayed.
- **pos**: The position of the label. If not defined label will default to bottom of icon. Possible values are:
- `t`
- `b`
- **h**: The height of the icon. If not defined this will default to 48 which is minimum.
### Image Shape
You can use the `image` shape to include an image in your flowchart. The syntax for defining an image shape is as follows:
```mermaid-example
flowchart TD
A@{ img: "https://example.com/image.png", label: "Image Label", pos: "t", w: 60, h: 60, constraint: "off" }
```
```mermaid
flowchart TD
A@{ img: "https://example.com/image.png", label: "Image Label", pos: "t", w: 60, h: 60, constraint: "off" }
```
### Parameters
- **img**: The URL of the image to be displayed.
- **label**: The text label associated with the image. This can be any string. If not defined, no label will be displayed.
- **pos**: The position of the label. If not defined, the label will default to the bottom of the image. Possible values are:
- `t`
- `b`
- **w**: The width of the image. If not defined, this will default to the natural width of the image.
- **h**: The height of the image. If not defined, this will default to the natural height of the image.
- **constraint**: Determines if the image should constrain the node size. This setting also ensures the image maintains its original aspect ratio, adjusting the height (`h`) accordingly to the width (`w`). If not defined, this will default to `off` Possible values are:
- `on`
- `off`
These new shapes provide additional flexibility and visual appeal to your flowcharts, making them more informative and engaging.
## Links between nodes ## Links between nodes
Nodes can be connected with links/edges. It is possible to have different types of links or attach a text string to a link. Nodes can be connected with links/edges. It is possible to have different types of links or attach a text string to a link.

View File

@ -220,7 +220,7 @@ There are ten types of arrows currently supported:
| `<<->>` | Solid line with bidirectional arrowheads (v11.0.0+) | | `<<->>` | Solid line with bidirectional arrowheads (v11.0.0+) |
| `<<-->>` | Dotted line with bidirectional arrowheads (v11.0.0+) | | `<<-->>` | Dotted line with bidirectional arrowheads (v11.0.0+) |
| `-x` | Solid line with a cross at the end | | `-x` | Solid line with a cross at the end |
| `--x` | Dotted line with a cross at the end. | | `--x` | Dotted line with a cross at the end |
| `-)` | Solid line with an open arrow at the end (async) | | `-)` | Solid line with an open arrow at the end (async) |
| `--)` | Dotted line with a open arrow at the end (async) | | `--)` | Dotted line with a open arrow at the end (async) |

View File

@ -64,7 +64,7 @@
}, },
"devDependencies": { "devDependencies": {
"@applitools/eyes-cypress": "^3.44.4", "@applitools/eyes-cypress": "^3.44.4",
"@argos-ci/cypress": "^2.1.0", "@argos-ci/cypress": "^2.2.2",
"@changesets/changelog-github": "^0.5.0", "@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.7", "@changesets/cli": "^2.27.7",
"@cspell/eslint-plugin": "^8.8.4", "@cspell/eslint-plugin": "^8.8.4",
@ -91,6 +91,7 @@
"cspell": "^8.6.0", "cspell": "^8.6.0",
"cypress": "^13.14.1", "cypress": "^13.14.1",
"cypress-image-snapshot": "^4.0.1", "cypress-image-snapshot": "^4.0.1",
"cypress-split": "^1.24.0",
"esbuild": "^0.21.5", "esbuild": "^0.21.5",
"eslint": "^9.4.0", "eslint": "^9.4.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
@ -103,7 +104,7 @@
"eslint-plugin-markdown": "^5.0.0", "eslint-plugin-markdown": "^5.0.0",
"eslint-plugin-no-only-tests": "^3.1.0", "eslint-plugin-no-only-tests": "^3.1.0",
"eslint-plugin-tsdoc": "^0.3.0", "eslint-plugin-tsdoc": "^0.3.0",
"eslint-plugin-unicorn": "^55.0.0", "eslint-plugin-unicorn": "^56.0.0",
"express": "^4.19.1", "express": "^4.19.1",
"globals": "^15.4.0", "globals": "^15.4.0",
"globby": "^14.0.1", "globby": "^14.0.1",

View File

@ -35,8 +35,8 @@
"clean": "rimraf dist", "clean": "rimraf dist",
"dev": "pnpm -w dev", "dev": "pnpm -w dev",
"docs:code": "typedoc src/defaultConfig.ts src/config.ts src/mermaid.ts && prettier --write ./src/docs/config/setup", "docs:code": "typedoc src/defaultConfig.ts src/config.ts src/mermaid.ts && prettier --write ./src/docs/config/setup",
"docs:build": "rimraf ../../docs && pnpm docs:spellcheck && pnpm docs:code && tsx scripts/docs.cli.mts", "docs:build": "rimraf ../../docs && pnpm docs:code && pnpm docs:spellcheck && tsx scripts/docs.cli.mts",
"docs:verify": "pnpm docs:spellcheck && pnpm docs:code && tsx scripts/docs.cli.mts --verify", "docs:verify": "pnpm docs:code && pnpm docs:spellcheck && tsx scripts/docs.cli.mts --verify",
"docs:pre:vitepress": "pnpm --filter ./src/docs prefetch && rimraf src/vitepress && pnpm docs:code && tsx scripts/docs.cli.mts --vitepress && pnpm --filter ./src/vitepress install --no-frozen-lockfile --ignore-scripts", "docs:pre:vitepress": "pnpm --filter ./src/docs prefetch && rimraf src/vitepress && pnpm docs:code && tsx scripts/docs.cli.mts --vitepress && pnpm --filter ./src/vitepress install --no-frozen-lockfile --ignore-scripts",
"docs:build:vitepress": "pnpm docs:pre:vitepress && (cd src/vitepress && pnpm run build) && cpy --flat src/docs/landing/ ./src/vitepress/.vitepress/dist/landing", "docs:build:vitepress": "pnpm docs:pre:vitepress && (cd src/vitepress && pnpm run build) && cpy --flat src/docs/landing/ ./src/vitepress/.vitepress/dist/landing",
"docs:dev": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./src/vitepress dev\" \"tsx scripts/docs.cli.mts --watch --vitepress\"", "docs:dev": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./src/vitepress dev\" \"tsx scripts/docs.cli.mts --watch --vitepress\"",
@ -70,12 +70,14 @@
"@braintree/sanitize-url": "^7.0.1", "@braintree/sanitize-url": "^7.0.1",
"@iconify/utils": "^2.1.32", "@iconify/utils": "^2.1.32",
"@mermaid-js/parser": "workspace:^", "@mermaid-js/parser": "workspace:^",
"@types/d3": "^7.4.3",
"@types/dompurify": "^3.0.5",
"cytoscape": "^3.29.2", "cytoscape": "^3.29.2",
"cytoscape-cose-bilkent": "^4.1.0", "cytoscape-cose-bilkent": "^4.1.0",
"cytoscape-fcose": "^2.2.0", "cytoscape-fcose": "^2.2.0",
"d3": "^7.9.0", "d3": "^7.9.0",
"d3-sankey": "^0.12.3", "d3-sankey": "^0.12.3",
"dagre-d3-es": "7.0.10", "dagre-d3-es": "7.0.11",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"dompurify": "^3.0.11 <3.1.7", "dompurify": "^3.0.11 <3.1.7",
"katex": "^0.16.9", "katex": "^0.16.9",
@ -92,13 +94,11 @@
"@iconify/types": "^2.0.0", "@iconify/types": "^2.0.0",
"@types/cytoscape": "^3.21.4", "@types/cytoscape": "^3.21.4",
"@types/cytoscape-fcose": "^2.2.4", "@types/cytoscape-fcose": "^2.2.4",
"@types/d3": "^7.4.3",
"@types/d3-sankey": "^0.12.4", "@types/d3-sankey": "^0.12.4",
"@types/d3-scale": "^4.0.8", "@types/d3-scale": "^4.0.8",
"@types/d3-scale-chromatic": "^3.0.3", "@types/d3-scale-chromatic": "^3.0.3",
"@types/d3-selection": "^3.0.10", "@types/d3-selection": "^3.0.10",
"@types/d3-shape": "^3.1.6", "@types/d3-shape": "^3.1.6",
"@types/dompurify": "^3.0.5",
"@types/jsdom": "^21.1.6", "@types/jsdom": "^21.1.6",
"@types/katex": "^0.16.7", "@types/katex": "^0.16.7",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",

View File

@ -41,7 +41,8 @@ import { exec } from 'child_process';
import { globby } from 'globby'; import { globby } from 'globby';
import { JSDOM } from 'jsdom'; import { JSDOM } from 'jsdom';
import { dump, load, JSON_SCHEMA } from 'js-yaml'; import { dump, load, JSON_SCHEMA } from 'js-yaml';
import type { Code, ListItem, Root, Text, YAML } from 'mdast'; import type { Code, ListItem, PhrasingContent, Root, Text, YAML } from 'mdast';
import { register } from 'node:module';
import { posix, dirname, relative, join } from 'path'; import { posix, dirname, relative, join } from 'path';
import prettier from 'prettier'; import prettier from 'prettier';
import { remark } from 'remark'; import { remark } from 'remark';
@ -53,6 +54,10 @@ import mm from 'micromatch';
import flatmap from 'unist-util-flatmap'; import flatmap from 'unist-util-flatmap';
import { visit } from 'unist-util-visit'; import { visit } from 'unist-util-visit';
// short-circuit `.schema.yaml` imports, so that we can safely import `shapes.js`
register('./loadHook.mjs', import.meta.url);
const { shapesDefs } = await import('../src/rendering-util/rendering-elements/shapes.js');
export const MERMAID_RELEASE_VERSION = JSON.parse(readFileSync('../mermaid/package.json', 'utf8')) export const MERMAID_RELEASE_VERSION = JSON.parse(readFileSync('../mermaid/package.json', 'utf8'))
.version as string; .version as string;
const MERMAID_MAJOR_VERSION = MERMAID_RELEASE_VERSION.split('.')[0]; const MERMAID_MAJOR_VERSION = MERMAID_RELEASE_VERSION.split('.')[0];
@ -103,6 +108,60 @@ const generateHeader = (file: string): string => {
> ## Please edit the corresponding file in [${filePathFromRoot}](${sourcePathRelativeToGenerated}).`; > ## Please edit the corresponding file in [${filePathFromRoot}](${sourcePathRelativeToGenerated}).`;
}; };
/**
* Builds a markdown list of shapes supported in flowcharts.
*/
export function buildShapeDoc() {
const data = shapesDefs
.sort((a, b) => a.semanticName.localeCompare(b.semanticName))
.map((shape): PhrasingContent[][] => {
const { name, semanticName, description, shortName, aliases = [] } = shape;
return [
[{ type: 'text', value: semanticName }],
[{ type: 'text', value: name }],
[{ type: 'inlineCode', value: shortName }],
[{ type: 'text', value: description }],
aliases.sort().flatMap((alias, index) => [
...(index !== 0 ? ([{ type: 'text', value: ', ' }] as const) : []),
{
type: 'inlineCode',
value: alias,
},
]),
];
});
// don't prettify this table, since we'd do it later
return remark()
.use(remarkGfm)
.stringify({
type: 'root',
children: [
{
type: 'table',
children: [
['Semantic Name', 'Shape Name', 'Short Name', 'Description', 'Alias Supported'].map(
(s): PhrasingContent[] => [
{
type: 'strong',
children: [{ type: 'text', value: s }],
},
]
),
...data,
].map((row) => ({
type: 'tableRow',
children: row.map((cell) => ({
type: 'tableCell',
children: cell,
})),
})),
},
],
})
.toString();
}
/** /**
* Given a source file name and path, return the documentation destination full path and file name * Given a source file name and path, return the documentation destination full path and file name
* Create the destination path if it does not already exist. * Create the destination path if it does not already exist.
@ -192,10 +251,22 @@ export const transformToBlockQuote = (
const injectPlaceholders = (text: string): string => const injectPlaceholders = (text: string): string =>
text.replace(/<MERMAID_VERSION>/g, MERMAID_MAJOR_VERSION).replace(/<CDN_URL>/g, CDN_URL); text.replace(/<MERMAID_VERSION>/g, MERMAID_MAJOR_VERSION).replace(/<CDN_URL>/g, CDN_URL);
const virtualGenerators: Record<string, () => string> = {
shapesTable: buildShapeDoc,
};
const transformIncludeStatements = (file: string, text: string): string => { const transformIncludeStatements = (file: string, text: string): string => {
// resolve includes - src https://github.com/vuejs/vitepress/blob/428eec3750d6b5648a77ac52d88128df0554d4d1/src/node/markdownToVue.ts#L65-L76 // resolve includes - src https://github.com/vuejs/vitepress/blob/428eec3750d6b5648a77ac52d88128df0554d4d1/src/node/markdownToVue.ts#L65-L76
return text.replace(includesRE, (m, m1) => { return text.replace(includesRE, (m, m1: string) => {
try { try {
if (m1.startsWith('virtual:')) {
const key = m1.replace('virtual:', '');
const generator = virtualGenerators[key];
if (!generator) {
throw new Error(`Unknown virtual generator: ${key} in "${file}"`);
}
return generator();
}
const includePath = join(dirname(file), m1).replaceAll('\\', '/'); const includePath = join(dirname(file), m1).replaceAll('\\', '/');
const content = readSyncedUTF8file(includePath); const content = readSyncedUTF8file(includePath);
includedFiles.add(changeToFinalDocDir(includePath)); includedFiles.add(changeToFinalDocDir(includePath));

View File

@ -1,4 +1,4 @@
import { transformMarkdownAst, transformToBlockQuote } from './docs.mjs'; import { buildShapeDoc, transformMarkdownAst, transformToBlockQuote } from './docs.mjs';
import { remark } from 'remark'; // import it this way so we can mock it import { remark } from 'remark'; // import it this way so we can mock it
import remarkFrontmatter from 'remark-frontmatter'; import remarkFrontmatter from 'remark-frontmatter';
@ -165,4 +165,59 @@ This Markdown should be kept.
}); });
}); });
}); });
describe('buildShapeDoc', () => {
it('should build shapesTable based on the shapeDefs', () => {
expect(buildShapeDoc()).toMatchInlineSnapshot(`
"| **Semantic Name** | **Shape Name** | **Short Name** | **Description** | **Alias Supported** |
| --------------------------------- | ---------------------- | -------------- | ------------------------------ | ---------------------------------------------------------------- |
| Card | Notched Rectangle | \`notch-rect\` | Represents a card | \`card\`, \`notched-rectangle\` |
| Collate | Hourglass | \`hourglass\` | Represents a collate operation | \`collate\`, \`hourglass\` |
| Com Link | Lightning Bolt | \`bolt\` | Communication link | \`com-link\`, \`lightning-bolt\` |
| Comment | Curly Brace | \`brace\` | Adds a comment | \`brace-l\`, \`comment\` |
| Comment Right | Curly Brace | \`brace-r\` | Adds a comment | |
| Comment with braces on both sides | Curly Braces | \`braces\` | Adds a comment | |
| Data Input/Output | Lean Right | \`lean-r\` | Represents input or output | \`in-out\`, \`lean-right\` |
| Data Input/Output | Lean Left | \`lean-l\` | Represents output or input | \`lean-left\`, \`out-in\` |
| Database | Cylinder | \`cyl\` | Database storage | \`cylinder\`, \`database\`, \`db\` |
| Decision | Diamond | \`diam\` | Decision-making step | \`decision\`, \`diamond\`, \`question\` |
| Delay | Half-Rounded Rectangle | \`delay\` | Represents a delay | \`half-rounded-rectangle\` |
| Direct Access Storage | Horizontal Cylinder | \`h-cyl\` | Direct access storage | \`das\`, \`horizontal-cylinder\` |
| Disk Storage | Lined Cylinder | \`lin-cyl\` | Disk storage | \`disk\`, \`lined-cylinder\` |
| Display | Curved Trapezoid | \`curv-trap\` | Represents a display | \`curved-trapezoid\`, \`display\` |
| Divided Process | Divided Rectangle | \`div-rect\` | Divided process shape | \`div-proc\`, \`divided-process\`, \`divided-rectangle\` |
| Document | Document | \`doc\` | Represents a document | \`doc\`, \`document\` |
| Event | Rounded Rectangle | \`rounded\` | Represents an event | \`event\` |
| Extract | Triangle | \`tri\` | Extraction process | \`extract\`, \`triangle\` |
| Fork/Join | Filled Rectangle | \`fork\` | Fork or join in process flow | \`join\` |
| Internal Storage | Window Pane | \`win-pane\` | Internal storage | \`internal-storage\`, \`window-pane\` |
| Junction | Filled Circle | \`f-circ\` | Junction point | \`filled-circle\`, \`junction\` |
| Lined Document | Lined Document | \`lin-doc\` | Lined document | \`lined-document\` |
| Lined/Shaded Process | Lined Rectangle | \`lin-rect\` | Lined process shape | \`lin-proc\`, \`lined-process\`, \`lined-rectangle\`, \`shaded-process\` |
| Loop Limit | Trapezoidal Pentagon | \`notch-pent\` | Loop limit step | \`loop-limit\`, \`notched-pentagon\` |
| Manual File | Flipped Triangle | \`flip-tri\` | Manual file operation | \`flipped-triangle\`, \`manual-file\` |
| Manual Input | Sloped Rectangle | \`sl-rect\` | Manual input step | \`manual-input\`, \`sloped-rectangle\` |
| Manual Operation | Trapezoid Base Top | \`trap-t\` | Represents a manual task | \`inv-trapezoid\`, \`manual\`, \`trapezoid-top\` |
| Multi-Document | Stacked Document | \`docs\` | Multiple documents | \`documents\`, \`st-doc\`, \`stacked-document\` |
| Multi-Process | Stacked Rectangle | \`st-rect\` | Multiple processes | \`processes\`, \`procs\`, \`stacked-rectangle\` |
| Odd | Odd | \`odd\` | Odd shape | |
| Paper Tape | Flag | \`flag\` | Paper tape | \`paper-tape\` |
| Prepare Conditional | Hexagon | \`hex\` | Preparation or condition step | \`hexagon\`, \`prepare\` |
| Priority Action | Trapezoid Base Bottom | \`trap-b\` | Priority action | \`priority\`, \`trapezoid\`, \`trapezoid-bottom\` |
| Process | Rectangle | \`rect\` | Standard process shape | \`proc\`, \`process\`, \`rectangle\` |
| Start | Circle | \`circle\` | Starting point | \`circ\` |
| Start | Small Circle | \`sm-circ\` | Small starting point | \`small-circle\`, \`start\` |
| Stop | Double Circle | \`dbl-circ\` | Represents a stop point | \`double-circle\` |
| Stop | Framed Circle | \`fr-circ\` | Stop point | \`framed-circle\`, \`stop\` |
| Stored Data | Bow Tie Rectangle | \`bow-rect\` | Stored data | \`bow-tie-rectangle\`, \`stored-data\` |
| Subprocess | Framed Rectangle | \`fr-rect\` | Subprocess | \`framed-rectangle\`, \`subproc\`, \`subprocess\`, \`subroutine\` |
| Summary | Crossed Circle | \`cross-circ\` | Summary | \`crossed-circle\`, \`summary\` |
| Tagged Document | Tagged Document | \`tag-doc\` | Tagged document | \`tag-doc\`, \`tagged-document\` |
| Tagged Process | Tagged Rectangle | \`tag-rect\` | Tagged process | \`tag-proc\`, \`tagged-process\`, \`tagged-rectangle\` |
| Terminal Point | Stadium | \`stadium\` | Terminal point | \`pill\`, \`terminal\` |
| Text Block | Text Block | \`text\` | Text block | |
"
`);
});
});
}); });

View File

@ -0,0 +1,22 @@
import { fileURLToPath } from 'node:url';
/** @import import { LoadHook } from "node:module"; */
/**
* @type {LoadHook}
*
* Load hook that short circuits the loading of `.schema.yaml` files with `export default {}`.
* These would normally be loaded using ESBuild, but that doesn't work for these local scripts.
*
* @see https://nodejs.org/api/module.html#loadurl-context-nextload
*/
export const load = async (url, context, nextLoad) => {
const filePath = url.startsWith('file://') ? fileURLToPath(url) : url;
if (filePath.endsWith('.schema.yaml')) {
return {
format: 'module',
shortCircuit: true,
source: `export default {}`,
};
} else {
return await nextLoad(url, context);
}
};

View File

@ -174,6 +174,7 @@ function sidebarConfig() {
{ text: 'API-Usage', link: '/config/usage' }, { text: 'API-Usage', link: '/config/usage' },
{ text: 'Mermaid API Configuration', link: '/config/setup/README' }, { text: 'Mermaid API Configuration', link: '/config/setup/README' },
{ text: 'Mermaid Configuration Options', link: '/config/schema-docs/config' }, { text: 'Mermaid Configuration Options', link: '/config/schema-docs/config' },
{ text: 'Registering icons', link: '/config/icons' },
{ text: 'Directives', link: '/config/directives' }, { text: 'Directives', link: '/config/directives' },
{ text: 'Theming', link: '/config/theming' }, { text: 'Theming', link: '/config/theming' },
{ text: 'Math', link: '/config/math' }, { text: 'Math', link: '/config/math' },

View File

@ -95,7 +95,7 @@ To add a new shape:
- **Example**: - **Example**:
```typescript ```typescript
import { Node, RenderOptions } from '../../types.d.ts'; import { Node, RenderOptions } from '../../types.ts';
export const myNewShape = async ( export const myNewShape = async (
parent: SVGAElement, parent: SVGAElement,
@ -111,7 +111,7 @@ To add a new shape:
### 2. Register the Shape ### 2. Register the Shape
- **Register the shape**: Add your shape to the `shapes` object in the main shapes module. This allows your shape to be recognized and used within the system. - **Register the shape**: Add your shape to the `shapes` object in the [main shapes module](../rendering-util/rendering-elements/shapes.ts). This allows your shape to be recognized and used within the system.
- **Example**: - **Example**:
@ -120,9 +120,14 @@ To add a new shape:
const shapes = { const shapes = {
..., ...,
'my-new-shape': myNewShape, {
// Shortened alias (if any). semanticName: 'My Shape',
'm-nsh': myNewShape name: 'Shape Name',
shortName: '<short-name>',
description: '<Description for the shape>',
aliases: ['<alias-one>', '<al-on>', '<alias-two>', '<al-two>'],
handler: myNewShape,
},
}; };
``` ```

View File

@ -0,0 +1,49 @@
# Registering icon pack in mermaid
The icon packs available can be found at [icones.js.org](https://icones.js.org/).
We use the name defined when registering the icon pack, to override the prefix field of the iconify pack. This allows the user to use shorter names for the icons. It also allows us to load a particular pack only when it is used in a diagram.
Using JSON file directly from CDN:
```js
import mermaid from 'CDN/mermaid.esm.mjs';
mermaid.registerIconPacks([
{
name: 'logos',
loader: () =>
fetch('https://unpkg.com/@iconify-json/logos@1/icons.json').then((res) => res.json()),
},
]);
```
Using packages and a bundler:
```bash
npm install @iconify-json/logos@1
```
With lazy loading
```js
import mermaid from 'mermaid';
mermaid.registerIconPacks([
{
name: 'logos',
loader: () => import('@iconify-json/logos').then((module) => module.icons),
},
]);
```
Without lazy loading
```js
import mermaid from 'mermaid';
import { icons } from '@iconify-json/logos';
mermaid.registerIconPacks([
{
name: icons.prefix, // To use the prefix defined in the icon pack
icons,
},
]);
```

View File

@ -195,15 +195,22 @@ Communication tools and platforms
- [Vim](https://www.vim.org) - [Vim](https://www.vim.org)
- [Vim Diagram Syntax](https://github.com/zhaozg/vim-diagram) - [Vim Diagram Syntax](https://github.com/zhaozg/vim-diagram)
- [Official Vim Syntax and ft plugin](https://github.com/craigmac/vim-mermaid) - [Official Vim Syntax and ft plugin](https://github.com/craigmac/vim-mermaid)
- [Zed](https://zed.dev)
- [zed-mermaid](https://github.com/gabeidx/zed-mermaid)
### Document Generation ### Document Generation
- [Astro](https://astro.build/)
- [Adding diagrams to your Astro site with MermaidJS and Playwright](https://agramont.net/blog/diagraming-with-mermaidjs-astro/)
- [Codedoc](https://codedoc.cc/) - [Codedoc](https://codedoc.cc/)
- [codedoc-mermaid-plugin](https://www.npmjs.com/package/codedoc-mermaid-plugin) - [codedoc-mermaid-plugin](https://www.npmjs.com/package/codedoc-mermaid-plugin)
- [Docsy Hugo Theme](https://www.docsy.dev/docs/adding-content/lookandfeel/#diagrams-with-mermaid) ✅ - [Docsy Hugo Theme](https://www.docsy.dev/docs/adding-content/lookandfeel/#diagrams-with-mermaid) ✅
- [Docusaurus](https://docusaurus.io/docs/markdown-features/diagrams) ✅ - [Docusaurus](https://docusaurus.io/docs/markdown-features/diagrams) ✅
- [Gatsby](https://www.gatsbyjs.com/) - [Gatsby](https://www.gatsbyjs.com/)
- [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid) - [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid)
- [Jekyll](https://jekyllrb.com/)
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
- [JSDoc](https://jsdoc.app/) - [JSDoc](https://jsdoc.app/)
- [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid) - [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid)
- [Madness](https://madness.dannyb.co/) - [Madness](https://madness.dannyb.co/)
@ -212,7 +219,7 @@ Communication tools and platforms
- [MkDocs](https://www.mkdocs.org) - [MkDocs](https://www.mkdocs.org)
- [mkdocs-mermaid2-plugin](https://github.com/fralau/mkdocs-mermaid2-plugin) - [mkdocs-mermaid2-plugin](https://github.com/fralau/mkdocs-mermaid2-plugin)
- [mkdocs-material](https://github.com/squidfunk/mkdocs-material), check the [docs](https://squidfunk.github.io/mkdocs-material/reference/diagrams/) - [mkdocs-material](https://github.com/squidfunk/mkdocs-material), check the [docs](https://squidfunk.github.io/mkdocs-material/reference/diagrams/)
- [Quarto](https://quarto.org/) - [Quarto](https://quarto.org/)
- [rehype](https://github.com/rehypejs/rehype) - [rehype](https://github.com/rehypejs/rehype)
- [rehype-mermaid](https://github.com/remcohaszing/rehype-mermaid) - [rehype-mermaid](https://github.com/remcohaszing/rehype-mermaid)
- [remark](https://remark.js.org/) - [remark](https://remark.js.org/)
@ -241,17 +248,12 @@ Communication tools and platforms
### Other ### Other
- [Astro](https://astro.build/)
- [Adding diagrams to your Astro site with MermaidJS and Playwright](https://agramont.net/blog/diagraming-with-mermaidjs-astro/)
- [Bisheng](https://www.npmjs.com/package/bisheng) - [Bisheng](https://www.npmjs.com/package/bisheng)
- [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid) - [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid)
- [Blazorade Mermaid: Render Mermaid diagrams in Blazor applications](https://github.com/Blazorade/Blazorade-Mermaid/wiki) - [Blazorade Mermaid: Render Mermaid diagrams in Blazor applications](https://github.com/Blazorade/Blazorade-Mermaid/wiki)
- [Codemia: A tool to practice system design problems](https://codemia.io) ✅ - [Codemia: A tool to practice system design problems](https://codemia.io) ✅
- [ExDoc](https://github.com/elixir-lang/ex_doc) - [ExDoc](https://github.com/elixir-lang/ex_doc)
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs) - [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
- [Jekyll](https://jekyllrb.com/)
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
- [MarkChart: Preview Mermaid diagrams on macOS](https://markchart.app/) - [MarkChart: Preview Mermaid diagrams on macOS](https://markchart.app/)
- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic) - [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic)
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server) - [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)

View File

@ -76,8 +76,8 @@ Mermaid offers a variety of styles or “looks” for your diagrams, allowing yo
**Available Looks:** **Available Looks:**
Hand-Drawn Look: For a more personal, creative touch, the hand-drawn look brings a sketch-like quality to your diagrams. This style is perfect for informal settings or when you want to add a bit of personality to your diagrams. - Hand-Drawn Look: For a more personal, creative touch, the hand-drawn look brings a sketch-like quality to your diagrams. This style is perfect for informal settings or when you want to add a bit of personality to your diagrams.
Classic Look: If you prefer the traditional Mermaid style, the classic look maintains the original appearance that many users are familiar with. Its great for consistency across projects or when you want to keep the familiar aesthetic. - Classic Look: If you prefer the traditional Mermaid style, the classic look maintains the original appearance that many users are familiar with. Its great for consistency across projects or when you want to keep the familiar aesthetic.
**How to Select a Look:** **How to Select a Look:**
@ -101,8 +101,8 @@ In addition to customizing the look of your diagrams, Mermaid Chart now allows y
#### Supported Layout Algorithms: #### Supported Layout Algorithms:
Dagre (default): This is the classic layout algorithm that has been used in Mermaid for a long time. It provides a good balance of simplicity and visual clarity, making it ideal for most diagrams. - Dagre (default): This is the classic layout algorithm that has been used in Mermaid for a long time. It provides a good balance of simplicity and visual clarity, making it ideal for most diagrams.
ELK: For those who need more sophisticated layout capabilities, especially when working with large or intricate diagrams, the ELK (Eclipse Layout Kernel) layout offers advanced options. It provides a more optimized arrangement, potentially reducing overlapping and improving readability. This is not included out the box but needs to be added when integrating mermaid for sites/applications that want to have elk support. - ELK: For those who need more sophisticated layout capabilities, especially when working with large or intricate diagrams, the ELK (Eclipse Layout Kernel) layout offers advanced options. It provides a more optimized arrangement, potentially reducing overlapping and improving readability. This is not included out the box but needs to be added when integrating mermaid for sites/applications that want to have elk support.
#### How to Select a Layout Algorithm: #### How to Select a Layout Algorithm:

View File

@ -59,15 +59,15 @@ service {service id}({icon name})[{title}] (in {parent id})?
Put together: Put together:
``` ```
service database(db)[Database] service database1(database)[My Database]
``` ```
creates the service identified as `database`, using the icon `db`, with the label `Database`. creates the service identified as `database1`, using the icon `database`, with the label `My Database`.
If the service belongs to a group, it can be placed inside it through the optional `in` keyword If the service belongs to a group, it can be placed inside it through the optional `in` keyword
``` ```
service database(db)[Database] in private_api service database1(database)[My Database] in private_api
``` ```
### Edges ### Edges
@ -156,55 +156,7 @@ architecture-beta
## Icons ## Icons
By default, architecture diagram supports the following icons: `cloud`, `database`, `disk`, `internet`, `server`. By default, architecture diagram supports the following icons: `cloud`, `database`, `disk`, `internet`, `server`.
Users can use any of the 200,000+ icons available in iconify.design, or add their own custom icons, by following the steps below. Users can use any of the 200,000+ icons available in iconify.design, or add their own custom icons, by following the steps [here](../config/icons.md).
The icon packs available can be found at [icones.js.org](https://icones.js.org/).
We use the name defined when registering the icon pack, to override the prefix field of the iconify pack. This allows the user to use shorter names for the icons. It also allows us to load a particular pack only when it is used in a diagram.
Using JSON file directly from CDN:
```js
import mermaid from 'CDN/mermaid.esm.mjs';
mermaid.registerIconPacks([
{
name: 'logos',
loader: () =>
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
},
]);
```
Using packages and a bundler:
```bash
npm install @iconify-json/logos
```
With lazy loading
```js
import mermaid from 'mermaid';
mermaid.registerIconPacks([
{
name: 'logos',
loader: () => import('@iconify-json/logos').then((module) => module.icons),
},
]);
```
Without lazy loading
```js
import mermaid from 'mermaid';
import { icons } from '@iconify-json/logos';
mermaid.registerIconPacks([
{
name: icons.prefix, // To use the prefix defined in the icon pack
icons,
},
]);
```
After the icons are installed, they can be used in the architecture diagram by using the format "name:icon-name", where name is the value used when registering the icon pack. After the icons are installed, they can be used in the architecture diagram by using the format "name:icon-name", where name is the value used when registering the icon pack.

View File

@ -106,7 +106,7 @@ block-beta
a["A label"] b:2 c:2 d a["A label"] b:2 c:2 d
``` ```
In this example, the block labeled "A wide one" spans two columns, while blocks 'b', 'c', and 'd' are allocated their own columns. This flexibility in block sizing is crucial for accurately representing systems with components of varying significance or size. In this example, the block labeled "A labels" spans one column, while blocks 'b', 'c' span 2 columns, and 'd' is again allocated its own column. This flexibility in block sizing is crucial for accurately representing systems with components of varying significance or size.
### Creating Composite Blocks ### Creating Composite Blocks

View File

@ -212,53 +212,7 @@ This syntax creates a node A as a rectangle. It renders in the same way as `A["A
Below is a comprehensive list of the newly introduced shapes and their corresponding semantic meanings, short names, and aliases: Below is a comprehensive list of the newly introduced shapes and their corresponding semantic meanings, short names, and aliases:
| **Semantic Name** | **Shape Name** | **Short Name** | **Description** | **Alias Supported** | <!--@include: virtual:shapesTable -->
| ------------------------------------- | ---------------------- | -------------- | ------------------------------ | -------------------------------------------------------------- |
| **Process** | Rectangle | `rect` | Standard process shape | `proc`, `process`, `rectangle` |
| **Event** | Rounded Rectangle | `rounded` | Represents an event | `event` |
| **Terminal Point** | Stadium | `stadium` | Terminal point | `terminal`, `pill` |
| **Subprocess** | Framed Rectangle | `fr-rect` | Subprocess | `subprocess`,`subproc`, `framed-rectangle`, `subroutine` |
| **Database** | Cylinder | `cyl` | Database storage | `db`, `database`, `cylinder` |
| **Start** | Circle | `circle` | Starting point | `circ` |
| **Odd** | Odd | `odd` | Odd shape | |
| **Decision** | Diamond | `diam` | Decision-making step | `decision`, `diamond` |
| **Prepare Conditional** | Hexagon | `hex` | Preparation or condition step | `hexagon`, `prepare` |
| **Data Input/Output** | Lean Right | `lean-r` | Represents input or output | `lean-right`, `in-out` |
| **Data Input/Output** | Lean Left | `lean-l` | Represents output or input | `lean-left`, `out-in` |
| **Priority Action** | Trapezoid Base Bottom | `trap-b` | Priority action | `priority`, `trapezoid-bottom` |
| **Manual Operation** | Trapezoid Base Top | `trap-t` | Represents a manual task | `manual`, `trapezoid-top` |
| **Stop** | Double Circle | `dbl-circ` | Represents a stop point | `double-circle` |
| **Text Block** | Text Block | `text` | Text block | - |
| **Card** | Notched Rectangle | `notch-rect` | Represents a card | `card`, `notched-rectangle` |
| **Lined/Shaded Process** | Lined Rectangle | `lin-rect` | Lined process shape | `lined-rectangle`,`lined-process`, `lin-proc`,`shaded-process` |
| **Start** | Small Circle | `sm-circ` | Small starting point | `start`, `small-circle` |
| **Stop** | Framed Circle | `fr-circ` | Stop point | `stop`, `framed-circle` |
| **Fork/Join** | Filled Rectangle | `fork` | Fork or join in process flow | `join` |
| **Collate** | Hourglass | `hourglass` | Represents a collate operation | `hourglass` |
| **Comment** | Curly Brace | `brace` | Adds a comment | `comment`, `brace-l` |
| **Comment Right** | Curly Brace | `brace-r` | Adds a comment | - |
| **Comment with braces on both sides** | Curly Braces | `braces` | Adds a comment | - |
| **Com Link** | Lightning Bolt | `bolt` | Communication link | `com-link`, `lightning-bolt` |
| **Document** | Document | `doc` | Represents a document | `doc`, `document` |
| **Delay** | Half-Rounded Rectangle | `delay` | Represents a delay | `half-rounded-rectangle` |
| **Direct Access Storage** | Horizontal Cylinder | `h-cyl` | Direct access storage | `das`, `horizontal-cylinder` |
| **Disk Storage** | Lined Cylinder | `lin-cyl` | Disk storage | `disk`, `lined-cylinder` |
| **Display** | Curved Trapezoid | `curv-trap` | Represents a display | `curved-trapezoid`, `display` |
| **Divided Process** | Divided Rectangle | `div-rect` | Divided process shape | `div-proc`, `divided-rectangle`, `divided-process` |
| **Extract** | Triangle | `tri` | Extraction process | `extract`, `triangle` |
| **Internal Storage** | Window Pane | `win-pane` | Internal storage | `internal-storage`, `window-pane` |
| **Junction** | Filled Circle | `f-circ` | Junction point | `junction`, `filled-circle` |
| **Lined Document** | Lined Document | `lin-doc` | Lined document | `lined-document` |
| **Loop Limit** | Trapezoidal Pentagon | `notch-pent` | Loop limit step | `loop-limit`, `notched-pentagon` |
| **Manual File** | Flipped Triangle | `flip-tri` | Manual file operation | `manual-file`, `flipped-triangle` |
| **Manual Input** | Sloped Rectangle | `sl-rect` | Manual input step | `manual-input`, `sloped-rectangle` |
| **Multi-Document** | Stacked Document | `docs` | Multiple documents | `documents`, `st-doc`, `stacked-document` |
| **Multi-Process** | Stacked Rectangle | `st-rect` | Multiple processes | `procs`, `processes`, `stacked-rectangle` |
| **Paper Tape** | Flag | `flag` | Paper tape | `paper-tape` |
| **Stored Data** | Bow Tie Rectangle | `bow-rect` | Stored data | `stored-data`, `bow-tie-rectangle` |
| **Summary** | Crossed Circle | `cross-circ` | Summary | `summary`, `crossed-circle` |
| **Tagged Document** | Tagged Document | `tag-doc` | Tagged document | `tag-doc`, `tagged-document` |
| **Tagged Process** | Tagged Rectangle | `tag-rect` | Tagged process | `tagged-rectangle`,`tag-proc`, `tagged-process` |
### Example Flowchart with New Shapes ### Example Flowchart with New Shapes
@ -588,6 +542,56 @@ flowchart TD
A@{ shape: tag-rect, label: "Tagged process" } A@{ shape: tag-rect, label: "Tagged process" }
``` ```
## Special shapes in Mermaid Flowcharts (v11.3.0+)
Mermaid also introduces 2 special shapes to enhance your flowcharts: **icon** and **image**. These shapes allow you to include icons and images directly within your flowcharts, providing more visual context and clarity.
### Icon Shape
You can use the `icon` shape to include an icon in your flowchart. To use icons, you need to register the icon pack first. Follow the instructions provided [here](../config/icons.md). The syntax for defining an icon shape is as follows:
```mermaid-example
flowchart TD
A@{ icon: "fa:user", form: "square", label: "User Icon", pos: "t", h: 60 }
```
### Parameters
- **icon**: The name of the icon from the registered icon pack.
- **form**: Specifies the background shape of the icon. If not defined there will be no background to icon. Options include:
- `square`
- `circle`
- `rounded`
- **label**: The text label associated with the icon. This can be any string. If not defined, no label will be displayed.
- **pos**: The position of the label. If not defined label will default to bottom of icon. Possible values are:
- `t`
- `b`
- **h**: The height of the icon. If not defined this will default to 48 which is minimum.
### Image Shape
You can use the `image` shape to include an image in your flowchart. The syntax for defining an image shape is as follows:
```mermaid-example
flowchart TD
A@{ img: "https://example.com/image.png", label: "Image Label", pos: "t", w: 60, h: 60, constraint: "off" }
```
### Parameters
- **img**: The URL of the image to be displayed.
- **label**: The text label associated with the image. This can be any string. If not defined, no label will be displayed.
- **pos**: The position of the label. If not defined, the label will default to the bottom of the image. Possible values are:
- `t`
- `b`
- **w**: The width of the image. If not defined, this will default to the natural width of the image.
- **h**: The height of the image. If not defined, this will default to the natural height of the image.
- **constraint**: Determines if the image should constrain the node size. This setting also ensures the image maintains its original aspect ratio, adjusting the height (`h`) accordingly to the width (`w`). If not defined, this will default to `off` Possible values are:
- `on`
- `off`
These new shapes provide additional flexibility and visual appeal to your flowcharts, making them more informative and engaging.
## Links between nodes ## Links between nodes
Nodes can be connected with links/edges. It is possible to have different types of links or attach a text string to a link. Nodes can be connected with links/edges. It is possible to have different types of links or attach a text string to a link.

View File

@ -155,7 +155,7 @@ There are ten types of arrows currently supported:
| `<<->>` | Solid line with bidirectional arrowheads (v11.0.0+) | | `<<->>` | Solid line with bidirectional arrowheads (v11.0.0+) |
| `<<-->>` | Dotted line with bidirectional arrowheads (v11.0.0+) | | `<<-->>` | Dotted line with bidirectional arrowheads (v11.0.0+) |
| `-x` | Solid line with a cross at the end | | `-x` | Solid line with a cross at the end |
| `--x` | Dotted line with a cross at the end. | | `--x` | Dotted line with a cross at the end |
| `-)` | Solid line with an open arrow at the end (async) | | `-)` | Solid line with an open arrow at the end (async) |
| `--)` | Dotted line with a open arrow at the end (async) | | `--)` | Dotted line with a open arrow at the end (async) |

View File

@ -1,307 +1,5 @@
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { state } from './shapes/state.ts'; import { shapes } from './shapes.js';
import { roundedRect } from './shapes/roundedRect.ts';
import { squareRect } from './shapes/squareRect.ts';
import { stateStart } from './shapes/stateStart.ts';
import { stateEnd } from './shapes/stateEnd.ts';
import { forkJoin } from './shapes/forkJoin.ts';
import { choice } from './shapes/choice.ts';
import { note } from './shapes/note.ts';
import { stadium } from './shapes/stadium.js';
import { rectWithTitle } from './shapes/rectWithTitle.js';
import { subroutine } from './shapes/subroutine.js';
import { cylinder } from './shapes/cylinder.js';
import { circle } from './shapes/circle.js';
import { doublecircle } from './shapes/doubleCircle.js';
import { rect_left_inv_arrow } from './shapes/rectLeftInvArrow.js';
import { question } from './shapes/question.js';
import { hexagon } from './shapes/hexagon.js';
import { text } from './shapes/text.js';
import { card } from './shapes/card.js';
import { shadedProcess } from './shapes/shadedProcess.js';
import { anchor } from './shapes/anchor.js';
import { lean_right } from './shapes/leanRight.js';
import { lean_left } from './shapes/leanLeft.js';
import { trapezoid } from './shapes/trapezoid.js';
import { inv_trapezoid } from './shapes/invertedTrapezoid.js';
import { labelRect } from './shapes/labelRect.js';
import { triangle } from './shapes/triangle.js';
import { halfRoundedRectangle } from './shapes/halfRoundedRectangle.js';
import { curvedTrapezoid } from './shapes/curvedTrapezoid.js';
import { slopedRect } from './shapes/slopedRect.js';
import { bowTieRect } from './shapes/bowTieRect.js';
import { dividedRectangle } from './shapes/dividedRect.js';
import { crossedCircle } from './shapes/crossedCircle.js';
import { waveRectangle } from './shapes/waveRectangle.js';
import { tiltedCylinder } from './shapes/tiltedCylinder.js';
import { trapezoidalPentagon } from './shapes/trapezoidalPentagon.js';
import { flippedTriangle } from './shapes/flippedTriangle.js';
import { hourglass } from './shapes/hourglass.js';
import { taggedRect } from './shapes/taggedRect.js';
import { multiRect } from './shapes/multiRect.js';
import { linedCylinder } from './shapes/linedCylinder.js';
import { waveEdgedRectangle } from './shapes/waveEdgedRectangle.js';
import { lightningBolt } from './shapes/lightningBolt.js';
import { filledCircle } from './shapes/filledCircle.js';
import { multiWaveEdgedRectangle } from './shapes/multiWaveEdgedRectangle.js';
import { windowPane } from './shapes/windowPane.js';
import { linedWaveEdgedRect } from './shapes/linedWaveEdgedRect.js';
import { taggedWaveEdgedRectangle } from './shapes/taggedWaveEdgedRectangle.js';
import { curlyBraceLeft } from './shapes/curlyBraceLeft.js';
import { curlyBraceRight } from './shapes/curlyBraceRight.js';
import { curlyBraces } from './shapes/curlyBraces.js';
import { iconSquare } from './shapes/iconSquare.js';
import { iconCircle } from './shapes/iconCircle.js';
import { icon } from './shapes/icon.js';
import { imageSquare } from './shapes/imageSquare.js';
import { iconRounded } from './shapes/iconRounded.js';
import { kanbanItem } from './shapes/kanbanItem.js';
//Use these names as the left side to render shapes.
export const shapes = {
// States
state,
stateStart,
stateEnd,
forkJoin,
choice,
note,
// Rectangles
rectWithTitle,
roundedRect,
squareRect,
// Rectangle with alias: 'process', 'rect', 'proc', 'rectangle'
rectangle: squareRect,
rect: squareRect,
process: squareRect,
proc: squareRect,
// Rounded Rectangle with alias: 'event', 'rounded'
rounded: roundedRect,
event: roundedRect,
// Stadium with alias: 'terminal','pill', 'stadium'
stadium,
pill: stadium,
terminal: stadium,
// Subprocess with alias: 'fr-rect', 'subproc', 'subprocess', 'framed-rectangle', 'subroutine'
subroutine,
'framed-rectangle': subroutine,
'fr-rect': subroutine,
subprocess: subroutine,
subproc: subroutine,
// Cylinder with alias: 'db', 'database', 'cylinder', 'cyl'
cylinder,
db: cylinder,
cyl: cylinder,
database: cylinder,
// Diamond with alias: 'diam', 'decision', 'diamond'
question,
diam: question,
diamond: question,
decision: question,
// Hexagon with alias: 'hex', 'hexagon', 'prepare'
hexagon,
hex: hexagon,
prepare: hexagon,
// Lean Right with alias: 'lean-r', 'lean-right', 'in-out'
lean_right, // used in old syntax for flowchart
'lean-r': lean_right,
'lean-right': lean_right,
'in-out': lean_right,
// Lean Left with alias: 'lean-l', 'lean-left', 'out-in'
lean_left, // used in old syntax for flowchart
'lean-l': lean_left,
'lean-left': lean_left,
'out-in': lean_left,
// Trapezoid with alias: 'trap-b', 'trapezoid-bottom', 'priority'
trapezoid, // used in old syntax for flowchart
'trap-b': trapezoid,
'trapezoid-bottom': trapezoid,
priority: trapezoid,
// Inverted Trapezoid with alias: 'inv-trapezoid', 'trapezoid-top', 'trap-t', 'manual'
inv_trapezoid, // used in old syntax for flowchart
'inv-trapezoid': inv_trapezoid,
'trapezoid-top': inv_trapezoid,
'trap-t': inv_trapezoid,
manual: inv_trapezoid,
// Double Circle with alias: 'dbl-circ', 'double-circle'
doublecircle, // used in old syntax for flowchart
'dbl-circ': doublecircle,
'double-circle': doublecircle,
// circle with alias: 'circ', 'circle'
circle,
circ: circle,
// Rect Left Inv Arrow with alias: 'odd', 'rect-left-inv-arrow'
rect_left_inv_arrow,
odd: rect_left_inv_arrow,
// Notched Rectangle with alias: 'notched-rectangle', 'notch-rect', 'card'
card,
'notched-rectangle': card,
'notch-rect': card,
// Lined rectangle with alias: 'lin-rect', 'lined-rectangle', 'lin-proc', lined-process', 'shaded-process'
'lined-rectangle': shadedProcess,
'lin-rect': shadedProcess,
'lin-proc': shadedProcess,
'lined-process': shadedProcess,
'shaded-process': shadedProcess,
// Small circle with alias: 'sm-circ', 'small-circle', 'start'
'small-circle': stateStart,
'sm-circ': stateStart,
start: stateStart,
// framed circle with alias: 'stop', 'framed-circle', 'fr-circ'
stop: stateEnd,
'framed-circle': stateEnd,
'fr-circ': stateEnd,
// fork with alias: 'join', 'fork'
join: forkJoin,
fork: forkJoin,
// comment with alias: 'comment', 'brace-l'
comment: curlyBraceLeft,
'brace-l': curlyBraceLeft,
// lightening bolt with alias: 'bolt', 'com-link', 'lightning-bolt'
bolt: lightningBolt,
'com-link': lightningBolt,
'lightning-bolt': lightningBolt,
// document with alias: 'doc', 'document'
doc: waveEdgedRectangle,
document: waveEdgedRectangle,
// delay with alias: 'delay', 'half-rounded-rectangle'
delay: halfRoundedRectangle,
'half-rounded-rectangle': halfRoundedRectangle,
// horizontal cylinder with alias: 'h-cyl', 'das', 'horizontal-cylinder'
'horizontal-cylinder': tiltedCylinder,
'h-cyl': tiltedCylinder,
das: tiltedCylinder,
// lined cylinder with alias: 'lin-cyl', 'lined-cylinder', 'disk'
'lined-cylinder': linedCylinder,
'lin-cyl': linedCylinder,
disk: linedCylinder,
// curved trapezoid with alias: 'curv-trap', 'curved-trapezoid', 'display'
'curved-trapezoid': curvedTrapezoid,
'curv-trap': curvedTrapezoid,
display: curvedTrapezoid,
// divided rectangle with alias: 'div-rect', 'divided-rectangle', 'div-proc', 'divided-process'
'divided-rectangle': dividedRectangle,
'div-rect': dividedRectangle,
'div-proc': dividedRectangle,
'divided-process': dividedRectangle,
// triangle with alias: 'tri', 'triangle', 'extract'
triangle,
tri: triangle,
extract: triangle,
// window pane with alias: 'window-pane', 'win-pane', 'internal-storage'
'window-pane': windowPane,
'win-pane': windowPane,
'internal-storage': windowPane,
// filled circle with alias: 'f-circ', 'filled-circle', 'junction'
'f-circ': filledCircle,
junction: filledCircle,
'filled-circle': filledCircle,
// lined document with alias: 'lin-doc', 'lined-document'
'lin-doc': linedWaveEdgedRect,
'lined-document': linedWaveEdgedRect,
// notched pentagon with alias: 'notch-pent', 'notched-pentagon', 'loop-limit'
'notched-pentagon': trapezoidalPentagon,
'notch-pent': trapezoidalPentagon,
'loop-limit': trapezoidalPentagon,
// flipped triangle with alias: 'flip-tri', 'flipped-triangle', 'manual-file'
'flipped-triangle': flippedTriangle,
'flip-tri': flippedTriangle,
'manual-file': flippedTriangle,
// sloped rectangle with alias: 'sl-rect', 'sloped-rectangle', 'manual-input'
'sloped-rectangle': slopedRect,
'sl-rect': slopedRect,
'manual-input': slopedRect,
// documents with alias: 'docs', 'documents', 'st-doc', 'stacked-document'
docs: multiWaveEdgedRectangle,
documents: multiWaveEdgedRectangle,
'st-doc': multiWaveEdgedRectangle,
'stacked-document': multiWaveEdgedRectangle,
// 'processes' with alias: 'procs', 'processes', 'st-rect', 'stacked-rectangle'
processes: multiRect,
procs: multiRect,
'stacked-rectangle': multiRect,
'st-rect': multiRect,
// flag with alias: 'flag', 'paper-tape'
flag: waveRectangle,
'paper-tape': waveRectangle,
// bow tie rectangle with alias: 'bow-rect', 'bow-tie-rectangle', 'stored-data'
'bow-tie-rectangle': bowTieRect,
'bow-rect': bowTieRect,
'stored-data': bowTieRect,
// crossed circle with alias: 'cross-circ', 'crossed-circle', 'summary'
'crossed-circle': crossedCircle,
'cross-circ': crossedCircle,
summary: crossedCircle,
// tagged document with alias: 'tag-doc', 'tagged-document'
'tag-doc': taggedWaveEdgedRectangle,
'tagged-document': taggedWaveEdgedRectangle,
// tagged rectangle with alias: 'tag-rect', 'tagged-rectangle', 'tag-proc', 'tagged-process'
'tag-rect': taggedRect,
'tagged-rectangle': taggedRect,
'tag-proc': taggedRect,
'tagged-process': taggedRect,
// hourglass with alias: 'hourglass', 'collate'
hourglass,
collate: hourglass,
text,
anchor,
brace: curlyBraceLeft,
labelRect,
'brace-r': curlyBraceRight,
braces: curlyBraces,
iconSquare,
iconCircle,
icon,
iconRounded,
imageSquare,
kanbanItem,
};
const nodeElems = new Map(); const nodeElems = new Map();
@ -309,8 +7,6 @@ export const insertNode = async (elem, node, renderOptions) => {
let newEl; let newEl;
let el; let el;
// console.log("node is ", node.icon, node.shape)
//special check for rect shape (with or without rounded corners) //special check for rect shape (with or without rounded corners)
if (node.shape === 'rect') { if (node.shape === 'rect') {
if (node.rx && node.ry) { if (node.rx && node.ry) {
@ -320,7 +16,9 @@ export const insertNode = async (elem, node, renderOptions) => {
} }
} }
if (!shapes[node.shape]) { const shapeHandler = shapes[node.shape];
if (!shapeHandler) {
throw new Error(`No such shape: ${node.shape}. Please check your syntax.`); throw new Error(`No such shape: ${node.shape}. Please check your syntax.`);
} }
@ -333,9 +31,9 @@ export const insertNode = async (elem, node, renderOptions) => {
target = node.linkTarget || '_blank'; target = node.linkTarget || '_blank';
} }
newEl = elem.insert('svg:a').attr('xlink:href', node.link).attr('target', target); newEl = elem.insert('svg:a').attr('xlink:href', node.link).attr('target', target);
el = await shapes[node.shape](newEl, node, renderOptions); el = await shapeHandler(newEl, node, renderOptions);
} else { } else {
el = await shapes[node.shape](elem, node, renderOptions); el = await shapeHandler(elem, node, renderOptions);
newEl = el; newEl = el;
} }
if (node.tooltip) { if (node.tooltip) {
@ -349,9 +47,11 @@ export const insertNode = async (elem, node, renderOptions) => {
} }
return newEl; return newEl;
}; };
export const setNodeElem = (elem, node) => { export const setNodeElem = (elem, node) => {
nodeElems.set(node.id, elem); nodeElems.set(node.id, elem);
}; };
export const clear = () => { export const clear = () => {
nodeElems.clear(); nodeElems.clear();
}; };

View File

@ -1,5 +1,5 @@
import exp from 'constants'; import { shapes } from './shapes.js';
import { shapes } from './nodes.js'; import { describe, it, expect } from 'vitest';
describe('Test Alias for shapes', function () { describe('Test Alias for shapes', function () {
// for each shape in docs/syntax/flowchart.md, along with its semantic name, short name, and alias name, add a test case // for each shape in docs/syntax/flowchart.md, along with its semantic name, short name, and alias name, add a test case

View File

@ -0,0 +1,490 @@
import type { Node, ShapeRenderOptions } from '../types.js';
import { anchor } from './shapes/anchor.js';
import { bowTieRect } from './shapes/bowTieRect.js';
import { card } from './shapes/card.js';
import { choice } from './shapes/choice.js';
import { circle } from './shapes/circle.js';
import { crossedCircle } from './shapes/crossedCircle.js';
import { curlyBraceLeft } from './shapes/curlyBraceLeft.js';
import { curlyBraceRight } from './shapes/curlyBraceRight.js';
import { curlyBraces } from './shapes/curlyBraces.js';
import { curvedTrapezoid } from './shapes/curvedTrapezoid.js';
import { cylinder } from './shapes/cylinder.js';
import { dividedRectangle } from './shapes/dividedRect.js';
import { doublecircle } from './shapes/doubleCircle.js';
import { filledCircle } from './shapes/filledCircle.js';
import { flippedTriangle } from './shapes/flippedTriangle.js';
import { forkJoin } from './shapes/forkJoin.js';
import { halfRoundedRectangle } from './shapes/halfRoundedRectangle.js';
import { hexagon } from './shapes/hexagon.js';
import { hourglass } from './shapes/hourglass.js';
import { icon } from './shapes/icon.js';
import { iconCircle } from './shapes/iconCircle.js';
import { iconRounded } from './shapes/iconRounded.js';
import { iconSquare } from './shapes/iconSquare.js';
import { imageSquare } from './shapes/imageSquare.js';
import { inv_trapezoid } from './shapes/invertedTrapezoid.js';
import { labelRect } from './shapes/labelRect.js';
import { lean_left } from './shapes/leanLeft.js';
import { lean_right } from './shapes/leanRight.js';
import { lightningBolt } from './shapes/lightningBolt.js';
import { linedCylinder } from './shapes/linedCylinder.js';
import { linedWaveEdgedRect } from './shapes/linedWaveEdgedRect.js';
import { multiRect } from './shapes/multiRect.js';
import { multiWaveEdgedRectangle } from './shapes/multiWaveEdgedRectangle.js';
import { note } from './shapes/note.js';
import { question } from './shapes/question.js';
import { rect_left_inv_arrow } from './shapes/rectLeftInvArrow.js';
import { rectWithTitle } from './shapes/rectWithTitle.js';
import { roundedRect } from './shapes/roundedRect.js';
import { shadedProcess } from './shapes/shadedProcess.js';
import { slopedRect } from './shapes/slopedRect.js';
import { squareRect } from './shapes/squareRect.js';
import { stadium } from './shapes/stadium.js';
import { state } from './shapes/state.js';
import { stateEnd } from './shapes/stateEnd.js';
import { stateStart } from './shapes/stateStart.js';
import { subroutine } from './shapes/subroutine.js';
import { taggedRect } from './shapes/taggedRect.js';
import { taggedWaveEdgedRectangle } from './shapes/taggedWaveEdgedRectangle.js';
import { text } from './shapes/text.js';
import { tiltedCylinder } from './shapes/tiltedCylinder.js';
import { trapezoid } from './shapes/trapezoid.js';
import { trapezoidalPentagon } from './shapes/trapezoidalPentagon.js';
import { triangle } from './shapes/triangle.js';
import { waveEdgedRectangle } from './shapes/waveEdgedRectangle.js';
import { waveRectangle } from './shapes/waveRectangle.js';
import { windowPane } from './shapes/windowPane.js';
import { kanbanItem } from './shapes/kanbanItem.js';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ShapeHandler = (parent: any, node: Node, options: ShapeRenderOptions) => unknown;
export interface ShapeDefinition {
semanticName: string;
name: string;
shortName: string;
description: string;
/**
* Aliases can include descriptive names, other short names, etc.
*/
aliases?: string[];
/**
* These are names used by mermaid before the introduction of new shapes. These will not be in standard formats, and shouldn't be used by the users
*/
internalAliases?: string[];
handler: ShapeHandler;
}
export const shapesDefs: ShapeDefinition[] = [
{
semanticName: 'Process',
name: 'Rectangle',
shortName: 'rect',
description: 'Standard process shape',
aliases: ['proc', 'process', 'rectangle'],
internalAliases: ['squareRect'],
handler: squareRect,
},
{
semanticName: 'Event',
name: 'Rounded Rectangle',
shortName: 'rounded',
description: 'Represents an event',
aliases: ['event'],
internalAliases: ['roundedRect'],
handler: roundedRect,
},
{
semanticName: 'Terminal Point',
name: 'Stadium',
shortName: 'stadium',
description: 'Terminal point',
aliases: ['terminal', 'pill'],
handler: stadium,
},
{
semanticName: 'Subprocess',
name: 'Framed Rectangle',
shortName: 'fr-rect',
description: 'Subprocess',
aliases: ['subprocess', 'subproc', 'framed-rectangle', 'subroutine'],
handler: subroutine,
},
{
semanticName: 'Database',
name: 'Cylinder',
shortName: 'cyl',
description: 'Database storage',
aliases: ['db', 'database', 'cylinder'],
handler: cylinder,
},
{
semanticName: 'Start',
name: 'Circle',
shortName: 'circle',
description: 'Starting point',
aliases: ['circ'],
handler: circle,
},
{
semanticName: 'Decision',
name: 'Diamond',
shortName: 'diam',
description: 'Decision-making step',
aliases: ['decision', 'diamond', 'question'],
handler: question,
},
{
semanticName: 'Prepare Conditional',
name: 'Hexagon',
shortName: 'hex',
description: 'Preparation or condition step',
aliases: ['hexagon', 'prepare'],
handler: hexagon,
},
{
semanticName: 'Data Input/Output',
name: 'Lean Right',
shortName: 'lean-r',
description: 'Represents input or output',
aliases: ['lean-right', 'in-out'],
internalAliases: ['lean_right'],
handler: lean_right,
},
{
semanticName: 'Data Input/Output',
name: 'Lean Left',
shortName: 'lean-l',
description: 'Represents output or input',
aliases: ['lean-left', 'out-in'],
internalAliases: ['lean_left'],
handler: lean_left,
},
{
semanticName: 'Priority Action',
name: 'Trapezoid Base Bottom',
shortName: 'trap-b',
description: 'Priority action',
aliases: ['priority', 'trapezoid-bottom', 'trapezoid'],
handler: trapezoid,
},
{
semanticName: 'Manual Operation',
name: 'Trapezoid Base Top',
shortName: 'trap-t',
description: 'Represents a manual task',
aliases: ['manual', 'trapezoid-top', 'inv-trapezoid'],
internalAliases: ['inv_trapezoid'],
handler: inv_trapezoid,
},
{
semanticName: 'Stop',
name: 'Double Circle',
shortName: 'dbl-circ',
description: 'Represents a stop point',
aliases: ['double-circle'],
internalAliases: ['doublecircle'],
handler: doublecircle,
},
{
semanticName: 'Text Block',
name: 'Text Block',
shortName: 'text',
description: 'Text block',
handler: text,
},
{
semanticName: 'Card',
name: 'Notched Rectangle',
shortName: 'notch-rect',
description: 'Represents a card',
aliases: ['card', 'notched-rectangle'],
handler: card,
},
{
semanticName: 'Lined/Shaded Process',
name: 'Lined Rectangle',
shortName: 'lin-rect',
description: 'Lined process shape',
aliases: ['lined-rectangle', 'lined-process', 'lin-proc', 'shaded-process'],
handler: shadedProcess,
},
{
semanticName: 'Start',
name: 'Small Circle',
shortName: 'sm-circ',
description: 'Small starting point',
aliases: ['start', 'small-circle'],
internalAliases: ['stateStart'],
handler: stateStart,
},
{
semanticName: 'Stop',
name: 'Framed Circle',
shortName: 'fr-circ',
description: 'Stop point',
aliases: ['stop', 'framed-circle'],
internalAliases: ['stateEnd'],
handler: stateEnd,
},
{
semanticName: 'Fork/Join',
name: 'Filled Rectangle',
shortName: 'fork',
description: 'Fork or join in process flow',
aliases: ['join'],
internalAliases: ['forkJoin'],
handler: forkJoin,
},
{
semanticName: 'Collate',
name: 'Hourglass',
shortName: 'hourglass',
description: 'Represents a collate operation',
aliases: ['hourglass', 'collate'],
handler: hourglass,
},
{
semanticName: 'Comment',
name: 'Curly Brace',
shortName: 'brace',
description: 'Adds a comment',
aliases: ['comment', 'brace-l'],
handler: curlyBraceLeft,
},
{
semanticName: 'Comment Right',
name: 'Curly Brace',
shortName: 'brace-r',
description: 'Adds a comment',
handler: curlyBraceRight,
},
{
semanticName: 'Comment with braces on both sides',
name: 'Curly Braces',
shortName: 'braces',
description: 'Adds a comment',
handler: curlyBraces,
},
{
semanticName: 'Com Link',
name: 'Lightning Bolt',
shortName: 'bolt',
description: 'Communication link',
aliases: ['com-link', 'lightning-bolt'],
handler: lightningBolt,
},
{
semanticName: 'Document',
name: 'Document',
shortName: 'doc',
description: 'Represents a document',
aliases: ['doc', 'document'],
handler: waveEdgedRectangle,
},
{
semanticName: 'Delay',
name: 'Half-Rounded Rectangle',
shortName: 'delay',
description: 'Represents a delay',
aliases: ['half-rounded-rectangle'],
handler: halfRoundedRectangle,
},
{
semanticName: 'Direct Access Storage',
name: 'Horizontal Cylinder',
shortName: 'h-cyl',
description: 'Direct access storage',
aliases: ['das', 'horizontal-cylinder'],
handler: tiltedCylinder,
},
{
semanticName: 'Disk Storage',
name: 'Lined Cylinder',
shortName: 'lin-cyl',
description: 'Disk storage',
aliases: ['disk', 'lined-cylinder'],
handler: linedCylinder,
},
{
semanticName: 'Display',
name: 'Curved Trapezoid',
shortName: 'curv-trap',
description: 'Represents a display',
aliases: ['curved-trapezoid', 'display'],
handler: curvedTrapezoid,
},
{
semanticName: 'Divided Process',
name: 'Divided Rectangle',
shortName: 'div-rect',
description: 'Divided process shape',
aliases: ['div-proc', 'divided-rectangle', 'divided-process'],
handler: dividedRectangle,
},
{
semanticName: 'Extract',
name: 'Triangle',
shortName: 'tri',
description: 'Extraction process',
aliases: ['extract', 'triangle'],
handler: triangle,
},
{
semanticName: 'Internal Storage',
name: 'Window Pane',
shortName: 'win-pane',
description: 'Internal storage',
aliases: ['internal-storage', 'window-pane'],
handler: windowPane,
},
{
semanticName: 'Junction',
name: 'Filled Circle',
shortName: 'f-circ',
description: 'Junction point',
aliases: ['junction', 'filled-circle'],
handler: filledCircle,
},
{
semanticName: 'Loop Limit',
name: 'Trapezoidal Pentagon',
shortName: 'notch-pent',
description: 'Loop limit step',
aliases: ['loop-limit', 'notched-pentagon'],
handler: trapezoidalPentagon,
},
{
semanticName: 'Manual File',
name: 'Flipped Triangle',
shortName: 'flip-tri',
description: 'Manual file operation',
aliases: ['manual-file', 'flipped-triangle'],
handler: flippedTriangle,
},
{
semanticName: 'Kanban Item',
name: 'Kanban Item',
shortName: 'kanbanItem',
description: 'Item on a kanban board',
aliases: ['kanban-item'],
handler: kanbanItem,
},
{
semanticName: 'Manual Input',
name: 'Sloped Rectangle',
shortName: 'sl-rect',
description: 'Manual input step',
aliases: ['manual-input', 'sloped-rectangle'],
handler: slopedRect,
},
{
semanticName: 'Multi-Document',
name: 'Stacked Document',
shortName: 'docs',
description: 'Multiple documents',
aliases: ['documents', 'st-doc', 'stacked-document'],
handler: multiWaveEdgedRectangle,
},
{
semanticName: 'Multi-Process',
name: 'Stacked Rectangle',
shortName: 'st-rect',
description: 'Multiple processes',
aliases: ['procs', 'processes', 'stacked-rectangle'],
handler: multiRect,
},
{
semanticName: 'Stored Data',
name: 'Bow Tie Rectangle',
shortName: 'bow-rect',
description: 'Stored data',
aliases: ['stored-data', 'bow-tie-rectangle'],
handler: bowTieRect,
},
{
semanticName: 'Summary',
name: 'Crossed Circle',
shortName: 'cross-circ',
description: 'Summary',
aliases: ['summary', 'crossed-circle'],
handler: crossedCircle,
},
{
semanticName: 'Tagged Document',
name: 'Tagged Document',
shortName: 'tag-doc',
description: 'Tagged document',
aliases: ['tag-doc', 'tagged-document'],
handler: taggedWaveEdgedRectangle,
},
{
semanticName: 'Tagged Process',
name: 'Tagged Rectangle',
shortName: 'tag-rect',
description: 'Tagged process',
aliases: ['tagged-rectangle', 'tag-proc', 'tagged-process'],
handler: taggedRect,
},
{
semanticName: 'Paper Tape',
name: 'Flag',
shortName: 'flag',
description: 'Paper tape',
aliases: ['paper-tape'],
handler: waveRectangle,
},
{
semanticName: 'Odd',
name: 'Odd',
shortName: 'odd',
description: 'Odd shape',
internalAliases: ['rect_left_inv_arrow'],
handler: rect_left_inv_arrow,
},
{
semanticName: 'Lined Document',
name: 'Lined Document',
shortName: 'lin-doc',
description: 'Lined document',
aliases: ['lined-document'],
handler: linedWaveEdgedRect,
},
];
const generateShapeMap = () => {
// These are the shapes that didn't have documentation present
const shapeMap: Record<string, ShapeHandler> = {
// States
state,
choice,
note,
// Rectangles
rectWithTitle,
labelRect,
// Icons
iconSquare,
iconCircle,
icon,
iconRounded,
imageSquare,
anchor,
};
for (const shape of shapesDefs) {
for (const alias of [
shape.shortName,
...(shape.aliases ?? []),
...(shape.internalAliases ?? []),
]) {
shapeMap[alias] = shape.handler;
}
}
return shapeMap;
};
export const shapes = generateShapeMap();

View File

@ -1,7 +1,7 @@
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { updateNodeBounds, getNodeClasses } from './util.js'; import { updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,7 +1,7 @@
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { getNodeClasses, updateNodeBounds } from './util.js'; import { getNodeClasses, updateNodeBounds } from './util.js';
import type { SVG } from '../../../diagram-api/types.js'; import type { SVG } from '../../../diagram-api/types.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -6,7 +6,7 @@ import {
generateCirclePoints, generateCirclePoints,
} from './util.js'; } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,7 +1,7 @@
import rough from 'roughjs'; import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js'; import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import type { Node, ShapeRenderOptions } from '../../types.d.ts'; import type { Node, ShapeRenderOptions } from '../../types.ts';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { getNodeClasses, updateNodeBounds } from './util.js'; import { getNodeClasses, updateNodeBounds } from './util.js';

View File

@ -1,7 +1,7 @@
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';
import { createPathFromPoints } from './util.js'; import { createPathFromPoints } from './util.js';

View File

@ -7,7 +7,7 @@ import {
generateCirclePoints, generateCirclePoints,
} from './util.js'; } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,7 +1,7 @@
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -2,7 +2,7 @@ import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js'; import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { getIconSVG } from '../../icons.js'; import { getIconSVG } from '../../icons.js';
import type { Node, ShapeRenderOptions } from '../../types.d.ts'; import type { Node, ShapeRenderOptions } from '../../types.ts';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js'; import { labelHelper, updateNodeBounds } from './util.js';
@ -77,7 +77,7 @@ export const icon = async (
: -bbox.height / 2 - labelPadding / 2 - iconHeight / 2 - iconY : -bbox.height / 2 - labelPadding / 2 - iconHeight / 2 - iconY
})` })`
); );
iconElem.selectAll('path').attr('fill', stylesMap.get('stroke') || nodeBorder); iconElem.attr('style', `color: ${stylesMap.get('stroke') ?? nodeBorder};`);
} }
label.attr( label.attr(

View File

@ -2,7 +2,7 @@ import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js'; import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { getIconSVG } from '../../icons.js'; import { getIconSVG } from '../../icons.js';
import type { Node, ShapeRenderOptions } from '../../types.d.ts'; import type { Node, ShapeRenderOptions } from '../../types.ts';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js'; import { labelHelper, updateNodeBounds } from './util.js';
@ -26,10 +26,10 @@ export const iconCircle = async (
const topLabel = node.pos === 't'; const topLabel = node.pos === 't';
const { nodeBorder, mainBkg } = themeVariables; const { nodeBorder } = themeVariables;
const { stylesMap } = compileStyles(node); const { stylesMap } = compileStyles(node);
const rc = rough.svg(shapeSvg); const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { stroke: stylesMap.get('fill') || mainBkg }); const options = userNodeOverrides(node, { stroke: 'transparent' });
if (node.look !== 'handDrawn') { if (node.look !== 'handDrawn') {
options.roughness = 0; options.roughness = 0;
@ -74,7 +74,7 @@ export const iconCircle = async (
: -bbox.height / 2 - labelPadding / 2 - iconHeight / 2 - iconY : -bbox.height / 2 - labelPadding / 2 - iconHeight / 2 - iconY
})` })`
); );
iconElem.selectAll('path').attr('fill', stylesMap.get('stroke') || nodeBorder); iconElem.attr('style', `color: ${stylesMap.get('stroke') ?? nodeBorder};`);
label.attr( label.attr(
'transform', 'transform',
`translate(${-bbox.width / 2 - (bbox.x - (bbox.left ?? 0))},${ `translate(${-bbox.width / 2 - (bbox.x - (bbox.left ?? 0))},${

View File

@ -2,7 +2,7 @@ import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js'; import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { getIconSVG } from '../../icons.js'; import { getIconSVG } from '../../icons.js';
import type { Node, ShapeRenderOptions } from '../../types.d.ts'; import type { Node, ShapeRenderOptions } from '../../types.ts';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { createRoundedRectPathD } from './roundedRectPath.js'; import { createRoundedRectPathD } from './roundedRectPath.js';
@ -30,7 +30,7 @@ export const iconRounded = async (
const height = iconSize + halfPadding * 2; const height = iconSize + halfPadding * 2;
const width = iconSize + halfPadding * 2; const width = iconSize + halfPadding * 2;
const { nodeBorder, mainBkg } = themeVariables; const { nodeBorder } = themeVariables;
const { stylesMap } = compileStyles(node); const { stylesMap } = compileStyles(node);
const x = -width / 2; const x = -width / 2;
@ -39,7 +39,7 @@ export const iconRounded = async (
const labelPadding = node.label ? 8 : 0; const labelPadding = node.label ? 8 : 0;
const rc = rough.svg(shapeSvg); const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { stroke: stylesMap.get('fill') || mainBkg }); const options = userNodeOverrides(node, { stroke: 'transparent' });
if (node.look !== 'handDrawn') { if (node.look !== 'handDrawn') {
options.roughness = 0; options.roughness = 0;
@ -82,7 +82,7 @@ export const iconRounded = async (
: -bbox.height / 2 - labelPadding / 2 - iconHeight / 2 - iconY : -bbox.height / 2 - labelPadding / 2 - iconHeight / 2 - iconY
})` })`
); );
iconElem.selectAll('path').attr('fill', stylesMap.get('stroke') ?? nodeBorder); iconElem.attr('style', `color: ${stylesMap.get('stroke') ?? nodeBorder};`);
} }
label.attr( label.attr(

View File

@ -2,7 +2,7 @@ import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js'; import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { getIconSVG } from '../../icons.js'; import { getIconSVG } from '../../icons.js';
import type { Node, ShapeRenderOptions } from '../../types.d.ts'; import type { Node, ShapeRenderOptions } from '../../types.ts';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js'; import { labelHelper, updateNodeBounds } from './util.js';
@ -29,7 +29,7 @@ export const iconSquare = async (
const height = iconSize + halfPadding * 2; const height = iconSize + halfPadding * 2;
const width = iconSize + halfPadding * 2; const width = iconSize + halfPadding * 2;
const { nodeBorder, mainBkg } = themeVariables; const { nodeBorder } = themeVariables;
const { stylesMap } = compileStyles(node); const { stylesMap } = compileStyles(node);
const x = -width / 2; const x = -width / 2;
@ -38,7 +38,7 @@ export const iconSquare = async (
const labelPadding = node.label ? 8 : 0; const labelPadding = node.label ? 8 : 0;
const rc = rough.svg(shapeSvg); const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { stroke: stylesMap.get('fill') || mainBkg }); const options = userNodeOverrides(node, { stroke: 'transparent' });
if (node.look !== 'handDrawn') { if (node.look !== 'handDrawn') {
options.roughness = 0; options.roughness = 0;
@ -81,7 +81,7 @@ export const iconSquare = async (
: -bbox.height / 2 - labelPadding / 2 - iconHeight / 2 - iconY : -bbox.height / 2 - labelPadding / 2 - iconHeight / 2 - iconY
})` })`
); );
iconElem.selectAll('path').attr('fill', stylesMap.get('stroke') ?? nodeBorder); iconElem.attr('style', `color: ${stylesMap.get('stroke') ?? nodeBorder};`);
} }
label.attr( label.attr(

View File

@ -1,7 +1,7 @@
import rough from 'roughjs'; import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js'; import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import type { Node, ShapeRenderOptions } from '../../types.d.ts'; import type { Node, ShapeRenderOptions } from '../../types.ts';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js'; import { labelHelper, updateNodeBounds } from './util.js';

View File

@ -1,10 +1,11 @@
import { labelHelper, insertLabel, updateNodeBounds, getNodeClasses } from './util.js'; import { labelHelper, insertLabel, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { KanbanNode } from '../../types.js'; import type { SVG } from '../../../diagram-api/types.js';
import type { Node, KanbanNode, ShapeRenderOptions } from '../../types.js';
import { createRoundedRectPathD } from './roundedRectPath.js'; import { createRoundedRectPathD } from './roundedRectPath.js';
import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js'; import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';
import type { MermaidConfig } from '../../../config.type.js';
const colorFromPriority = (priority: KanbanNode['priority']) => { const colorFromPriority = (priority: KanbanNode['priority']) => {
switch (priority) { switch (priority) {
case 'Very High': case 'Very High':
@ -17,33 +18,28 @@ const colorFromPriority = (priority: KanbanNode['priority']) => {
return 'lightblue'; return 'lightblue';
} }
}; };
export const kanbanItem = async ( export const kanbanItem = async (parent: SVG, node: Node, { config }: ShapeRenderOptions) => {
parent: SVGAElement, const unknownNode = node as unknown;
node: KanbanNode, const kanbanNode = unknownNode as KanbanNode;
{ config }: { config: MermaidConfig } const { labelStyles, nodeStyles } = styles2String(kanbanNode);
) => { kanbanNode.labelStyle = labelStyles;
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
// console.log('IPI labelStyles:', labelStyles);
// const labelPaddingX = 10;
const labelPaddingX = 10; const labelPaddingX = 10;
const orgWidth = node.width; const orgWidth = kanbanNode.width;
node.width = (node.width ?? 200) - 10; kanbanNode.width = (kanbanNode.width ?? 200) - 10;
// console.log('APA123 kanbanItem priority', node?.priority);
const { const {
shapeSvg, shapeSvg,
bbox, bbox,
label: labelElTitle, label: labelElTitle,
} = await labelHelper(parent, node, getNodeClasses(node)); } = await labelHelper(parent, kanbanNode, getNodeClasses(kanbanNode));
const padding = node.padding || 10; const padding = kanbanNode.padding || 10;
// elem.insert('svg:a').attr('xlink:href', node.link).attr('target', target);
// console.log('STO node config.kanban:', config.kanban, config.kanban);
let ticketUrl = ''; let ticketUrl = '';
let link; let link;
// console.log('STO ticket:', node.ticket);
if (node.ticket && config?.kanban?.ticketBaseUrl) { if (kanbanNode.ticket && config?.kanban?.ticketBaseUrl) {
ticketUrl = config?.kanban?.ticketBaseUrl.replace('#TICKET#', node.ticket); ticketUrl = config?.kanban?.ticketBaseUrl.replace('#TICKET#', kanbanNode.ticket);
link = shapeSvg link = shapeSvg
.insert('svg:a', ':first-child') .insert('svg:a', ':first-child')
.attr('class', 'kanban-ticket-link') .attr('class', 'kanban-ticket-link')
@ -52,29 +48,30 @@ export const kanbanItem = async (
} }
const options = { const options = {
useHtmlLabels: node.useHtmlLabels, useHtmlLabels: kanbanNode.useHtmlLabels,
labelStyle: node.labelStyle, labelStyle: kanbanNode.labelStyle,
width: node.width, width: kanbanNode.width,
icon: node.icon, icon: kanbanNode.icon,
img: node.img, img: kanbanNode.img,
padding: node.padding, padding: kanbanNode.padding,
centerLabel: false, centerLabel: false,
}; };
const { label: labelEl, bbox: bbox2 } = await insertLabel( const { label: labelEl, bbox: bbox2 } = await insertLabel(
link ? link : shapeSvg, link ? link : shapeSvg,
node.ticket || '', kanbanNode.ticket || '',
options options
); );
const { label: labelElAssigned, bbox: bboxAssigned } = await insertLabel( const { label: labelElAssigned, bbox: bboxAssigned } = await insertLabel(
shapeSvg, shapeSvg,
node.assigned || '', kanbanNode.assigned || '',
options options
); );
node.width = orgWidth; kanbanNode.width = orgWidth;
const labelPaddingY = 10; const labelPaddingY = 10;
const totalWidth = node?.width || 0; const totalWidth = kanbanNode?.width || 0;
const heightAdj = Math.max(bbox2.height, bboxAssigned.height) / 2; const heightAdj = Math.max(bbox2.height, bboxAssigned.height) / 2;
const totalHeight = Math.max(bbox.height + labelPaddingY * 2, node?.height || 0) + heightAdj; const totalHeight =
Math.max(bbox.height + labelPaddingY * 2, kanbanNode?.height || 0) + heightAdj;
const x = -totalWidth / 2; const x = -totalWidth / 2;
const y = -totalHeight / 2; const y = -totalHeight / 2;
labelElTitle.attr( labelElTitle.attr(
@ -93,17 +90,16 @@ export const kanbanItem = async (
(-heightAdj + bbox.height / 2) + (-heightAdj + bbox.height / 2) +
')' ')'
); );
// log.info('IPI node = ', node);
let rect; let rect;
const { rx, ry } = node; const { rx, ry } = kanbanNode;
const { cssStyles } = node; const { cssStyles } = kanbanNode;
if (node.look === 'handDrawn') { if (kanbanNode.look === 'handDrawn') {
// @ts-ignore TODO: Fix rough typings // @ts-ignore TODO: Fix rough typings
const rc = rough.svg(shapeSvg); const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {}); const options = userNodeOverrides(kanbanNode, {});
const roughNode = const roughNode =
rx || ry rx || ry
@ -124,7 +120,7 @@ export const kanbanItem = async (
.attr('y', y) .attr('y', y)
.attr('width', totalWidth) .attr('width', totalWidth)
.attr('height', totalHeight); .attr('height', totalHeight);
if (node.priority) { if (kanbanNode.priority) {
const line = shapeSvg.append('line', ':first-child'); const line = shapeSvg.append('line', ':first-child');
const lineX = x + 2; const lineX = x + 2;
@ -137,15 +133,15 @@ export const kanbanItem = async (
.attr('y2', y2) .attr('y2', y2)
.attr('stroke-width', '4') .attr('stroke-width', '4')
.attr('stroke', colorFromPriority(node.priority)); .attr('stroke', colorFromPriority(kanbanNode.priority));
} }
} }
updateNodeBounds(node, rect); updateNodeBounds(kanbanNode, rect);
node.height = totalHeight; kanbanNode.height = totalHeight;
node.intersect = function (point) { kanbanNode.intersect = function (point) {
return intersect.rect(node, point); return intersect.rect(kanbanNode, point);
}; };
return shapeSvg; return shapeSvg;

View File

@ -1,6 +1,6 @@
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { getNodeClasses, updateNodeBounds } from './util.js'; import { getNodeClasses, updateNodeBounds } from './util.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import type { SVG } from '../../../diagram-api/types.js'; import type { SVG } from '../../../diagram-api/types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -5,7 +5,7 @@ import {
generateFullSineWavePoints, generateFullSineWavePoints,
} from './util.js'; } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import rough from 'roughjs'; import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';

View File

@ -1,5 +1,5 @@
import { labelHelper, getNodeClasses, updateNodeBounds, createPathFromPoints } from './util.js'; import { labelHelper, getNodeClasses, updateNodeBounds, createPathFromPoints } from './util.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';

View File

@ -6,7 +6,7 @@ import {
generateFullSineWavePoints, generateFullSineWavePoints,
} from './util.js'; } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import rough from 'roughjs'; import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,5 +1,5 @@
import { labelHelper, getNodeClasses, updateNodeBounds, createPathFromPoints } from './util.js'; import { labelHelper, getNodeClasses, updateNodeBounds, createPathFromPoints } from './util.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';

View File

@ -6,7 +6,7 @@ import {
createPathFromPoints, createPathFromPoints,
} from './util.js'; } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import rough from 'roughjs'; import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String } from './handDrawnShapeStyles.js'; import { styles2String } from './handDrawnShapeStyles.js';
export async function text(parent: SVGAElement, node: Node): Promise<SVGAElement> { export async function text(parent: SVGAElement, node: Node): Promise<SVGAElement> {

View File

@ -1,5 +1,5 @@
import { labelHelper, getNodeClasses, updateNodeBounds } from './util.js'; import { labelHelper, getNodeClasses, updateNodeBounds } from './util.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';

View File

@ -1,6 +1,6 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,7 +1,7 @@
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js'; import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';
import { createPathFromPoints } from './util.js'; import { createPathFromPoints } from './util.js';

View File

@ -6,7 +6,7 @@ import {
createPathFromPoints, createPathFromPoints,
} from './util.js'; } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import rough from 'roughjs'; import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';

View File

@ -6,7 +6,7 @@ import {
generateFullSineWavePoints, generateFullSineWavePoints,
} from './util.js'; } from './util.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';

View File

@ -1,5 +1,5 @@
import { labelHelper, getNodeClasses, updateNodeBounds } from './util.js'; import { labelHelper, getNodeClasses, updateNodeBounds } from './util.js';
import type { Node } from '../../types.d.ts'; import type { Node } from '../../types.ts';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js'; import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs'; import rough from 'roughjs';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';

6135
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,10 @@
{ {
"groupName": "eslint", "groupName": "eslint",
"matchPackagePatterns": ["eslint"] "matchPackagePatterns": ["eslint"]
},
{
"groupName": "dompurify",
"matchPackagePatterns": ["dompurify"]
} }
], ],
"dependencyDashboard": false, "dependencyDashboard": false,