@vertigis/react-ui 16.2.0 → 16.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.
@@ -12,13 +12,21 @@ export interface IconMenuClasses {
12
12
  }
13
13
  export type IconMenuClassKey = keyof IconMenuClasses;
14
14
  export interface IconMenuProps extends BoxProps {
15
- /** Additional CSS classes to be applied to the component. */
15
+ /**
16
+ * Additional CSS classes to be applied to the component.
17
+ */
16
18
  classes?: Partial<IconMenuClasses>;
17
- /** Whether the icon button should be disabled. */
19
+ /**
20
+ * Whether the icon button should be disabled.
21
+ */
18
22
  disabled?: boolean;
19
- /** The icon to show. */
23
+ /**
24
+ * The icon to show.
25
+ */
20
26
  icon: ReactNode;
21
- /** A ref for the menu element */
27
+ /**
28
+ * A ref for the menu element
29
+ */
22
30
  menuRef?: React.MutableRefObject<HTMLDivElement>;
23
31
  /**
24
32
  * A 'virtual anchor' that can be provided to override the default behavior.
@@ -26,9 +34,13 @@ export interface IconMenuProps extends BoxProps {
26
34
  * open.
27
35
  */
28
36
  virtualAnchor?: DOMRect;
29
- /** Attributes applied to the `IconButton` component. */
37
+ /**
38
+ * Attributes applied to the `IconButton` component.
39
+ */
30
40
  IconButtonProps?: Partial<IconButtonProps>;
31
- /** Attributes applied to the `Menu` component. */
41
+ /**
42
+ * Attributes applied to the `Menu` component.
43
+ */
32
44
  MenuProps?: Partial<MenuProps>;
33
45
  }
34
46
  declare const IconMenu: import("react").ForwardRefExoticComponent<Omit<IconMenuProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
