diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.ts b/packages/mermaid/src/diagrams/flowchart/flowDb.ts index 3f44fb9fe..7fe2e3a73 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDb.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDb.ts @@ -813,6 +813,9 @@ const addNodeFromVertex = ( domId: vertex.domId, isGroup, look, + link: vertex.link, + linkTarget: vertex.linkTarget, + tooltip: getTooltip(vertex.id), }); } }; diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts index bf273f0e8..692c387e7 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts @@ -8,6 +8,7 @@ import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js import { getDirection } from './flowDb.js'; import utils from '../../utils.js'; +import { select } from 'd3'; // Configuration const conf: Record = {}; @@ -32,6 +33,15 @@ export const draw = async function (text: string, id: string, _version: string, log.info('Drawing state diagram (v2)', id); const { securityLevel, state: conf, layout } = getConfig(); + // Handle root and document for when rendering in sandbox mode + let sandboxElement; + if (securityLevel === 'sandbox') { + sandboxElement = select('#i' + id); + } + + // @ts-ignore - document is always available + const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document; + const DIR = getDirection(); // The getData method provided in all supported diagrams is used to extract the data from the parsed structure @@ -60,6 +70,41 @@ export const draw = async function (text: string, id: string, _version: string, diag.db.getDiagramTitle() ); setupViewPortForSVG(svg, padding, 'flowchart', conf?.useMaxWidth || false); + + // If node has a link, wrap it in an anchor SVG object. + data4Layout.nodes.forEach((vertex) => { + if (vertex.link) { + const node = select('#' + id + ' [id="' + vertex.id + '"]'); + if (node) { + const link = doc.createElementNS('http://www.w3.org/2000/svg', 'a'); + link.setAttributeNS('http://www.w3.org/2000/svg', 'class', vertex.cssClasses); + link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener'); + if (securityLevel === 'sandbox') { + link.setAttributeNS('http://www.w3.org/2000/svg', 'target', '_top'); + } else if (vertex.linkTarget) { + link.setAttributeNS('http://www.w3.org/2000/svg', 'target', vertex.linkTarget); + } + + const linkNode = node.insert(function () { + return link; + }, ':first-child'); + + const shape = node.select('.label-container'); + if (shape) { + linkNode.append(function () { + return shape.node(); + }); + } + + const label = node.select('.label'); + if (label) { + linkNode.append(function () { + return label.node(); + }); + } + } + } + }); }; export default { diff --git a/packages/mermaid/src/rendering-util/types.d.ts b/packages/mermaid/src/rendering-util/types.d.ts index 7addc5848..bece69659 100644 --- a/packages/mermaid/src/rendering-util/types.d.ts +++ b/packages/mermaid/src/rendering-util/types.d.ts @@ -15,7 +15,8 @@ interface Node { description?: string[]; parentId?: string; position?: string; // Keep, this is for notes 'left of', 'right of', etc. Move into nodeNode - cssStyles?: string; // Renamed from `styles` to `cssStyles` + cssStyles?: string[]; // Renamed from `styles` to `cssStyles` + cssCompiledStyles?: string[]; cssClasses?: string; // Renamed from `classes` to `cssClasses` // style?: string; //REMOVE ✅ // class?: string; //REMOVE ✅ @@ -23,7 +24,7 @@ interface Node { // props?: Record; //REMOVE ✅ // type: string; // REMOVE, replace with isGroup: boolean, default false ✅ // borders?: string; //REMOVE ✅ - labelStyle?: string; + labelStyle?: string; // REMOVE - use cssStyles instead ✅ // Flowchart specific properties labelType?: string; // REMOVE? Always use markdown string, need to check for KaTeX - ⏳ wait with this one @@ -34,6 +35,7 @@ interface Node { haveCallback?: boolean; link?: string; linkTarget?: string; + tooltip?: string; padding?: number; //REMOVE?, use from LayoutData.config - Keep, this could be shape specific shape?: string; tooltip?: string;