diff --git a/docs/syntax/flowchart.md b/docs/syntax/flowchart.md
index 1dd9fc22e..8edb5e208 100644
--- a/docs/syntax/flowchart.md
+++ b/docs/syntax/flowchart.md
@@ -1194,6 +1194,20 @@ flowchart TD
B-->E(fak:fa-custom-icon-name) %% custom icon
```
+And trying to render it
+
+```mermaid-example
+flowchart TD
+ B["fa:fa-twitter for peace"]
+ B-->C["fab:fa-truck-bold a custom icon"]
+```
+
+```mermaid
+flowchart TD
+ B["fa:fa-twitter for peace"]
+ B-->C["fab:fa-truck-bold a custom icon"]
+```
+
## Graph declarations with spaces between vertices and link and without semicolon
- In graph declarations, the statements also can now end without a semicolon. After release 0.2.16, ending a graph statement with semicolon is just optional. So the below graph declaration is also valid along with the old declarations of the graph.
diff --git a/packages/mermaid/src/dagre-wrapper/createLabel.js b/packages/mermaid/src/dagre-wrapper/createLabel.js
index ab0be6353..f49d65f25 100644
--- a/packages/mermaid/src/dagre-wrapper/createLabel.js
+++ b/packages/mermaid/src/dagre-wrapper/createLabel.js
@@ -3,6 +3,7 @@ import { log } from '../logger.js';
import { getConfig } from '../diagram-api/diagramAPI.js';
import { evaluate } from '../diagrams/common/common.js';
import { decodeEntities } from '../utils.js';
+import { replaceIconSubstring } from '../rendering-util/createText.js';
/**
* @param dom
@@ -59,10 +60,7 @@ const createLabel = (_vertexText, style, isTitle, isNode) => {
log.debug('vertexText' + vertexText);
const node = {
isNode,
- label: decodeEntities(vertexText).replace(
- /fa[bklrs]?:fa-[\w-]+/g, // cspell: disable-line
- (s) => ``
- ),
+ label: replaceIconSubstring(decodeEntities(vertexText)),
labelStyle: style.replace('fill:', 'color:'),
};
let vertexNode = addHtmlLabel(node);
diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer.js
index 9edfb6f47..b2e6bcc9c 100644
--- a/packages/mermaid/src/diagrams/flowchart/flowRenderer.js
+++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer.js
@@ -9,6 +9,7 @@ import common, { evaluate, renderKatex } from '../common/common.js';
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
import flowChartShapes from './flowChartShapes.js';
+import { replaceIconSubstring } from '../../rendering-util/createText.js';
const conf = {};
export const setConf = function (cnf) {
@@ -56,14 +57,9 @@ export const addVertices = async function (vert, g, svgId, root, _doc, diagObj)
let vertexNode;
if (evaluate(getConfig().flowchart.htmlLabels)) {
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
+ const replacedVertexText = replaceIconSubstring(vertexText);
const node = {
- label: await renderKatex(
- vertexText.replace(
- /fa[bklrs]?:fa-[\w-]+/g, // cspell:disable-line
- (s) => ``
- ),
- getConfig()
- ),
+ label: await renderKatex(replacedVertexText, getConfig()),
};
vertexNode = addHtmlLabel(svg, node).node();
vertexNode.parentNode.removeChild(vertexNode);
@@ -242,13 +238,7 @@ export const addEdges = async function (edges, g, diagObj) {
edgeData.labelType = 'html';
edgeData.label = `${await renderKatex(
- edge.text.replace(
- /fa[bklrs]?:fa-[\w-]+/g, // cspell:disable-line
- (s) => ``
- ),
- getConfig()
- )}`;
+ }">${await renderKatex(replaceIconSubstring(edge.text), getConfig())}`;
} else {
edgeData.labelType = 'text';
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
diff --git a/packages/mermaid/src/docs/syntax/flowchart.md b/packages/mermaid/src/docs/syntax/flowchart.md
index 86f7446a5..ba0e9ce9e 100644
--- a/packages/mermaid/src/docs/syntax/flowchart.md
+++ b/packages/mermaid/src/docs/syntax/flowchart.md
@@ -815,6 +815,14 @@ flowchart TD
B-->E(fak:fa-custom-icon-name) %% custom icon
```
+And trying to render it
+
+```mermaid-example
+flowchart TD
+ B["fa:fa-twitter for peace"]
+ B-->C["fab:fa-truck-bold a custom icon"]
+```
+
## Graph declarations with spaces between vertices and link and without semicolon
- In graph declarations, the statements also can now end without a semicolon. After release 0.2.16, ending a graph statement with semicolon is just optional. So the below graph declaration is also valid along with the old declarations of the graph.
diff --git a/packages/mermaid/src/rendering-util/createText.spec.ts b/packages/mermaid/src/rendering-util/createText.spec.ts
new file mode 100644
index 000000000..da0505ad8
--- /dev/null
+++ b/packages/mermaid/src/rendering-util/createText.spec.ts
@@ -0,0 +1,34 @@
+import { describe, it, expect } from 'vitest';
+import { replaceIconSubstring } from './createText.js';
+
+describe('replaceIconSubstring', () => {
+ it('converts FontAwesome icon notations to HTML tags', () => {
+ const input = 'This is an icon: fa:fa-user and fab:fa-github';
+ const output = replaceIconSubstring(input);
+ const expected =
+ "This is an icon: and ";
+ expect(output).toEqual(expected);
+ });
+
+ it('handles strings without FontAwesome icon notations', () => {
+ const input = 'This string has no icons';
+ const output = replaceIconSubstring(input);
+ expect(output).toEqual(input); // No change expected
+ });
+
+ it('correctly processes multiple FontAwesome icon notations in one string', () => {
+ const input = 'Icons galore: fa:fa-arrow-right, fak:fa-truck, fas:fa-home';
+ const output = replaceIconSubstring(input);
+ const expected =
+ "Icons galore: , , ";
+ expect(output).toEqual(expected);
+ });
+
+ it('correctly replaces a very long icon name with the fak prefix', () => {
+ const input = 'Here is a long icon: fak:fa-truck-driving-long-winding-road in use';
+ const output = replaceIconSubstring(input);
+ const expected =
+ "Here is a long icon: in use";
+ expect(output).toEqual(expected);
+ });
+});
diff --git a/packages/mermaid/src/rendering-util/createText.ts b/packages/mermaid/src/rendering-util/createText.ts
index c4cc2792c..ba872ac76 100644
--- a/packages/mermaid/src/rendering-util/createText.ts
+++ b/packages/mermaid/src/rendering-util/createText.ts
@@ -168,6 +168,21 @@ function updateTextContentAndStyles(tspan: any, wrappedLine: MarkdownWord[]) {
});
}
+/**
+ *
+ * @param text - The raw string to adjust
+ * @returns
+ */
+
+// Used for converting substrings in node labels/edges/text into fontawesome icons by using a regex pattern
+// The letters 'bklrs' stand for possible endings of the fontawesome prefix (e.g. 'fab' for brands, 'fak' for fa-kit) // cspell: disable-line
+export function replaceIconSubstring(text: string) {
+ return text.replace(
+ /fa[bklrs]?:fa-[\w-]+/g, // cspell: disable-line
+ (s) => ``
+ );
+}
+
// Note when using from flowcharts converting the API isNode means classes should be set accordingly. When using htmlLabels => to sett classes to'nodeLabel' when isNode=true otherwise 'edgeLabel'
// When not using htmlLabels => to set classes to 'title-row' when isTitle=true otherwise 'title-row'
export const createText = (
@@ -189,12 +204,10 @@ export const createText = (
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
const htmlText = markdownToHTML(text, config);
+ const decodedReplacedText = replaceIconSubstring(decodeEntities(htmlText));
const node = {
isNode,
- label: decodeEntities(htmlText).replace(
- /fa[bklrs]?:fa-[\w-]+/g, // cspell: disable-line
- (s) => ``
- ),
+ label: decodedReplacedText,
labelStyle: style.replace('fill:', 'color:'),
};
const vertexNode = addHtmlSpan(el, node, width, classes, addSvgBackground);