@etsoo/materialui 1.6.88 → 1.6.89

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,13 @@
1
+ import { SVGUtils } from "../src";
2
+
3
+ it("SVGUtils hexToCssFilter for black", () => {
4
+ const hex = "#fff";
5
+ const filter = SVGUtils.hexToCssFilter(hex);
6
+ expect(filter).toBeDefined();
7
+ });
8
+
9
+ it("SVGUtils hexToCssFilter", () => {
10
+ const hex = "#ff3922";
11
+ const filter = SVGUtils.hexToCssFilter(hex);
12
+ expect(filter).toBeDefined();
13
+ });
@@ -39,7 +39,7 @@ function ButtonPopover(props) {
39
39
  };
40
40
  const styles = position === "left" ? { left: 14 } : { right: 14 };
41
41
  // Layout
42
- return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [button((handler) => setAnchorEl(handler)), (0, jsx_runtime_1.jsx)(Popover_1.default, { anchorEl: anchorEl, open: open, onClose: handleClose, onClick: handleClose, transformOrigin: { horizontal: position, vertical: "top" }, anchorOrigin: { horizontal: position, vertical: "bottom" }, slotProps: {
42
+ return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [button((handler) => setAnchorEl(handler)), (0, jsx_runtime_1.jsx)(Popover_1.default, { anchorEl: anchorEl, open: open, onClose: handleClose, onClick: handleClose, transformOrigin: { horizontal: position, vertical: "top" }, anchorOrigin: { horizontal: position, vertical: "bottom" }, disableRestoreFocus: true, slotProps: {
43
43
  paper: {
44
44
  elevation: 0,
45
45
  sx: {
@@ -52,7 +52,7 @@ function InputTipField(props) {
52
52
  setTitle(title);
53
53
  });
54
54
  };
55
- return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [(0, jsx_runtime_1.jsx)(Popover_1.default, { open: anchorEl != null, anchorEl: anchorEl, onClose: () => setAnchorEl(undefined), anchorOrigin: {
55
+ return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [(0, jsx_runtime_1.jsx)(Popover_1.default, { disableRestoreFocus: true, open: anchorEl != null, anchorEl: anchorEl, onClose: () => setAnchorEl(undefined), anchorOrigin: {
56
56
  vertical: "bottom",
57
57
  horizontal: "left"
58
58
  }, children: data && (0, jsx_runtime_1.jsx)(List_1.default, { children: data.map((item) => renderItem(item)) }) }), (0, jsx_runtime_1.jsx)(Component, { changeDelay: changeDelay, fullWidth: fullWidth, onChangeDelay: (event) => {
@@ -63,7 +63,7 @@ function MenuButton(props) {
63
63
  ...{ sx }
64
64
  }
65
65
  }
66
- }, disableScrollLock: true, anchorEl: anchorEl, anchorOrigin: anchorOrigin, keepMounted: true, transformOrigin: transformOrigin, open: isMenuOpen, transitionDuration: 0, onClose: handleMenuClose, ...rest, children: items.map((item) => {
66
+ }, disableScrollLock: true, disableRestoreFocus: true, anchorEl: anchorEl, anchorOrigin: anchorOrigin, keepMounted: true, transformOrigin: transformOrigin, open: isMenuOpen, transitionDuration: 0, onClose: handleMenuClose, ...rest, children: items.map((item) => {
67
67
  const label = labelFormatter(item);
68
68
  return ((0, jsx_runtime_1.jsx)(MenuItem_1.default, { disabled: true, children: label }, item.id));
69
69
  }) })] }));
@@ -86,7 +86,7 @@ function MoreFab(props) {
86
86
  const hasIcon = actionsLocal.some((action) => action.icon != null);
87
87
  // Main
88
88
  const main = iconButton ? ((0, jsx_runtime_1.jsx)(IconButton_1.default, { color: color, size: size, title: title, onClick: handleClick, children: icon })) : ((0, jsx_runtime_1.jsx)(Fab_1.default, { color: color, size: size, title: title, onClick: handleClick, children: icon }));
89
- return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [main, (0, jsx_runtime_1.jsx)(Menu_1.default, { disableScrollLock: true, anchorEl: anchorEl, anchorOrigin: anchorOrigin, keepMounted: true, transformOrigin: transformOrigin, open: open, onClose: handleClose, slotProps: { paper: PaperProps }, children: actionsLocal.map(({ label, icon, action }, index) => label === "-" ? ((0, jsx_runtime_1.jsx)(Divider_1.default, {}, index)) : ((0, jsx_runtime_1.jsxs)(MenuItem_1.default, { ...(typeof action === "string"
89
+ return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [main, (0, jsx_runtime_1.jsx)(Menu_1.default, { disableScrollLock: true, disableRestoreFocus: true, anchorEl: anchorEl, anchorOrigin: anchorOrigin, keepMounted: true, transformOrigin: transformOrigin, open: open, onClose: handleClose, slotProps: { paper: PaperProps }, children: actionsLocal.map(({ label, icon, action }, index) => label === "-" ? ((0, jsx_runtime_1.jsx)(Divider_1.default, {}, index)) : ((0, jsx_runtime_1.jsxs)(MenuItem_1.default, { ...(typeof action === "string"
90
90
  ? action.includes("://")
91
91
  ? {
92
92
  component: "a",
@@ -285,7 +285,7 @@ class NotificationMU extends react_2.NotificationReact {
285
285
  const { content, id, open } = this;
286
286
  // Setup callback
287
287
  const options = this.renderSetup ? this.renderSetup({}) : undefined;
288
- return ((0, jsx_runtime_1.jsx)(Popover_1.default, { open: open, className: className, onClose: () => this.dismiss(), ...options, children: content }, id));
288
+ return ((0, jsx_runtime_1.jsx)(Popover_1.default, { open: open, className: className, onClose: () => this.dismiss(), disableRestoreFocus: true, ...options, children: content }, id));
289
289
  }
290
290
  // Create loading
291
291
  createLoading(_props, className) {
@@ -14,6 +14,10 @@ export interface IServiceApp extends ReactAppType {
14
14
  * Core system origin
15
15
  */
16
16
  readonly coreOrigin: string;
17
+ /**
18
+ * Core system web URL
19
+ */
20
+ readonly coreWebUrl: string;
17
21
  /**
18
22
  * Get token authorization request data
19
23
  * @param api API, if not provided, use the core API
@@ -23,6 +23,10 @@ export declare class ServiceApp<U extends IServiceUser = IServiceUser, S extends
23
23
  * Core system origin
24
24
  */
25
25
  readonly coreOrigin: string;
26
+ /**
27
+ * Core system web URL
28
+ */
29
+ readonly coreWebUrl: string;
26
30
  private coreAccessToken;
27
31
  /**
28
32
  * Constructor
@@ -24,6 +24,10 @@ class ServiceApp extends ReactApp_1.ReactApp {
24
24
  * Core system origin
25
25
  */
26
26
  coreOrigin;
27
+ /**
28
+ * Core system web URL
29
+ */
30
+ coreWebUrl;
27
31
  coreAccessToken;
28
32
  /**
29
33
  * Constructor
@@ -40,6 +44,7 @@ class ServiceApp extends ReactApp_1.ReactApp {
40
44
  }
41
45
  this.coreEndpoint = coreEndpoint;
42
46
  this.coreOrigin = new URL(coreEndpoint.webUrl).origin;
47
+ this.coreWebUrl = coreEndpoint.webUrl;
43
48
  this.coreApi = this.createApi(this.coreName, coreEndpoint);
44
49
  this.keepLogin = true;
45
50
  }
@@ -36,6 +36,7 @@ export * from "./texts/DateText";
36
36
  export * from "./texts/MoneyText";
37
37
  export * from "./texts/NumberText";
38
38
  export * from "./utils/CanvasUtils";
39
+ export * from "./utils/SVGUtils";
39
40
  export * from "./AddresSelector";
40
41
  export * from "./AuditDisplay";
41
42
  export * from "./AutocompleteExtendedProps";
package/lib/cjs/index.js CHANGED
@@ -56,6 +56,7 @@ __exportStar(require("./texts/DateText"), exports);
56
56
  __exportStar(require("./texts/MoneyText"), exports);
57
57
  __exportStar(require("./texts/NumberText"), exports);
58
58
  __exportStar(require("./utils/CanvasUtils"), exports);
59
+ __exportStar(require("./utils/SVGUtils"), exports);
59
60
  __exportStar(require("./AddresSelector"), exports);
60
61
  __exportStar(require("./AuditDisplay"), exports);
61
62
  __exportStar(require("./AutocompleteExtendedProps"), exports);
@@ -82,7 +82,7 @@ function UserMenu(props) {
82
82
  }
83
83
  }
84
84
  }
85
- }, disableScrollLock: true, anchorEl: anchorEl, anchorOrigin: {
85
+ }, disableScrollLock: true, disableRestoreFocus: true, anchorEl: anchorEl, anchorOrigin: {
86
86
  vertical: "bottom",
87
87
  horizontal: "right"
88
88
  }, keepMounted: true, transformOrigin: {
@@ -0,0 +1,24 @@
1
+ /**
2
+ * SVG utility functions
3
+ */
4
+ export declare namespace SVGUtils {
5
+ /**
6
+ * Create an SVG icon component
7
+ * @param icon Icon
8
+ * @param filterColor Filter color for the icon
9
+ * @returns Component
10
+ */
11
+ function createIcon(icon?: string | null, filterColor?: string | null): import("react").JSX.Element | undefined;
12
+ /**
13
+ * Hex color to CSS filter
14
+ * @param hex Hex color
15
+ * @returns Result
16
+ */
17
+ function hexToCssFilter(hex: string): string;
18
+ /**
19
+ * CSS filter to hex color
20
+ * @param filter CSS filter
21
+ * @returns Result
22
+ */
23
+ function cssFilterToHex(filter: string): Promise<string>;
24
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SVGUtils = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const Icon_1 = __importDefault(require("@mui/material/Icon"));
9
+ const css_filter_converter_1 = __importDefault(require("css-filter-converter"));
10
+ /**
11
+ * SVG utility functions
12
+ */
13
+ var SVGUtils;
14
+ (function (SVGUtils) {
15
+ /**
16
+ * Create an SVG icon component
17
+ * @param icon Icon
18
+ * @param filterColor Filter color for the icon
19
+ * @returns Component
20
+ */
21
+ // https://cdn.jsdelivr.net/npm/@material-design-icons/svg@latest/filled/local_mall.svg
22
+ function createIcon(icon, filterColor) {
23
+ if (!icon)
24
+ return undefined;
25
+ if (icon.startsWith("/"))
26
+ icon = "https://localhost:9002/" + icon;
27
+ else if (icon.startsWith("<path "))
28
+ icon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">${icon}</svg>`;
29
+ if (icon.startsWith("<svg "))
30
+ icon = `data:image/svg+xml;utf8,${encodeURIComponent(icon)}`;
31
+ const filter = !filterColor ? undefined : hexToCssFilter(filterColor);
32
+ return ((0, jsx_runtime_1.jsx)(Icon_1.default, { sx: { display: "flex", height: "inherit", width: "inherit" }, children: (0, jsx_runtime_1.jsx)("img", { src: icon, style: { filter } }) }));
33
+ }
34
+ SVGUtils.createIcon = createIcon;
35
+ /**
36
+ * Hex color to CSS filter
37
+ * @param hex Hex color
38
+ * @returns Result
39
+ */
40
+ function hexToCssFilter(hex) {
41
+ const result = css_filter_converter_1.default.hexToFilter(hex);
42
+ if (result == null || result.color == null)
43
+ throw result.error ?? new Error(`Invalid hex color: ${hex}`);
44
+ return result.color;
45
+ }
46
+ SVGUtils.hexToCssFilter = hexToCssFilter;
47
+ /**
48
+ * CSS filter to hex color
49
+ * @param filter CSS filter
50
+ * @returns Result
51
+ */
52
+ async function cssFilterToHex(filter) {
53
+ const result = await css_filter_converter_1.default.filterToHex(filter);
54
+ if (result == null || result.color == null)
55
+ throw result.error ?? new Error(`Invalid CSS filter: ${filter}`);
56
+ return result.color;
57
+ }
58
+ SVGUtils.cssFilterToHex = cssFilterToHex;
59
+ })(SVGUtils || (exports.SVGUtils = SVGUtils = {}));
@@ -33,7 +33,7 @@ export function ButtonPopover(props) {
33
33
  };
34
34
  const styles = position === "left" ? { left: 14 } : { right: 14 };
35
35
  // Layout
36
- return (_jsxs(React.Fragment, { children: [button((handler) => setAnchorEl(handler)), _jsx(Popover, { anchorEl: anchorEl, open: open, onClose: handleClose, onClick: handleClose, transformOrigin: { horizontal: position, vertical: "top" }, anchorOrigin: { horizontal: position, vertical: "bottom" }, slotProps: {
36
+ return (_jsxs(React.Fragment, { children: [button((handler) => setAnchorEl(handler)), _jsx(Popover, { anchorEl: anchorEl, open: open, onClose: handleClose, onClick: handleClose, transformOrigin: { horizontal: position, vertical: "top" }, anchorOrigin: { horizontal: position, vertical: "bottom" }, disableRestoreFocus: true, slotProps: {
37
37
  paper: {
38
38
  elevation: 0,
39
39
  sx: {
@@ -46,7 +46,7 @@ export function InputTipField(props) {
46
46
  setTitle(title);
47
47
  });
48
48
  };
49
- return (_jsxs(React.Fragment, { children: [_jsx(Popover, { open: anchorEl != null, anchorEl: anchorEl, onClose: () => setAnchorEl(undefined), anchorOrigin: {
49
+ return (_jsxs(React.Fragment, { children: [_jsx(Popover, { disableRestoreFocus: true, open: anchorEl != null, anchorEl: anchorEl, onClose: () => setAnchorEl(undefined), anchorOrigin: {
50
50
  vertical: "bottom",
51
51
  horizontal: "left"
52
52
  }, children: data && _jsx(List, { children: data.map((item) => renderItem(item)) }) }), _jsx(Component, { changeDelay: changeDelay, fullWidth: fullWidth, onChangeDelay: (event) => {
@@ -57,7 +57,7 @@ export function MenuButton(props) {
57
57
  ...{ sx }
58
58
  }
59
59
  }
60
- }, disableScrollLock: true, anchorEl: anchorEl, anchorOrigin: anchorOrigin, keepMounted: true, transformOrigin: transformOrigin, open: isMenuOpen, transitionDuration: 0, onClose: handleMenuClose, ...rest, children: items.map((item) => {
60
+ }, disableScrollLock: true, disableRestoreFocus: true, anchorEl: anchorEl, anchorOrigin: anchorOrigin, keepMounted: true, transformOrigin: transformOrigin, open: isMenuOpen, transitionDuration: 0, onClose: handleMenuClose, ...rest, children: items.map((item) => {
61
61
  const label = labelFormatter(item);
62
62
  return (_jsx(MenuItem, { disabled: true, children: label }, item.id));
63
63
  }) })] }));
@@ -80,7 +80,7 @@ export function MoreFab(props) {
80
80
  const hasIcon = actionsLocal.some((action) => action.icon != null);
81
81
  // Main
82
82
  const main = iconButton ? (_jsx(IconButton, { color: color, size: size, title: title, onClick: handleClick, children: icon })) : (_jsx(Fab, { color: color, size: size, title: title, onClick: handleClick, children: icon }));
83
- return (_jsxs(React.Fragment, { children: [main, _jsx(Menu, { disableScrollLock: true, anchorEl: anchorEl, anchorOrigin: anchorOrigin, keepMounted: true, transformOrigin: transformOrigin, open: open, onClose: handleClose, slotProps: { paper: PaperProps }, children: actionsLocal.map(({ label, icon, action }, index) => label === "-" ? (_jsx(Divider, {}, index)) : (_jsxs(MenuItem, { ...(typeof action === "string"
83
+ return (_jsxs(React.Fragment, { children: [main, _jsx(Menu, { disableScrollLock: true, disableRestoreFocus: true, anchorEl: anchorEl, anchorOrigin: anchorOrigin, keepMounted: true, transformOrigin: transformOrigin, open: open, onClose: handleClose, slotProps: { paper: PaperProps }, children: actionsLocal.map(({ label, icon, action }, index) => label === "-" ? (_jsx(Divider, {}, index)) : (_jsxs(MenuItem, { ...(typeof action === "string"
84
84
  ? action.includes("://")
85
85
  ? {
86
86
  component: "a",
@@ -279,7 +279,7 @@ export class NotificationMU extends NotificationReact {
279
279
  const { content, id, open } = this;
280
280
  // Setup callback
281
281
  const options = this.renderSetup ? this.renderSetup({}) : undefined;
282
- return (_jsx(Popover, { open: open, className: className, onClose: () => this.dismiss(), ...options, children: content }, id));
282
+ return (_jsx(Popover, { open: open, className: className, onClose: () => this.dismiss(), disableRestoreFocus: true, ...options, children: content }, id));
283
283
  }
284
284
  // Create loading
285
285
  createLoading(_props, className) {
@@ -14,6 +14,10 @@ export interface IServiceApp extends ReactAppType {
14
14
  * Core system origin
15
15
  */
16
16
  readonly coreOrigin: string;
17
+ /**
18
+ * Core system web URL
19
+ */
20
+ readonly coreWebUrl: string;
17
21
  /**
18
22
  * Get token authorization request data
19
23
  * @param api API, if not provided, use the core API
@@ -23,6 +23,10 @@ export declare class ServiceApp<U extends IServiceUser = IServiceUser, S extends
23
23
  * Core system origin
24
24
  */
25
25
  readonly coreOrigin: string;
26
+ /**
27
+ * Core system web URL
28
+ */
29
+ readonly coreWebUrl: string;
26
30
  private coreAccessToken;
27
31
  /**
28
32
  * Constructor
@@ -21,6 +21,10 @@ export class ServiceApp extends ReactApp {
21
21
  * Core system origin
22
22
  */
23
23
  coreOrigin;
24
+ /**
25
+ * Core system web URL
26
+ */
27
+ coreWebUrl;
24
28
  coreAccessToken;
25
29
  /**
26
30
  * Constructor
@@ -37,6 +41,7 @@ export class ServiceApp extends ReactApp {
37
41
  }
38
42
  this.coreEndpoint = coreEndpoint;
39
43
  this.coreOrigin = new URL(coreEndpoint.webUrl).origin;
44
+ this.coreWebUrl = coreEndpoint.webUrl;
40
45
  this.coreApi = this.createApi(this.coreName, coreEndpoint);
41
46
  this.keepLogin = true;
42
47
  }
@@ -36,6 +36,7 @@ export * from "./texts/DateText";
36
36
  export * from "./texts/MoneyText";
37
37
  export * from "./texts/NumberText";
38
38
  export * from "./utils/CanvasUtils";
39
+ export * from "./utils/SVGUtils";
39
40
  export * from "./AddresSelector";
40
41
  export * from "./AuditDisplay";
41
42
  export * from "./AutocompleteExtendedProps";
package/lib/mjs/index.js CHANGED
@@ -36,6 +36,7 @@ export * from "./texts/DateText";
36
36
  export * from "./texts/MoneyText";
37
37
  export * from "./texts/NumberText";
38
38
  export * from "./utils/CanvasUtils";
39
+ export * from "./utils/SVGUtils";
39
40
  export * from "./AddresSelector";
40
41
  export * from "./AuditDisplay";
41
42
  export * from "./AutocompleteExtendedProps";
@@ -75,7 +75,7 @@ export function UserMenu(props) {
75
75
  }
76
76
  }
77
77
  }
78
- }, disableScrollLock: true, anchorEl: anchorEl, anchorOrigin: {
78
+ }, disableScrollLock: true, disableRestoreFocus: true, anchorEl: anchorEl, anchorOrigin: {
79
79
  vertical: "bottom",
80
80
  horizontal: "right"
81
81
  }, keepMounted: true, transformOrigin: {
@@ -0,0 +1,24 @@
1
+ /**
2
+ * SVG utility functions
3
+ */
4
+ export declare namespace SVGUtils {
5
+ /**
6
+ * Create an SVG icon component
7
+ * @param icon Icon
8
+ * @param filterColor Filter color for the icon
9
+ * @returns Component
10
+ */
11
+ function createIcon(icon?: string | null, filterColor?: string | null): import("react").JSX.Element | undefined;
12
+ /**
13
+ * Hex color to CSS filter
14
+ * @param hex Hex color
15
+ * @returns Result
16
+ */
17
+ function hexToCssFilter(hex: string): string;
18
+ /**
19
+ * CSS filter to hex color
20
+ * @param filter CSS filter
21
+ * @returns Result
22
+ */
23
+ function cssFilterToHex(filter: string): Promise<string>;
24
+ }
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import Icon from "@mui/material/Icon";
3
+ import CssFilterConverter from "css-filter-converter";
4
+ /**
5
+ * SVG utility functions
6
+ */
7
+ export var SVGUtils;
8
+ (function (SVGUtils) {
9
+ /**
10
+ * Create an SVG icon component
11
+ * @param icon Icon
12
+ * @param filterColor Filter color for the icon
13
+ * @returns Component
14
+ */
15
+ // https://cdn.jsdelivr.net/npm/@material-design-icons/svg@latest/filled/local_mall.svg
16
+ function createIcon(icon, filterColor) {
17
+ if (!icon)
18
+ return undefined;
19
+ if (icon.startsWith("/"))
20
+ icon = "https://localhost:9002/" + icon;
21
+ else if (icon.startsWith("<path "))
22
+ icon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">${icon}</svg>`;
23
+ if (icon.startsWith("<svg "))
24
+ icon = `data:image/svg+xml;utf8,${encodeURIComponent(icon)}`;
25
+ const filter = !filterColor ? undefined : hexToCssFilter(filterColor);
26
+ return (_jsx(Icon, { sx: { display: "flex", height: "inherit", width: "inherit" }, children: _jsx("img", { src: icon, style: { filter } }) }));
27
+ }
28
+ SVGUtils.createIcon = createIcon;
29
+ /**
30
+ * Hex color to CSS filter
31
+ * @param hex Hex color
32
+ * @returns Result
33
+ */
34
+ function hexToCssFilter(hex) {
35
+ const result = CssFilterConverter.hexToFilter(hex);
36
+ if (result == null || result.color == null)
37
+ throw result.error ?? new Error(`Invalid hex color: ${hex}`);
38
+ return result.color;
39
+ }
40
+ SVGUtils.hexToCssFilter = hexToCssFilter;
41
+ /**
42
+ * CSS filter to hex color
43
+ * @param filter CSS filter
44
+ * @returns Result
45
+ */
46
+ async function cssFilterToHex(filter) {
47
+ const result = await CssFilterConverter.filterToHex(filter);
48
+ if (result == null || result.color == null)
49
+ throw result.error ?? new Error(`Invalid CSS filter: ${filter}`);
50
+ return result.color;
51
+ }
52
+ SVGUtils.cssFilterToHex = cssFilterToHex;
53
+ })(SVGUtils || (SVGUtils = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.6.88",
3
+ "version": "1.6.89",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -49,6 +49,7 @@
49
49
  "@mui/x-data-grid": "^9.13.0",
50
50
  "chart.js": "^4.5.1",
51
51
  "chartjs-plugin-datalabels": "^2.2.0",
52
+ "css-filter-converter": "^1.0.115",
52
53
  "dompurify": "^3.4.15",
53
54
  "eventemitter3": "^5.0.4",
54
55
  "pica": "^10.0.3",
@@ -79,6 +79,7 @@ export function ButtonPopover<T>(props: ButtonPopoverProps<T>) {
79
79
  onClick={handleClose}
80
80
  transformOrigin={{ horizontal: position, vertical: "top" }}
81
81
  anchorOrigin={{ horizontal: position, vertical: "bottom" }}
82
+ disableRestoreFocus
82
83
  slotProps={{
83
84
  paper: {
84
85
  elevation: 0,
@@ -133,6 +133,7 @@ export function InputTipField<T extends ItemType = ItemType>(
133
133
  return (
134
134
  <React.Fragment>
135
135
  <Popover
136
+ disableRestoreFocus
136
137
  open={anchorEl != null}
137
138
  anchorEl={anchorEl}
138
139
  onClose={() => setAnchorEl(undefined)}
@@ -34,8 +34,8 @@ export function MenuButton<T extends DataTypes.IdItem>(
34
34
  anchorOrigin.vertical === "center"
35
35
  ? "center"
36
36
  : anchorOrigin.vertical === "top"
37
- ? "bottom"
38
- : "top",
37
+ ? "bottom"
38
+ : "top",
39
39
  horizontal: anchorOrigin.horizontal
40
40
  },
41
41
  sx,
@@ -101,6 +101,7 @@ export function MenuButton<T extends DataTypes.IdItem>(
101
101
  }
102
102
  }}
103
103
  disableScrollLock
104
+ disableRestoreFocus
104
105
  anchorEl={anchorEl}
105
106
  anchorOrigin={anchorOrigin}
106
107
  keepMounted
package/src/MoreFab.tsx CHANGED
@@ -158,7 +158,8 @@ export function MoreFab(props: MoreFabProps) {
158
158
  <React.Fragment>
159
159
  {main}
160
160
  <Menu
161
- disableScrollLock={true}
161
+ disableScrollLock
162
+ disableRestoreFocus
162
163
  anchorEl={anchorEl}
163
164
  anchorOrigin={anchorOrigin}
164
165
  keepMounted
@@ -710,6 +710,7 @@ export class NotificationMU extends NotificationReact {
710
710
  open={open}
711
711
  className={className}
712
712
  onClose={() => this.dismiss()}
713
+ disableRestoreFocus
713
714
  {...options}
714
715
  >
715
716
  {content}
@@ -22,6 +22,11 @@ export interface IServiceApp extends ReactAppType {
22
22
  */
23
23
  readonly coreOrigin: string;
24
24
 
25
+ /**
26
+ * Core system web URL
27
+ */
28
+ readonly coreWebUrl: string;
29
+
25
30
  /**
26
31
  * Get token authorization request data
27
32
  * @param api API, if not provided, use the core API
@@ -46,6 +46,11 @@ export class ServiceApp<
46
46
  */
47
47
  readonly coreOrigin: string;
48
48
 
49
+ /**
50
+ * Core system web URL
51
+ */
52
+ readonly coreWebUrl: string;
53
+
49
54
  private coreAccessToken: string | undefined;
50
55
 
51
56
  /**
@@ -64,6 +69,7 @@ export class ServiceApp<
64
69
  }
65
70
  this.coreEndpoint = coreEndpoint;
66
71
  this.coreOrigin = new URL(coreEndpoint.webUrl).origin;
72
+ this.coreWebUrl = coreEndpoint.webUrl;
67
73
  this.coreApi = this.createApi(this.coreName, coreEndpoint);
68
74
 
69
75
  this.keepLogin = true;
package/src/index.ts CHANGED
@@ -42,6 +42,7 @@ export * from "./texts/MoneyText";
42
42
  export * from "./texts/NumberText";
43
43
 
44
44
  export * from "./utils/CanvasUtils";
45
+ export * from "./utils/SVGUtils";
45
46
 
46
47
  export * from "./AddresSelector";
47
48
  export * from "./AuditDisplay";
@@ -131,6 +131,7 @@ export function UserMenu(props: UserMenuProps) {
131
131
  }
132
132
  }}
133
133
  disableScrollLock
134
+ disableRestoreFocus
134
135
  anchorEl={anchorEl}
135
136
  anchorOrigin={{
136
137
  vertical: "bottom",
@@ -0,0 +1,60 @@
1
+ import Icon from "@mui/material/Icon";
2
+ import CssFilterConverter from "css-filter-converter";
3
+
4
+ /**
5
+ * SVG utility functions
6
+ */
7
+ export namespace SVGUtils {
8
+ /**
9
+ * Create an SVG icon component
10
+ * @param icon Icon
11
+ * @param filterColor Filter color for the icon
12
+ * @returns Component
13
+ */
14
+ // https://cdn.jsdelivr.net/npm/@material-design-icons/svg@latest/filled/local_mall.svg
15
+ export function createIcon(
16
+ icon?: string | null,
17
+ filterColor?: string | null
18
+ ) {
19
+ if (!icon) return undefined;
20
+
21
+ if (icon.startsWith("/")) icon = "https://localhost:9002/" + icon;
22
+ else if (icon.startsWith("<path "))
23
+ icon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">${icon}</svg>`;
24
+
25
+ if (icon.startsWith("<svg "))
26
+ icon = `data:image/svg+xml;utf8,${encodeURIComponent(icon)}`;
27
+
28
+ const filter = !filterColor ? undefined : hexToCssFilter(filterColor);
29
+
30
+ return (
31
+ <Icon sx={{ display: "flex", height: "inherit", width: "inherit" }}>
32
+ <img src={icon} style={{ filter }} />
33
+ </Icon>
34
+ );
35
+ }
36
+
37
+ /**
38
+ * Hex color to CSS filter
39
+ * @param hex Hex color
40
+ * @returns Result
41
+ */
42
+ export function hexToCssFilter(hex: string): string {
43
+ const result = CssFilterConverter.hexToFilter(hex);
44
+ if (result == null || result.color == null)
45
+ throw result.error ?? new Error(`Invalid hex color: ${hex}`);
46
+ return result.color;
47
+ }
48
+
49
+ /**
50
+ * CSS filter to hex color
51
+ * @param filter CSS filter
52
+ * @returns Result
53
+ */
54
+ export async function cssFilterToHex(filter: string): Promise<string> {
55
+ const result = await CssFilterConverter.filterToHex(filter);
56
+ if (result == null || result.color == null)
57
+ throw result.error ?? new Error(`Invalid CSS filter: ${filter}`);
58
+ return result.color;
59
+ }
60
+ }