@vertigis/react-ui 21.6.0 → 21.7.1

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.
@@ -1,17 +1,21 @@
1
- import type { FC } from "react";
1
+ import { type FC } from "react";
2
2
  import type { BoxProps } from "../Box/index.js";
3
3
  /**
4
4
  * Properties for the `Markdown` component.
5
5
  */
6
6
  export interface MarkdownProps extends BoxProps {
7
7
  /**
8
- * The markdown text to render.
8
+ * The markdown text to render. Optional, you can also supply the text as a
9
+ * child of this component.
9
10
  */
10
- markdown: string;
11
+ markdown?: string;
11
12
  /**
12
13
  * Override the default sanitization behaviour with a caller-supplied
13
14
  * sanitization function that ensures that the resulting HTML is safe to
14
15
  * insert into the DOM.
16
+ *
17
+ * @deprecated The Markdown component no longer operates by attaching raw
18
+ * HTML strings to the DOM, so this property is ignored.
15
19
  */
16
20
  sanitize?: (unsafeHtml: string) => string;
17
21
  /**
@@ -28,21 +32,30 @@ export interface MarkdownProps extends BoxProps {
28
32
  * Markdown syntax without also supporting HTML syntax. The default is
29
33
  * `false`.
30
34
  *
31
- * IMPORTANT: The resulting HTML still needs to be sanitized whether or not
32
- * this option is set.
35
+ * IMPORTANT: A sanitizer is run on any inline HTML before it is passed to
36
+ * React, but you should still probably set this to `true` when dealing with
37
+ * untrusted sources.
33
38
  */
34
39
  escapeHtml?: boolean;
35
40
  /**
36
41
  * 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>`.
42
+ * attribute. Defaults to "_blank".
41
43
  */
42
44
  linkTarget?: string;
45
+ /**
46
+ * Whether to use standard HTML elements instead of their `react-ui`
47
+ * equivalents. If this is `true` the VertiGIS 'Meridian' style will not be
48
+ * applied to the output. Defaults to `false`.
49
+ */
50
+ useBasicHtml?: boolean;
43
51
  }
44
52
  /**
45
- * A component that renders markdown as HTML.
53
+ * A component that renders markdown as React nodes.
54
+ *
55
+ * GitHub style sanitation is applied to any inline HTML encountered, see:
56
+ * https://github.com/gjtorikian/html-pipeline/blob/a2e02ac/lib/html_pipeline/sanitization_filter.rb
57
+ * However, it is still recommended to set `escapeHtml` to true with untrusted
58
+ * content.
46
59
  */
47
60
  declare const Markdown: FC<MarkdownProps>;
48
61
  export default Markdown;
@@ -1,12 +1,137 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
2
3
  import clsx from "clsx";
4
+ import { useMemo } from "react";
5
+ import ReactMarkdown, {} from "react-markdown";
6
+ import rehypeRaw from "rehype-raw";
7
+ import rehypeSanitize from "rehype-sanitize";
3
8
  import Box from "../Box/index.js";
4
- import { sanitizeHtml } from "../utils/html.js";
5
- import { markdownToHtml } from "../utils/markdown.js";
9
+ import Link, {} from "../Link/index.js";
10
+ import Typography, {} from "../Typography/index.js";
11
+ import { useTheme } from "../styles/index.js";
12
+ const disallowedInlineElements = [
13
+ "a",
14
+ "abbr",
15
+ "area",
16
+ "audio",
17
+ "b",
18
+ "bdi",
19
+ "bdo",
20
+ "br",
21
+ "button",
22
+ "canvas",
23
+ "cite",
24
+ "code",
25
+ "data",
26
+ "datalist",
27
+ "del",
28
+ "dfn",
29
+ "em",
30
+ "embed",
31
+ "i",
32
+ "iframe",
33
+ "img",
34
+ "input",
35
+ "ins",
36
+ "kbd",
37
+ "label",
38
+ "link",
39
+ "map",
40
+ "mark",
41
+ "math",
42
+ "meta",
43
+ "meter",
44
+ "noscript",
45
+ "object",
46
+ "output",
47
+ "picture",
48
+ "progress",
49
+ "q",
50
+ "ruby",
51
+ "s",
52
+ "samp",
53
+ "script",
54
+ "select",
55
+ "slot",
56
+ "small",
57
+ "span",
58
+ "strong",
59
+ "sub",
60
+ "sup",
61
+ "svg",
62
+ "template",
63
+ "textarea",
64
+ "time",
65
+ "u",
66
+ "var",
67
+ "video",
68
+ "wbr",
69
+ ];
6
70
  /**
7
- * A component that renders markdown as HTML.
71
+ * A component that renders markdown as React nodes.
72
+ *
73
+ * GitHub style sanitation is applied to any inline HTML encountered, see:
74
+ * https://github.com/gjtorikian/html-pipeline/blob/a2e02ac/lib/html_pipeline/sanitization_filter.rb
75
+ * However, it is still recommended to set `escapeHtml` to true with untrusted
76
+ * content.
8
77
  */
