@etsoo/materialui 1.5.23 → 1.5.25

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.
@@ -19,7 +19,7 @@ export type FileUploadButtonProps = ButtonProps<"label"> & {
19
19
  /**
20
20
  * Input field attributes
21
21
  */
22
- inputProps?: Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "hidden">;
22
+ inputProps?: Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "hidden" | "multiple">;
23
23
  /**
24
24
  * File invalid handler
25
25
  * @param values [expected, actual]
@@ -16,7 +16,7 @@ const FlexBox_1 = require("./FlexBox");
16
16
  */
17
17
  function FileUploadButton(props) {
18
18
  // Destruct
19
- const { dropFilesLabel, maxFiles, maxFileSize, inputProps, onFileInvalid, onUploadFiles, children = "Browse", ...rest } = props;
19
+ const { dropFilesLabel, maxFiles = 1, maxFileSize, inputProps, onFileInvalid, onUploadFiles, children = "Browse", ...rest } = props;
20
20
  const { onChange } = inputProps ?? {};
21
21
  const [dragOver, setDragOver] = react_1.default.useState(false);
22
22
  const handleDrop = (e) => {
@@ -33,7 +33,7 @@ function FileUploadButton(props) {
33
33
  const fl = files.length;
34
34
  if (fl === 0)
35
35
  return;
36
- if (maxFiles && maxFiles > 0 && fl > maxFiles) {
36
+ if (maxFiles > 0 && fl > maxFiles) {
37
37
  if (onFileInvalid)
38
38
  onFileInvalid([maxFiles, fl]);
39
39
  return;
@@ -58,7 +58,7 @@ function FileUploadButton(props) {
58
58
  onDragOver: handleDragOver,
59
59
  onDragLeave: handleDragLeave
60
60
  }), children: [dropFilesLabel &&
61
- (typeof dropFilesLabel === "string" ? ((0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", children: dropFilesLabel })) : (dropFilesLabel)), (0, jsx_runtime_1.jsxs)(Button_1.default, { component: "label", sx: { textTransform: "none" }, ...rest, children: [children, (0, jsx_runtime_1.jsx)("input", { type: "file", hidden: true, onChange: (event) => {
61
+ (typeof dropFilesLabel === "string" ? ((0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", children: dropFilesLabel })) : (dropFilesLabel)), (0, jsx_runtime_1.jsxs)(Button_1.default, { component: "label", sx: { textTransform: "none" }, ...rest, children: [children, (0, jsx_runtime_1.jsx)("input", { type: "file", multiple: maxFiles > 1, hidden: true, onChange: (event) => {
62
62
  if (onChange)
63
63
  onChange(event);
64
64
  if (event.isDefaultPrevented())
@@ -169,6 +169,6 @@ function UserAvatarEditor(props) {
169
169
  };
170
170
  // Load the component
171
171
  const AE = react_1.default.lazy(() => import("react-avatar-editor"));
172
- return ((0, jsx_runtime_1.jsxs)(Stack_1.default, { direction: "column", spacing: 0.5, width: containerWidth, children: [(0, jsx_runtime_1.jsx)(FileUploadButton_1.FileUploadButton, { variant: "outlined", size: "medium", startIcon: (0, jsx_runtime_1.jsx)(Image_1.default, {}), fullWidth: true, onUploadFiles: handleFileUpload, inputProps: { multiple: false, accept: "image/png, image/jpeg" }, children: selectFileLabel }), (0, jsx_runtime_1.jsxs)(Stack_1.default, { direction: "row", spacing: 0.5, children: [(0, jsx_runtime_1.jsx)(react_1.default.Suspense, { fallback: (0, jsx_runtime_1.jsx)(Skeleton_1.default, { variant: "rounded", width: width, height: localHeight }), children: (0, jsx_runtime_1.jsx)(AE, { ref: ref, border: border, width: width, height: localHeight, onLoadSuccess: handleLoad, image: previewImage ??
172
+ return ((0, jsx_runtime_1.jsxs)(Stack_1.default, { direction: "column", spacing: 0.5, width: containerWidth, children: [(0, jsx_runtime_1.jsx)(FileUploadButton_1.FileUploadButton, { variant: "outlined", size: "medium", startIcon: (0, jsx_runtime_1.jsx)(Image_1.default, {}), fullWidth: true, onUploadFiles: handleFileUpload, inputProps: { accept: "image/png, image/jpeg" }, children: selectFileLabel }), (0, jsx_runtime_1.jsxs)(Stack_1.default, { direction: "row", spacing: 0.5, children: [(0, jsx_runtime_1.jsx)(react_1.default.Suspense, { fallback: (0, jsx_runtime_1.jsx)(Skeleton_1.default, { variant: "rounded", width: width, height: localHeight }), children: (0, jsx_runtime_1.jsx)(AE, { ref: ref, border: border, width: width, height: localHeight, onLoadSuccess: handleLoad, image: previewImage ??
173
173
  "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=", scale: editorState.scale, rotate: editorState.rotate }) }), (0, jsx_runtime_1.jsxs)(ButtonGroup_1.default, { size: "small", orientation: "vertical", disabled: !ready, children: [(0, jsx_runtime_1.jsx)(Button_1.default, { onClick: () => handleRotate(90), title: labels.rotateRight, children: (0, jsx_runtime_1.jsx)(RotateRight_1.default, {}) }), (0, jsx_runtime_1.jsx)(Button_1.default, { onClick: () => handleRotate(-90), title: labels.rotateLeft, children: (0, jsx_runtime_1.jsx)(RotateLeft_1.default, {}) }), (0, jsx_runtime_1.jsx)(Button_1.default, { onClick: handleReset, title: labels.reset, children: (0, jsx_runtime_1.jsx)(ClearAll_1.default, {}) })] })] }), (0, jsx_runtime_1.jsxs)(Stack_1.default, { spacing: 0.5, direction: "row", sx: { paddingBottom: 2 }, alignItems: "center", children: [(0, jsx_runtime_1.jsx)(IconButton_1.default, { size: "small", disabled: !ready || editorState.scale <= min, onClick: () => adjustScale(false), children: (0, jsx_runtime_1.jsx)(Remove_1.default, {}) }), (0, jsx_runtime_1.jsx)(Slider_1.default, { title: labels.zoom, disabled: !ready, min: min, max: max, step: step, value: editorState.scale, valueLabelDisplay: "auto", valueLabelFormat: (value) => `${Math.round(100 * value) / 100}`, marks: marks, onChange: handleZoom }), (0, jsx_runtime_1.jsx)(IconButton_1.default, { size: "small", disabled: !ready || editorState.scale >= max, onClick: () => adjustScale(true), children: (0, jsx_runtime_1.jsx)(Add_1.default, {}) })] }), (0, jsx_runtime_1.jsx)(Button_1.default, { ref: buttonRef, variant: "contained", startIcon: (0, jsx_runtime_1.jsx)(Done_1.default, {}), disabled: !ready, onClick: handleDone, children: labels.done })] }));
174
174
  }
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.HtmlDiv = HtmlDiv;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const shared_1 = require("@etsoo/shared");
8
9
  const dompurify_1 = __importDefault(require("dompurify"));
9
10
  class HtmlDivElement extends HTMLElement {
10
11
  constructor() {
@@ -15,10 +16,16 @@ class HtmlDivElement extends HTMLElement {
15
16
  const shadow = this.attachShadow({ mode: "open" });
16
17
  // Create a wrapper element to hold the sanitized HTML content
17
18
  const wrapper = document.createElement("div");
18
- if (this.textContent) {
19
+ const html = this.innerHTML;
20
+ if (shared_1.Utils.hasHtmlEntity(html) &&
21
+ !shared_1.Utils.hasHtmlTag(html) &&
22
+ this.textContent) {
19
23
  wrapper.innerHTML = dompurify_1.default.sanitize(this.textContent);
20
- this.textContent = null; // Clear the textContent to avoid duplication
21
24
  }
25
+ else {
26
+ wrapper.innerHTML = dompurify_1.default.sanitize(html);
27
+ }
28
+ this.textContent = null; // Clear the textContent to avoid duplication
22
29
  shadow.appendChild(wrapper);
23
30
  }
24
31
  }
@@ -19,7 +19,7 @@ export type FileUploadButtonProps = ButtonProps<"label"> & {
19
19
  /**
20
20
  * Input field attributes
21
21
  */
22
- inputProps?: Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "hidden">;
22
+ inputProps?: Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "hidden" | "multiple">;
23
23
  /**
24
24
  * File invalid handler
25
25
  * @param values [expected, actual]
@@ -10,7 +10,7 @@ import { HBox } from "./FlexBox";
10
10
  */
11
11
  export function FileUploadButton(props) {
12
12
  // Destruct
13
- const { dropFilesLabel, maxFiles, maxFileSize, inputProps, onFileInvalid, onUploadFiles, children = "Browse", ...rest } = props;
13
+ const { dropFilesLabel, maxFiles = 1, maxFileSize, inputProps, onFileInvalid, onUploadFiles, children = "Browse", ...rest } = props;
14
14
  const { onChange } = inputProps ?? {};
15
15
  const [dragOver, setDragOver] = React.useState(false);
16
16
  const handleDrop = (e) => {
@@ -27,7 +27,7 @@ export function FileUploadButton(props) {
27
27
  const fl = files.length;
28
28
  if (fl === 0)
29
29
  return;
30
- if (maxFiles && maxFiles > 0 && fl > maxFiles) {
30
+ if (maxFiles > 0 && fl > maxFiles) {
31
31
  if (onFileInvalid)
32
32
  onFileInvalid([maxFiles, fl]);
33
33
  return;
@@ -52,7 +52,7 @@ export function FileUploadButton(props) {
52
52
  onDragOver: handleDragOver,
53
53
  onDragLeave: handleDragLeave
54
54
  }), children: [dropFilesLabel &&
55
- (typeof dropFilesLabel === "string" ? (_jsx(Typography, { variant: "body2", children: dropFilesLabel })) : (dropFilesLabel)), _jsxs(Button, { component: "label", sx: { textTransform: "none" }, ...rest, children: [children, _jsx("input", { type: "file", hidden: true, onChange: (event) => {
55
+ (typeof dropFilesLabel === "string" ? (_jsx(Typography, { variant: "body2", children: dropFilesLabel })) : (dropFilesLabel)), _jsxs(Button, { component: "label", sx: { textTransform: "none" }, ...rest, children: [children, _jsx("input", { type: "file", multiple: maxFiles > 1, hidden: true, onChange: (event) => {
56
56
  if (onChange)
57
57
  onChange(event);
58
58
  if (event.isDefaultPrevented())
@@ -163,6 +163,6 @@ export function UserAvatarEditor(props) {
163
163
  };
164
164
  // Load the component
165
165
  const AE = React.lazy(() => import("react-avatar-editor"));
166
- return (_jsxs(Stack, { direction: "column", spacing: 0.5, width: containerWidth, children: [_jsx(FileUploadButton, { variant: "outlined", size: "medium", startIcon: _jsx(ImageIcon, {}), fullWidth: true, onUploadFiles: handleFileUpload, inputProps: { multiple: false, accept: "image/png, image/jpeg" }, children: selectFileLabel }), _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(React.Suspense, { fallback: _jsx(Skeleton, { variant: "rounded", width: width, height: localHeight }), children: _jsx(AE, { ref: ref, border: border, width: width, height: localHeight, onLoadSuccess: handleLoad, image: previewImage ??
166
+ return (_jsxs(Stack, { direction: "column", spacing: 0.5, width: containerWidth, children: [_jsx(FileUploadButton, { variant: "outlined", size: "medium", startIcon: _jsx(ImageIcon, {}), fullWidth: true, onUploadFiles: handleFileUpload, inputProps: { accept: "image/png, image/jpeg" }, children: selectFileLabel }), _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(React.Suspense, { fallback: _jsx(Skeleton, { variant: "rounded", width: width, height: localHeight }), children: _jsx(AE, { ref: ref, border: border, width: width, height: localHeight, onLoadSuccess: handleLoad, image: previewImage ??
167
167
  "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=", scale: editorState.scale, rotate: editorState.rotate }) }), _jsxs(ButtonGroup, { size: "small", orientation: "vertical", disabled: !ready, children: [_jsx(Button, { onClick: () => handleRotate(90), title: labels.rotateRight, children: _jsx(RotateRightIcon, {}) }), _jsx(Button, { onClick: () => handleRotate(-90), title: labels.rotateLeft, children: _jsx(RotateLeftIcon, {}) }), _jsx(Button, { onClick: handleReset, title: labels.reset, children: _jsx(ClearAllIcon, {}) })] })] }), _jsxs(Stack, { spacing: 0.5, direction: "row", sx: { paddingBottom: 2 }, alignItems: "center", children: [_jsx(IconButton, { size: "small", disabled: !ready || editorState.scale <= min, onClick: () => adjustScale(false), children: _jsx(RemoveIcon, {}) }), _jsx(Slider, { title: labels.zoom, disabled: !ready, min: min, max: max, step: step, value: editorState.scale, valueLabelDisplay: "auto", valueLabelFormat: (value) => `${Math.round(100 * value) / 100}`, marks: marks, onChange: handleZoom }), _jsx(IconButton, { size: "small", disabled: !ready || editorState.scale >= max, onClick: () => adjustScale(true), children: _jsx(AddIcon, {}) })] }), _jsx(Button, { ref: buttonRef, variant: "contained", startIcon: _jsx(DoneIcon, {}), disabled: !ready, onClick: handleDone, children: labels.done })] }));
168
168
  }
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Utils } from "@etsoo/shared";
2
3
  import DOMPurify from "dompurify";
3
4
  class HtmlDivElement extends HTMLElement {
4
5
  constructor() {
@@ -9,10 +10,16 @@ class HtmlDivElement extends HTMLElement {
9
10
  const shadow = this.attachShadow({ mode: "open" });
10
11
  // Create a wrapper element to hold the sanitized HTML content
11
12
  const wrapper = document.createElement("div");
12
- if (this.textContent) {
13
+ const html = this.innerHTML;
14
+ if (Utils.hasHtmlEntity(html) &&
15
+ !Utils.hasHtmlTag(html) &&
16
+ this.textContent) {
13
17
  wrapper.innerHTML = DOMPurify.sanitize(this.textContent);
14
- this.textContent = null; // Clear the textContent to avoid duplication
15
18
  }
19
+ else {
20
+ wrapper.innerHTML = DOMPurify.sanitize(html);
21
+ }
22
+ this.textContent = null; // Clear the textContent to avoid duplication
16
23
  shadow.appendChild(wrapper);
17
24
  }
18
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.5.23",
3
+ "version": "1.5.25",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -43,7 +43,7 @@
43
43
  "@etsoo/appscript": "^1.6.22",
44
44
  "@etsoo/notificationbase": "^1.1.60",
45
45
  "@etsoo/react": "^1.8.38",
46
- "@etsoo/shared": "^1.2.66",
46
+ "@etsoo/shared": "^1.2.68",
47
47
  "@mui/icons-material": "^7.0.2",
48
48
  "@mui/material": "^7.0.2",
49
49
  "@mui/x-data-grid": "^7.28.3",
@@ -27,7 +27,7 @@ export type FileUploadButtonProps = ButtonProps<"label"> & {
27
27
  */
28
28
  inputProps?: Omit<
29
29
  React.InputHTMLAttributes<HTMLInputElement>,
30
- "type" | "hidden"
30
+ "type" | "hidden" | "multiple"
31
31
  >;
32
32
 
33
33
  /**
@@ -53,7 +53,7 @@ export function FileUploadButton(props: FileUploadButtonProps) {
53
53
  // Destruct
54
54
  const {
55
55
  dropFilesLabel,
56
- maxFiles,
56
+ maxFiles = 1,
57
57
  maxFileSize,
58
58
  inputProps,
59
59
  onFileInvalid,
@@ -83,7 +83,7 @@ export function FileUploadButton(props: FileUploadButtonProps) {
83
83
  const fl = files.length;
84
84
  if (fl === 0) return;
85
85
 
86
- if (maxFiles && maxFiles > 0 && fl > maxFiles) {
86
+ if (maxFiles > 0 && fl > maxFiles) {
87
87
  if (onFileInvalid) onFileInvalid([maxFiles, fl]);
88
88
  return;
89
89
  }
@@ -128,6 +128,7 @@ export function FileUploadButton(props: FileUploadButtonProps) {
128
128
  {children}
129
129
  <input
130
130
  type="file"
131
+ multiple={maxFiles > 1}
131
132
  hidden={true}
132
133
  onChange={(event) => {
133
134
  if (onChange) onChange(event);
@@ -304,7 +304,7 @@ export function UserAvatarEditor(props: UserAvatarEditorProps) {
304
304
  startIcon={<ImageIcon />}
305
305
  fullWidth
306
306
  onUploadFiles={handleFileUpload}
307
- inputProps={{ multiple: false, accept: "image/png, image/jpeg" }}
307
+ inputProps={{ accept: "image/png, image/jpeg" }}
308
308
  >
309
309
  {selectFileLabel}
310
310
  </FileUploadButton>
@@ -1,3 +1,4 @@
1
+ import { Utils } from "@etsoo/shared";
1
2
  import DOMPurify from "dompurify";
2
3
  import { HTMLAttributes } from "react";
3
4
 
@@ -12,11 +13,19 @@ class HtmlDivElement extends HTMLElement {
12
13
 
13
14
  // Create a wrapper element to hold the sanitized HTML content
14
15
  const wrapper = document.createElement("div");
15
- if (this.textContent) {
16
+ const html = this.innerHTML;
17
+ if (
18
+ Utils.hasHtmlEntity(html) &&
19
+ !Utils.hasHtmlTag(html) &&
20
+ this.textContent
21
+ ) {
16
22
  wrapper.innerHTML = DOMPurify.sanitize(this.textContent);
17
- this.textContent = null; // Clear the textContent to avoid duplication
23
+ } else {
24
+ wrapper.innerHTML = DOMPurify.sanitize(html);
18
25
  }
19
26
 
27
+ this.textContent = null; // Clear the textContent to avoid duplication
28
+
20
29
  shadow.appendChild(wrapper);
21
30
  }
22
31
  }