@vertigis/react-ui 9.2.2 → 9.3.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.
@@ -0,0 +1,39 @@
1
+ import { FC } from "react";
2
+ import { BoxProps } from "../Box";
3
+ /**
4
+ * Properties for the `Markdown` component.
5
+ */
6
+ export interface MarkdownProps extends BoxProps {
7
+ /**
8
+ * The markdown text to render.
9
+ */
10
+ markdown: string;
11
+ /**
12
+ * A caller-supplied sanitization function to ensure that the resulting HTML
13
+ * is safe to insert into the DOM. Required.
14
+ */
15
+ sanitize: (unsafeHtml: string) => string;
16
+ /**
17
+ * If specified, produces HTML that is valid for contexts where only inline
18
+ * content is allowed (e.g. inside `<h1>`>` or `<span>` tags). HTML tags for
19
+ * block-level elements will be removed, but any text content will be
20
+ * preserved.
21
+ */
22
+ inline?: boolean;
23
+ /**
24
+ * If true, any HTML in the markdown will be escaped rather than passed
25
+ * through directly to the output as normal (since Markdown is a superset of
26
+ * HTML). This is useful in situations where you wish to only support pure
27
+ * Markdown syntax without also supporting HTML syntax. The default is
28
+ * `false`.
29
+ *
30
+ * IMPORTANT: The resulting HTML still needs to be sanitized whether or not
31
+ * this option is set.
32
+ */
33
+ escapeHtml?: boolean;
34
+ }
35
+ /**
36
+ * A component that renders markdown as HTML.
37
+ */
38
+ declare const Markdown: FC<MarkdownProps>;
39
+ export default Markdown;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import clsx from "clsx";
3
+ import Box from "../Box";
4
+ import { markdownToHtml } from "../utils/markdown";
5
+ /**
6
+ * A component that renders markdown as HTML.
7
+ */
8
+ const Markdown = ({ markdown, inline, escapeHtml, sanitize, className, ...otherProps }) => {
9
+ return (_jsx(Box, Object.assign({ component: inline ? "span" : "div", className: clsx("GcxMarkdown", className), dangerouslySetInnerHTML: {
10
+ __html: sanitize(markdownToHtml(markdown, { inline, escapeHtml })),
11
+ } }, otherProps), void 0));
12
+ };
13
+ export default Markdown;
@@ -0,0 +1,2 @@
1
+ export * from "./Markdown";
2
+ export { default } from "./Markdown";
@@ -0,0 +1,2 @@
1
+ export * from "./Markdown";
2
+ export { default } from "./Markdown";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertigis/react-ui",
3
- "version": "9.2.2",
3
+ "version": "9.3.0",
4
4
  "description": "Utilities and React components used in VertiGIS applications.",
5
5
  "keywords": [
6
6
  "vertigis",
@@ -22,6 +22,7 @@
22
22
  "@mui/material": "5.2.8",
23
23
  "clsx": "^1.1.1",
24
24
  "lodash": "^4.17.21",
25
+ "marked": "^4.0.12",
25
26
  "tslib": "^2.1.0"
26
27
  },
27
28
  "devDependencies": {
@@ -29,6 +30,7 @@
29
30
  "@testing-library/react": "^12.1.2",
30
31
  "@testing-library/user-event": "^13.5.0",
31
32
  "@types/lodash": "^4.14.168",
33
+ "@types/marked": "^4.0.2",
32
34
  "@types/react": "^17.0.34",
33
35
  "@types/react-dom": "^17.0.11",
34
36
  "react": "^17.0.2",
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Options for the markdownToHtml() function.
3
+ */
4
+ export interface MarkdownToHtmlOptions {
5
+ /**
6
+ * If specified, produces HTML that is valid to place within an HTML element
7
+ * that only supports inline content (called "phrasing content" in the HTML5
8
+ * spec). Example elements that only support phrasing content are <span> and
9
+ * <h2>. In this mode, any block-level elements resulting from the Markdown
10
+ * conversion will be stripped. The default is `false`.
11
+ */
12
+ inline?: boolean;
13
+ /**
14
+ * If true, any HTML in the markdown will be escaped rather than passed
15
+ * through directly to the output (since Markdown is a superset of HTML).
16
+ * This is useful in situations where you wish to only support pure Markdown
17
+ * syntax without also supporting HTML syntax. The default is `false`.
18
+ *
19
+ * IMPORTANT: The resulting HTML still needs to be sanitized whether or not
20
+ * this option is set.
21
+ */
22
+ escapeHtml?: boolean;
23
+ }
24
+ /**
25
+ * Converts markdown text into HTML.
26
+ *
27
+ * NOTE: The resulting HTML is NOT sanitized by this function. It is the
28
+ * caller's responsibility to sanitize the resulting HTML prior to inserting it
29
+ * into the DOM. You must do this even if `escapeHtml` is set to true.
30
+ *
31
+ * @param markdown The markdown text to convert.
32
+ * @param options Options that affect how the text is converted.
33
+ */
34
+ export declare function markdownToHtml(markdown: string | undefined, options?: MarkdownToHtmlOptions): string;
@@ -0,0 +1,44 @@
1
+ import escapeHtml from "lodash/escape";
2
+ import { marked } from "marked";
3
+ /**
4
+ * A custom marked renderer that escapes HTML in the original markdown.
5
+ */
6
+ class EscapeHtmlRenderer extends marked.Renderer {
7
+ html(html) {
8
+ return escapeHtml(html);
9
+ }
10
+ }
11
+ EscapeHtmlRenderer.instance = new EscapeHtmlRenderer();
12
+ /**
13
+ * Converts markdown text into HTML.
14
+ *
15
+ * NOTE: The resulting HTML is NOT sanitized by this function. It is the
16
+ * caller's responsibility to sanitize the resulting HTML prior to inserting it
17
+ * into the DOM. You must do this even if `escapeHtml` is set to true.
18
+ *
19
+ * @param markdown The markdown text to convert.
20
+ * @param options Options that affect how the text is converted.
21
+ */
22
+ export function markdownToHtml(markdown, options) {
23
+ if (!markdown) {
24
+ return "";
25
+ }
26
+ const { inline, escapeHtml } = { inline: false, escapeHtml: false, ...options };
27
+ const markedOptions = {
28
+ ...(escapeHtml && {
29
+ renderer: EscapeHtmlRenderer.instance,
30
+ }),
31
+ };
32
+ const html = marked(markdown, markedOptions);
33
+ return inline ? stripBlockElements(html) : html;
34
+ }
35
+ /**
36
+ * Strips all HTML elements that are not suitable for placing within an inline
37
+ * HTML element.
38
+ *
39
+ * @param html The HTML to process.
40
+ */
41
+ function stripBlockElements(html) {
42
+ // Derived from here: https://html.spec.whatwg.org/multipage/dom.html#phrasing-content
43
+ return html.replace(/(?:<(\/?))(?!(?:\/|a|abbr|area|audio|b|bdi|bdo|br|button|canvas|cite|code|data|datalist|del|dfn|em|embed|i|iframe|img|input|ins|kbd|label|link|map|mark|math|meta|meter|noscript|object|output|picture|progress|q|ruby|s|samp|script|select|slot|small|span|strong|sub|sup|svg|template|textarea|time|u|var|video|wbr)\b)[^>]*>/gi, (match, s1) => (s1 === "/" ? " " : ""));
44
+ }