@@ -30,7 +30,7 @@ const StyledPopover = styled(Popover)(({ theme: { spacing, typography: { pxToRem
30
30
  [`& .${inlineHelpClasses.paper}`]: {
31
31
  maxWidth: pxToRem(350),
32
32
  padding: spacing(2),
33
- wordWrap: "break-word",
33
+ overflowWrap: "anywhere",
34
34
  },
35
35
  }));
36
36
  const InlineHelp = forwardRef(({ children, classes: classesProp, className, icon, onClose, title, url, ...other }, ref) => {
@@ -1,11 +1,17 @@
1
1
  import { type AlertProps } from "@mui/material";
2
2
  import type { FC } from "react";
3
3
  import type { SnackbarProps } from "../Snackbar";
4
- /** Properties for the Notification component. */
4
+ /**
5
+ * Properties for the Notification component.
6
+ */
5
7
  export interface NotificationProperties extends SnackbarProps {
6
- /** The title for the close button. */
8
+ /**
9
+ * The title for the close button.
10
+ */
7
11
  closeButtonTitle: string;
8
- /** Optional alert properties. */
12
+ /**
13
+ * Optional alert properties.
14
+ */
9
15
  alertProps?: AlertProps;
10
16
  }
11
17
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertigis/react-ui",
3
- "version": "16.2.0",
3
+ "version": "16.3.0",
4
4
  "description": "Utilities and React components used in VertiGIS applications.",
5
5
  "keywords": [
6
6
  "vertigis",
@@ -20,4 +20,4 @@ export type { Direction } from "@mui/material/styles";
20
20
  * original theme.
21
21
  * @returns A new theme that is the merger of the original theme plus overrides.
22
22
  */
23
- export declare function overrideTheme(theme: Theme, overrides: Partial<Theme>): Theme;
23
+ export declare function overrideTheme(theme: Theme, overrides: ThemeOptions): Theme;
@@ -1,113 +1,90 @@
1
1
  import { alpha, createTheme as createMuiTheme } from "@mui/material/styles";
2
+ import { defaultPalette, getPaletteOverrides } from "./palette.js";
2
3
  import blue from "../colors/blue.js";
3
- import common from "../colors/common.js";
4
- import green from "../colors/green.js";
5
- import grey from "../colors/grey.js";
6
- import red from "../colors/red.js";
7
- const secondaryTextColor = "#666666";
8
- const primaryTextColor = "#333333";
9
- const primaryErrorColor = "#B22222";
10
- const primaryWarningColor = "#BF5300";
11
- const primarySuccessColor = "#008040";
12
4
  const fontWeightLightest = 200;
13
5
  const fontWeightLight = 300;
14
6
  const fontWeightRegular = 400;
15
7
  const fontWeightMedium = 600;
16
8
  const fontWeightBold = 700;
17
- const lightThemeOverrides = {
18
- palette: {
19
- background: {
20
- default: common.white,
9
+ const getDefaultOptions = (theme) => {
10
+ const { palette, typography: { pxToRem }, } = theme;
11
+ return {
12
+ palette: { ...defaultPalette, ...getPaletteOverrides(palette) },
13
+ // Defaults should match https://meridian.vertigis.com/docs/design-language/#typography
14
+ // Use `pxToRem` so clients with different root font sizes still work properly.
15
+ typography: {
16
+ fontFamily: '"Segoe UI", "Helvetica Neue", "Roboto", Helvetica, Arial, sans-serif',
17
+ fontWeightLight,
18
+ fontWeightRegular,
19
+ fontWeightMedium,
20
+ fontWeightBold,
21
+ h1: {
22
+ fontSize: pxToRem(32),
23
+ fontWeight: fontWeightLight,
24
+ lineHeight: 1.25,
25
+ },
26
+ h2: {
27
+ fontSize: pxToRem(26),
28
+ fontWeight: fontWeightLight,
29
+ lineHeight: 1.25,
30
+ },
31
+ h3: {
32
+ fontSize: pxToRem(22),
33
+ fontWeight: fontWeightLightest,
34
+ lineHeight: 1.25,
35
+ },
36
+ h4: {
37
+ fontSize: pxToRem(20),
38
+ fontWeight: fontWeightRegular,
39
+ lineHeight: 1.25,
40
+ },
41
+ h5: {
42
+ fontSize: pxToRem(18),
43
+ fontWeight: fontWeightMedium,
44
+ lineHeight: 1.25,
45
+ },
46
+ h6: {
47
+ fontSize: pxToRem(16),
48
+ fontWeight: fontWeightMedium,
49
+ lineHeight: 1.125,
50
+ },
51
+ subtitle1: {
52
+ fontSize: pxToRem(16),
53
+ fontWeight: fontWeightRegular,
54
+ lineHeight: 1.125,
55
+ letterSpacing: pxToRem(0.15),
56
+ },
57
+ subtitle2: {
58
+ fontSize: pxToRem(14),
59
+ fontWeight: fontWeightMedium,
60
+ lineHeight: 1.5,
61
+ letterSpacing: pxToRem(0.17),
62
+ },
63
+ body1: {
64
+ fontSize: pxToRem(14),
65
+ fontWeight: fontWeightRegular,
66
+ lineHeight: 1.5,
67
+ },
68
+ body2: {
69
+ fontSize: pxToRem(12),
70
+ fontWeight: fontWeightRegular,
71
+ lineHeight: 1.375,
72
+ },
73
+ caption: {
74
+ fontSize: pxToRem(14),
75
+ fontWeight: fontWeightRegular,
76
+ fontStyle: "italic",
77
+ lineHeight: 1.625,
78
+ },
79
+ button: {
80
+ fontSize: pxToRem(14),
81
+ fontWeight: fontWeightRegular,
82
+ lineHeight: 1.75,
83
+ textTransform: "none",
84
+ },
21
85
  },
22
- },
23
- text: {
24
- primary: primaryTextColor,
25
- secondary: secondaryTextColor,
26
- },
86
+ };
27
87
  };
28
- const getDefaultOptions = (pxToRem) => ({
29
- palette: {
30
- primary: blue,
31
- secondary: green,
32
- grey: { ...grey, main: grey[300], dark: grey[400] },
33
- error: { ...red, main: primaryErrorColor },
34
- warning: { main: primaryWarningColor },
35
- success: { main: primarySuccessColor },
36
- },
37
- // Defaults should match https://meridian.vertigis.com/docs/design-language/#typography
38
- // Use `pxToRem` so clients with different root font sizes still work properly.
39
- typography: {
40
- fontFamily: '"Segoe UI", "Helvetica Neue", "Roboto", Helvetica, Arial, sans-serif',
41
- fontWeightLight,
42
- fontWeightRegular,
43
- fontWeightMedium,
44
- fontWeightBold,
45
- h1: {
46
- fontSize: pxToRem(32),
47
- fontWeight: fontWeightLight,
48
- lineHeight: 1.25,
49
- },
50
- h2: {
51
- fontSize: pxToRem(26),
52
- fontWeight: fontWeightLight,
53
- lineHeight: 1.25,
54
- },
55
- h3: {
56
- fontSize: pxToRem(22),
57
- fontWeight: fontWeightLightest,
58
- lineHeight: 1.25,
59
- },
60
- h4: {
61
- fontSize: pxToRem(20),
62
- fontWeight: fontWeightRegular,
63
- lineHeight: 1.25,
64
- },
65
- h5: {
66
- fontSize: pxToRem(18),
67
- fontWeight: fontWeightMedium,
68
- lineHeight: 1.25,
69
- },
70
- h6: {
71
- fontSize: pxToRem(16),
72
- fontWeight: fontWeightMedium,
73
- lineHeight: 1.125,
74
- },
75
- subtitle1: {
76
- fontSize: pxToRem(16),
77
- fontWeight: fontWeightRegular,
78
- lineHeight: 1.125,
79
- letterSpacing: pxToRem(0.15),
80
- },
81
- subtitle2: {
82
- fontSize: pxToRem(14),
83
- fontWeight: fontWeightMedium,
84
- lineHeight: 1.5,
85
- letterSpacing: pxToRem(0.17),
86
- },
87
- body1: {
88
- fontSize: pxToRem(14),
89
- fontWeight: fontWeightRegular,
90
- lineHeight: 1.5,
91
- },
92
- body2: {
93
- fontSize: pxToRem(12),
94
- fontWeight: fontWeightRegular,
95
- lineHeight: 1.375,
96
- },
97
- caption: {
98
- fontSize: pxToRem(14),
99
- fontWeight: fontWeightRegular,
100
- fontStyle: "italic",
101
- lineHeight: 1.625,
102
- },
103
- button: {
104
- fontSize: pxToRem(14),
105
- fontWeight: fontWeightRegular,
106
- lineHeight: 1.75,
107
- textTransform: "none",
108
- },
109
- },
110
- });
111
88
  const defaultDenseOptions = {
112
89
  spacing: 6,
113
90
  components: {
@@ -158,7 +135,9 @@ const defaultDenseOptions = {
158
135
  },
159
136
  },
160
137
  };
161
- /** Common style overrides for both Select and NativeSelect. */
138
+ /**
139
+ * Common style overrides for both Select and NativeSelect.
140
+ */
162
141
  const getSelectStyles = (theme) => ({
163
142
  borderRadius: theme.shape.borderRadius,
164
143
  "&:focus": {
@@ -172,7 +151,9 @@ const getFocusHighlightStyles = ({ palette }) => ({
172
151
  0 0 0 3px ${palette.common.white} inset,
173
152
  0 0 0 5px ${palette.grey[600]} inset`,
174
153
  });
175
- /** Common style overrides for both MenuItem and ListItemButton. */
154
+ /**
155
+ * Common style overrides for both MenuItem and ListItemButton.
156
+ */
176
157
  const getMenuItemStyles = ({ palette, transitions }) => ({
177
158
  overflow: "hidden",
178
159
  "&:hover": {
@@ -210,9 +191,8 @@ const getMenuItemStyles = ({ palette, transitions }) => ({
210
191
  * The overrides may be based on the theme's palette. We must create these
211
192
  * separately after the fact.
212
193
  */
213
- function getOverrides(theme) {
194
+ function getComponentOverrides(theme) {
214
195
  const { palette, shape, spacing, transitions, typography: { pxToRem, fontWeightMedium, fontWeightBold, body1, subtitle2 }, } = theme;
215
- const isDarkMode = palette.mode === "dark";
216
196
  return {
217
197
  components: {
218
198
  MuiAutocomplete: {
@@ -323,16 +303,12 @@ function getOverrides(theme) {
323
303
  props: { variant: "outlined", color: "grey" },
324
304
  style: {
325
305
  color: palette.text.primary,
326
- borderColor: palette.mode === "light"
327
- ? "rgba(0, 0, 0, 0.23)"
328
- : "rgba(255, 255, 255, 0.23)",
306
+ borderColor: palette.custom.greyOutline,
329
307
  "&.Mui-disabled": {
330
308
  border: `1px solid ${palette.action.disabledBackground}`,
331
309
  },
332
310
  "&:hover": {
333
- borderColor: palette.mode === "light"
334
- ? "rgba(0, 0, 0, 0.23)"
335
- : "rgba(255, 255, 255, 0.23)",
311
+ borderColor: palette.custom.greyOutline,
336
312
  backgroundColor: alpha(palette.text.primary, palette.action.hoverOpacity),
337
313
  },
338
314
  },
@@ -492,7 +468,7 @@ function getOverrides(theme) {
492
468
  marginBottom: spacing(0.5),
493
469
  "&.Mui-error": {
494
470
  borderRadius: shape.borderRadius,
495
- color: isDarkMode ? palette.text.primary : palette.error.main,
471
+ color: palette.custom.errorText,
496
472
  fontStyle: "italic",
497
473
  backgroundColor: palette.background.default,
498
474
  },
@@ -523,14 +499,12 @@ function getOverrides(theme) {
523
499
  marginRight: "4px",
524
500
  alignItems: "center",
525
501
  borderRadius: "50%",
526
- backgroundColor: isDarkMode
527
- ? palette.text.primary
528
- : palette.error.main,
502
+ backgroundColor: palette.custom.errorText,
529
503
  },
530
504
  },
531
505
  "&.Mui-error .GcxFormLabel-errorIcon": {
532
506
  margin: "0px 0px 2px 0px",
533
- color: isDarkMode ? palette.error.main : palette.background.default,
507
+ color: palette.custom.errorBackground,
534
508
  },
535
509
  "&.Mui-focused": {
536
510
  color: "currentColor",
@@ -589,11 +563,11 @@ function getOverrides(theme) {
589
563
  borderWidth: "2px",
590
564
  borderColor: palette.error.main,
591
565
  boxSizing: "border-box",
592
- boxShadow: `0 0 0 1px ${isDarkMode ? palette.common.white : "transparent"} inset, 0 0 0 1px ${isDarkMode ? palette.common.white : "transparent"}`,
566
+ boxShadow: `0 0 0 1px ${palette.custom.darkModeEmphasis} inset, 0 0 0 1px ${palette.custom.darkModeEmphasis}`,
593
567
  },
594
568
  "&.Mui-disabled": {
595
569
  borderColor: palette.grey[300],
596
- backgroundColor: isDarkMode ? palette.grey[900] : palette.grey[100],
570
+ backgroundColor: palette.custom.greyBackground,
597
571
  },
598
572
  },
599
573
  inputMultiline: {
@@ -790,16 +764,12 @@ function getOverrides(theme) {
790
764
  },
791
765
  colorPrimary: {
792
766
  "&.Mui-checked": {
793
- color: palette.mode === "light"
794
- ? palette.common.black
795
- : palette.common.white,
767
+ color: palette.custom.negativeSpace,
796
768
  },
797
769
  },
798
770
  colorSecondary: {
799
771
  "&.Mui-checked": {
800
- color: palette.mode === "light"
801
- ? palette.common.black
802
- : palette.common.white,
772
+ color: palette.custom.negativeSpace,
803
773
  },
804
774
  },
805
775
  sizeSmall: {
@@ -838,7 +808,7 @@ function getOverrides(theme) {
838
808
  width: 16,
839
809
  height: 16,
840
810
  borderRadius: 2,
841
- backgroundColor: palette.mode === "light" ? palette.common.white : palette.common.black,
811
+ backgroundColor: palette.custom.negativeSpace,
842
812
  },
843
813
  track: {
844
814
  borderRadius: shape.borderRadius,
@@ -851,7 +821,7 @@ function getOverrides(theme) {
851
821
  },
852
822
  styleOverrides: {
853
823
  root: {
854
- backgroundColor: isDarkMode ? palette.grey[900] : palette.grey[100],
824
+ backgroundColor: palette.custom.greyBackground,
855
825
  borderStyle: "solid",
856
826
  borderWidth: 1,
857
827
  borderColor: palette.grey[400],
@@ -879,17 +849,14 @@ function getOverrides(theme) {
879
849
  root: {
880
850
  border: `1px solid ${palette.grey[400]}`,
881
851
  padding: 12,
882
- // TODO: Change to overflowWrap: "anywhere" when Safari supports it
883
- // as "break-word" is deprecated
884
- // https://caniuse.com/#feat=mdn-css_properties_overflow-wrap_anywhere
885
- wordWrap: "break-word",
852
+ overflowWrap: "anywhere",
886
853
  "&:last-child": {
887
854
  paddingRight: undefined,
888
855
  },
889
856
  },
890
857
  head: {
891
858
  // Chosen to match PanelGroup in react-ui-internal.
892
- backgroundColor: isDarkMode ? palette.grey[900] : palette.grey[200],
859
+ backgroundColor: palette.custom.greyBackground,
893
860
  fontWeight: "bold",
894
861
  fontSize: pxToRem(14),
895
862
  },
@@ -1063,19 +1030,24 @@ function getOverrides(theme) {
1063
1030
  };
1064
1031
  }
1065
1032
  function createTheme(options = {}) {
1066
- // Merge the VertiGIS Studio theme defaults with any user specified theme options
1067
- const mode = options?.palette && options.palette.mode === "dark" ? "dark" : "light";
1068
- // If we are using light mode, then we want to use our defined light theme palette
1069
- const modeOptions = mode === "light" ? lightThemeOverrides : {};
1070
1033
  const { dense = false, ...overrides } = options;
1071
1034
  // If the incoming options override either the fontSize or htmlFontSize,
1072
1035
  // these need to be specified when creating the theme so that we end up
1073
1036
  // with the correct implementation of pxToRem().
1074
1037
  const { fontSize = 14, htmlFontSize = 16 } = options.typography ?? {};
1075
- const defaultTheme = createMuiTheme({ typography: { fontSize, htmlFontSize } });
1076
- const mergedOptions = deepAssign({}, getDefaultOptions(defaultTheme.typography.pxToRem), modeOptions, dense ? defaultDenseOptions : {}, overrides);
1038
+ // Populate a "default" MUI theme with our base colors and typography settings.
1039
+ // This will be used to create a theme options object that can take into
1040
+ // account the default values MUI creates.
1041
+ const defaultTheme = createMuiTheme({
1042
+ palette: { mode: options?.palette?.mode ?? "light", ...defaultPalette },
1043
+ typography: { fontSize, htmlFontSize },
1044
+ });
1045
+ // Merge the VertiGIS Studio theme defaults with any user specified theme options
1046
+ const mergedOptions = deepAssign({}, getDefaultOptions(defaultTheme), dense ? defaultDenseOptions : {}, overrides);
1077
1047
  const createdTheme = createMuiTheme(mergedOptions);
1078
- return overrideTheme(createdTheme, getOverrides(createdTheme));
1048
+ // The component overrides use the final palette and so must be applied
1049
+ // last.
1050
+ return overrideTheme(createdTheme, getComponentOverrides(createdTheme));
1079
1051
  }
1080
1052
  export default createTheme;
1081
1053
  /**
@@ -1089,7 +1061,9 @@ export default createTheme;
1089
1061
  export function overrideTheme(theme, overrides) {
1090
1062
  return deepAssign({}, theme, overrides);
1091
1063
  }
1092
- /** A recursive version of Object.assign(). */
1064
+ /**
1065
+ * A recursive version of Object.assign().
1066
+ */
1093
1067
  function deepAssign(target, ...sources) {
1094
1068
  if (target === null || target === undefined) {
1095
1069
  throw new TypeError("Cannot convert undefined or null to object.");
@@ -0,0 +1,82 @@
1
+ import type { Theme, ThemeOptions } from "@mui/material/styles";
2
+ declare module "@mui/material/styles" {
3
+ interface Palette {
4
+ custom: {
5
+ /**
6
+ * Emphasis that appears only when the user is in dark mode.
7
+ */
8
+ darkModeEmphasis: string;
9
+ /**
10
+ * A text color for error messages.
11
+ */
12
+ errorText: string;
13
+ /**
14
+ * A background for error messages.
15
+ */
16
+ errorBackground: string;
17
+ /**
18
+ * A light grey background color.
19
+ */
20
+ greyBackground: string;
21
+ /**
22
+ * A subtle grey outline.
23
+ */
24
+ greyOutline: string;
25
+ /**
26
+ * The inverse of either black or white, depending on the selected
27
+ * mode.
28
+ */
29
+ negativeSpace: string;
30
+ };
31
+ }
32
+ interface PaletteOptions {
33
+ custom?: Partial<Palette["custom"]>;
34
+ }
35
+ }
36
+ export declare const getPaletteOverrides: (palette: Theme["palette"]) => ThemeOptions["palette"];
37
+ export declare const defaultPalette: {
38
+ primary: import("@mui/material").Color;
39
+ secondary: import("@mui/material").Color;
40
+ grey: {
41
+ main: string;
42
+ dark: string;
43
+ 50: string;
44
+ 100: string;
45
+ 200: string;
46
+ 300: string;
47
+ 400: string;
48
+ 500: string;
49
+ 600: string;
50
+ 700: string;
51
+ 800: string;
52
+ 900: string;
53
+ A100: string;
54
+ A200: string;
55
+ A400: string;
56
+ A700: string;
57
+ };
58
+ error: {
59
+ main: string;
60
+ 50: string;
61
+ 100: string;
62
+ 200: string;
63
+ 300: string;
64
+ 400: string;
65
+ 500: string;
66
+ 600: string;
67
+ 700: string;
68
+ 800: string;
69
+ 900: string;
70
+ A100: string;
71
+ A200: string;
72
+ A400: string;
73
+ A700: string;
74
+ dark?: string | undefined;
75
+ };
76
+ warning: {
77
+ main: string;
78
+ };
79
+ success: {
80
+ main: string;
81
+ };
82
+ };
@@ -0,0 +1,48 @@
1
+ import blue from "../colors/blue.js";
2
+ import common from "../colors/common.js";
3
+ import green from "../colors/green.js";
4
+ import grey from "../colors/grey.js";
5
+ import red from "../colors/red.js";
6
+ const secondaryTextColor = "#666666";
7
+ const primaryTextColor = "#333333";
8
+ const primaryErrorColor = "#B22222";
9
+ const primaryWarningColor = "#BF5300";
10
+ const primarySuccessColor = "#008040";
11
+ const lightModePaletteOverrides = (palette) => ({
12
+ background: {
13
+ default: common.white,
14
+ },
15
+ text: {
16
+ primary: primaryTextColor,
17
+ secondary: secondaryTextColor,
18
+ },
19
+ custom: {
20
+ errorText: palette.error.main,
21
+ errorBackground: palette.background.default,
22
+ darkModeEmphasis: "transparent",
23
+ greyBackground: grey[100],
24
+ greyOutline: "rgba(0, 0, 0, 0.23)",
25
+ negativeSpace: palette.common.white,
26
+ },
27
+ });
28
+ const darkModePaletteOverrides = (palette) => ({
29
+ custom: {
30
+ errorText: palette.text.primary,
31
+ errorBackground: palette.error.main,
32
+ darkModeEmphasis: common.white,
33
+ greyBackground: grey[900],
34
+ greyOutline: "rgba(255, 255, 255, 0.23)",
35
+ negativeSpace: palette.common.black,
36
+ },
37
+ });
38
+ export const getPaletteOverrides = (palette) => palette.mode === "light"
39
+ ? lightModePaletteOverrides(palette)
40
+ : darkModePaletteOverrides(palette);
41
+ export const defaultPalette = {
42
+ primary: blue,
43
+ secondary: green,
44
+ grey: { ...grey, main: grey[300], dark: grey[400] },
45
+ error: { ...red, main: primaryErrorColor },
46
+ warning: { main: primaryWarningColor },
47
+ success: { main: primarySuccessColor },
48
+ };