9
- const Markdown = ({ markdown, inline, escapeHtml, sanitize = sanitizeHtml, linkTarget, className, ...otherProps }) => (_jsx(Box, { component: inline ? "span" : "div", className: clsx("GcxMarkdown", className), dangerouslySetInnerHTML: {
10
- __html: sanitize(markdownToHtml(markdown, { inline, escapeHtml, linkTarget })),
11
- }, ...otherProps }));
78
+ const Markdown = ({ markdown, inline, escapeHtml, sanitize, linkTarget = "_blank", children, className, useBasicHtml, ...otherProps }) => {
79
+ const theme = useTheme();
80
+ const disallowedElements = useMemo(() => (inline ? disallowedInlineElements : []), [inline]);
81
+ const components = useMemo(() => useBasicHtml
82
+ ? {}
83
+ : {
84
+ a({ node, href, ...props }) {
85
+ const localLink = href?.startsWith(`${location.protocol}//${location.hostname}`) ||
86
+ href?.startsWith(location.hostname) ||
87
+ href?.startsWith("#") ||
88
+ href?.startsWith("/");
89
+ return (_jsx(Link, { target: href?.startsWith("#") ? undefined : linkTarget, showExternalLinkIcon: !localLink, href: href, ...props }));
90
+ },
91
+ // Default margin values based on https://www.w3.org/TR/CSS2/sample.html
92
+ h1({ node, ...props }) {
93
+ return (_jsx(Typography, { ...props, sx: {
94
+ marginBlockStart: theme.spacing(0.67),
95
+ marginBlockEnd: theme.spacing(0.67),
96
+ }, variant: "h1" }));
97
+ },
98
+ h2({ node, ...props }) {
99
+ return (_jsx(Typography, { ...props, sx: {
100
+ marginBlockStart: theme.spacing(0.75),
101
+ marginBlockEnd: theme.spacing(0.75),
102
+ }, variant: "h2" }));
103
+ },
104
+ h3({ node, ...props }) {
105
+ return (_jsx(Typography, { ...props, sx: {
106
+ marginBlockStart: theme.spacing(0.83),
107
+ marginBlockEnd: theme.spacing(0.83),
108
+ }, variant: "h3" }));
109
+ },
110
+ h4({ node, ...props }) {
111
+ return (_jsx(Typography, { ...props, sx: {
112
+ marginBlockStart: theme.spacing(1),
113
+ marginBlockEnd: theme.spacing(1),
114
+ }, variant: "h4" }));
115
+ },
116
+ h5({ node, ...props }) {
117
+ return (_jsx(Typography, { ...props, sx: {
118
+ marginBlockStart: theme.spacing(1.5),
119
+ marginBlockEnd: theme.spacing(1.5),
120
+ }, variant: "h5" }));
121
+ },
122
+ h6({ node, ...props }) {
123
+ return (_jsx(Typography, { ...props, sx: {
124
+ marginBlockStart: theme.spacing(1.67),
125
+ marginBlockEnd: theme.spacing(1.67),
126
+ }, variant: "h6" }));
127
+ },
128
+ p({ node, ...props }) {
129
+ return (_jsx(Typography, { component: "p", ...props, sx: {
130
+ marginBlockStart: theme.spacing(1),
131
+ marginBlockEnd: theme.spacing(1),
132
+ }, variant: "body1" }));
133
+ },
134
+ }, [linkTarget, theme, useBasicHtml]);
135
+ return (_jsx(Box, { component: inline ? "span" : "div", className: clsx("GcxMarkdown", className), ...otherProps, children: _jsx(ReactMarkdown, { components: components, disallowedElements: disallowedElements, rehypePlugins: escapeHtml ? [] : [rehypeRaw, rehypeSanitize], children: children && typeof children === "string" ? children : markdown }) }));
136
+ };
12
137
  export default Markdown;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertigis/react-ui",
