@vertigis/react-ui 9.2.0 → 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";
@@ -1,6 +1,6 @@
1
1
  import type { ButtonBaseClasses } from "@mui/material/ButtonBase";
2
2
  import type { IconButtonClasses } from "@mui/material/IconButton";
3
- import Switch, { SwitchProps as MUISwitchProps, SwitchClasses as MUISwitchClasses } from "@mui/material/Switch";
3
+ import { SwitchProps as MUISwitchProps, SwitchClasses as MUISwitchClasses } from "@mui/material/Switch";
4
4
  export * from "@mui/material/Switch";
5
5
  export interface SwitchClasses extends MUISwitchClasses, IconButtonClasses, ButtonBaseClasses {
6
6
  }
@@ -8,4 +8,5 @@ export declare type SwitchClassKey = keyof SwitchClasses;
8
8
  export declare type SwitchProps = Omit<MUISwitchProps, "classes"> & {
9
9
  classes?: Partial<SwitchClasses>;
10
10
  };
11
+ declare const Switch: import("@emotion/styled").StyledComponent<MUISwitchProps & import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles/createTheme").Theme>, {}, {}>;
11
12
  export default Switch;
package/Switch/Switch.js CHANGED
@@ -1,4 +1,11 @@
1
- import Switch from "@mui/material/Switch";
1
+ import SwitchBase from "@mui/material/Switch";
2
+ import { styled } from "../styles";
2
3
  // MUST be the first export, since some of the exports are overridden below.
3
4
  export * from "@mui/material/Switch";
5
+ const Switch = styled(SwitchBase)(({ color = "secondary", theme: { palette } }) => ({
6
+ "&::before": {
7
+ // Calculate dot color based on track color.
8
+ color: palette.getContrastText(palette[color].main),
9
+ }
10
+ }));
4
11
  export default Switch;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertigis/react-ui",
3
- "version": "9.2.0",
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",
@@ -465,6 +465,31 @@ function getOverrides(theme) {
465
465
  },
466
466
  },
467
467
  MuiListItem: {
468
+ styleOverrides: {
469
+ root: {
470
+ "&.MuiListItem-secondaryAction, &>.MuiListItemButton-root": {
471
+ // Disable the right padding of 48px that MUI uses
472
+ // to make room for secondary actions, since we use
473
+ // flex for those rather than absolute positioning
474
+ // (see MuiListItemSecondaryAction overrides). Note
475
+ // that there are two distinct cases we need to
476
+ // handle, depending on whether a
477
+ // <ListItemSecondaryAction> element is used
478
+ // explicitly, or whether the ListItem's
479
+ // `secondaryAction` prop is used.
480
+ paddingRight: spacing(1),
481
+ },
482
+ },
483
+ container: {
484
+ // A wrapper element with this class is added around a
485
+ // list item when a <ListItemSecondaryAction> child is
486
+ // present. Use flex to position the secondary actions
487
+ // next to the list item content rather than absolute
488
+ // positioning so that nothing overlaps.
489
+ display: "flex",
490
+ alignItems: "center",
491
+ },
492
+ },
468
493
  variants: [
469
494
  {
470
495
  // HACK: The button prop is deprecated in MUI 5 in favor
@@ -478,6 +503,18 @@ function getOverrides(theme) {
478
503
  },
479
504
  ],
480
505
  },
506
+ MuiListItemSecondaryAction: {
507
+ styleOverrides: {
508
+ root: {
509
+ // We use flex instead of absolute positioning so that
510
+ // secondary buttons don't overlap the item text.
511
+ position: "static",
512
+ transform: "unset",
513
+ flex: "0 0 auto",
514
+ paddingRight: spacing(1),
515
+ },
516
+ },
517
+ },
481
518
  MuiListItemText: {
482
519
  styleOverrides: {
483
520
  primary: {
@@ -557,6 +594,7 @@ function getOverrides(theme) {
557
594
  },
558
595
  MuiSwitch: {
559
596
  defaultProps: {
597
+ color: "secondary",
560
598
  focusRipple: false,
561
599
  },
562
600
  styleOverrides: {
@@ -568,8 +606,6 @@ function getOverrides(theme) {
568
606
  "&::before": {
569
607
  content: "'•'",
570
608
  position: "absolute",
571
- // Get contrast text color based on track color
572
- color: palette.getContrastText(palette.secondary.main),
573
609
  left: 14,
574
610
  top: 7,
575
611
  fontSize: 18,
@@ -618,7 +654,6 @@ function getOverrides(theme) {
618
654
  transform: "translateX(33%)",
619
655
  },
620
656
  "&.Mui-checked + .MuiSwitch-track": {
621
- backgroundColor: palette.secondary.main,
622
657
  opacity: 1,
623
658
  },
624
659
  },
@@ -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
+ }