mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-11-04 12:54:08 +01:00 
			
		
		
		
	Merge from upstream mermaid OS develop
This commit is contained in:
		
							
								
								
									
										5
									
								
								.changeset/angry-bags-brake.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/angry-bags-brake.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': patch
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fix: architecture diagrams no longer grow to extreme heights due to conflicting alignments
 | 
				
			||||||
							
								
								
									
										8
									
								
								.changeset/great-ghosts-rule.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.changeset/great-ghosts-rule.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': minor
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Flowchart new syntax for node metadata bugs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Incorrect label mapping for nodes when using `&`
 | 
				
			||||||
 | 
					- Syntax error when `}` with trailing spaces before new line
 | 
				
			||||||
							
								
								
									
										5
									
								
								.changeset/many-brooms-promise.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/many-brooms-promise.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': minor
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Adding support for animation of flowchart edges
 | 
				
			||||||
@@ -171,6 +171,58 @@ describe.skip('architecture diagram', () => {
 | 
				
			|||||||
            `
 | 
					            `
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should render an architecture diagram with a resonable height', () => {
 | 
				
			||||||
 | 
					    imgSnapshotTest(
 | 
				
			||||||
 | 
					      `architecture-beta
 | 
				
			||||||
 | 
					              group federated(cloud)[Federated Environment]
 | 
				
			||||||
 | 
					                  service server1(server)[System] in federated
 | 
				
			||||||
 | 
					                  service edge(server)[Edge Device] in federated
 | 
				
			||||||
 | 
					                  server1:R -- L:edge
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              group on_prem(cloud)[Hub]
 | 
				
			||||||
 | 
					                  service firewall(server)[Firewall Device] in on_prem
 | 
				
			||||||
 | 
					                  service server(server)[Server] in on_prem
 | 
				
			||||||
 | 
					                  firewall:R -- L:server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  service db1(database)[db1] in on_prem
 | 
				
			||||||
 | 
					                  service db2(database)[db2] in on_prem
 | 
				
			||||||
 | 
					                  service db3(database)[db3] in on_prem
 | 
				
			||||||
 | 
					                  service db4(database)[db4] in on_prem
 | 
				
			||||||
 | 
					                  service db5(database)[db5] in on_prem
 | 
				
			||||||
 | 
					                  service db6(database)[db6] in on_prem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  junction mid in on_prem
 | 
				
			||||||
 | 
					                  server:B -- T:mid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  junction 1Leftofmid in on_prem
 | 
				
			||||||
 | 
					                  1Leftofmid:R -- L:mid
 | 
				
			||||||
 | 
					                  1Leftofmid:B -- T:db1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  junction 2Leftofmid in on_prem
 | 
				
			||||||
 | 
					                  2Leftofmid:R -- L:1Leftofmid
 | 
				
			||||||
 | 
					                  2Leftofmid:B -- T:db2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  junction 3Leftofmid in on_prem
 | 
				
			||||||
 | 
					                  3Leftofmid:R -- L:2Leftofmid
 | 
				
			||||||
 | 
					                  3Leftofmid:B -- T:db3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  junction 1RightOfMid in on_prem
 | 
				
			||||||
 | 
					                  mid:R -- L:1RightOfMid
 | 
				
			||||||
 | 
					                  1RightOfMid:B -- T:db4
 | 
				
			||||||
 | 
					                  
 | 
				
			||||||
 | 
					                  junction 2RightOfMid in on_prem
 | 
				
			||||||
 | 
					                  1RightOfMid:R -- L:2RightOfMid
 | 
				
			||||||
 | 
					                  2RightOfMid:B -- T:db5        
 | 
				
			||||||
 | 
					                  
 | 
				
			||||||
 | 
					                  junction 3RightOfMid in on_prem
 | 
				
			||||||
 | 
					                  2RightOfMid:R -- L:3RightOfMid
 | 
				
			||||||
 | 
					                  3RightOfMid:B -- T:db6         
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  edge:R -- L:firewall
 | 
				
			||||||
 | 
					      `
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Skipped as the layout is not deterministic, and causes issues in E2E tests.
 | 
					// Skipped as the layout is not deterministic, and causes issues in E2E tests.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1076,4 +1076,32 @@ end
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					  describe('New @ sytax for node metadata edge cases', () => {
 | 
				
			||||||
 | 
					    it('should be possible to use @  syntax to add labels on multi nodes', () => {
 | 
				
			||||||
 | 
					      imgSnapshotTest(
 | 
				
			||||||
 | 
					        `flowchart TB
 | 
				
			||||||
 | 
					       n2["label for n2"] &   n4@{ label: "labe for n4"}   & n5@{ label: "labe for n5"}
 | 
				
			||||||
 | 
					        `,
 | 
				
			||||||
 | 
					        {}
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('should be possible to use @  syntax to add labels with trail spaces and &', () => {
 | 
				
			||||||
 | 
					      imgSnapshotTest(
 | 
				
			||||||
 | 
					        `flowchart TB
 | 
				
			||||||
 | 
					       n2["label for n2"] &   n4@{ label: "labe for n4"}   & n5@{ label: "labe for n5"}   
 | 
				
			||||||
 | 
					        `,
 | 
				
			||||||
 | 
					        {}
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('should be possible to use @  syntax to add labels with trail spaces', () => {
 | 
				
			||||||
 | 
					      imgSnapshotTest(
 | 
				
			||||||
 | 
					        `flowchart TB
 | 
				
			||||||
 | 
					       n2["label for n2"]
 | 
				
			||||||
 | 
					       n4@{ label: "labe for n4"}
 | 
				
			||||||
 | 
					       n5@{ label: "labe for n5"}  
 | 
				
			||||||
 | 
					        `,
 | 
				
			||||||
 | 
					        {}
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,29 +86,66 @@
 | 
				
			|||||||
      /* tspan {
 | 
					      /* tspan {
 | 
				
			||||||
              font-size: 6px !important;
 | 
					              font-size: 6px !important;
 | 
				
			||||||
            } */
 | 
					            } */
 | 
				
			||||||
 | 
					      /* .flowchart-link {
 | 
				
			||||||
 | 
					        stroke-dasharray: 4, 4 !important;
 | 
				
			||||||
 | 
					        animation: flow 1s linear infinite;
 | 
				
			||||||
 | 
					        animation: dashdraw 4.93282s linear infinite;
 | 
				
			||||||
 | 
					        stroke-width: 2px !important;
 | 
				
			||||||
 | 
					      } */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @keyframes dashdraw {
 | 
				
			||||||
 | 
					        from {
 | 
				
			||||||
 | 
					          stroke-dashoffset: 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /*stroke-width:2;stroke-dasharray:10.000000,9.865639;stroke-dashoffset:-198.656393;animation:    4.932820s linear infinite;*/
 | 
				
			||||||
 | 
					      /* stroke-width:2;stroke-dasharray:10.000000,9.865639;stroke-dashoffset:-198.656393;animation: dashdraw 4.932820s linear infinite;*/
 | 
				
			||||||
    </style>
 | 
					    </style>
 | 
				
			||||||
  </head>
 | 
					  </head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <body>
 | 
					  <body>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
---
 | 
					 | 
				
			||||||
config:
 | 
					 | 
				
			||||||
  layout: elk
 | 
					 | 
				
			||||||
---
 | 
					 | 
				
			||||||
      flowchart LR
 | 
					      flowchart LR
 | 
				
			||||||
      subgraph S2
 | 
					        A --> B
 | 
				
			||||||
      subgraph s1["APA"]
 | 
					 | 
				
			||||||
      D{"Use the editor"}
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      D -- Mermaid js --> I{"fa:fa-code Text"}
 | 
					 | 
				
			||||||
            D --> I
 | 
					 | 
				
			||||||
            D --> I
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
 | 
					      flowchart LR
 | 
				
			||||||
 | 
					        A e1@==> B
 | 
				
			||||||
 | 
					        e1@{ animate: true}
 | 
				
			||||||
 | 
					    </pre>
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@--> B
 | 
				
			||||||
 | 
					  classDef animate stroke-width:2,stroke-dasharray:10\,8,stroke-dashoffset:-180,animation: edge-animation-frame 6s linear infinite, stroke-linecap: round
 | 
				
			||||||
 | 
					  class e1 animate
 | 
				
			||||||
 | 
					    </pre>
 | 
				
			||||||
 | 
					    <h2>infinite</h2>
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@--> B
 | 
				
			||||||
 | 
					  classDef animate stroke-dasharray: 9\,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
 | 
				
			||||||
 | 
					  class e1 animate
 | 
				
			||||||
 | 
					    </pre>
 | 
				
			||||||
 | 
					    <h2>Mermaid - edge-animation-slow</h2>
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@--> B
 | 
				
			||||||
 | 
					e1@{ animation: fast}
 | 
				
			||||||
 | 
					    </pre>
 | 
				
			||||||
 | 
					    <h2>Mermaid - edge-animation-fast</h2>
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@--> B
 | 
				
			||||||
 | 
					  classDef animate stroke-dasharray: 1000,stroke-dashoffset: 1000,animation: dash 10s linear;
 | 
				
			||||||
 | 
					  class e1 edge-animation-fast
 | 
				
			||||||
 | 
					    </pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					info    </pre
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -133,7 +170,7 @@ config:
 | 
				
			|||||||
      end
 | 
					      end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -146,7 +183,7 @@ config:
 | 
				
			|||||||
      D-->I
 | 
					      D-->I
 | 
				
			||||||
      D-->I
 | 
					      D-->I
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -185,7 +222,7 @@ flowchart LR
 | 
				
			|||||||
    n8@{ shape: rect}
 | 
					    n8@{ shape: rect}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -201,7 +238,7 @@ flowchart LR
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -210,7 +247,7 @@ flowchart LR
 | 
				
			|||||||
    A{A} --> B & C
 | 
					    A{A} --> B & C
 | 
				
			||||||
</pre
 | 
					</pre
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -222,7 +259,7 @@ flowchart LR
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
</pre
 | 
					</pre
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid2">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/rendering-util/types.ts:145](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L145)
 | 
					[packages/mermaid/src/rendering-util/types.ts:148](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L148)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,7 +30,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/rendering-util/types.ts:144](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L144)
 | 
					[packages/mermaid/src/rendering-util/types.ts:147](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L147)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,4 +40,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/rendering-util/types.ts:143](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L143)
 | 
					[packages/mermaid/src/rendering-util/types.ts:146](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L146)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,4 +19,4 @@ The `parseError` function will not be called.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/types.ts:61](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L61)
 | 
					[packages/mermaid/src/types.ts:66](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L66)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@ The mermaid code after extracting the config.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/types.ts:69](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L69)
 | 
					[packages/mermaid/src/types.ts:74](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L74)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,7 +30,7 @@ The config passed as YAML frontmatter or directives
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/types.ts:73](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L73)
 | 
					[packages/mermaid/src/types.ts:78](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L78)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,7 +40,7 @@ The config passed as YAML frontmatter or directives
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/types.ts:75](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L75)
 | 
					[packages/mermaid/src/types.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L80)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -52,7 +52,7 @@ The error that occurred during parsing, if any.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/types.ts:79](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L79)
 | 
					[packages/mermaid/src/types.ts:84](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L84)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -62,7 +62,7 @@ The error that occurred during parsing, if any.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/types.ts:65](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L65)
 | 
					[packages/mermaid/src/types.ts:70](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L70)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -72,4 +72,4 @@ The error that occurred during parsing, if any.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/types.ts:74](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L74)
 | 
					[packages/mermaid/src/types.ts:79](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L79)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/types.ts:108](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L108)
 | 
					[packages/mermaid/src/types.ts:113](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L113)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -51,7 +51,7 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/types.ts:98](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L98)
 | 
					[packages/mermaid/src/types.ts:103](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L103)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,4 +63,4 @@ The svg code for the rendered graph.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Defined in
 | 
					#### Defined in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[packages/mermaid/src/types.ts:94](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L94)
 | 
					[packages/mermaid/src/types.ts:99](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L99)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1183,6 +1183,91 @@ flowchart TB
 | 
				
			|||||||
    B --> D
 | 
					    B --> D
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Attaching an ID to Edges
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Mermaid now supports assigning IDs to edges, similar to how IDs and metadata can be attached to nodes. This feature lays the groundwork for more advanced styling, classes, and animation capabilities on edges.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Syntax:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To give an edge an ID, prepend the edge syntax with the ID followed by an `@` character. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid-example
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@–> B
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@–> B
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In this example, `e1` is the ID of the edge connecting `A` to `B`. You can then use this ID in later definitions or style statements, just like with nodes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Turning an Animation On
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once you have assigned an ID to an edge, you can turn on animations for that edge by defining the edge’s properties:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid-example
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@==> B
 | 
				
			||||||
 | 
					  e1@{ animate: true }
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@==> B
 | 
				
			||||||
 | 
					  e1@{ animate: true }
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This tells Mermaid that the edge `e1` should be animated.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Selecting Type of Animation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the initial version, two animation speeds are supported: `fast` and `slow`. Selecting a specific animation type is a shorthand for enabling animation and setting the animation speed in one go.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Examples:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid-example
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@–> B
 | 
				
			||||||
 | 
					  e1@{ animation: fast }
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@–> B
 | 
				
			||||||
 | 
					  e1@{ animation: fast }
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is equivalent to `{ animate: true, animation: fast }`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Using classDef Statements for Animations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can also animate edges by assigning a class to them and then defining animation properties in a `classDef` statement. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid-example
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@–> B
 | 
				
			||||||
 | 
					  classDef animate stroke-dasharray: 9,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
 | 
				
			||||||
 | 
					  class e1 animate
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@–> B
 | 
				
			||||||
 | 
					  classDef animate stroke-dasharray: 9,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
 | 
				
			||||||
 | 
					  class e1 animate
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In this snippet:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `e1@-->` creates an edge with ID `e1`.
 | 
				
			||||||
 | 
					- `classDef animate` defines a class named `animate` with styling and animation properties.
 | 
				
			||||||
 | 
					- `class e1 animate` applies the `animate` class to the edge `e1`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Note on Escaping Commas:**
 | 
				
			||||||
 | 
					When setting the `stroke-dasharray` property, remember to escape commas as `\,` since commas are used as delimiters in Mermaid’s style definitions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## New arrow types
 | 
					## New arrow types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
There are new types of arrows supported:
 | 
					There are new types of arrows supported:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -500,7 +500,7 @@ mermaid.ganttConfig = {
 | 
				
			|||||||
  sectionFontSize: 24, // Font size for sections
 | 
					  sectionFontSize: 24, // Font size for sections
 | 
				
			||||||
  numberSectionStyles: 1, // The number of alternating section styles
 | 
					  numberSectionStyles: 1, // The number of alternating section styles
 | 
				
			||||||
  axisFormat: '%d/%m', // Date/time format of the axis
 | 
					  axisFormat: '%d/%m', // Date/time format of the axis
 | 
				
			||||||
  tickInterval: '1 week', // Axis ticks
 | 
					  tickInterval: '1week', // Axis ticks
 | 
				
			||||||
  topAxis: true, // When this flag is set, date labels will be added to the top of the chart
 | 
					  topAxis: true, // When this flag is set, date labels will be added to the top of the chart
 | 
				
			||||||
  displayMode: 'compact', // Turns compact mode on
 | 
					  displayMode: 'compact', // Turns compact mode on
 | 
				
			||||||
  weekday: 'sunday', // On which day a week-based interval should start
 | 
					  weekday: 'sunday', // On which day a week-based interval should start
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ import {
 | 
				
			|||||||
  setDiagramTitle,
 | 
					  setDiagramTitle,
 | 
				
			||||||
} from '../common/commonDb.js';
 | 
					} from '../common/commonDb.js';
 | 
				
			||||||
import type {
 | 
					import type {
 | 
				
			||||||
 | 
					  ArchitectureAlignment,
 | 
				
			||||||
  ArchitectureDB,
 | 
					  ArchitectureDB,
 | 
				
			||||||
  ArchitectureDirectionPair,
 | 
					  ArchitectureDirectionPair,
 | 
				
			||||||
  ArchitectureDirectionPairMap,
 | 
					  ArchitectureDirectionPairMap,
 | 
				
			||||||
@@ -25,6 +26,7 @@ import type {
 | 
				
			|||||||
  ArchitectureState,
 | 
					  ArchitectureState,
 | 
				
			||||||
} from './architectureTypes.js';
 | 
					} from './architectureTypes.js';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
 | 
					  getArchitectureDirectionAlignment,
 | 
				
			||||||
  getArchitectureDirectionPair,
 | 
					  getArchitectureDirectionPair,
 | 
				
			||||||
  isArchitectureDirection,
 | 
					  isArchitectureDirection,
 | 
				
			||||||
  isArchitectureJunction,
 | 
					  isArchitectureJunction,
 | 
				
			||||||
@@ -211,12 +213,18 @@ const addEdge = function ({
 | 
				
			|||||||
const getEdges = (): ArchitectureEdge[] => state.records.edges;
 | 
					const getEdges = (): ArchitectureEdge[] => state.records.edges;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Returns the current diagram's adjacency list & spatial map.
 | 
					 * Returns the current diagram's adjacency list, spatial map, & group alignments.
 | 
				
			||||||
 * If they have not been created, run the algorithms to generate them.
 | 
					 * If they have not been created, run the algorithms to generate them.
 | 
				
			||||||
 * @returns
 | 
					 * @returns
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const getDataStructures = () => {
 | 
					const getDataStructures = () => {
 | 
				
			||||||
  if (state.records.dataStructures === undefined) {
 | 
					  if (state.records.dataStructures === undefined) {
 | 
				
			||||||
 | 
					    // Tracks how groups are aligned with one another. Generated while creating the adj list
 | 
				
			||||||
 | 
					    const groupAlignments: Record<
 | 
				
			||||||
 | 
					      string,
 | 
				
			||||||
 | 
					      Record<string, Exclude<ArchitectureAlignment, 'bend'>>
 | 
				
			||||||
 | 
					    > = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create an adjacency list of the diagram to perform BFS on
 | 
					    // Create an adjacency list of the diagram to perform BFS on
 | 
				
			||||||
    // Outer reduce applied on all services
 | 
					    // Outer reduce applied on all services
 | 
				
			||||||
    // Inner reduce applied on the edges for a service
 | 
					    // Inner reduce applied on the edges for a service
 | 
				
			||||||
@@ -224,6 +232,19 @@ const getDataStructures = () => {
 | 
				
			|||||||
      Record<string, ArchitectureDirectionPairMap>
 | 
					      Record<string, ArchitectureDirectionPairMap>
 | 
				
			||||||
    >((prevOuter, [id, service]) => {
 | 
					    >((prevOuter, [id, service]) => {
 | 
				
			||||||
      prevOuter[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prevInner, edge) => {
 | 
					      prevOuter[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prevInner, edge) => {
 | 
				
			||||||
 | 
					        // track the direction groups connect to one another
 | 
				
			||||||
 | 
					        const lhsGroupId = getNode(edge.lhsId)?.in;
 | 
				
			||||||
 | 
					        const rhsGroupId = getNode(edge.rhsId)?.in;
 | 
				
			||||||
 | 
					        if (lhsGroupId && rhsGroupId && lhsGroupId !== rhsGroupId) {
 | 
				
			||||||
 | 
					          const alignment = getArchitectureDirectionAlignment(edge.lhsDir, edge.rhsDir);
 | 
				
			||||||
 | 
					          if (alignment !== 'bend') {
 | 
				
			||||||
 | 
					            groupAlignments[lhsGroupId] ??= {};
 | 
				
			||||||
 | 
					            groupAlignments[lhsGroupId][rhsGroupId] = alignment;
 | 
				
			||||||
 | 
					            groupAlignments[rhsGroupId] ??= {};
 | 
				
			||||||
 | 
					            groupAlignments[rhsGroupId][lhsGroupId] = alignment;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (edge.lhsId === id) {
 | 
					        if (edge.lhsId === id) {
 | 
				
			||||||
          // source is LHS
 | 
					          // source is LHS
 | 
				
			||||||
          const pair = getArchitectureDirectionPair(edge.lhsDir, edge.rhsDir);
 | 
					          const pair = getArchitectureDirectionPair(edge.lhsDir, edge.rhsDir);
 | 
				
			||||||
@@ -245,6 +266,7 @@ const getDataStructures = () => {
 | 
				
			|||||||
    // Configuration for the initial pass of BFS
 | 
					    // Configuration for the initial pass of BFS
 | 
				
			||||||
    const firstId = Object.keys(adjList)[0];
 | 
					    const firstId = Object.keys(adjList)[0];
 | 
				
			||||||
    const visited = { [firstId]: 1 };
 | 
					    const visited = { [firstId]: 1 };
 | 
				
			||||||
 | 
					    // If a key is present in this object, it has not been visited
 | 
				
			||||||
    const notVisited = Object.keys(adjList).reduce(
 | 
					    const notVisited = Object.keys(adjList).reduce(
 | 
				
			||||||
      (prev, id) => (id === firstId ? prev : { ...prev, [id]: 1 }),
 | 
					      (prev, id) => (id === firstId ? prev : { ...prev, [id]: 1 }),
 | 
				
			||||||
      {} as Record<string, number>
 | 
					      {} as Record<string, number>
 | 
				
			||||||
@@ -283,6 +305,7 @@ const getDataStructures = () => {
 | 
				
			|||||||
    state.records.dataStructures = {
 | 
					    state.records.dataStructures = {
 | 
				
			||||||
      adjList,
 | 
					      adjList,
 | 
				
			||||||
      spatialMaps,
 | 
					      spatialMaps,
 | 
				
			||||||
 | 
					      groupAlignments,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return state.records.dataStructures;
 | 
					  return state.records.dataStructures;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,9 @@ import { setupGraphViewbox } from '../../setupGraphViewbox.js';
 | 
				
			|||||||
import { getConfigField } from './architectureDb.js';
 | 
					import { getConfigField } from './architectureDb.js';
 | 
				
			||||||
import { architectureIcons } from './architectureIcons.js';
 | 
					import { architectureIcons } from './architectureIcons.js';
 | 
				
			||||||
import type {
 | 
					import type {
 | 
				
			||||||
 | 
					  ArchitectureAlignment,
 | 
				
			||||||
  ArchitectureDataStructures,
 | 
					  ArchitectureDataStructures,
 | 
				
			||||||
 | 
					  ArchitectureGroupAlignments,
 | 
				
			||||||
  ArchitectureJunction,
 | 
					  ArchitectureJunction,
 | 
				
			||||||
  ArchitectureSpatialMap,
 | 
					  ArchitectureSpatialMap,
 | 
				
			||||||
  EdgeSingular,
 | 
					  EdgeSingular,
 | 
				
			||||||
@@ -149,25 +151,91 @@ function addEdges(edges: ArchitectureEdge[], cy: cytoscape.Core) {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function getAlignments(spatialMaps: ArchitectureSpatialMap[]): fcose.FcoseAlignmentConstraint {
 | 
					function getAlignments(
 | 
				
			||||||
 | 
					  db: ArchitectureDB,
 | 
				
			||||||
 | 
					  spatialMaps: ArchitectureSpatialMap[],
 | 
				
			||||||
 | 
					  groupAlignments: ArchitectureGroupAlignments
 | 
				
			||||||
 | 
					): fcose.FcoseAlignmentConstraint {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Flattens the alignment object so nodes in different groups will be in the same alignment array IFF their groups don't connect in a conflicting alignment
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * i.e., two groups which connect horizontally should not have nodes with vertical alignments to one another
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * See: #5952
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param alignmentObj - alignment object with the outer key being the row/col # and the inner key being the group name mapped to the nodes on that axis in the group
 | 
				
			||||||
 | 
					   * @param alignmentDir - alignment direction
 | 
				
			||||||
 | 
					   * @returns flattened alignment object with an arbitrary key mapping to nodes in the same row/col
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  const flattenAlignments = (
 | 
				
			||||||
 | 
					    alignmentObj: Record<number, Record<string, string[]>>,
 | 
				
			||||||
 | 
					    alignmentDir: ArchitectureAlignment
 | 
				
			||||||
 | 
					  ): Record<string, string[]> => {
 | 
				
			||||||
 | 
					    return Object.entries(alignmentObj).reduce(
 | 
				
			||||||
 | 
					      (prev, [dir, alignments]) => {
 | 
				
			||||||
 | 
					        // prev is the mapping of x/y coordinate to an array of the nodes in that row/column
 | 
				
			||||||
 | 
					        let cnt = 0;
 | 
				
			||||||
 | 
					        const arr = Object.entries(alignments); // [group name, array of nodes within the group on axis dir]
 | 
				
			||||||
 | 
					        if (arr.length === 1) {
 | 
				
			||||||
 | 
					          // If only one group exists in the row/column, we don't need to do anything else
 | 
				
			||||||
 | 
					          prev[dir] = arr[0][1];
 | 
				
			||||||
 | 
					          return prev;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (let i = 0; i < arr.length - 1; i++) {
 | 
				
			||||||
 | 
					          for (let j = i + 1; j < arr.length; j++) {
 | 
				
			||||||
 | 
					            const [aGroupId, aNodeIds] = arr[i];
 | 
				
			||||||
 | 
					            const [bGroupId, bNodeIds] = arr[j];
 | 
				
			||||||
 | 
					            const alignment = groupAlignments[aGroupId]?.[bGroupId]; // Get how the two groups are intended to align (undefined if they aren't)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (alignment === alignmentDir) {
 | 
				
			||||||
 | 
					              // If the intended alignment between the two groups is the same as the alignment we are parsing
 | 
				
			||||||
 | 
					              prev[dir] ??= [];
 | 
				
			||||||
 | 
					              prev[dir] = [...prev[dir], ...aNodeIds, ...bNodeIds]; // add the node ids of both groups to the axis array in prev
 | 
				
			||||||
 | 
					            } else if (aGroupId === 'default' || bGroupId === 'default') {
 | 
				
			||||||
 | 
					              // If either of the groups are in the default space (not in a group), use the same behavior as above
 | 
				
			||||||
 | 
					              prev[dir] ??= [];
 | 
				
			||||||
 | 
					              prev[dir] = [...prev[dir], ...aNodeIds, ...bNodeIds];
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              // Otherwise, the nodes in the two groups are not intended to align
 | 
				
			||||||
 | 
					              const keyA = `${dir}-${cnt++}`;
 | 
				
			||||||
 | 
					              prev[keyA] = aNodeIds;
 | 
				
			||||||
 | 
					              const keyB = `${dir}-${cnt++}`;
 | 
				
			||||||
 | 
					              prev[keyB] = bNodeIds;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return prev;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {} as Record<string, string[]>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const alignments = spatialMaps.map((spatialMap) => {
 | 
					  const alignments = spatialMaps.map((spatialMap) => {
 | 
				
			||||||
    const horizontalAlignments: Record<number, string[]> = {};
 | 
					    const horizontalAlignments: Record<number, Record<string, string[]>> = {};
 | 
				
			||||||
    const verticalAlignments: Record<number, string[]> = {};
 | 
					    const verticalAlignments: Record<number, Record<string, string[]>> = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Group service ids in an object with their x and y coordinate as the key
 | 
					    // Group service ids in an object with their x and y coordinate as the key
 | 
				
			||||||
    Object.entries(spatialMap).forEach(([id, [x, y]]) => {
 | 
					    Object.entries(spatialMap).forEach(([id, [x, y]]) => {
 | 
				
			||||||
      if (!horizontalAlignments[y]) {
 | 
					      const nodeGroup = db.getNode(id)?.in ?? 'default';
 | 
				
			||||||
        horizontalAlignments[y] = [];
 | 
					
 | 
				
			||||||
      }
 | 
					      horizontalAlignments[y] ??= {};
 | 
				
			||||||
      if (!verticalAlignments[x]) {
 | 
					      horizontalAlignments[y][nodeGroup] ??= [];
 | 
				
			||||||
        verticalAlignments[x] = [];
 | 
					      horizontalAlignments[y][nodeGroup].push(id);
 | 
				
			||||||
      }
 | 
					
 | 
				
			||||||
      horizontalAlignments[y].push(id);
 | 
					      verticalAlignments[x] ??= {};
 | 
				
			||||||
      verticalAlignments[x].push(id);
 | 
					      verticalAlignments[x][nodeGroup] ??= [];
 | 
				
			||||||
 | 
					      verticalAlignments[x][nodeGroup].push(id);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Merge the values of each object into a list if the inner list has at least 2 elements
 | 
					    // Merge the values of each object into a list if the inner list has at least 2 elements
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      horiz: Object.values(horizontalAlignments).filter((arr) => arr.length > 1),
 | 
					      horiz: Object.values(flattenAlignments(horizontalAlignments, 'horizontal')).filter(
 | 
				
			||||||
      vert: Object.values(verticalAlignments).filter((arr) => arr.length > 1),
 | 
					        (arr) => arr.length > 1
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      vert: Object.values(flattenAlignments(verticalAlignments, 'vertical')).filter(
 | 
				
			||||||
 | 
					        (arr) => arr.length > 1
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -244,7 +312,8 @@ function layoutArchitecture(
 | 
				
			|||||||
  junctions: ArchitectureJunction[],
 | 
					  junctions: ArchitectureJunction[],
 | 
				
			||||||
  groups: ArchitectureGroup[],
 | 
					  groups: ArchitectureGroup[],
 | 
				
			||||||
  edges: ArchitectureEdge[],
 | 
					  edges: ArchitectureEdge[],
 | 
				
			||||||
  { spatialMaps }: ArchitectureDataStructures
 | 
					  db: ArchitectureDB,
 | 
				
			||||||
 | 
					  { spatialMaps, groupAlignments }: ArchitectureDataStructures
 | 
				
			||||||
): Promise<cytoscape.Core> {
 | 
					): Promise<cytoscape.Core> {
 | 
				
			||||||
  return new Promise((resolve) => {
 | 
					  return new Promise((resolve) => {
 | 
				
			||||||
    const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');
 | 
					    const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');
 | 
				
			||||||
@@ -318,9 +387,8 @@ function layoutArchitecture(
 | 
				
			|||||||
    addServices(services, cy);
 | 
					    addServices(services, cy);
 | 
				
			||||||
    addJunctions(junctions, cy);
 | 
					    addJunctions(junctions, cy);
 | 
				
			||||||
    addEdges(edges, cy);
 | 
					    addEdges(edges, cy);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Use the spatial map to create alignment arrays for fcose
 | 
					    // Use the spatial map to create alignment arrays for fcose
 | 
				
			||||||
    const alignmentConstraint = getAlignments(spatialMaps);
 | 
					    const alignmentConstraint = getAlignments(db, spatialMaps, groupAlignments);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create the relative constraints for fcose by using an inverse of the spatial map and performing BFS on it
 | 
					    // Create the relative constraints for fcose by using an inverse of the spatial map and performing BFS on it
 | 
				
			||||||
    const relativePlacementConstraint = getRelativeConstraints(spatialMaps);
 | 
					    const relativePlacementConstraint = getRelativeConstraints(spatialMaps);
 | 
				
			||||||
@@ -454,7 +522,7 @@ export const draw: DrawDefinition = async (text, id, _version, diagObj: Diagram)
 | 
				
			|||||||
  await drawServices(db, servicesElem, services);
 | 
					  await drawServices(db, servicesElem, services);
 | 
				
			||||||
  drawJunctions(db, servicesElem, junctions);
 | 
					  drawJunctions(db, servicesElem, junctions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const cy = await layoutArchitecture(services, junctions, groups, edges, ds);
 | 
					  const cy = await layoutArchitecture(services, junctions, groups, edges, db, ds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await drawEdges(edgesElem, cy);
 | 
					  await drawEdges(edgesElem, cy);
 | 
				
			||||||
  await drawGroups(groupElem, cy);
 | 
					  await drawGroups(groupElem, cy);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@ import type cytoscape from 'cytoscape';
 | 
				
			|||||||
|       Architecture Diagram Types        |
 | 
					|       Architecture Diagram Types        |
 | 
				
			||||||
\*=======================================*/
 | 
					\*=======================================*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type ArchitectureAlignment = 'vertical' | 'horizontal' | 'bend';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type ArchitectureDirection = 'L' | 'R' | 'T' | 'B';
 | 
					export type ArchitectureDirection = 'L' | 'R' | 'T' | 'B';
 | 
				
			||||||
export type ArchitectureDirectionX = Extract<ArchitectureDirection, 'L' | 'R'>;
 | 
					export type ArchitectureDirectionX = Extract<ArchitectureDirection, 'L' | 'R'>;
 | 
				
			||||||
export type ArchitectureDirectionY = Extract<ArchitectureDirection, 'T' | 'B'>;
 | 
					export type ArchitectureDirectionY = Extract<ArchitectureDirection, 'T' | 'B'>;
 | 
				
			||||||
@@ -170,6 +172,18 @@ export const getArchitectureDirectionXYFactors = function (
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getArchitectureDirectionAlignment = function (
 | 
				
			||||||
 | 
					  a: ArchitectureDirection,
 | 
				
			||||||
 | 
					  b: ArchitectureDirection
 | 
				
			||||||
 | 
					): ArchitectureAlignment {
 | 
				
			||||||
 | 
					  if (isArchitectureDirectionXY(a, b)) {
 | 
				
			||||||
 | 
					    return 'bend';
 | 
				
			||||||
 | 
					  } else if (isArchitectureDirectionX(a)) {
 | 
				
			||||||
 | 
					    return 'horizontal';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return 'vertical';
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ArchitectureStyleOptions {
 | 
					export interface ArchitectureStyleOptions {
 | 
				
			||||||
  archEdgeColor: string;
 | 
					  archEdgeColor: string;
 | 
				
			||||||
  archEdgeArrowColor: string;
 | 
					  archEdgeArrowColor: string;
 | 
				
			||||||
@@ -249,9 +263,27 @@ export interface ArchitectureDB extends DiagramDB {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export type ArchitectureAdjacencyList = Record<string, ArchitectureDirectionPairMap>;
 | 
					export type ArchitectureAdjacencyList = Record<string, ArchitectureDirectionPairMap>;
 | 
				
			||||||
export type ArchitectureSpatialMap = Record<string, number[]>;
 | 
					export type ArchitectureSpatialMap = Record<string, number[]>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Maps the direction that groups connect from.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * **Outer key**: ID of group A
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * **Inner key**: ID of group B
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * **Value**: 'vertical' or 'horizontal'
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note: tmp[groupA][groupB] == tmp[groupB][groupA]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type ArchitectureGroupAlignments = Record<
 | 
				
			||||||
 | 
					  string,
 | 
				
			||||||
 | 
					  Record<string, Exclude<ArchitectureAlignment, 'bend'>>
 | 
				
			||||||
 | 
					>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ArchitectureDataStructures {
 | 
					export interface ArchitectureDataStructures {
 | 
				
			||||||
  adjList: ArchitectureAdjacencyList;
 | 
					  adjList: ArchitectureAdjacencyList;
 | 
				
			||||||
  spatialMaps: ArchitectureSpatialMap[];
 | 
					  spatialMaps: ArchitectureSpatialMap[];
 | 
				
			||||||
 | 
					  groupAlignments: ArchitectureGroupAlignments;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ArchitectureState extends Record<string, unknown> {
 | 
					export interface ArchitectureState extends Record<string, unknown> {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ import type {
 | 
				
			|||||||
  FlowLink,
 | 
					  FlowLink,
 | 
				
			||||||
  FlowVertexTypeParam,
 | 
					  FlowVertexTypeParam,
 | 
				
			||||||
} from './types.js';
 | 
					} from './types.js';
 | 
				
			||||||
import type { NodeMetaData } from '../../types.js';
 | 
					import type { NodeMetaData, EdgeMetaData } from '../../types.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MERMAID_DOM_ID_PREFIX = 'flowchart-';
 | 
					const MERMAID_DOM_ID_PREFIX = 'flowchart-';
 | 
				
			||||||
let vertexCounter = 0;
 | 
					let vertexCounter = 0;
 | 
				
			||||||
@@ -71,12 +71,38 @@ export const addVertex = function (
 | 
				
			|||||||
  classes: string[],
 | 
					  classes: string[],
 | 
				
			||||||
  dir: string,
 | 
					  dir: string,
 | 
				
			||||||
  props = {},
 | 
					  props = {},
 | 
				
			||||||
  shapeData: any
 | 
					  metadata: any
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
  // console.log('addVertex', id, shapeData);
 | 
					 | 
				
			||||||
  if (!id || id.trim().length === 0) {
 | 
					  if (!id || id.trim().length === 0) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  // Extract the metadata from the shapeData, the syntax for adding metadata for nodes and edges is the same
 | 
				
			||||||
 | 
					  // so at this point we don't know if it's a node or an edge, but we can still extract the metadata
 | 
				
			||||||
 | 
					  let doc;
 | 
				
			||||||
 | 
					  if (metadata !== undefined) {
 | 
				
			||||||
 | 
					    let yamlData;
 | 
				
			||||||
 | 
					    // detect if shapeData contains a newline character
 | 
				
			||||||
 | 
					    if (!metadata.includes('\n')) {
 | 
				
			||||||
 | 
					      yamlData = '{\n' + metadata + '\n}';
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      yamlData = metadata + '\n';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    doc = yaml.load(yamlData, { schema: yaml.JSON_SCHEMA }) as NodeMetaData;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Check if this is an edge
 | 
				
			||||||
 | 
					  const edge = edges.find((e) => e.id === id);
 | 
				
			||||||
 | 
					  if (edge) {
 | 
				
			||||||
 | 
					    const edgeDoc = doc as EdgeMetaData;
 | 
				
			||||||
 | 
					    if (edgeDoc?.animate) {
 | 
				
			||||||
 | 
					      edge.animate = edgeDoc.animate;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (edgeDoc?.animation) {
 | 
				
			||||||
 | 
					      edge.animation = edgeDoc.animation;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let txt;
 | 
					  let txt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let vertex = vertices.get(id);
 | 
					  let vertex = vertices.get(id);
 | 
				
			||||||
@@ -128,19 +154,7 @@ export const addVertex = function (
 | 
				
			|||||||
    Object.assign(vertex.props, props);
 | 
					    Object.assign(vertex.props, props);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (shapeData !== undefined) {
 | 
					  if (doc !== undefined) {
 | 
				
			||||||
    let yamlData;
 | 
					 | 
				
			||||||
    // detect if shapeData contains a newline character
 | 
					 | 
				
			||||||
    // console.log('shapeData', shapeData);
 | 
					 | 
				
			||||||
    if (!shapeData.includes('\n')) {
 | 
					 | 
				
			||||||
      // console.log('yamlData shapeData has no new lines', shapeData);
 | 
					 | 
				
			||||||
      yamlData = '{\n' + shapeData + '\n}';
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      // console.log('yamlData shapeData has new lines', shapeData);
 | 
					 | 
				
			||||||
      yamlData = shapeData + '\n';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // console.log('yamlData', yamlData);
 | 
					 | 
				
			||||||
    const doc = yaml.load(yamlData, { schema: yaml.JSON_SCHEMA }) as NodeMetaData;
 | 
					 | 
				
			||||||
    if (doc.shape) {
 | 
					    if (doc.shape) {
 | 
				
			||||||
      if (doc.shape !== doc.shape.toLowerCase() || doc.shape.includes('_')) {
 | 
					      if (doc.shape !== doc.shape.toLowerCase() || doc.shape.includes('_')) {
 | 
				
			||||||
        throw new Error(`No such shape: ${doc.shape}. Shape names should be lowercase.`);
 | 
					        throw new Error(`No such shape: ${doc.shape}. Shape names should be lowercase.`);
 | 
				
			||||||
@@ -187,11 +201,18 @@ export const addVertex = function (
 | 
				
			|||||||
 * Function called by parser when a link/edge definition has been found
 | 
					 * Function called by parser when a link/edge definition has been found
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export const addSingleLink = function (_start: string, _end: string, type: any) {
 | 
					export const addSingleLink = function (_start: string, _end: string, type: any, id?: string) {
 | 
				
			||||||
  const start = _start;
 | 
					  const start = _start;
 | 
				
			||||||
  const end = _end;
 | 
					  const end = _end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const edge: FlowEdge = { start: start, end: end, type: undefined, text: '', labelType: 'text' };
 | 
					  const edge: FlowEdge = {
 | 
				
			||||||
 | 
					    start: start,
 | 
				
			||||||
 | 
					    end: end,
 | 
				
			||||||
 | 
					    type: undefined,
 | 
				
			||||||
 | 
					    text: '',
 | 
				
			||||||
 | 
					    labelType: 'text',
 | 
				
			||||||
 | 
					    classes: [],
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
  log.info('abc78 Got edge...', edge);
 | 
					  log.info('abc78 Got edge...', edge);
 | 
				
			||||||
  const linkTextObj = type.text;
 | 
					  const linkTextObj = type.text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -210,6 +231,9 @@ export const addSingleLink = function (_start: string, _end: string, type: any)
 | 
				
			|||||||
    edge.stroke = type.stroke;
 | 
					    edge.stroke = type.stroke;
 | 
				
			||||||
    edge.length = type.length > 10 ? 10 : type.length;
 | 
					    edge.length = type.length > 10 ? 10 : type.length;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if (id) {
 | 
				
			||||||
 | 
					    edge.id = id;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (edges.length < (config.maxEdges ?? 500)) {
 | 
					  if (edges.length < (config.maxEdges ?? 500)) {
 | 
				
			||||||
    log.info('Pushing edge...');
 | 
					    log.info('Pushing edge...');
 | 
				
			||||||
@@ -225,11 +249,27 @@ You have to call mermaid.initialize.`
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addLink = function (_start: string[], _end: string[], type: unknown) {
 | 
					interface LinkData {
 | 
				
			||||||
  log.info('addLink', _start, _end, type);
 | 
					  id: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isLinkData(value: unknown): value is LinkData {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    value !== null &&
 | 
				
			||||||
 | 
					    typeof value === 'object' &&
 | 
				
			||||||
 | 
					    'id' in value &&
 | 
				
			||||||
 | 
					    typeof (value as LinkData).id === 'string'
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const addLink = function (_start: string[], _end: string[], linkData: unknown) {
 | 
				
			||||||
 | 
					  const id = isLinkData(linkData) ? linkData.id.replace('@', '') : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  log.info('addLink', _start, _end, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (const start of _start) {
 | 
					  for (const start of _start) {
 | 
				
			||||||
    for (const end of _end) {
 | 
					    for (const end of _end) {
 | 
				
			||||||
      addSingleLink(start, end, type);
 | 
					      addSingleLink(start, end, linkData, id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -267,9 +307,6 @@ export const updateLink = function (positions: ('default' | number)[], style: st
 | 
				
			|||||||
    if (pos === 'default') {
 | 
					    if (pos === 'default') {
 | 
				
			||||||
      edges.defaultStyle = style;
 | 
					      edges.defaultStyle = style;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // if (utils.isSubstringInArray('fill', style) === -1) {
 | 
					 | 
				
			||||||
      //   style.push('fill:none');
 | 
					 | 
				
			||||||
      // }
 | 
					 | 
				
			||||||
      edges[pos].style = style;
 | 
					      edges[pos].style = style;
 | 
				
			||||||
      // if edges[pos].style does have fill not set, set it to none
 | 
					      // if edges[pos].style does have fill not set, set it to none
 | 
				
			||||||
      if (
 | 
					      if (
 | 
				
			||||||
@@ -282,7 +319,13 @@ export const updateLink = function (positions: ('default' | number)[], style: st
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addClass = function (ids: string, style: string[]) {
 | 
					export const addClass = function (ids: string, _style: string[]) {
 | 
				
			||||||
 | 
					  const style = _style
 | 
				
			||||||
 | 
					    .join()
 | 
				
			||||||
 | 
					    .replace(/\\,/g, '§§§')
 | 
				
			||||||
 | 
					    .replace(/,/g, ';')
 | 
				
			||||||
 | 
					    .replace(/§§§/g, ',')
 | 
				
			||||||
 | 
					    .split(';');
 | 
				
			||||||
  ids.split(',').forEach(function (id) {
 | 
					  ids.split(',').forEach(function (id) {
 | 
				
			||||||
    let classNode = classes.get(id);
 | 
					    let classNode = classes.get(id);
 | 
				
			||||||
    if (classNode === undefined) {
 | 
					    if (classNode === undefined) {
 | 
				
			||||||
@@ -337,6 +380,10 @@ export const setClass = function (ids: string, className: string) {
 | 
				
			|||||||
    if (vertex) {
 | 
					    if (vertex) {
 | 
				
			||||||
      vertex.classes.push(className);
 | 
					      vertex.classes.push(className);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    const edge = edges.find((e) => e.id === id);
 | 
				
			||||||
 | 
					    if (edge) {
 | 
				
			||||||
 | 
					      edge.classes.push(className);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    const subGraph = subGraphLookup.get(id);
 | 
					    const subGraph = subGraphLookup.get(id);
 | 
				
			||||||
    if (subGraph) {
 | 
					    if (subGraph) {
 | 
				
			||||||
      subGraph.classes.push(className);
 | 
					      subGraph.classes.push(className);
 | 
				
			||||||
@@ -998,7 +1045,7 @@ export const getData = () => {
 | 
				
			|||||||
      styles.push(...rawEdge.style);
 | 
					      styles.push(...rawEdge.style);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const edge: Edge = {
 | 
					    const edge: Edge = {
 | 
				
			||||||
      id: getEdgeId(rawEdge.start, rawEdge.end, { counter: index, prefix: 'L' }),
 | 
					      id: getEdgeId(rawEdge.start, rawEdge.end, { counter: index, prefix: 'L' }, rawEdge.id),
 | 
				
			||||||
      start: rawEdge.start,
 | 
					      start: rawEdge.start,
 | 
				
			||||||
      end: rawEdge.end,
 | 
					      end: rawEdge.end,
 | 
				
			||||||
      type: rawEdge.type ?? 'normal',
 | 
					      type: rawEdge.type ?? 'normal',
 | 
				
			||||||
@@ -1010,16 +1057,22 @@ export const getData = () => {
 | 
				
			|||||||
        rawEdge?.stroke === 'invisible'
 | 
					        rawEdge?.stroke === 'invisible'
 | 
				
			||||||
          ? ''
 | 
					          ? ''
 | 
				
			||||||
          : 'edge-thickness-normal edge-pattern-solid flowchart-link',
 | 
					          : 'edge-thickness-normal edge-pattern-solid flowchart-link',
 | 
				
			||||||
      arrowTypeStart: rawEdge?.stroke === 'invisible' ? 'none' : arrowTypeStart,
 | 
					      arrowTypeStart:
 | 
				
			||||||
      arrowTypeEnd: rawEdge?.stroke === 'invisible' ? 'none' : arrowTypeEnd,
 | 
					        rawEdge?.stroke === 'invisible' || rawEdge?.type === 'arrow_open' ? 'none' : arrowTypeStart,
 | 
				
			||||||
 | 
					      arrowTypeEnd:
 | 
				
			||||||
 | 
					        rawEdge?.stroke === 'invisible' || rawEdge?.type === 'arrow_open' ? 'none' : arrowTypeEnd,
 | 
				
			||||||
      arrowheadStyle: 'fill: #333',
 | 
					      arrowheadStyle: 'fill: #333',
 | 
				
			||||||
 | 
					      cssCompiledStyles: getCompiledStyles(rawEdge.classes),
 | 
				
			||||||
      labelStyle: styles,
 | 
					      labelStyle: styles,
 | 
				
			||||||
      style: styles,
 | 
					      style: styles,
 | 
				
			||||||
      pattern: rawEdge.stroke,
 | 
					      pattern: rawEdge.stroke,
 | 
				
			||||||
      look: config.look,
 | 
					      look: config.look,
 | 
				
			||||||
      curve: config.flowchart?.curve,
 | 
					      curve: config.flowchart?.curve,
 | 
				
			||||||
      showPoints: config.flowchart?.edgeDebug,
 | 
					      showPoints: config.flowchart?.edgeDebug,
 | 
				
			||||||
 | 
					      animate: rawEdge.animate,
 | 
				
			||||||
 | 
					      animation: rawEdge.animation,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    edges.push(edge);
 | 
					    edges.push(edge);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,8 @@ import { setConfig } from '../../diagram-api/diagramAPI.js';
 | 
				
			|||||||
import flowDb from './flowDb.js';
 | 
					import flowDb from './flowDb.js';
 | 
				
			||||||
import renderer from './flowRenderer-v3-unified.js';
 | 
					import renderer from './flowRenderer-v3-unified.js';
 | 
				
			||||||
// @ts-ignore: JISON doesn't support types
 | 
					// @ts-ignore: JISON doesn't support types
 | 
				
			||||||
import flowParser from './parser/flow.jison';
 | 
					//import flowParser from './parser/flow.jison';
 | 
				
			||||||
 | 
					import flowParser from './parser/flowParser.ts';
 | 
				
			||||||
import flowStyles from './styles.js';
 | 
					import flowStyles from './styles.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const diagram = {
 | 
					export const diagram = {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
import { cleanupComments } from '../../../diagram-api/comments.js';
 | 
					import { cleanupComments } from '../../../diagram-api/comments.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
@@ -39,6 +39,27 @@ const doubleEndedEdges = [
 | 
				
			|||||||
  { edgeStart: '<==', edgeEnd: '==>', stroke: 'thick', type: 'double_arrow_point' },
 | 
					  { edgeStart: '<==', edgeEnd: '==>', stroke: 'thick', type: 'double_arrow_point' },
 | 
				
			||||||
  { edgeStart: '<-.', edgeEnd: '.->', stroke: 'dotted', type: 'double_arrow_point' },
 | 
					  { edgeStart: '<-.', edgeEnd: '.->', stroke: 'dotted', type: 'double_arrow_point' },
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					const regularEdges = [
 | 
				
			||||||
 | 
					  { edgeStart: '--', edgeEnd: '--x', stroke: 'normal', type: 'arrow_cross' },
 | 
				
			||||||
 | 
					  { edgeStart: '==', edgeEnd: '==x', stroke: 'thick', type: 'arrow_cross' },
 | 
				
			||||||
 | 
					  { edgeStart: '-.', edgeEnd: '.-x', stroke: 'dotted', type: 'arrow_cross' },
 | 
				
			||||||
 | 
					  { edgeStart: '--', edgeEnd: '--o', stroke: 'normal', type: 'arrow_circle' },
 | 
				
			||||||
 | 
					  { edgeStart: '==', edgeEnd: '==o', stroke: 'thick', type: 'arrow_circle' },
 | 
				
			||||||
 | 
					  { edgeStart: '-.', edgeEnd: '.-o', stroke: 'dotted', type: 'arrow_circle' },
 | 
				
			||||||
 | 
					  { edgeStart: '--', edgeEnd: '-->', stroke: 'normal', type: 'arrow_point' },
 | 
				
			||||||
 | 
					  { edgeStart: '==', edgeEnd: '==>', stroke: 'thick', type: 'arrow_point' },
 | 
				
			||||||
 | 
					  { edgeStart: '-.', edgeEnd: '.->', stroke: 'dotted', type: 'arrow_point' },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  { edgeStart: '--', edgeEnd: '----x', stroke: 'normal', type: 'arrow_cross' },
 | 
				
			||||||
 | 
					  { edgeStart: '==', edgeEnd: '====x', stroke: 'thick', type: 'arrow_cross' },
 | 
				
			||||||
 | 
					  { edgeStart: '-.', edgeEnd: '...-x', stroke: 'dotted', type: 'arrow_cross' },
 | 
				
			||||||
 | 
					  { edgeStart: '--', edgeEnd: '----o', stroke: 'normal', type: 'arrow_circle' },
 | 
				
			||||||
 | 
					  { edgeStart: '==', edgeEnd: '====o', stroke: 'thick', type: 'arrow_circle' },
 | 
				
			||||||
 | 
					  { edgeStart: '-.', edgeEnd: '...-o', stroke: 'dotted', type: 'arrow_circle' },
 | 
				
			||||||
 | 
					  { edgeStart: '--', edgeEnd: '---->', stroke: 'normal', type: 'arrow_point' },
 | 
				
			||||||
 | 
					  { edgeStart: '==', edgeEnd: '====>', stroke: 'thick', type: 'arrow_point' },
 | 
				
			||||||
 | 
					  { edgeStart: '-.', edgeEnd: '...->', stroke: 'dotted', type: 'arrow_point' },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('[Edges] when parsing', () => {
 | 
					describe('[Edges] when parsing', () => {
 | 
				
			||||||
  beforeEach(function () {
 | 
					  beforeEach(function () {
 | 
				
			||||||
@@ -67,6 +88,74 @@ describe('[Edges] when parsing', () => {
 | 
				
			|||||||
    expect(edges[0].type).toBe('arrow_circle');
 | 
					    expect(edges[0].type).toBe('arrow_circle');
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('edges with ids', function () {
 | 
				
			||||||
 | 
					    describe('open ended edges with ids and labels', function () {
 | 
				
			||||||
 | 
					      regularEdges.forEach((edgeType) => {
 | 
				
			||||||
 | 
					        it(`should handle ${edgeType.stroke} ${edgeType.type} with no text`, function () {
 | 
				
			||||||
 | 
					          const res = flow.parser.parse(
 | 
				
			||||||
 | 
					            `flowchart TD;\nA e1@${edgeType.edgeStart}${edgeType.edgeEnd} B;`
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          const vert = flow.parser.yy.getVertices();
 | 
				
			||||||
 | 
					          const edges = flow.parser.yy.getEdges();
 | 
				
			||||||
 | 
					          expect(vert.get('A').id).toBe('A');
 | 
				
			||||||
 | 
					          expect(vert.get('B').id).toBe('B');
 | 
				
			||||||
 | 
					          expect(edges.length).toBe(1);
 | 
				
			||||||
 | 
					          expect(edges[0].id).toBe('e1');
 | 
				
			||||||
 | 
					          expect(edges[0].start).toBe('A');
 | 
				
			||||||
 | 
					          expect(edges[0].end).toBe('B');
 | 
				
			||||||
 | 
					          expect(edges[0].type).toBe(`${edgeType.type}`);
 | 
				
			||||||
 | 
					          expect(edges[0].text).toBe('');
 | 
				
			||||||
 | 
					          expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        it(`should handle ${edgeType.stroke} ${edgeType.type} with text`, function () {
 | 
				
			||||||
 | 
					          const res = flow.parser.parse(
 | 
				
			||||||
 | 
					            `flowchart TD;\nA e1@${edgeType.edgeStart}${edgeType.edgeEnd} B;`
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          const vert = flow.parser.yy.getVertices();
 | 
				
			||||||
 | 
					          const edges = flow.parser.yy.getEdges();
 | 
				
			||||||
 | 
					          expect(vert.get('A').id).toBe('A');
 | 
				
			||||||
 | 
					          expect(vert.get('B').id).toBe('B');
 | 
				
			||||||
 | 
					          expect(edges.length).toBe(1);
 | 
				
			||||||
 | 
					          expect(edges[0].id).toBe('e1');
 | 
				
			||||||
 | 
					          expect(edges[0].start).toBe('A');
 | 
				
			||||||
 | 
					          expect(edges[0].end).toBe('B');
 | 
				
			||||||
 | 
					          expect(edges[0].type).toBe(`${edgeType.type}`);
 | 
				
			||||||
 | 
					          expect(edges[0].text).toBe('');
 | 
				
			||||||
 | 
					          expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('should handle normal edges where you also have a node with metadata', function () {
 | 
				
			||||||
 | 
					        const res = flow.parser.parse(`flowchart LR
 | 
				
			||||||
 | 
					A id1@-->B
 | 
				
			||||||
 | 
					A@{ shape: 'rect' }
 | 
				
			||||||
 | 
					`);
 | 
				
			||||||
 | 
					        const edges = flow.parser.yy.getEdges();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expect(edges[0].id).toBe('id1');
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    describe('double ended edges with ids and labels', function () {
 | 
				
			||||||
 | 
					      doubleEndedEdges.forEach((edgeType) => {
 | 
				
			||||||
 | 
					        it(`should handle ${edgeType.stroke} ${edgeType.type} with  text`, function () {
 | 
				
			||||||
 | 
					          const res = flow.parser.parse(
 | 
				
			||||||
 | 
					            `flowchart TD;\nA e1@${edgeType.edgeStart} label ${edgeType.edgeEnd} B;`
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          const vert = flow.parser.yy.getVertices();
 | 
				
			||||||
 | 
					          const edges = flow.parser.yy.getEdges();
 | 
				
			||||||
 | 
					          expect(vert.get('A').id).toBe('A');
 | 
				
			||||||
 | 
					          expect(vert.get('B').id).toBe('B');
 | 
				
			||||||
 | 
					          expect(edges.length).toBe(1);
 | 
				
			||||||
 | 
					          expect(edges[0].id).toBe('e1');
 | 
				
			||||||
 | 
					          expect(edges[0].start).toBe('A');
 | 
				
			||||||
 | 
					          expect(edges[0].end).toBe('B');
 | 
				
			||||||
 | 
					          expect(edges[0].type).toBe(`${edgeType.type}`);
 | 
				
			||||||
 | 
					          expect(edges[0].text).toBe('label');
 | 
				
			||||||
 | 
					          expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe('edges', function () {
 | 
					  describe('edges', function () {
 | 
				
			||||||
    doubleEndedEdges.forEach((edgeType) => {
 | 
					    doubleEndedEdges.forEach((edgeType) => {
 | 
				
			||||||
      it(`should handle ${edgeType.stroke} ${edgeType.type} with no text`, function () {
 | 
					      it(`should handle ${edgeType.stroke} ${edgeType.type} with no text`, function () {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
import { vi } from 'vitest';
 | 
					import { vi } from 'vitest';
 | 
				
			||||||
const spyOn = vi.spyOn;
 | 
					const spyOn = vi.spyOn;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
@@ -290,4 +290,28 @@ describe('when parsing directions', function () {
 | 
				
			|||||||
    expect(data4Layout.nodes[0].shape).toEqual('squareRect');
 | 
					    expect(data4Layout.nodes[0].shape).toEqual('squareRect');
 | 
				
			||||||
    expect(data4Layout.nodes[0].label).toEqual('This is a string with}');
 | 
					    expect(data4Layout.nodes[0].label).toEqual('This is a string with}');
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it(' should be possible to use @  syntax to add labels on multi nodes', function () {
 | 
				
			||||||
 | 
					    const res = flow.parser.parse(`flowchart TB
 | 
				
			||||||
 | 
					       n2["label for n2"] &   n4@{ label: "labe for n4"}   & n5@{ label: "labe for n5"}
 | 
				
			||||||
 | 
					      `);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const data4Layout = flow.parser.yy.getData();
 | 
				
			||||||
 | 
					    expect(data4Layout.nodes.length).toBe(3);
 | 
				
			||||||
 | 
					    expect(data4Layout.nodes[0].label).toEqual('label for n2');
 | 
				
			||||||
 | 
					    expect(data4Layout.nodes[1].label).toEqual('labe for n4');
 | 
				
			||||||
 | 
					    expect(data4Layout.nodes[2].label).toEqual('labe for n5');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  it.skip(' should be possible to use @  syntax to add labels with trail spaces', function () {
 | 
				
			||||||
 | 
					    const res = flow.parser.parse(
 | 
				
			||||||
 | 
					      `flowchart TB
 | 
				
			||||||
 | 
					       n2["label for n2"] &   n4@{ label: "labe for n4"}   & n5@{ label: "labe for n5"} `
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const data4Layout = flow.parser.yy.getData();
 | 
				
			||||||
 | 
					    expect(data4Layout.nodes.length).toBe(3);
 | 
				
			||||||
 | 
					    expect(data4Layout.nodes[0].label).toEqual('label for n2');
 | 
				
			||||||
 | 
					    expect(data4Layout.nodes[1].label).toEqual('labe for n4');
 | 
				
			||||||
 | 
					    expect(data4Layout.nodes[2].label).toEqual('labe for n5');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -141,6 +141,7 @@ that id.
 | 
				
			|||||||
.*direction\s+RL[^\n]*       return 'direction_rl';
 | 
					.*direction\s+RL[^\n]*       return 'direction_rl';
 | 
				
			||||||
.*direction\s+LR[^\n]*       return 'direction_lr';
 | 
					.*direction\s+LR[^\n]*       return 'direction_lr';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[^\s]+\@(?=[^\{])               { return 'LINK_ID'; }
 | 
				
			||||||
[0-9]+                       return 'NUM';
 | 
					[0-9]+                       return 'NUM';
 | 
				
			||||||
\#                           return 'BRKT';
 | 
					\#                           return 'BRKT';
 | 
				
			||||||
":::"                        return 'STYLE_SEPARATOR';
 | 
					":::"                        return 'STYLE_SEPARATOR';
 | 
				
			||||||
@@ -201,7 +202,9 @@ that id.
 | 
				
			|||||||
"*"                   return 'MULT';
 | 
					"*"                   return 'MULT';
 | 
				
			||||||
"#"                   return 'BRKT';
 | 
					"#"                   return 'BRKT';
 | 
				
			||||||
"&"                   return 'AMP';
 | 
					"&"                   return 'AMP';
 | 
				
			||||||
([A-Za-z0-9!"\#$%&'*+\.`?\\_\/]|\-(?=[^\>\-\.])|=(?!=))+  return 'NODE_STRING';
 | 
					([A-Za-z0-9!"\#$%&'*+\.`?\\_\/]|\-(?=[^\>\-\.])|=(?!=))+  {
 | 
				
			||||||
 | 
					    return 'NODE_STRING';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
"-"                   return 'MINUS'
 | 
					"-"                   return 'MINUS'
 | 
				
			||||||
[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|
 | 
					[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|
 | 
				
			||||||
[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|
 | 
					[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|
 | 
				
			||||||
@@ -361,7 +364,7 @@ spaceList
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
statement
 | 
					statement
 | 
				
			||||||
    : vertexStatement separator
 | 
					    : vertexStatement separator
 | 
				
			||||||
    { /* console.warn('finat vs', $vertexStatement.nodes); */ $$=$vertexStatement.nodes}
 | 
					    { $$=$vertexStatement.nodes}
 | 
				
			||||||
    | styleStatement separator
 | 
					    | styleStatement separator
 | 
				
			||||||
    {$$=[];}
 | 
					    {$$=[];}
 | 
				
			||||||
    | linkStyleStatement separator
 | 
					    | linkStyleStatement separator
 | 
				
			||||||
@@ -404,7 +407,7 @@ vertexStatement: vertexStatement link node shapeData
 | 
				
			|||||||
    |node spaceList { /*console.warn('vertexStatement: node spaceList', $node);*/ $$ = {stmt: $node, nodes:$node }}
 | 
					    |node spaceList { /*console.warn('vertexStatement: node spaceList', $node);*/ $$ = {stmt: $node, nodes:$node }}
 | 
				
			||||||
    |node shapeData {
 | 
					    |node shapeData {
 | 
				
			||||||
        /*console.warn('vertexStatement: node shapeData', $node[0], $shapeData);*/
 | 
					        /*console.warn('vertexStatement: node shapeData', $node[0], $shapeData);*/
 | 
				
			||||||
        yy.addVertex($node[0],undefined,undefined,undefined, undefined,undefined, undefined,$shapeData);
 | 
					        yy.addVertex($node[$node.length-1],undefined,undefined,undefined, undefined,undefined, undefined,$shapeData);
 | 
				
			||||||
        $$ = {stmt: $node, nodes:$node, shapeData: $shapeData}
 | 
					        $$ = {stmt: $node, nodes:$node, shapeData: $shapeData}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    |node { /* console.warn('vertexStatement: single node', $node); */ $$ = {stmt: $node, nodes:$node }}
 | 
					    |node { /* console.warn('vertexStatement: single node', $node); */ $$ = {stmt: $node, nodes:$node }}
 | 
				
			||||||
@@ -413,7 +416,7 @@ vertexStatement: vertexStatement link node shapeData
 | 
				
			|||||||
node: styledVertex
 | 
					node: styledVertex
 | 
				
			||||||
        { /*console.warn('nod', $styledVertex);*/ $$ = [$styledVertex];}
 | 
					        { /*console.warn('nod', $styledVertex);*/ $$ = [$styledVertex];}
 | 
				
			||||||
    | node shapeData spaceList AMP spaceList styledVertex
 | 
					    | node shapeData spaceList AMP spaceList styledVertex
 | 
				
			||||||
        {  yy.addVertex($node[0],undefined,undefined,undefined, undefined,undefined, undefined,$shapeData); $$ = $node.concat($styledVertex); /*console.warn('pip2', $node[0], $styledVertex, $$);*/  }
 | 
					        {  yy.addVertex($node[$node.length-1],undefined,undefined,undefined, undefined,undefined, undefined,$shapeData); $$ = $node.concat($styledVertex); /*console.warn('pip2', $node[0], $styledVertex, $$);*/  }
 | 
				
			||||||
    | node spaceList AMP spaceList styledVertex
 | 
					    | node spaceList AMP spaceList styledVertex
 | 
				
			||||||
        { $$ = $node.concat($styledVertex); /*console.warn('pip', $node[0], $styledVertex, $$);*/  }
 | 
					        { $$ = $node.concat($styledVertex); /*console.warn('pip', $node[0], $styledVertex, $$);*/  }
 | 
				
			||||||
    ;
 | 
					    ;
 | 
				
			||||||
@@ -472,6 +475,8 @@ link: linkStatement arrowText
 | 
				
			|||||||
    {$$ = $linkStatement;}
 | 
					    {$$ = $linkStatement;}
 | 
				
			||||||
    | START_LINK edgeText LINK
 | 
					    | START_LINK edgeText LINK
 | 
				
			||||||
        {var inf = yy.destructLink($LINK, $START_LINK); $$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length,"text":$edgeText};}
 | 
					        {var inf = yy.destructLink($LINK, $START_LINK); $$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length,"text":$edgeText};}
 | 
				
			||||||
 | 
					    | LINK_ID START_LINK edgeText LINK
 | 
				
			||||||
 | 
					        {var inf = yy.destructLink($LINK, $START_LINK); $$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length,"text":$edgeText, "id": $LINK_ID};}
 | 
				
			||||||
    ;
 | 
					    ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
edgeText: edgeTextToken
 | 
					edgeText: edgeTextToken
 | 
				
			||||||
@@ -487,6 +492,8 @@ edgeText: edgeTextToken
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
linkStatement: LINK
 | 
					linkStatement: LINK
 | 
				
			||||||
        {var inf = yy.destructLink($LINK);$$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length};}
 | 
					        {var inf = yy.destructLink($LINK);$$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length};}
 | 
				
			||||||
 | 
					    | LINK_ID LINK
 | 
				
			||||||
 | 
					        {var inf = yy.destructLink($LINK);$$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length, "id": $LINK_ID};}
 | 
				
			||||||
        ;
 | 
					        ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
arrowText:
 | 
					arrowText:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { cleanupComments } from '../../../diagram-api/comments.js';
 | 
					import { cleanupComments } from '../../../diagram-api/comments.js';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								packages/mermaid/src/diagrams/flowchart/parser/flowParser.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								packages/mermaid/src/diagrams/flowchart/parser/flowParser.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					// @ts-ignore: JISON doesn't support types
 | 
				
			||||||
 | 
					import flowJisonParser from './flow.jison';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const newParser = Object.assign({}, flowJisonParser);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newParser.parse = (src: string): unknown => {
 | 
				
			||||||
 | 
					  // remove the trailing whitespace after closing curly braces when ending a line break
 | 
				
			||||||
 | 
					  const newSrc = src.replace(/}\s*\n/g, '}\n');
 | 
				
			||||||
 | 
					  return flowJisonParser.parse(newSrc);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default newParser;
 | 
				
			||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import flowDb from '../flowDb.js';
 | 
					import flowDb from '../flowDb.js';
 | 
				
			||||||
import flow from './flow.jison';
 | 
					import flow from './flowParser.ts';
 | 
				
			||||||
import { setConfig } from '../../../config.js';
 | 
					import { setConfig } from '../../../config.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setConfig({
 | 
					setConfig({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,6 +62,10 @@ export interface FlowEdge {
 | 
				
			|||||||
  length?: number;
 | 
					  length?: number;
 | 
				
			||||||
  text: string;
 | 
					  text: string;
 | 
				
			||||||
  labelType: 'text';
 | 
					  labelType: 'text';
 | 
				
			||||||
 | 
					  classes: string[];
 | 
				
			||||||
 | 
					  id?: string;
 | 
				
			||||||
 | 
					  animation?: 'fast' | 'slow';
 | 
				
			||||||
 | 
					  animate?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface FlowClass {
 | 
					export interface FlowClass {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -711,6 +711,67 @@ flowchart TB
 | 
				
			|||||||
    B --> D
 | 
					    B --> D
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Attaching an ID to Edges
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Mermaid now supports assigning IDs to edges, similar to how IDs and metadata can be attached to nodes. This feature lays the groundwork for more advanced styling, classes, and animation capabilities on edges.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Syntax:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To give an edge an ID, prepend the edge syntax with the ID followed by an `@` character. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@–> B
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In this example, `e1` is the ID of the edge connecting `A` to `B`. You can then use this ID in later definitions or style statements, just like with nodes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Turning an Animation On
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once you have assigned an ID to an edge, you can turn on animations for that edge by defining the edge’s properties:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@==> B
 | 
				
			||||||
 | 
					  e1@{ animate: true }
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This tells Mermaid that the edge `e1` should be animated.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Selecting Type of Animation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the initial version, two animation speeds are supported: `fast` and `slow`. Selecting a specific animation type is a shorthand for enabling animation and setting the animation speed in one go.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Examples:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@–> B
 | 
				
			||||||
 | 
					  e1@{ animation: fast }
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is equivalent to `{ animate: true, animation: fast }`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Using classDef Statements for Animations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can also animate edges by assigning a class to them and then defining animation properties in a `classDef` statement. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```mermaid
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					  A e1@–> B
 | 
				
			||||||
 | 
					  classDef animate stroke-dasharray: 9,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
 | 
				
			||||||
 | 
					  class e1 animate
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In this snippet:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `e1@-->` creates an edge with ID `e1`.
 | 
				
			||||||
 | 
					- `classDef animate` defines a class named `animate` with styling and animation properties.
 | 
				
			||||||
 | 
					- `class e1 animate` applies the `animate` class to the edge `e1`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Note on Escaping Commas:**
 | 
				
			||||||
 | 
					When setting the `stroke-dasharray` property, remember to escape commas as `\,` since commas are used as delimiters in Mermaid’s style definitions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## New arrow types
 | 
					## New arrow types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
There are new types of arrows supported:
 | 
					There are new types of arrows supported:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -390,7 +390,7 @@ mermaid.ganttConfig = {
 | 
				
			|||||||
  sectionFontSize: 24, // Font size for sections
 | 
					  sectionFontSize: 24, // Font size for sections
 | 
				
			||||||
  numberSectionStyles: 1, // The number of alternating section styles
 | 
					  numberSectionStyles: 1, // The number of alternating section styles
 | 
				
			||||||
  axisFormat: '%d/%m', // Date/time format of the axis
 | 
					  axisFormat: '%d/%m', // Date/time format of the axis
 | 
				
			||||||
  tickInterval: '1 week', // Axis ticks
 | 
					  tickInterval: '1week', // Axis ticks
 | 
				
			||||||
  topAxis: true, // When this flag is set, date labels will be added to the top of the chart
 | 
					  topAxis: true, // When this flag is set, date labels will be added to the top of the chart
 | 
				
			||||||
  displayMode: 'compact', // Turns compact mode on
 | 
					  displayMode: 'compact', // Turns compact mode on
 | 
				
			||||||
  weekday: 'sunday', // On which day a week-based interval should start
 | 
					  weekday: 'sunday', // On which day a week-based interval should start
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import { curveBasis, curveLinear, curveCardinal, line, select } from 'd3';
 | 
				
			|||||||
import rough from 'roughjs';
 | 
					import rough from 'roughjs';
 | 
				
			||||||
import createLabel from './createLabel.js';
 | 
					import createLabel from './createLabel.js';
 | 
				
			||||||
import { addEdgeMarkers } from './edgeMarker.ts';
 | 
					import { addEdgeMarkers } from './edgeMarker.ts';
 | 
				
			||||||
 | 
					import { isLabelStyle } from './shapes/handDrawnShapeStyles.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const edgeLabels = new Map();
 | 
					const edgeLabels = new Map();
 | 
				
			||||||
const terminalLabels = new Map();
 | 
					const terminalLabels = new Map();
 | 
				
			||||||
@@ -430,6 +431,13 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
  let pointsHasChanged = false;
 | 
					  let pointsHasChanged = false;
 | 
				
			||||||
  const tail = startNode;
 | 
					  const tail = startNode;
 | 
				
			||||||
  var head = endNode;
 | 
					  var head = endNode;
 | 
				
			||||||
 | 
					  const edgeClassStyles = [];
 | 
				
			||||||
 | 
					  for (const key in edge.cssCompiledStyles) {
 | 
				
			||||||
 | 
					    if (isLabelStyle(key)) {
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    edgeClassStyles.push(edge.cssCompiledStyles[key]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (head.intersect && tail.intersect) {
 | 
					  if (head.intersect && tail.intersect) {
 | 
				
			||||||
    points = points.slice(1, edge.points.length - 1);
 | 
					    points = points.slice(1, edge.points.length - 1);
 | 
				
			||||||
@@ -532,6 +540,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
      ? generateRoundedPath(applyMarkerOffsetsToPoints(lineData, edge), 5)
 | 
					      ? generateRoundedPath(applyMarkerOffsetsToPoints(lineData, edge), 5)
 | 
				
			||||||
      : lineFunction(lineData);
 | 
					      : lineFunction(lineData);
 | 
				
			||||||
  const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
 | 
					  const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (edge.look === 'handDrawn') {
 | 
					  if (edge.look === 'handDrawn') {
 | 
				
			||||||
    const rc = rough.svg(elem);
 | 
					    const rc = rough.svg(elem);
 | 
				
			||||||
    Object.assign([], lineData);
 | 
					    Object.assign([], lineData);
 | 
				
			||||||
@@ -552,12 +561,27 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
    svgPath.attr('d', d);
 | 
					    svgPath.attr('d', d);
 | 
				
			||||||
    elem.node().appendChild(svgPath.node());
 | 
					    elem.node().appendChild(svgPath.node());
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
 | 
					    const stylesFromClasses = edgeClassStyles.join(';');
 | 
				
			||||||
 | 
					    const styles = edgeStyles ? edgeStyles.reduce((acc, style) => acc + style + ';', '') : '';
 | 
				
			||||||
 | 
					    let animationClass = '';
 | 
				
			||||||
 | 
					    if (edge.animate) {
 | 
				
			||||||
 | 
					      animationClass = ' edge-animation-fast';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (edge.animation) {
 | 
				
			||||||
 | 
					      animationClass = ' edge-animation-' + edge.animation;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    svgPath = elem
 | 
					    svgPath = elem
 | 
				
			||||||
      .append('path')
 | 
					      .append('path')
 | 
				
			||||||
      .attr('d', linePath)
 | 
					      .attr('d', linePath)
 | 
				
			||||||
      .attr('id', edge.id)
 | 
					      .attr('id', edge.id)
 | 
				
			||||||
      .attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''))
 | 
					      .attr(
 | 
				
			||||||
      .attr('style', edgeStyles ? edgeStyles.reduce((acc, style) => acc + ';' + style, '') : '');
 | 
					        'class',
 | 
				
			||||||
 | 
					        ' ' +
 | 
				
			||||||
 | 
					          strokeClasses +
 | 
				
			||||||
 | 
					          (edge.classes ? ' ' + edge.classes : '') +
 | 
				
			||||||
 | 
					          (animationClass ? animationClass : '')
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      .attr('style', stylesFromClasses ? stylesFromClasses + ';' + styles + ';' : styles);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // MC Special
 | 
					  // MC Special
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,28 @@ export const styles2Map = (styles: string[]) => {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
  return styleMap;
 | 
					  return styleMap;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					export const isLabelStyle = (key: string) => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    key === 'color' ||
 | 
				
			||||||
 | 
					    key === 'font-size' ||
 | 
				
			||||||
 | 
					    key === 'font-family' ||
 | 
				
			||||||
 | 
					    key === 'font-weight' ||
 | 
				
			||||||
 | 
					    key === 'font-style' ||
 | 
				
			||||||
 | 
					    key === 'text-decoration' ||
 | 
				
			||||||
 | 
					    key === 'text-align' ||
 | 
				
			||||||
 | 
					    key === 'text-transform' ||
 | 
				
			||||||
 | 
					    key === 'line-height' ||
 | 
				
			||||||
 | 
					    key === 'letter-spacing' ||
 | 
				
			||||||
 | 
					    key === 'word-spacing' ||
 | 
				
			||||||
 | 
					    key === 'text-shadow' ||
 | 
				
			||||||
 | 
					    key === 'text-overflow' ||
 | 
				
			||||||
 | 
					    key === 'white-space' ||
 | 
				
			||||||
 | 
					    key === 'word-wrap' ||
 | 
				
			||||||
 | 
					    key === 'word-break' ||
 | 
				
			||||||
 | 
					    key === 'overflow-wrap' ||
 | 
				
			||||||
 | 
					    key === 'hyphens'
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
export const styles2String = (node: Node) => {
 | 
					export const styles2String = (node: Node) => {
 | 
				
			||||||
  const { stylesArray } = compileStyles(node);
 | 
					  const { stylesArray } = compileStyles(node);
 | 
				
			||||||
  const labelStyles: string[] = [];
 | 
					  const labelStyles: string[] = [];
 | 
				
			||||||
@@ -42,26 +63,7 @@ export const styles2String = (node: Node) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  stylesArray.forEach((style) => {
 | 
					  stylesArray.forEach((style) => {
 | 
				
			||||||
    const key = style[0];
 | 
					    const key = style[0];
 | 
				
			||||||
    if (
 | 
					    if (isLabelStyle(key)) {
 | 
				
			||||||
      key === 'color' ||
 | 
					 | 
				
			||||||
      key === 'font-size' ||
 | 
					 | 
				
			||||||
      key === 'font-family' ||
 | 
					 | 
				
			||||||
      key === 'font-weight' ||
 | 
					 | 
				
			||||||
      key === 'font-style' ||
 | 
					 | 
				
			||||||
      key === 'text-decoration' ||
 | 
					 | 
				
			||||||
      key === 'text-align' ||
 | 
					 | 
				
			||||||
      key === 'text-transform' ||
 | 
					 | 
				
			||||||
      key === 'line-height' ||
 | 
					 | 
				
			||||||
      key === 'letter-spacing' ||
 | 
					 | 
				
			||||||
      key === 'word-spacing' ||
 | 
					 | 
				
			||||||
      key === 'text-shadow' ||
 | 
					 | 
				
			||||||
      key === 'text-overflow' ||
 | 
					 | 
				
			||||||
      key === 'white-space' ||
 | 
					 | 
				
			||||||
      key === 'word-wrap' ||
 | 
					 | 
				
			||||||
      key === 'word-break' ||
 | 
					 | 
				
			||||||
      key === 'overflow-wrap' ||
 | 
					 | 
				
			||||||
      key === 'hyphens'
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
      labelStyles.push(style.join(':') + ' !important');
 | 
					      labelStyles.push(style.join(':') + ' !important');
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      nodeStyles.push(style.join(':') + ' !important');
 | 
					      nodeStyles.push(style.join(':') + ' !important');
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -96,11 +96,14 @@ export interface Edge {
 | 
				
			|||||||
  label?: string;
 | 
					  label?: string;
 | 
				
			||||||
  classes?: string;
 | 
					  classes?: string;
 | 
				
			||||||
  style?: string[];
 | 
					  style?: string[];
 | 
				
			||||||
 | 
					  animate?: boolean;
 | 
				
			||||||
 | 
					  animation?: 'fast' | 'slow';
 | 
				
			||||||
  // Properties common to both Flowchart and State Diagram edges
 | 
					  // Properties common to both Flowchart and State Diagram edges
 | 
				
			||||||
  arrowhead?: string;
 | 
					  arrowhead?: string;
 | 
				
			||||||
  arrowheadStyle?: string;
 | 
					  arrowheadStyle?: string;
 | 
				
			||||||
  arrowTypeEnd?: string;
 | 
					  arrowTypeEnd?: string;
 | 
				
			||||||
  arrowTypeStart?: string;
 | 
					  arrowTypeStart?: string;
 | 
				
			||||||
 | 
					  cssCompiledStyles?: string[];
 | 
				
			||||||
  // Flowchart specific properties
 | 
					  // Flowchart specific properties
 | 
				
			||||||
  defaultInterpolate?: string;
 | 
					  defaultInterpolate?: string;
 | 
				
			||||||
  end?: string;
 | 
					  end?: string;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,28 @@ const getStyles = (
 | 
				
			|||||||
    font-size: ${options.fontSize};
 | 
					    font-size: ${options.fontSize};
 | 
				
			||||||
    fill: ${options.textColor}
 | 
					    fill: ${options.textColor}
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  @keyframes edge-animation-frame {
 | 
				
			||||||
 | 
					    from {
 | 
				
			||||||
 | 
					      stroke-dashoffset: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  @keyframes dash {
 | 
				
			||||||
 | 
					    to {
 | 
				
			||||||
 | 
					      stroke-dashoffset: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  & .edge-animation-slow {
 | 
				
			||||||
 | 
					    stroke-dasharray: 9,5 !important;
 | 
				
			||||||
 | 
					    stroke-dashoffset: 900;
 | 
				
			||||||
 | 
					    animation: dash 50s linear infinite;
 | 
				
			||||||
 | 
					    stroke-linecap: round;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  & .edge-animation-fast {
 | 
				
			||||||
 | 
					    stroke-dasharray: 9,5 !important;
 | 
				
			||||||
 | 
					    stroke-dashoffset: 900;
 | 
				
			||||||
 | 
					    animation: dash 20s linear infinite;
 | 
				
			||||||
 | 
					    stroke-linecap: round;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  /* Classes common for multiple diagrams */
 | 
					  /* Classes common for multiple diagrams */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  & .error-icon {
 | 
					  & .error-icon {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,11 @@ export interface NodeMetaData {
 | 
				
			|||||||
  ticket?: string;
 | 
					  ticket?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface EdgeMetaData {
 | 
				
			||||||
 | 
					  animation?: 'fast' | 'slow';
 | 
				
			||||||
 | 
					  animate?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Point {
 | 
					export interface Point {
 | 
				
			||||||
  x: number;
 | 
					  x: number;
 | 
				
			||||||
  y: number;
 | 
					  y: number;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -937,8 +937,12 @@ export const getEdgeId = (
 | 
				
			|||||||
    counter?: number;
 | 
					    counter?: number;
 | 
				
			||||||
    prefix?: string;
 | 
					    prefix?: string;
 | 
				
			||||||
    suffix?: string;
 | 
					    suffix?: string;
 | 
				
			||||||
  }
 | 
					  },
 | 
				
			||||||
 | 
					  id?: string
 | 
				
			||||||
) => {
 | 
					) => {
 | 
				
			||||||
 | 
					  if (id) {
 | 
				
			||||||
 | 
					    return id;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  return `${prefix ? `${prefix}_` : ''}${from}_${to}_${counter}${suffix ? `_${suffix}` : ''}`;
 | 
					  return `${prefix ? `${prefix}_` : ''}${from}_${to}_${counter}${suffix ? `_${suffix}` : ''}`;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user