diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json
index 325985c7c..71abdfdb4 100644
--- a/packages/mermaid/package.json
+++ b/packages/mermaid/package.json
@@ -68,10 +68,6 @@
},
"dependencies": {
"@braintree/sanitize-url": "^7.0.1",
- "@fortawesome/fontawesome-svg-core": "^6.7.2",
- "@fortawesome/free-brands-svg-icons": "^6.7.2",
- "@fortawesome/free-regular-svg-icons": "^6.7.2",
- "@fortawesome/free-solid-svg-icons": "^6.7.2",
"@iconify/utils": "^2.1.32",
"@mermaid-js/parser": "workspace:^",
"@types/d3": "^7.4.3",
diff --git a/packages/mermaid/src/dagre-wrapper/clusters.js b/packages/mermaid/src/dagre-wrapper/clusters.js
index 2c7746876..4103c48f3 100644
--- a/packages/mermaid/src/dagre-wrapper/clusters.js
+++ b/packages/mermaid/src/dagre-wrapper/clusters.js
@@ -7,7 +7,7 @@ import { getConfig } from '../diagram-api/diagramAPI.js';
import { evaluate } from '../diagrams/common/common.js';
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
-const rect = (parent, node) => {
+const rect = async (parent, node) => {
log.info('Creating subgraph rect for ', node.id, node);
const siteConfig = getConfig();
@@ -31,7 +31,9 @@ const rect = (parent, node) => {
const text =
node.labelType === 'markdown'
? createText(label, node.labelText, { style: node.labelStyle, useHtmlLabels }, siteConfig)
- : label.node().appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
+ : label
+ .node()
+ .appendChild(await createLabel(node.labelText, node.labelStyle, undefined, true));
// Get the size of the label
let bbox = text.getBBox();
@@ -129,7 +131,7 @@ const noteGroup = (parent, node) => {
return shapeSvg;
};
-const roundedWithTitle = (parent, node) => {
+const roundedWithTitle = async (parent, node) => {
const siteConfig = getConfig();
// Add outer g element
@@ -144,7 +146,7 @@ const roundedWithTitle = (parent, node) => {
const text = label
.node()
- .appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
+ .appendChild(await createLabel(node.labelText, node.labelStyle, undefined, true));
// Get the size of the label
let bbox = text.getBBox();
@@ -236,13 +238,13 @@ const shapes = { rect, roundedWithTitle, noteGroup, divider };
let clusterElems = {};
-export const insertCluster = (elem, node) => {
+export const insertCluster = async (elem, node) => {
log.trace('Inserting cluster');
const shape = node.shape || 'rect';
- clusterElems[node.id] = shapes[shape](elem, node);
+ clusterElems[node.id] = await shapes[shape](elem, node);
};
-export const getClusterTitleWidth = (elem, node) => {
- const label = createLabel(node.labelText, node.labelStyle, undefined, true);
+export const getClusterTitleWidth = async (elem, node) => {
+ const label = await createLabel(node.labelText, node.labelStyle, undefined, true);
elem.node().appendChild(label);
const width = label.getBBox().width;
elem.node().removeChild(label);
diff --git a/packages/mermaid/src/dagre-wrapper/createLabel.js b/packages/mermaid/src/dagre-wrapper/createLabel.js
index d2b59b5a9..467eed260 100644
--- a/packages/mermaid/src/dagre-wrapper/createLabel.js
+++ b/packages/mermaid/src/dagre-wrapper/createLabel.js
@@ -44,7 +44,7 @@ function addHtmlLabel(node) {
* @param isNode
* @deprecated svg-util/createText instead
*/
-const createLabel = (_vertexText, style, isTitle, isNode) => {
+const createLabel = async (_vertexText, style, isTitle, isNode) => {
let vertexText = _vertexText || '';
if (typeof vertexText === 'object') {
vertexText = vertexText[0];
@@ -53,9 +53,10 @@ const createLabel = (_vertexText, style, isTitle, isNode) => {
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
vertexText = vertexText.replace(/\\n|\n/g, '
');
log.debug('vertexText' + vertexText);
+ const label = await replaceIconSubstring(decodeEntities(vertexText));
const node = {
isNode,
- label: replaceIconSubstring(decodeEntities(vertexText)),
+ label,
labelStyle: style.replace('fill:', 'color:'),
};
let vertexNode = addHtmlLabel(node);
diff --git a/packages/mermaid/src/dagre-wrapper/edges.js b/packages/mermaid/src/dagre-wrapper/edges.js
index 1a72328e8..c1e985fdb 100644
--- a/packages/mermaid/src/dagre-wrapper/edges.js
+++ b/packages/mermaid/src/dagre-wrapper/edges.js
@@ -17,7 +17,7 @@ export const clear = () => {
terminalLabels = {};
};
-export const insertEdgeLabel = (elem, edge) => {
+export const insertEdgeLabel = async (elem, edge) => {
const config = getConfig();
const useHtmlLabels = evaluate(config.flowchart.htmlLabels);
// Create the actual text element
@@ -33,7 +33,7 @@ export const insertEdgeLabel = (elem, edge) => {
},
config
)
- : createLabel(edge.label, edge.labelStyle);
+ : await createLabel(edge.label, edge.labelStyle);
// Create outer g, edgeLabel, this will be positioned after graph layout
const edgeLabel = elem.insert('g').attr('class', 'edgeLabel');
@@ -63,7 +63,7 @@ export const insertEdgeLabel = (elem, edge) => {
let fo;
if (edge.startLabelLeft) {
// Create the actual text element
- const startLabelElement = createLabel(edge.startLabelLeft, edge.labelStyle);
+ const startLabelElement = await createLabel(edge.startLabelLeft, edge.labelStyle);
const startEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals');
const inner = startEdgeLabelLeft.insert('g').attr('class', 'inner');
fo = inner.node().appendChild(startLabelElement);
@@ -77,7 +77,7 @@ export const insertEdgeLabel = (elem, edge) => {
}
if (edge.startLabelRight) {
// Create the actual text element
- const startLabelElement = createLabel(edge.startLabelRight, edge.labelStyle);
+ const startLabelElement = await createLabel(edge.startLabelRight, edge.labelStyle);
const startEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
const inner = startEdgeLabelRight.insert('g').attr('class', 'inner');
fo = startEdgeLabelRight.node().appendChild(startLabelElement);
@@ -93,7 +93,7 @@ export const insertEdgeLabel = (elem, edge) => {
}
if (edge.endLabelLeft) {
// Create the actual text element
- const endLabelElement = createLabel(edge.endLabelLeft, edge.labelStyle);
+ const endLabelElement = await createLabel(edge.endLabelLeft, edge.labelStyle);
const endEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals');
const inner = endEdgeLabelLeft.insert('g').attr('class', 'inner');
fo = inner.node().appendChild(endLabelElement);
@@ -110,7 +110,7 @@ export const insertEdgeLabel = (elem, edge) => {
}
if (edge.endLabelRight) {
// Create the actual text element
- const endLabelElement = createLabel(edge.endLabelRight, edge.labelStyle);
+ const endLabelElement = await createLabel(edge.endLabelRight, edge.labelStyle);
const endEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
const inner = endEdgeLabelRight.insert('g').attr('class', 'inner');
diff --git a/packages/mermaid/src/dagre-wrapper/index.js b/packages/mermaid/src/dagre-wrapper/index.js
index 86ae7e284..f000dbe01 100644
--- a/packages/mermaid/src/dagre-wrapper/index.js
+++ b/packages/mermaid/src/dagre-wrapper/index.js
@@ -120,7 +120,7 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
// Move the nodes to the correct place
let diff = 0;
const { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
- sortNodesByHierarchy(graph).forEach(function (v) {
+ for (const v of sortNodesByHierarchy(graph)) {
const node = graph.node(v);
log.info('Position ' + v + ': ' + JSON.stringify(graph.node(v)));
log.info(
@@ -141,14 +141,14 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
// A cluster in the non-recursive way
// positionCluster(node);
node.height += subGraphTitleTotalMargin;
- insertCluster(clusters, node);
+ await insertCluster(clusters, node);
clusterDb[node.id].node = node;
} else {
node.y += subGraphTitleTotalMargin / 2;
positionNode(node);
}
}
- });
+ }
// Move the edge labels to the correct place after layout
graph.edges().forEach(function (e) {
diff --git a/packages/mermaid/src/dagre-wrapper/nodes.js b/packages/mermaid/src/dagre-wrapper/nodes.js
index 2677fd785..24dd5610f 100644
--- a/packages/mermaid/src/dagre-wrapper/nodes.js
+++ b/packages/mermaid/src/dagre-wrapper/nodes.js
@@ -553,7 +553,7 @@ function applyNodePropertyBorders(rect, borders, totalWidth, totalHeight) {
rect.attr('stroke-dasharray', strokeDashArray.join(' '));
}
-const rectWithTitle = (parent, node) => {
+const rectWithTitle = async (parent, node) => {
// const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes);
let classes;
@@ -586,7 +586,7 @@ const rectWithTitle = (parent, node) => {
}
log.info('Label text abc79', title, text2, typeof text2 === 'object');
- const text = label.node().appendChild(createLabel(title, node.labelStyle, true, true));
+ const text = label.node().appendChild(await createLabel(title, node.labelStyle, true, true));
let bbox = { width: 0, height: 0 };
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = text.children[0];
@@ -601,7 +601,12 @@ const rectWithTitle = (parent, node) => {
const descr = label
.node()
.appendChild(
- createLabel(textRows.join ? textRows.join('
') : textRows, node.labelStyle, true, true)
+ await createLabel(
+ textRows.join ? textRows.join('
') : textRows,
+ node.labelStyle,
+ true,
+ true
+ )
);
if (evaluate(getConfig().flowchart.htmlLabels)) {
@@ -876,7 +881,7 @@ const end = (parent, node) => {
return shapeSvg;
};
-const class_box = (parent, node) => {
+const class_box = async (parent, node) => {
const halfPadding = node.padding / 2;
const rowPadding = 4;
const lineHeight = 8;
@@ -910,7 +915,7 @@ const class_box = (parent, node) => {
: '';
const interfaceLabel = labelContainer
.node()
- .appendChild(createLabel(interfaceLabelText, node.labelStyle, true, true));
+ .appendChild(await createLabel(interfaceLabelText, node.labelStyle, true, true));
let interfaceBBox = interfaceLabel.getBBox();
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = interfaceLabel.children[0];
@@ -935,7 +940,7 @@ const class_box = (parent, node) => {
}
const classTitleLabel = labelContainer
.node()
- .appendChild(createLabel(classTitleString, node.labelStyle, true, true));
+ .appendChild(await createLabel(classTitleString, node.labelStyle, true, true));
select(classTitleLabel).attr('class', 'classTitle');
let classTitleBBox = classTitleLabel.getBBox();
if (evaluate(getConfig().flowchart.htmlLabels)) {
@@ -950,7 +955,7 @@ const class_box = (parent, node) => {
maxWidth = classTitleBBox.width;
}
const classAttributes = [];
- node.classData.members.forEach((member) => {
+ node.classData.members.forEach(async (member) => {
const parsedInfo = member.getDisplayDetails();
let parsedText = parsedInfo.displayText;
if (getConfig().flowchart.htmlLabels) {
@@ -959,7 +964,7 @@ const class_box = (parent, node) => {
const lbl = labelContainer
.node()
.appendChild(
- createLabel(
+ await createLabel(
parsedText,
parsedInfo.cssStyle ? parsedInfo.cssStyle : node.labelStyle,
true,
@@ -984,7 +989,7 @@ const class_box = (parent, node) => {
maxHeight += lineHeight;
const classMethods = [];
- node.classData.methods.forEach((member) => {
+ node.classData.methods.forEach(async (member) => {
const parsedInfo = member.getDisplayDetails();
let displayText = parsedInfo.displayText;
if (getConfig().flowchart.htmlLabels) {
@@ -993,7 +998,7 @@ const class_box = (parent, node) => {
const lbl = labelContainer
.node()
.appendChild(
- createLabel(
+ await createLabel(
displayText,
parsedInfo.cssStyle ? parsedInfo.cssStyle : node.labelStyle,
true,
diff --git a/packages/mermaid/src/dagre-wrapper/shapes/util.js b/packages/mermaid/src/dagre-wrapper/shapes/util.js
index 1d0d2d77e..cbe683604 100644
--- a/packages/mermaid/src/dagre-wrapper/shapes/util.js
+++ b/packages/mermaid/src/dagre-wrapper/shapes/util.js
@@ -48,7 +48,12 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
);
} else {
text = textNode.appendChild(
- createLabel(sanitizeText(decodeEntities(labelText), config), node.labelStyle, false, isNode)
+ await createLabel(
+ sanitizeText(decodeEntities(labelText), config),
+ node.labelStyle,
+ false,
+ isNode
+ )
);
}
// Get the size of the label
diff --git a/packages/mermaid/src/diagrams/block/styles.ts b/packages/mermaid/src/diagrams/block/styles.ts
index 38f44ae9d..eac1f2d83 100644
--- a/packages/mermaid/src/diagrams/block/styles.ts
+++ b/packages/mermaid/src/diagrams/block/styles.ts
@@ -142,11 +142,20 @@ const getStyles = (options: BlockChartStyleOptions) =>
font-size: 18px;
fill: ${options.textColor};
}
- .node .svg-inline--fa path {
+ .node label-icon path {
fill: currentColor;
stroke: revert;
stroke-width: revert;
}
+ /**
+ * These are copied from font-awesome.css
+ */
+ .label-icon {
+ display: inline-block;
+ height: 1em;
+ overflow: visible;
+ vertical-align: -0.125em;
+ }
`;
export default getStyles;
diff --git a/packages/mermaid/src/diagrams/class/styles.js b/packages/mermaid/src/diagrams/class/styles.js
index a2ca1f9dd..c88585ad0 100644
--- a/packages/mermaid/src/diagrams/class/styles.js
+++ b/packages/mermaid/src/diagrams/class/styles.js
@@ -157,10 +157,19 @@ g.classGroup line {
font-size: 18px;
fill: ${options.textColor};
}
-.node .svg-inline--fa path {
+.node label-icon path {
fill: currentColor;
stroke: revert;
stroke-width: revert;
+}
+ /**
+ * These are copied from font-awesome.css
+ */
+.label-icon {
+ display: inline-block;
+ height: 1em;
+ overflow: visible;
+ vertical-align: -0.125em;
}
`;
diff --git a/packages/mermaid/src/diagrams/flowchart/styles.ts b/packages/mermaid/src/diagrams/flowchart/styles.ts
index 878b97b18..dc10f7917 100644
--- a/packages/mermaid/src/diagrams/flowchart/styles.ts
+++ b/packages/mermaid/src/diagrams/flowchart/styles.ts
@@ -177,10 +177,19 @@ const getStyles = (options: FlowChartStyleOptions) =>
}
text-align: center;
}
- .node .svg-inline--fa path {
+ .node .label-icon path {
fill: currentColor;
stroke: revert;
stroke-width: revert;
+ }
+ /**
+ * These are copied from font-awesome.css
+ */
+ .label-icon {
+ display: inline-block;
+ height: 1em;
+ overflow: visible;
+ vertical-align: -0.125em;
}
`;
diff --git a/packages/mermaid/src/diagrams/kanban/styles.ts b/packages/mermaid/src/diagrams/kanban/styles.ts
index 7150b3cdc..c71b7f873 100644
--- a/packages/mermaid/src/diagrams/kanban/styles.ts
+++ b/packages/mermaid/src/diagrams/kanban/styles.ts
@@ -105,10 +105,19 @@ const getStyles: DiagramStylesProvider = (options) =>
dominant-baseline: middle;
text-align: center;
}
- .node .svg-inline--fa path {
+ .node label-icon path {
fill: currentColor;
stroke: revert;
stroke-width: revert;
}
+ /**
+ * These are copied from font-awesome.css
+ */
+ .label-icon {
+ display: inline-block;
+ height: 1em;
+ overflow: visible;
+ vertical-align: -0.125em;
+ }
`;
export default getStyles;
diff --git a/packages/mermaid/src/diagrams/user-journey/styles.js b/packages/mermaid/src/diagrams/user-journey/styles.js
index 0ef15c375..fb3d3be0f 100644
--- a/packages/mermaid/src/diagrams/user-journey/styles.js
+++ b/packages/mermaid/src/diagrams/user-journey/styles.js
@@ -131,11 +131,20 @@ const getStyles = (options) =>
.actor-5 {
${options.actor5 ? `fill: ${options.actor5}` : ''};
}
- .node .svg-inline--fa path {
+ .node label-icon path {
fill: currentColor;
stroke: revert;
stroke-width: revert;
}
+ /**
+ * These are copied from font-awesome.css
+ */
+ .label-icon {
+ display: inline-block;
+ height: 1em;
+ overflow: visible;
+ vertical-align: -0.125em;
+ }
`;
export default getStyles;
diff --git a/packages/mermaid/src/rendering-util/createText.spec.ts b/packages/mermaid/src/rendering-util/createText.spec.ts
index 7229072ce..c99ae2b58 100644
--- a/packages/mermaid/src/rendering-util/createText.spec.ts
+++ b/packages/mermaid/src/rendering-util/createText.spec.ts
@@ -1,35 +1,57 @@
-import { describe, it, expect } from 'vitest';
+import { describe, expect, it } from 'vitest';
import { replaceIconSubstring } from './createText.js';
-import { icon } from '@fortawesome/fontawesome-svg-core';
-import { faUser, faArrowRight, faHome } from '@fortawesome/free-solid-svg-icons';
-import { faGithub } from '@fortawesome/free-brands-svg-icons';
+import mermaid from '../mermaid.js';
describe('replaceIconSubstring', () => {
- it('converts FontAwesome icon notations to HTML tags', () => {
+ it('converts FontAwesome icon notations to HTML tags', async () => {
const input = 'This is an icon: fa:fa-user and fab:fa-github';
- const output = replaceIconSubstring(input);
- const expected = `This is an icon: ${icon(faUser).html.join('')} and ${icon(faGithub).html.join('')}`;
+ const output = await replaceIconSubstring(input);
+ const expected = `This is an icon: and `;
expect(output).toEqual(expected);
});
- it('handles strings without FontAwesome icon notations', () => {
+ it('handles strings without FontAwesome icon notations', async () => {
const input = 'This string has no icons';
- const output = replaceIconSubstring(input);
+ const output = await replaceIconSubstring(input);
expect(output).toEqual(input); // No change expected
});
- it('correctly processes multiple FontAwesome icon notations in one string', () => {
+ it('correctly processes multiple FontAwesome icon notations in one string', async () => {
const input = 'Icons galore: fa:fa-arrow-right, fak:fa-truck, fas:fa-home';
- const output = replaceIconSubstring(input);
- const expected = `Icons galore: ${icon(faArrowRight).html.join()}, , ${icon(faHome).html.join()}`;
+ const output = await replaceIconSubstring(input);
+ const expected = `Icons galore: , , `;
expect(output).toEqual(expected);
});
- it('correctly replaces a very long icon name with the fak prefix', () => {
+ it('correctly replaces a very long icon name with the fak prefix', async () => {
const input = 'Here is a long icon: fak:fa-truck-driving-long-winding-road in use';
- const output = replaceIconSubstring(input);
+ const output = await replaceIconSubstring(input);
const expected =
"Here is a long icon: in use";
expect(output).toEqual(expected);
});
+
+ it('correctly process the registered icons', async () => {
+ const staticBellIconPack = {
+ prefix: 'fa6-regular',
+ icons: {
+ bell: {
+ body: '',
+ width: 448,
+ },
+ },
+ width: 512,
+ height: 512,
+ };
+ mermaid.registerIconPacks([
+ {
+ name: 'fa',
+ loader: () => Promise.resolve(staticBellIconPack),
+ },
+ ]);
+ const input = 'Icons galore: fa:fa-bell';
+ const output = await replaceIconSubstring(input);
+ const expected = staticBellIconPack.icons.bell.body;
+ expect(output).toContain(expected);
+ });
});
diff --git a/packages/mermaid/src/rendering-util/createText.ts b/packages/mermaid/src/rendering-util/createText.ts
index 3fa01a777..c45255fe2 100644
--- a/packages/mermaid/src/rendering-util/createText.ts
+++ b/packages/mermaid/src/rendering-util/createText.ts
@@ -1,32 +1,17 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// @ts-nocheck TODO: Fix types
-import { getConfig } from '../diagram-api/diagramAPI.js';
-import common, { hasKatex, renderKatex } from '../diagrams/common/common.js';
import { select } from 'd3';
import type { MermaidConfig } from '../config.type.js';
+import { getConfig } from '../diagram-api/diagramAPI.js';
import type { SVGGroup } from '../diagram-api/types.js';
+import common, { hasKatex, renderKatex } from '../diagrams/common/common.js';
import type { D3TSpanElement, D3TextElement } from '../diagrams/common/commonTypes.js';
import { log } from '../logger.js';
import { markdownToHTML, markdownToLines } from '../rendering-util/handle-markdown-text.js';
import { decodeEntities } from '../utils.js';
+import { getIconSVG, isIconAvailable } from './icons.js';
import { splitLineToFitWidth } from './splitText.js';
import type { MarkdownLine, MarkdownWord } from './types.js';
-import { library, icon } from '@fortawesome/fontawesome-svg-core';
-import * as fab from '@fortawesome/free-brands-svg-icons';
-import * as fas from '@fortawesome/free-solid-svg-icons';
-import * as far from '@fortawesome/free-regular-svg-icons';
-
-const iconListFab = Object.keys(fab)
- .filter((key) => key !== 'fab' && key !== 'prefix')
- .map((icon) => fab[icon]);
-const iconListFas = Object.keys(fas)
- .filter((key) => key !== 'fas' && key !== 'prefix')
- .map((icon) => fas[icon]);
-const iconListFar = Object.keys(far)
- .filter((key) => key !== 'far' && key !== 'prefix')
- .map((icon) => far[icon]);
-
-library.add(...iconListFab, ...iconListFas, ...iconListFar);
function applyStyle(dom, styleFn) {
if (styleFn) {
@@ -198,7 +183,7 @@ function updateTextContentAndStyles(tspan: any, wrappedLine: MarkdownWord[]) {
* @param text - The raw string to convert
* @returns string with fontawesome icons as i tags if they are from pro pack and as svg if they are from free pack
*/
-export function replaceIconSubstring(text) {
+export async function replaceIconSubstring(text) {
const iconRegex = /(fas|fab|far|fa|fal|fak|fad):fa-([a-z-]+)/g;
const classNameMap = {
fas: 'fa-solid',
@@ -209,23 +194,34 @@ export function replaceIconSubstring(text) {
fad: 'fa-duotone',
fak: 'fak',
} as const;
- const freeIconPack = ['fas', 'fab', 'far', 'fa'];
+ const matches = [...text.matchAll(iconRegex)];
+ if (matches.length === 0) {
+ return text;
+ }
- return text.replace(iconRegex, (match, prefix, iconName) => {
- const isFreeIcon = freeIconPack.includes(prefix);
+ let newText = text;
+
+ for (const match of matches) {
+ const [fullMatch, prefix, iconName] = match;
const className = classNameMap[prefix];
- if (!isFreeIcon) {
- log.warn(`Icon ${prefix}:fa-${iconName} is pro icon.`);
- return ``;
- }
- const faIcon = icon({ prefix: prefix, iconName: iconName });
- if (!faIcon) {
- log.warn(`Icon ${prefix}:fa-${iconName} not found.`);
- return match;
- }
+ const registeredIconName = `${prefix}:${iconName}`;
- return faIcon.html.join('');
- });
+ try {
+ const isFreeIcon = await isIconAvailable(registeredIconName);
+ if (!isFreeIcon) {
+ log.warn(`Icon ${registeredIconName} is a pro icon.`);
+ newText = newText.replace(fullMatch, ``);
+ continue;
+ }
+ const faIcon = await getIconSVG(registeredIconName, undefined, { class: 'label-icon' });
+ if (faIcon) {
+ newText = newText.replace(fullMatch, faIcon);
+ }
+ } catch (error) {
+ log.error(`Error processing ${registeredIconName}:`, error);
+ }
+ }
+ return newText;
}
// 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'
@@ -259,7 +255,7 @@ export const createText = async (
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
const htmlText = markdownToHTML(text, config);
- const decodedReplacedText = replaceIconSubstring(decodeEntities(htmlText));
+ const decodedReplacedText = await replaceIconSubstring(decodeEntities(htmlText));
//for Katex the text could contain escaped characters, \\relax that should be transformed to \relax
const inputForKatex = text.replace(/\\\\/g, '\\');
diff --git a/packages/mermaid/src/rendering-util/icons.ts b/packages/mermaid/src/rendering-util/icons.ts
index 5eef3f7eb..50b1bbeb9 100644
--- a/packages/mermaid/src/rendering-util/icons.ts
+++ b/packages/mermaid/src/rendering-util/icons.ts
@@ -85,7 +85,8 @@ export const isIconAvailable = async (iconName: string) => {
export const getIconSVG = async (
iconName: string,
- customisations?: IconifyIconCustomisations & { fallbackPrefix?: string }
+ customisations?: IconifyIconCustomisations & { fallbackPrefix?: string },
+ extraAttributes?: Record
) => {
let iconData: ExtendedIconifyIcon;
try {
@@ -95,6 +96,9 @@ export const getIconSVG = async (
iconData = unknownIcon;
}
const renderData = iconToSVG(iconData, customisations);
- const svg = iconToHTML(replaceIDs(renderData.body), renderData.attributes);
+ const svg = iconToHTML(replaceIDs(renderData.body), {
+ ...renderData.attributes,
+ ...extraAttributes,
+ });
return svg;
};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 178fb27ec..17621c1d9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -30,7 +30,7 @@ importers:
version: 8.14.4(eslint@9.12.0(jiti@1.21.6))
'@cypress/code-coverage':
specifier: ^3.12.30
- version: 3.13.4(@babel/core@7.25.7)(@babel/preset-env@7.26.7(@babel/core@7.25.7))(babel-loader@9.2.1(@babel/core@7.25.7)(webpack@5.95.0(esbuild@0.21.5)))(cypress@13.15.0)(webpack@5.95.0(esbuild@0.21.5))
+ version: 3.13.4(@babel/core@7.25.7)(@babel/preset-env@7.26.8(@babel/core@7.25.7))(babel-loader@9.2.1(@babel/core@7.25.7)(webpack@5.95.0(esbuild@0.21.5)))(cypress@13.15.0)(webpack@5.95.0(esbuild@0.21.5))
'@eslint/js':
specifier: ^9.4.0
version: 9.12.0
@@ -217,18 +217,6 @@ importers:
'@braintree/sanitize-url':
specifier: ^7.0.1
version: 7.1.0
- '@fortawesome/fontawesome-svg-core':
- specifier: ^6.7.2
- version: 6.7.2
- '@fortawesome/free-brands-svg-icons':
- specifier: ^6.7.2
- version: 6.7.2
- '@fortawesome/free-regular-svg-icons':
- specifier: ^6.7.2
- version: 6.7.2
- '@fortawesome/free-solid-svg-icons':
- specifier: ^6.7.2
- version: 6.7.2
'@iconify/utils':
specifier: ^2.1.32
version: 2.1.33
@@ -1478,12 +1466,6 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/preset-env@7.26.7':
- resolution: {integrity: sha512-Ycg2tnXwixaXOVb29rana8HNPgLVBof8qqtNQ9LE22IoyZboQbGSxI6ZySMdW3K5nAe6gu35IaJefUJflhUFTQ==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
'@babel/preset-env@7.26.8':
resolution: {integrity: sha512-um7Sy+2THd697S4zJEfv/U5MHGJzkN2xhtsR3T/SWRbVSic62nbISh51VVfU9JiO/L/Z97QczHTaFVkOU8IzNg==}
engines: {node: '>=6.9.0'}
@@ -2237,26 +2219,6 @@ packages:
'@floating-ui/vue@1.1.5':
resolution: {integrity: sha512-ynL1p5Z+woPVSwgMGqeDrx6HrJfGIDzFyESFkyqJKilGW1+h/8yVY29Khn0LaU6wHBRwZ13ntG6reiHWK6jyzw==}
- '@fortawesome/fontawesome-common-types@6.7.2':
- resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==}
- engines: {node: '>=6'}
-
- '@fortawesome/fontawesome-svg-core@6.7.2':
- resolution: {integrity: sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==}
- engines: {node: '>=6'}
-
- '@fortawesome/free-brands-svg-icons@6.7.2':
- resolution: {integrity: sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==}
- engines: {node: '>=6'}
-
- '@fortawesome/free-regular-svg-icons@6.7.2':
- resolution: {integrity: sha512-7Z/ur0gvCMW8G93dXIQOkQqHo2M5HLhYrRVC0//fakJXxcF1VmMPsxnG6Ee8qEylA8b8Q3peQXWMNZ62lYF28g==}
- engines: {node: '>=6'}
-
- '@fortawesome/free-solid-svg-icons@6.7.2':
- resolution: {integrity: sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==}
- engines: {node: '>=6'}
-
'@hapi/hoek@9.3.0':
resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
@@ -3932,11 +3894,6 @@ packages:
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
- babel-plugin-polyfill-corejs3@0.10.6:
- resolution: {integrity: sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==}
- peerDependencies:
- '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
-
babel-plugin-polyfill-corejs3@0.11.1:
resolution: {integrity: sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==}
peerDependencies:
@@ -11630,7 +11587,7 @@ snapshots:
'@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.8)
'@babel/helper-plugin-utils': 7.26.5
- '@babel/preset-env@7.26.7(@babel/core@7.25.7)':
+ '@babel/preset-env@7.26.8(@babel/core@7.25.7)':
dependencies:
'@babel/compat-data': 7.26.8
'@babel/core': 7.25.7
@@ -11698,7 +11655,7 @@ snapshots:
'@babel/plugin-transform-unicode-sets-regex': 7.25.9(@babel/core@7.25.7)
'@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.25.7)
babel-plugin-polyfill-corejs2: 0.4.12(@babel/core@7.25.7)
- babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.25.7)
+ babel-plugin-polyfill-corejs3: 0.11.1(@babel/core@7.25.7)
babel-plugin-polyfill-regenerator: 0.6.3(@babel/core@7.25.7)
core-js-compat: 3.40.0
semver: 6.3.1
@@ -12246,11 +12203,11 @@ snapshots:
'@cspell/url@8.14.4': {}
- '@cypress/code-coverage@3.13.4(@babel/core@7.25.7)(@babel/preset-env@7.26.7(@babel/core@7.25.7))(babel-loader@9.2.1(@babel/core@7.25.7)(webpack@5.95.0(esbuild@0.21.5)))(cypress@13.15.0)(webpack@5.95.0(esbuild@0.21.5))':
+ '@cypress/code-coverage@3.13.4(@babel/core@7.25.7)(@babel/preset-env@7.26.8(@babel/core@7.25.7))(babel-loader@9.2.1(@babel/core@7.25.7)(webpack@5.95.0(esbuild@0.21.5)))(cypress@13.15.0)(webpack@5.95.0(esbuild@0.21.5))':
dependencies:
'@babel/core': 7.25.7
- '@babel/preset-env': 7.26.7(@babel/core@7.25.7)
- '@cypress/webpack-preprocessor': 6.0.2(@babel/core@7.25.7)(@babel/preset-env@7.26.7(@babel/core@7.25.7))(babel-loader@9.2.1(@babel/core@7.25.7)(webpack@5.95.0(esbuild@0.21.5)))(webpack@5.95.0(esbuild@0.21.5))
+ '@babel/preset-env': 7.26.8(@babel/core@7.25.7)
+ '@cypress/webpack-preprocessor': 6.0.2(@babel/core@7.25.7)(@babel/preset-env@7.26.8(@babel/core@7.25.7))(babel-loader@9.2.1(@babel/core@7.25.7)(webpack@5.95.0(esbuild@0.21.5)))(webpack@5.95.0(esbuild@0.21.5))
babel-loader: 9.2.1(@babel/core@7.25.7)(webpack@5.95.0(esbuild@0.21.5))
chalk: 4.1.2
cypress: 13.15.0
@@ -12286,10 +12243,10 @@ snapshots:
tunnel-agent: 0.6.0
uuid: 8.3.2
- '@cypress/webpack-preprocessor@6.0.2(@babel/core@7.25.7)(@babel/preset-env@7.26.7(@babel/core@7.25.7))(babel-loader@9.2.1(@babel/core@7.25.7)(webpack@5.95.0(esbuild@0.21.5)))(webpack@5.95.0(esbuild@0.21.5))':
+ '@cypress/webpack-preprocessor@6.0.2(@babel/core@7.25.7)(@babel/preset-env@7.26.8(@babel/core@7.25.7))(babel-loader@9.2.1(@babel/core@7.25.7)(webpack@5.95.0(esbuild@0.21.5)))(webpack@5.95.0(esbuild@0.21.5))':
dependencies:
'@babel/core': 7.25.7
- '@babel/preset-env': 7.26.7(@babel/core@7.25.7)
+ '@babel/preset-env': 7.26.8(@babel/core@7.25.7)
babel-loader: 9.2.1(@babel/core@7.25.7)(webpack@5.95.0(esbuild@0.21.5))
bluebird: 3.7.1
debug: 4.3.7(supports-color@8.1.1)
@@ -12565,24 +12522,6 @@ snapshots:
- '@vue/composition-api'
- vue
- '@fortawesome/fontawesome-common-types@6.7.2': {}
-
- '@fortawesome/fontawesome-svg-core@6.7.2':
- dependencies:
- '@fortawesome/fontawesome-common-types': 6.7.2
-
- '@fortawesome/free-brands-svg-icons@6.7.2':
- dependencies:
- '@fortawesome/fontawesome-common-types': 6.7.2
-
- '@fortawesome/free-regular-svg-icons@6.7.2':
- dependencies:
- '@fortawesome/fontawesome-common-types': 6.7.2
-
- '@fortawesome/free-solid-svg-icons@6.7.2':
- dependencies:
- '@fortawesome/fontawesome-common-types': 6.7.2
-
'@hapi/hoek@9.3.0': {}
'@hapi/topo@5.1.0':
@@ -14619,7 +14558,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.25.7):
+ babel-plugin-polyfill-corejs3@0.11.1(@babel/core@7.25.7):
dependencies:
'@babel/core': 7.25.7
'@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.25.7)