From 8abc5e8a1610a8369f10f7c0c29ee888f1721974 Mon Sep 17 00:00:00 2001 From: Ryan Jackson Date: Sun, 29 Dec 2024 13:26:33 -0500 Subject: [PATCH 1/6] Add support for markdown-style links in line messages --- .../mermaid/src/diagrams/common/common.ts | 10 +++ .../mermaid/src/diagrams/sequence/styles.js | 4 + .../mermaid/src/diagrams/sequence/svgDraw.js | 81 +++++++++++++++++-- 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/packages/mermaid/src/diagrams/common/common.ts b/packages/mermaid/src/diagrams/common/common.ts index fd76d0a45d..b7af186e97 100644 --- a/packages/mermaid/src/diagrams/common/common.ts +++ b/packages/mermaid/src/diagrams/common/common.ts @@ -303,6 +303,16 @@ export const katexRegex = /\$\$(.*)\$\$/g; */ export const hasKatex = (text: string): boolean => (text.match(katexRegex)?.length ?? 0) > 0; +export const markdownLinkRegex = /\[([^\]]+)]\(([^)]+)\)/; + +/** + * Detect markdown links + * + * @param text - The text to test + * @returns Whether or not the text has markdown links + */ +export const hasMarkdownLink = (text: string): boolean => markdownLinkRegex.test(text); + /** * Computes the minimum dimensions needed to display a div containing MathML * diff --git a/packages/mermaid/src/diagrams/sequence/styles.js b/packages/mermaid/src/diagrams/sequence/styles.js index 5c36b4ed19..10b01138e1 100644 --- a/packages/mermaid/src/diagrams/sequence/styles.js +++ b/packages/mermaid/src/diagrams/sequence/styles.js @@ -48,6 +48,10 @@ const getStyles = (options) => stroke: none; } + .link { + fill: #0000EE; + } + .labelBox { stroke: ${options.labelBoxBorderColor}; fill: ${options.labelBoxBkgColor}; diff --git a/packages/mermaid/src/diagrams/sequence/svgDraw.js b/packages/mermaid/src/diagrams/sequence/svgDraw.js index c681c94918..6b401891b8 100644 --- a/packages/mermaid/src/diagrams/sequence/svgDraw.js +++ b/packages/mermaid/src/diagrams/sequence/svgDraw.js @@ -1,4 +1,10 @@ -import common, { calculateMathMLDimensions, hasKatex, renderKatex } from '../common/common.js'; +import common, { + calculateMathMLDimensions, + hasKatex, + renderKatex, + hasMarkdownLink, + markdownLinkRegex, +} from '../common/common.js'; import * as svgDrawCommon from '../common/svgDrawCommon.js'; import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js'; import { sanitizeUrl } from '@braintree/sanitize-url'; @@ -127,6 +133,65 @@ export const drawKatex = async function (elem, textData, msgModel = null) { return [textElem]; }; +export const drawLink = function (elem, label, url) { + elem + .append('a') + .attr('xlink:href', sanitizeUrl(url)) + .attr('xlink:show', 'new') + .attr('target', '_blank') + .attr('rel', 'noopener noreferrer') + .append('tspan') + .attr('class', 'link') + .text(label); +}; + +export const drawMarkdownLinkText = function (elem, text) { + // Split text into segments - links and text between links + const segments = []; + let remainingText = text; + let match; + + // Markdown link regex: [text](url) + const linkRegex = markdownLinkRegex; + + while ((match = remainingText.match(linkRegex))) { + // Push text before link if exists + if (match.index > 0) { + segments.push({ + type: 'text', + content: remainingText.substring(0, match.index), + }); + } + + // Push link + segments.push({ + type: 'link', + text: match[1], + url: match[2], + }); + + // Update remaining text + remainingText = remainingText.substring(match.index + match[0].length); + } + + // Push remaining text if any + if (remainingText) { + segments.push({ + type: 'text', + content: remainingText, + }); + } + + // Append all segments + segments.forEach((segment) => { + if (segment.type === 'link') { + drawLink(elem, segment.text, segment.url); + } else { + elem.append('tspan').text(segment.content); + } + }); +}; + export const drawText = function (elem, textData) { let prevTextHeight = 0; let textHeight = 0; @@ -234,13 +299,19 @@ export const drawText = function (elem, textData) { } const text = line || ZERO_WIDTH_SPACE; + let textSpan; if (textData.tspan) { - const span = textElem.append('tspan'); - span.attr('x', textData.x); + textSpan = textElem.append('tspan'); + textSpan.attr('x', textData.x); if (textData.fill !== undefined) { - span.attr('fill', textData.fill); + textSpan.attr('fill', textData.fill); } - span.text(text); + } else { + textSpan = textElem; + } + + if (hasMarkdownLink(text)) { + drawMarkdownLinkText(textSpan, text); } else { textElem.text(text); } From 402cc44f52c36e1457e9ae5a8813e26e0e87bf61 Mon Sep 17 00:00:00 2001 From: Ryan Jackson Date: Sun, 29 Dec 2024 14:20:55 -0500 Subject: [PATCH 2/6] Add new and backup href and target --- packages/mermaid/src/diagrams/sequence/svgDraw.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/diagrams/sequence/svgDraw.js b/packages/mermaid/src/diagrams/sequence/svgDraw.js index 6b401891b8..e1212bf9e7 100644 --- a/packages/mermaid/src/diagrams/sequence/svgDraw.js +++ b/packages/mermaid/src/diagrams/sequence/svgDraw.js @@ -134,11 +134,13 @@ export const drawKatex = async function (elem, textData, msgModel = null) { }; export const drawLink = function (elem, label, url) { + const sanitizedUrl = sanitizeUrl(url); elem .append('a') - .attr('xlink:href', sanitizeUrl(url)) - .attr('xlink:show', 'new') + .attr('href', sanitizedUrl) + .attr('xlink:href', sanitizedUrl) .attr('target', '_blank') + .attr('xlink:show', 'new') .attr('rel', 'noopener noreferrer') .append('tspan') .attr('class', 'link') From 6e159445ccbb8b9d79eaa1aa5252b8100af4bb47 Mon Sep 17 00:00:00 2001 From: Ryan Jackson Date: Sun, 29 Dec 2024 15:16:06 -0500 Subject: [PATCH 3/6] Document markdown links --- docs/syntax/sequenceDiagram.md | 22 +++++++++++++++++++ .../src/docs/syntax/sequenceDiagram.md | 17 ++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/docs/syntax/sequenceDiagram.md b/docs/syntax/sequenceDiagram.md index 84240a0cd3..9f732156e7 100644 --- a/docs/syntax/sequenceDiagram.md +++ b/docs/syntax/sequenceDiagram.md @@ -209,6 +209,8 @@ Messages can be of two displayed either solid or with a dotted line. [Actor][Arrow][Actor]:Message text ``` +### Arrow Types + There are ten types of arrows currently supported: | Type | Description | @@ -224,6 +226,26 @@ There are ten types of arrows currently supported: | `-)` | Solid line with an open arrow at the end (async) | | `--)` | Dotted line with a open arrow at the end (async) | +### Links in Messages (v\+) + +You can add one or more markdown-style links to messages. + +``` +[Actor][Arrow][Actor]:[Label](URL) +``` + +Example: + +```mermaid-example +sequenceDiagram + Alice->>John: Alice shared [MermaidJS](https://mermaid.js.org/) and [the Getting Started guide](https://mermaid.js.org/intro/getting-started.html) with John +``` + +```mermaid +sequenceDiagram + Alice->>John: Alice shared [MermaidJS](https://mermaid.js.org/) and [the Getting Started guide](https://mermaid.js.org/intro/getting-started.html) with John +``` + ## Activations It is possible to activate and deactivate an actor. (de)activation can be dedicated declarations: diff --git a/packages/mermaid/src/docs/syntax/sequenceDiagram.md b/packages/mermaid/src/docs/syntax/sequenceDiagram.md index 2357b9bf43..d15d3397d0 100644 --- a/packages/mermaid/src/docs/syntax/sequenceDiagram.md +++ b/packages/mermaid/src/docs/syntax/sequenceDiagram.md @@ -144,6 +144,8 @@ Messages can be of two displayed either solid or with a dotted line. [Actor][Arrow][Actor]:Message text ``` +### Arrow Types + There are ten types of arrows currently supported: | Type | Description | @@ -159,6 +161,21 @@ There are ten types of arrows currently supported: | `-)` | Solid line with an open arrow at the end (async) | | `--)` | Dotted line with a open arrow at the end (async) | +### Links in Messages (v+) + +You can add one or more markdown-style links to messages. + +``` +[Actor][Arrow][Actor]:[Label](URL) +``` + +Example: + +```mermaid-example +sequenceDiagram + Alice->>John: Alice shared [MermaidJS](https://mermaid.js.org/) and [the Getting Started guide](https://mermaid.js.org/intro/getting-started.html) with John +``` + ## Activations It is possible to activate and deactivate an actor. (de)activation can be dedicated declarations: From 0893a4630409479154b783fd0ffeeef948155ac5 Mon Sep 17 00:00:00 2001 From: Ryan Jackson Date: Mon, 30 Dec 2024 11:20:30 -0500 Subject: [PATCH 4/6] Add changeset --- .changeset/witty-beds-turn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/witty-beds-turn.md diff --git a/.changeset/witty-beds-turn.md b/.changeset/witty-beds-turn.md new file mode 100644 index 0000000000..617a2f6f47 --- /dev/null +++ b/.changeset/witty-beds-turn.md @@ -0,0 +1,5 @@ +--- +'mermaid': minor +--- + +Added support for markdown-style links in line messages and notes From 65bdccd03fe19883b49cc1755894a0f80f3ff41b Mon Sep 17 00:00:00 2001 From: Ryan Jackson Date: Mon, 30 Dec 2024 11:30:25 -0500 Subject: [PATCH 5/6] Add integration test with link --- cypress/integration/rendering/sequencediagram.spec.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cypress/integration/rendering/sequencediagram.spec.js b/cypress/integration/rendering/sequencediagram.spec.js index f18e99abf8..8a9987ab87 100644 --- a/cypress/integration/rendering/sequencediagram.spec.js +++ b/cypress/integration/rendering/sequencediagram.spec.js @@ -79,6 +79,15 @@ describe('Sequence diagram', () => { ` ); }); + it('should render links', () => { + imgSnapshotTest( + ` + sequenceDiagram + Alice->John: Look at [MermaidJS](https://mermaid.js.org/) + John->>Alice: Thanks for the link + ` + ); + }); it('should handle different line breaks', () => { imgSnapshotTest( ` From c69c21d7a035b1ae70f83066e396b4af8350f772 Mon Sep 17 00:00:00 2001 From: Ryan Jackson Date: Mon, 30 Dec 2024 11:33:20 -0500 Subject: [PATCH 6/6] Update changeset message prefix --- .changeset/witty-beds-turn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/witty-beds-turn.md b/.changeset/witty-beds-turn.md index 617a2f6f47..a0a3ee8b10 100644 --- a/.changeset/witty-beds-turn.md +++ b/.changeset/witty-beds-turn.md @@ -2,4 +2,4 @@ 'mermaid': minor --- -Added support for markdown-style links in line messages and notes +feat:Added support for markdown-style links in line messages and notes