@vertigis/react-ui 11.19.0 → 11.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,6 +32,14 @@ export interface MarkdownProps extends BoxProps {
32
32
  * this option is set.
33
33
  */
34
34
  escapeHtml?: boolean;
35
+ /**
36
+ * An optional value to apply to external hyperlinks via the `target`
37
+ * attribute.
38
+ *
39
+ * If this is omitted, links may still open in a separate target if the host
40
+ * page specifies a `target` via the `<base>` element in its `<head>`.
41
+ */
42
+ linkTarget?: string;
35
43
  }
36
44
  /**
37
45
  * A component that renders markdown as HTML.
@@ -6,9 +6,9 @@ import { markdownToHtml } from "../utils/markdown.js";
6
6
  /**
7
7
  * A component that renders markdown as HTML.
8
8
  */
9
- const Markdown = ({ markdown, inline, escapeHtml, sanitize = sanitizeHtml, className, ...otherProps }) => {
9
+ const Markdown = ({ markdown, inline, escapeHtml, sanitize = sanitizeHtml, linkTarget, className, ...otherProps }) => {
10
10
  return (_jsx(Box, { component: inline ? "span" : "div", className: clsx("GcxMarkdown", className), dangerouslySetInnerHTML: {
11
- __html: sanitize(markdownToHtml(markdown, { inline, escapeHtml })),
11
+ __html: sanitize(markdownToHtml(markdown, { inline, escapeHtml, linkTarget })),
12
12
  }, ...otherProps }));
13
13
  };
14
14
  export default Markdown;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertigis/react-ui",
3
- "version": "11.19.0",
3
+ "version": "11.20.0",
4
4
  "description": "Utilities and React components used in VertiGIS applications.",
5
5
  "keywords": [
6
6
  "vertigis",
@@ -20,6 +20,14 @@ export interface MarkdownToHtmlOptions {
20
20
  * this option is set.
21
21
  */
22
22
  escapeHtml?: boolean;
23
+ /**
24
+ * An optional value to apply to external hyperlinks via the `target`
25
+ * attribute.
26
+ *
27
+ * If this is omitted, links may still open in a separate target if the host
28
+ * page specifies a `target` via the `<base>` element in its `<head>`.
29
+ */
30
+ linkTarget?: string;
23
31
  }
24
32
  /**
25
33
  * Converts markdown text into HTML. The resulting HTML is sanitized and safe to
package/utils/markdown.js CHANGED
@@ -2,14 +2,33 @@ import escapeHtml from "lodash.escape";
2
2
  import { marked } from "marked";
3
3
  import { sanitizeHtml } from "./html.js";
4
4
  /**
5
- * A custom marked renderer that escapes HTML in the original markdown.
5
+ * A custom marked renderer that supports a few additional features of our own:
6
+ *
7
+ * - If `escapeHtml` is true, it escapes HTML in the original markdown.
8
+ * - If `linkTarget` is set, it adds a `target` attribute to all external links.
6
9
  */
7
- class EscapeHtmlRenderer extends marked.Renderer {
10
+ class CustomRenderer extends marked.Renderer {
11
+ constructor(escapeHtml, linkTarget) {
12
+ super();
13
+ this.escapeHtml = false;
14
+ this.linkTarget = undefined;
15
+ this.escapeHtml = escapeHtml;
16
+ this.linkTarget = linkTarget;
17
+ }
8
18
  html(html) {
9
- return escapeHtml(html);
19
+ return this.escapeHtml ? escapeHtml(html) : html;
20
+ }
21
+ link(href, title, text) {
22
+ if (this.linkTarget) {
23
+ const localLink = href?.startsWith(`${location.protocol}//${location.hostname}`);
24
+ const html = super.link(href, title, text);
25
+ return localLink ? html : html.replace(/^<a /, `<a target="${this.linkTarget}" `);
26
+ }
27
+ else {
28
+ return super.link(href, title, text);
29
+ }
10
30
  }
11
31
  }
12
- EscapeHtmlRenderer.instance = new EscapeHtmlRenderer();
13
32
  /**
14
33
  * Converts markdown text into HTML. The resulting HTML is sanitized and safe to
15
34
  * insert into the DOM.
@@ -34,13 +53,14 @@ export function markdownToHtml(markdown, options) {
34
53
  if (!markdown) {
35
54
  return "";
36
55
  }
37
- const { inline, escapeHtml } = { inline: false, escapeHtml: false, ...options };
38
- const markedOptions = {
39
- ...(escapeHtml && {
40
- renderer: EscapeHtmlRenderer.instance,
41
- }),
56
+ const { inline, escapeHtml, linkTarget } = {
57
+ inline: false,
58
+ escapeHtml: false,
59
+ linkTarget: undefined,
60
+ ...options,
42
61
  };
43
- const html = marked(markdown, markedOptions);
62
+ const renderer = new CustomRenderer(escapeHtml, linkTarget);
63
+ const html = marked(markdown, { renderer });
44
64
  return inline ? stripBlockElements(html) : html;
45
65
  }
46
66
  /**