1 | import { l as log, H as decodeEntities } from "./mermaid-a953d906.js";
|
2 | import { fromMarkdown } from "mdast-util-from-markdown";
|
3 | import { dedent } from "ts-dedent";
|
4 | function preprocessMarkdown(markdown) {
|
5 | const withoutMultipleNewlines = markdown.replace(/\n{2,}/g, "\n");
|
6 | const withoutExtraSpaces = dedent(withoutMultipleNewlines);
|
7 | return withoutExtraSpaces;
|
8 | }
|
9 | function markdownToLines(markdown) {
|
10 | const preprocessedMarkdown = preprocessMarkdown(markdown);
|
11 | const { children } = fromMarkdown(preprocessedMarkdown);
|
12 | const lines = [[]];
|
13 | let currentLine = 0;
|
14 | function processNode(node, parentType = "normal") {
|
15 | if (node.type === "text") {
|
16 | const textLines = node.value.split("\n");
|
17 | textLines.forEach((textLine, index) => {
|
18 | if (index !== 0) {
|
19 | currentLine++;
|
20 | lines.push([]);
|
21 | }
|
22 | textLine.split(" ").forEach((word) => {
|
23 | if (word) {
|
24 | lines[currentLine].push({ content: word, type: parentType });
|
25 | }
|
26 | });
|
27 | });
|
28 | } else if (node.type === "strong" || node.type === "emphasis") {
|
29 | node.children.forEach((contentNode) => {
|
30 | processNode(contentNode, node.type);
|
31 | });
|
32 | }
|
33 | }
|
34 | children.forEach((treeNode) => {
|
35 | if (treeNode.type === "paragraph") {
|
36 | treeNode.children.forEach((contentNode) => {
|
37 | processNode(contentNode);
|
38 | });
|
39 | }
|
40 | });
|
41 | return lines;
|
42 | }
|
43 | function markdownToHTML(markdown) {
|
44 | const { children } = fromMarkdown(markdown);
|
45 | function output(node) {
|
46 | if (node.type === "text") {
|
47 | return node.value.replace(/\n/g, "<br/>");
|
48 | } else if (node.type === "strong") {
|
49 | return `<strong>${node.children.map(output).join("")}</strong>`;
|
50 | } else if (node.type === "emphasis") {
|
51 | return `<em>${node.children.map(output).join("")}</em>`;
|
52 | } else if (node.type === "paragraph") {
|
53 | return `<p>${node.children.map(output).join("")}</p>`;
|
54 | }
|
55 | return `Unsupported markdown: ${node.type}`;
|
56 | }
|
57 | return children.map(output).join("");
|
58 | }
|
59 | function applyStyle(dom, styleFn) {
|
60 | if (styleFn) {
|
61 | dom.attr("style", styleFn);
|
62 | }
|
63 | }
|
64 | function addHtmlSpan(element, node, width, classes, addBackground = false) {
|
65 | const fo = element.append("foreignObject");
|
66 | const div = fo.append("xhtml:div");
|
67 | const label = node.label;
|
68 | const labelClass = node.isNode ? "nodeLabel" : "edgeLabel";
|
69 | div.html(
|
70 | `
|
71 | <span class="${labelClass} ${classes}" ` + (node.labelStyle ? 'style="' + node.labelStyle + '"' : "") + ">" + label + "</span>"
|
72 | );
|
73 | applyStyle(div, node.labelStyle);
|
74 | div.style("display", "table-cell");
|
75 | div.style("white-space", "nowrap");
|
76 | div.style("max-width", width + "px");
|
77 | div.attr("xmlns", "http://www.w3.org/1999/xhtml");
|
78 | if (addBackground) {
|
79 | div.attr("class", "labelBkg");
|
80 | }
|
81 | let bbox = div.node().getBoundingClientRect();
|
82 | if (bbox.width === width) {
|
83 | div.style("display", "table");
|
84 | div.style("white-space", "break-spaces");
|
85 | div.style("width", width + "px");
|
86 | bbox = div.node().getBoundingClientRect();
|
87 | }
|
88 | fo.style("width", bbox.width);
|
89 | fo.style("height", bbox.height);
|
90 | return fo.node();
|
91 | }
|
92 | function createTspan(textElement, lineIndex, lineHeight) {
|
93 | return textElement.append("tspan").attr("class", "text-outer-tspan").attr("x", 0).attr("y", lineIndex * lineHeight - 0.1 + "em").attr("dy", lineHeight + "em");
|
94 | }
|
95 | function createFormattedText(width, g, structuredText, addBackground = false) {
|
96 | const lineHeight = 1.1;
|
97 | const labelGroup = g.append("g");
|
98 | let bkg = labelGroup.insert("rect").attr("class", "background");
|
99 | const textElement = labelGroup.append("text").attr("y", "-10.1");
|
100 | let lineIndex = -1;
|
101 | structuredText.forEach((line) => {
|
102 | lineIndex++;
|
103 | let tspan = createTspan(textElement, lineIndex, lineHeight);
|
104 | let words = [...line].reverse();
|
105 | let currentWord;
|
106 | let wrappedLine = [];
|
107 | while (words.length) {
|
108 | currentWord = words.pop();
|
109 | wrappedLine.push(currentWord);
|
110 | updateTextContentAndStyles(tspan, wrappedLine);
|
111 | if (tspan.node().getComputedTextLength() > width) {
|
112 | wrappedLine.pop();
|
113 | words.push(currentWord);
|
114 | updateTextContentAndStyles(tspan, wrappedLine);
|
115 | wrappedLine = [];
|
116 | lineIndex++;
|
117 | tspan = createTspan(textElement, lineIndex, lineHeight);
|
118 | }
|
119 | }
|
120 | });
|
121 | if (addBackground) {
|
122 | const bbox = textElement.node().getBBox();
|
123 | const padding = 2;
|
124 | bkg.attr("x", -padding).attr("y", -padding).attr("width", bbox.width + 2 * padding).attr("height", bbox.height + 2 * padding);
|
125 | return labelGroup.node();
|
126 | } else {
|
127 | return textElement.node();
|
128 | }
|
129 | }
|
130 | function updateTextContentAndStyles(tspan, wrappedLine) {
|
131 | tspan.text("");
|
132 | wrappedLine.forEach((word, index) => {
|
133 | const innerTspan = tspan.append("tspan").attr("font-style", word.type === "em" ? "italic" : "normal").attr("class", "text-inner-tspan").attr("font-weight", word.type === "strong" ? "bold" : "normal");
|
134 | if (index === 0) {
|
135 | innerTspan.text(word.content);
|
136 | } else {
|
137 | innerTspan.text(" " + word.content);
|
138 | }
|
139 | });
|
140 | }
|
141 | const createText = (el, text = "", {
|
142 | style = "",
|
143 | isTitle = false,
|
144 | classes = "",
|
145 | useHtmlLabels = true,
|
146 | isNode = true,
|
147 | width,
|
148 | addSvgBackground = false
|
149 | } = {}) => {
|
150 | log.info("createText", text, style, isTitle, classes, useHtmlLabels, isNode, addSvgBackground);
|
151 | if (useHtmlLabels) {
|
152 | const htmlText = markdownToHTML(text);
|
153 | const node = {
|
154 | isNode,
|
155 | label: decodeEntities(htmlText).replace(
|
156 | /fa[blrs]?:fa-[\w-]+/g,
|
157 | (s) => `<i class='${s.replace(":", " ")}'></i>`
|
158 | ),
|
159 | labelStyle: style.replace("fill:", "color:")
|
160 | };
|
161 | let vertexNode = addHtmlSpan(el, node, width, classes, addSvgBackground);
|
162 | return vertexNode;
|
163 | } else {
|
164 | const structuredText = markdownToLines(text);
|
165 | const svgLabel = createFormattedText(width, el, structuredText, addSvgBackground);
|
166 | return svgLabel;
|
167 | }
|
168 | };
|
169 | export {
|
170 | createText as c
|
171 | };
|