3
- "version": "21.6.0",
3
+ "version": "21.7.1",
4
4
  "description": "Utilities and React components used in VertiGIS applications.",
5
5
  "keywords": [
6
6
  "vertigis",
@@ -25,8 +25,11 @@
25
25
  "clsx": "^2.1.0",
26
26
  "color": "^4.2.3",
27
27
  "lodash.escape": "^4.0.1",
28
- "marked": "^12.0.1",
28
+ "marked": "~15.0.12",
29
29
  "react-color": "^2.19.3",
30
+ "react-markdown": "^10.1.0",
31
+ "rehype-raw": "^7.0.0",
32
+ "rehype-sanitize": "^6.0.0",
30
33
  "tslib": "^2.6.2",
31
34
  "xss": "^1.0.15"
32
35
  },
@@ -33,6 +33,8 @@ export interface MarkdownToHtmlOptions {
33
33
  * Converts markdown text into HTML. The resulting HTML is sanitized and safe to
34
34
  * insert into the DOM.
35
35
  *
36
+ * @deprecated Use the `Markdown` component to add markdown safely without
37
+ * parsing raw HTML strings.
36
38
  * @param markdown The markdown text to convert.
37
39
  * @param options Options that affect how the text is converted.
38
40
  */
@@ -44,6 +46,8 @@ export declare function markdownToSafeHtml(markdown: string, options?: MarkdownT
44
46
  * caller's responsibility to sanitize the resulting HTML prior to inserting it
45
47
  * into the DOM. You must do this even if `escapeHtml` is set to true.
46
48
  *
49
+ * @deprecated Use the `Markdown` component to add markdown safely without
50
+ * parsing raw HTML strings.
47
51
  * @param markdown The markdown text to convert.
48
52
  * @param options Options that affect how the text is converted.
49
53
  */
package/utils/markdown.js CHANGED
@@ -15,17 +15,17 @@ class CustomRenderer extends marked.Renderer {
15
15
  this.escapeHtml = escapeHtml;
16
16
  this.linkTarget = linkTarget;
17
17
  }
18
- html(html) {
19
- return this.escapeHtml ? escapeHtml(html) : html;
18
+ html({ text }) {
19
+ return this.escapeHtml ? escapeHtml(text) : text;
20
20
  }
21
- link(href, title, text) {
21
+ link({ href, title, tokens }) {
22
22
  if (this.linkTarget) {
23
23
  const localLink = href?.startsWith(`${location.protocol}//${location.hostname}`);
24
- const html = super.link(href, title, text);
24
+ const html = super.link({ href, title, tokens });
25
25
  return localLink ? html : html.replace(/^<a /, `<a target="${this.linkTarget}" `);
26
26
  }
27
27
  else {
28
- return super.link(href, title, text);
28
+ return super.link({ href, title, tokens });
29
29
  }
30
30
  }
31
31
  }
@@ -33,6 +33,8 @@ class CustomRenderer extends marked.Renderer {
33
33
  * Converts markdown text into HTML. The resulting HTML is sanitized and safe to
34
34
  * insert into the DOM.
35
35
  *
36
+ * @deprecated Use the `Markdown` component to add markdown safely without
37
+ * parsing raw HTML strings.
36
38
  * @param markdown The markdown text to convert.
37
39
  * @param options Options that affect how the text is converted.
38
40
  */
@@ -46,6 +48,8 @@ export function markdownToSafeHtml(markdown, options) {
46
48
  * caller's responsibility to sanitize the resulting HTML prior to inserting it
47
49
  * into the DOM. You must do this even if `escapeHtml` is set to true.
48
50
  *
51
+ * @deprecated Use the `Markdown` component to add markdown safely without
52
+ * parsing raw HTML strings.
49
53
  * @param markdown The markdown text to convert.
50
54
  * @param options Options that affect how the text is converted.
51
55
  */