@etsoo/materialui 1.5.18 → 1.5.20

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.
@@ -4,6 +4,10 @@ import React from "react";
4
4
  * File upload button props
5
5
  */
6
6
  export type FileUploadButtonProps = ButtonProps<"label"> & {
7
+ /**
8
+ * Drop files label
9
+ */
10
+ dropFilesLabel?: React.ReactNode;
7
11
  /**
8
12
  * Max files allowed
9
13
  */
@@ -26,7 +30,7 @@ export type FileUploadButtonProps = ButtonProps<"label"> & {
26
30
  * Upload files callback
27
31
  * @param files Files
28
32
  */
29
- onUploadFiles?: (files: FileList) => void;
33
+ onUploadFiles: (files: FileList) => void;
30
34
  };
31
35
  /**
32
36
  * File upload button
@@ -5,7 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.FileUploadButton = FileUploadButton;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const material_1 = require("@mui/material");
8
9
  const Button_1 = __importDefault(require("@mui/material/Button"));
10
+ const react_1 = __importDefault(require("react"));
11
+ const FlexBox_1 = require("./FlexBox");
9
12
  /**
10
13
  * File upload button
11
14
  * @param props Props
@@ -13,37 +16,59 @@ const Button_1 = __importDefault(require("@mui/material/Button"));
13
16
  */
14
17
  function FileUploadButton(props) {
15
18
  // Destruct
16
- const { maxFiles, maxFileSize, inputProps, onFileInvalid, onUploadFiles, children, ...rest } = props;
19
+ const { dropFilesLabel, maxFiles, maxFileSize, inputProps, onFileInvalid, onUploadFiles, children = "Browse", ...rest } = props;
17
20
  const { onChange } = inputProps ?? {};
21
+ const [dragOver, setDragOver] = react_1.default.useState(false);
22
+ const handleDrop = (e) => {
23
+ e.preventDefault();
24
+ setDragOver(false);
25
+ validateFiles(e.dataTransfer.files);
26
+ };
27
+ const handleDragOver = (e) => {
28
+ e.preventDefault();
29
+ setDragOver(true);
30
+ };
31
+ const handleDragLeave = () => setDragOver(false);
32
+ const validateFiles = (files) => {
33
+ const fl = files.length;
34
+ if (fl === 0)
35
+ return;
36
+ if (maxFiles && maxFiles > 0 && fl > maxFiles) {
37
+ if (onFileInvalid)
38
+ onFileInvalid([maxFiles, fl]);
39
+ return;
40
+ }
41
+ if (maxFileSize && maxFileSize > 0) {
42
+ for (let f = 0; f < fl; f++) {
43
+ const file = files[f];
44
+ if (file.size > maxFileSize) {
45
+ if (onFileInvalid)
46
+ onFileInvalid([maxFileSize, file.size], file);
47
+ return;
48
+ }
49
+ }
50
+ }
51
+ onUploadFiles(files);
52
+ };
18
53
  // Layout
19
- return ((0, jsx_runtime_1.jsxs)(Button_1.default, { component: "label", ...rest, children: [children, (0, jsx_runtime_1.jsx)("input", { type: "file", hidden: true, onChange: (event) => {
20
- if (onChange)
21
- onChange(event);
22
- if (event.isDefaultPrevented())
23
- return;
24
- if (onUploadFiles) {
25
- const files = event.target.files;
26
- if (files == null)
27
- return;
28
- const fl = files.length;
29
- if (fl === 0)
30
- return;
31
- if (maxFiles && maxFiles > 0 && fl > maxFiles) {
32
- if (onFileInvalid)
33
- onFileInvalid([maxFiles, fl]);
34
- return;
35
- }
36
- if (maxFileSize && maxFileSize > 0) {
37
- for (let f = 0; f < fl; f++) {
38
- const file = files[f];
39
- if (file.size > maxFileSize) {
40
- if (onFileInvalid)
41
- onFileInvalid([maxFileSize, file.size], file);
42
- return;
43
- }
44
- }
45
- }
46
- onUploadFiles(files);
47
- }
48
- }, ...inputProps })] }));
54
+ return ((0, jsx_runtime_1.jsxs)(FlexBox_1.HBox, { alignItems: "center", flexWrap: "wrap", border: (theme) => dragOver ? "1px dashed " + theme.palette.warning.main : undefined, spacing: 0.5, ...(dropFilesLabel == null
55
+ ? undefined
56
+ : {
57
+ onDrop: handleDrop,
58
+ onDragOver: handleDragOver,
59
+ onDragLeave: handleDragLeave
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) => {
62
+ if (onChange)
63
+ onChange(event);
64
+ if (event.isDefaultPrevented())
65
+ return;
66
+ const files = event.target.files;
67
+ if (files == null)
68
+ return;
69
+ const fl = files.length;
70
+ if (fl === 0)
71
+ return;
72
+ validateFiles(files);
73
+ }, ...inputProps })] })] }));
49
74
  }
@@ -31,6 +31,7 @@ export type ViewPageGridItemProps = GridProps & {
31
31
  data: React.ReactNode;
32
32
  label?: React.ReactNode;
33
33
  singleRow?: ViewPageRowType;
34
+ horizontal?: boolean;
34
35
  };
35
36
  /**
36
37
  * View page grid item
@@ -58,6 +59,10 @@ export interface ViewPageField<T extends object> extends GridProps {
58
59
  * Display as single row
59
60
  */
60
61
  singleRow?: ViewPageRowType;
62
+ /**
63
+ * Render as horizontal or not
64
+ */
65
+ horizontal?: boolean;
61
66
  /**
62
67
  * Render props
63
68
  */
@@ -42,7 +42,7 @@ function getResp(singleRow) {
42
42
  }
43
43
  function getItemField(app, field, data) {
44
44
  // Item data and label
45
- let itemData, itemLabel, gridProps = {}, size;
45
+ let itemData, itemLabel, gridProps = {}, size, isHorizontal;
46
46
  if (Array.isArray(field)) {
47
47
  const [fieldData, fieldType, renderProps, singleRow = "small"] = field;
48
48
  itemData = (0, GridDataFormat_1.GridDataFormat)(data[fieldData], fieldType, renderProps);
@@ -52,7 +52,9 @@ function getItemField(app, field, data) {
52
52
  }
53
53
  else if (typeof field === "object") {
54
54
  // Destruct
55
- const { data: fieldData, dataType, label: fieldLabel, renderProps, singleRow = "default", ...rest } = field;
55
+ const { data: fieldData, dataType, label: fieldLabel, renderProps, singleRow = "default", horizontal, ...rest } = field;
56
+ // Horizontal or not
57
+ isHorizontal = horizontal;
56
58
  // Size
57
59
  size = getResp(singleRow);
58
60
  gridProps = {
@@ -85,7 +87,7 @@ function getItemField(app, field, data) {
85
87
  size = ViewPageSize.small;
86
88
  gridProps = { size };
87
89
  }
88
- return [itemData, itemLabel, gridProps, size];
90
+ return [itemData, itemLabel, gridProps, size, isHorizontal];
89
91
  }
90
92
  function getItemSize(bp, size) {
91
93
  const v = size[bp];
@@ -149,7 +151,7 @@ var ViewPageSize;
149
151
  */
150
152
  function ViewPageGridItem(props) {
151
153
  // Destruct
152
- const { data, label, singleRow, ...gridProps } = props;
154
+ const { data, label, singleRow, horizontal = false, ...gridProps } = props;
153
155
  // Default options
154
156
  let options = {};
155
157
  if (gridProps.size == null) {
@@ -159,7 +161,7 @@ function ViewPageGridItem(props) {
159
161
  options = getResp(singleRow ?? "small");
160
162
  }
161
163
  // Layout
162
- return ((0, jsx_runtime_1.jsxs)(Grid_1.default, { ...gridProps, ...options, children: [label != null && ((0, jsx_runtime_1.jsxs)(Typography_1.default, { variant: "caption", component: "div", children: [label, ":"] })), typeof data === "object" ? (data) : ((0, jsx_runtime_1.jsx)(Typography_1.default, { variant: "subtitle2", children: data }))] }));
164
+ return ((0, jsx_runtime_1.jsxs)(Grid_1.default, { ...gridProps, ...options, children: [label != null && ((0, jsx_runtime_1.jsxs)(Typography_1.default, { variant: "caption", component: horizontal ? "span" : "div", children: [label, ":"] })), typeof data === "object" ? (data) : horizontal ? ((0, jsx_runtime_1.jsx)(Typography_1.default, { variant: "subtitle2", component: "span", marginLeft: 0.5, children: data })) : ((0, jsx_runtime_1.jsx)(Typography_1.default, { variant: "subtitle2", children: data }))] }));
163
165
  }
164
166
  function ViewContainer(props) {
165
167
  // Global app
@@ -196,12 +198,12 @@ function ViewContainer(props) {
196
198
  }
197
199
  }
198
200
  else {
199
- const [itemData, itemLabel, gridProps, size] = getItemField(app, field, data);
201
+ const [itemData, itemLabel, gridProps, size, horizontal] = getItemField(app, field, data);
200
202
  // Some callback function may return '' instead of undefined
201
203
  if (itemData == null || itemData === "")
202
204
  continue;
203
205
  oneSize = size;
204
- oneItem = ((0, react_1.createElement)(ViewPageGridItem, { ...gridProps, key: i, data: itemData, label: itemLabel }));
206
+ oneItem = ((0, react_1.createElement)(ViewPageGridItem, { ...gridProps, key: i, data: itemData, label: itemLabel, horizontal: horizontal }));
205
207
  }
206
208
  // Max lines
207
209
  if (maxItems > 0) {
@@ -4,6 +4,10 @@ import React from "react";
4
4
  * File upload button props
5
5
  */
6
6
  export type FileUploadButtonProps = ButtonProps<"label"> & {
7
+ /**
8
+ * Drop files label
9
+ */
10
+ dropFilesLabel?: React.ReactNode;
7
11
  /**
8
12
  * Max files allowed
9
13
  */
@@ -26,7 +30,7 @@ export type FileUploadButtonProps = ButtonProps<"label"> & {
26
30
  * Upload files callback
27
31
  * @param files Files
28
32
  */
29
- onUploadFiles?: (files: FileList) => void;
33
+ onUploadFiles: (files: FileList) => void;
30
34
  };
31
35
  /**
32
36
  * File upload button
@@ -1,5 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Typography } from "@mui/material";
2
3
  import Button from "@mui/material/Button";
4
+ import React from "react";
5
+ import { HBox } from "./FlexBox";
3
6
  /**
4
7
  * File upload button
5
8
  * @param props Props
@@ -7,37 +10,59 @@ import Button from "@mui/material/Button";
7
10
  */
8
11
  export function FileUploadButton(props) {
9
12
  // Destruct
10
- const { maxFiles, maxFileSize, inputProps, onFileInvalid, onUploadFiles, children, ...rest } = props;
13
+ const { dropFilesLabel, maxFiles, maxFileSize, inputProps, onFileInvalid, onUploadFiles, children = "Browse", ...rest } = props;
11
14
  const { onChange } = inputProps ?? {};
15
+ const [dragOver, setDragOver] = React.useState(false);
16
+ const handleDrop = (e) => {
17
+ e.preventDefault();
18
+ setDragOver(false);
19
+ validateFiles(e.dataTransfer.files);
20
+ };
21
+ const handleDragOver = (e) => {
22
+ e.preventDefault();
23
+ setDragOver(true);
24
+ };
25
+ const handleDragLeave = () => setDragOver(false);
26
+ const validateFiles = (files) => {
27
+ const fl = files.length;
28
+ if (fl === 0)
29
+ return;
30
+ if (maxFiles && maxFiles > 0 && fl > maxFiles) {
31
+ if (onFileInvalid)
32
+ onFileInvalid([maxFiles, fl]);
33
+ return;
34
+ }
35
+ if (maxFileSize && maxFileSize > 0) {
36
+ for (let f = 0; f < fl; f++) {
37
+ const file = files[f];
38
+ if (file.size > maxFileSize) {
39
+ if (onFileInvalid)
40
+ onFileInvalid([maxFileSize, file.size], file);
41
+ return;
42
+ }
43
+ }
44
+ }
45
+ onUploadFiles(files);
46
+ };
12
47
  // Layout
13
- return (_jsxs(Button, { component: "label", ...rest, children: [children, _jsx("input", { type: "file", hidden: true, onChange: (event) => {
14
- if (onChange)
15
- onChange(event);
16
- if (event.isDefaultPrevented())
17
- return;
18
- if (onUploadFiles) {
19
- const files = event.target.files;
20
- if (files == null)
21
- return;
22
- const fl = files.length;
23
- if (fl === 0)
24
- return;
25
- if (maxFiles && maxFiles > 0 && fl > maxFiles) {
26
- if (onFileInvalid)
27
- onFileInvalid([maxFiles, fl]);
28
- return;
29
- }
30
- if (maxFileSize && maxFileSize > 0) {
31
- for (let f = 0; f < fl; f++) {
32
- const file = files[f];
33
- if (file.size > maxFileSize) {
34
- if (onFileInvalid)
35
- onFileInvalid([maxFileSize, file.size], file);
36
- return;
37
- }
38
- }
39
- }
40
- onUploadFiles(files);
41
- }
42
- }, ...inputProps })] }));
48
+ return (_jsxs(HBox, { alignItems: "center", flexWrap: "wrap", border: (theme) => dragOver ? "1px dashed " + theme.palette.warning.main : undefined, spacing: 0.5, ...(dropFilesLabel == null
49
+ ? undefined
50
+ : {
51
+ onDrop: handleDrop,
52
+ onDragOver: handleDragOver,
53
+ onDragLeave: handleDragLeave
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) => {
56
+ if (onChange)
57
+ onChange(event);
58
+ if (event.isDefaultPrevented())
59
+ return;
60
+ const files = event.target.files;
61
+ if (files == null)
62
+ return;
63
+ const fl = files.length;
64
+ if (fl === 0)
65
+ return;
66
+ validateFiles(files);
67
+ }, ...inputProps })] })] }));
43
68
  }
@@ -31,6 +31,7 @@ export type ViewPageGridItemProps = GridProps & {
31
31
  data: React.ReactNode;
32
32
  label?: React.ReactNode;
33
33
  singleRow?: ViewPageRowType;
34
+ horizontal?: boolean;
34
35
  };
35
36
  /**
36
37
  * View page grid item
@@ -58,6 +59,10 @@ export interface ViewPageField<T extends object> extends GridProps {
58
59
  * Display as single row
59
60
  */
60
61
  singleRow?: ViewPageRowType;
62
+ /**
63
+ * Render as horizontal or not
64
+ */
65
+ horizontal?: boolean;
61
66
  /**
62
67
  * Render props
63
68
  */
@@ -34,7 +34,7 @@ function getResp(singleRow) {
34
34
  }
35
35
  function getItemField(app, field, data) {
36
36
  // Item data and label
37
- let itemData, itemLabel, gridProps = {}, size;
37
+ let itemData, itemLabel, gridProps = {}, size, isHorizontal;
38
38
  if (Array.isArray(field)) {
39
39
  const [fieldData, fieldType, renderProps, singleRow = "small"] = field;
40
40
  itemData = GridDataFormat(data[fieldData], fieldType, renderProps);
@@ -44,7 +44,9 @@ function getItemField(app, field, data) {
44
44
  }
45
45
  else if (typeof field === "object") {
46
46
  // Destruct
47
- const { data: fieldData, dataType, label: fieldLabel, renderProps, singleRow = "default", ...rest } = field;
47
+ const { data: fieldData, dataType, label: fieldLabel, renderProps, singleRow = "default", horizontal, ...rest } = field;
48
+ // Horizontal or not
49
+ isHorizontal = horizontal;
48
50
  // Size
49
51
  size = getResp(singleRow);
50
52
  gridProps = {
@@ -77,7 +79,7 @@ function getItemField(app, field, data) {
77
79
  size = ViewPageSize.small;
78
80
  gridProps = { size };
79
81
  }
80
- return [itemData, itemLabel, gridProps, size];
82
+ return [itemData, itemLabel, gridProps, size, isHorizontal];
81
83
  }
82
84
  function getItemSize(bp, size) {
83
85
  const v = size[bp];
@@ -141,7 +143,7 @@ export var ViewPageSize;
141
143
  */
142
144
  export function ViewPageGridItem(props) {
143
145
  // Destruct
144
- const { data, label, singleRow, ...gridProps } = props;
146
+ const { data, label, singleRow, horizontal = false, ...gridProps } = props;
145
147
  // Default options
146
148
  let options = {};
147
149
  if (gridProps.size == null) {
@@ -151,7 +153,7 @@ export function ViewPageGridItem(props) {
151
153
  options = getResp(singleRow ?? "small");
152
154
  }
153
155
  // Layout
154
- return (_jsxs(Grid, { ...gridProps, ...options, children: [label != null && (_jsxs(Typography, { variant: "caption", component: "div", children: [label, ":"] })), typeof data === "object" ? (data) : (_jsx(Typography, { variant: "subtitle2", children: data }))] }));
156
+ return (_jsxs(Grid, { ...gridProps, ...options, children: [label != null && (_jsxs(Typography, { variant: "caption", component: horizontal ? "span" : "div", children: [label, ":"] })), typeof data === "object" ? (data) : horizontal ? (_jsx(Typography, { variant: "subtitle2", component: "span", marginLeft: 0.5, children: data })) : (_jsx(Typography, { variant: "subtitle2", children: data }))] }));
155
157
  }
156
158
  export function ViewContainer(props) {
157
159
  // Global app
@@ -188,12 +190,12 @@ export function ViewContainer(props) {
188
190
  }
189
191
  }
190
192
  else {
191
- const [itemData, itemLabel, gridProps, size] = getItemField(app, field, data);
193
+ const [itemData, itemLabel, gridProps, size, horizontal] = getItemField(app, field, data);
192
194
  // Some callback function may return '' instead of undefined
193
195
  if (itemData == null || itemData === "")
194
196
  continue;
195
197
  oneSize = size;
196
- oneItem = (_createElement(ViewPageGridItem, { ...gridProps, key: i, data: itemData, label: itemLabel }));
198
+ oneItem = (_createElement(ViewPageGridItem, { ...gridProps, key: i, data: itemData, label: itemLabel, horizontal: horizontal }));
197
199
  }
198
200
  // Max lines
199
201
  if (maxItems > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.5.18",
3
+ "version": "1.5.20",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -40,9 +40,9 @@
40
40
  "@dnd-kit/sortable": "^10.0.0",
41
41
  "@emotion/react": "^11.14.0",
42
42
  "@emotion/styled": "^11.14.0",
43
- "@etsoo/appscript": "^1.6.21",
43
+ "@etsoo/appscript": "^1.6.22",
44
44
  "@etsoo/notificationbase": "^1.1.60",
45
- "@etsoo/react": "^1.8.37",
45
+ "@etsoo/react": "^1.8.38",
46
46
  "@etsoo/shared": "^1.2.66",
47
47
  "@mui/icons-material": "^7.0.1",
48
48
  "@mui/material": "^7.0.1",
@@ -1,10 +1,17 @@
1
+ import { Typography } from "@mui/material";
1
2
  import Button, { ButtonProps } from "@mui/material/Button";
2
3
  import React from "react";
4
+ import { HBox } from "./FlexBox";
3
5
 
4
6
  /**
5
7
  * File upload button props
6
8
  */
7
9
  export type FileUploadButtonProps = ButtonProps<"label"> & {
10
+ /**
11
+ * Drop files label
12
+ */
13
+ dropFilesLabel?: React.ReactNode;
14
+
8
15
  /**
9
16
  * Max files allowed
10
17
  */
@@ -34,7 +41,7 @@ export type FileUploadButtonProps = ButtonProps<"label"> & {
34
41
  * Upload files callback
35
42
  * @param files Files
36
43
  */
37
- onUploadFiles?: (files: FileList) => void;
44
+ onUploadFiles: (files: FileList) => void;
38
45
  };
39
46
 
40
47
  /**
@@ -45,56 +52,98 @@ export type FileUploadButtonProps = ButtonProps<"label"> & {
45
52
  export function FileUploadButton(props: FileUploadButtonProps) {
46
53
  // Destruct
47
54
  const {
55
+ dropFilesLabel,
48
56
  maxFiles,
49
57
  maxFileSize,
50
58
  inputProps,
51
59
  onFileInvalid,
52
60
  onUploadFiles,
53
- children,
61
+ children = "Browse",
54
62
  ...rest
55
63
  } = props;
56
64
 
57
65
  const { onChange } = inputProps ?? {};
58
66
 
67
+ const [dragOver, setDragOver] = React.useState(false);
68
+
69
+ const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
70
+ e.preventDefault();
71
+ setDragOver(false);
72
+ validateFiles(e.dataTransfer.files);
73
+ };
74
+
75
+ const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
76
+ e.preventDefault();
77
+ setDragOver(true);
78
+ };
79
+
80
+ const handleDragLeave = () => setDragOver(false);
81
+
82
+ const validateFiles = (files: FileList) => {
83
+ const fl = files.length;
84
+ if (fl === 0) return;
85
+
86
+ if (maxFiles && maxFiles > 0 && fl > maxFiles) {
87
+ if (onFileInvalid) onFileInvalid([maxFiles, fl]);
88
+ return;
89
+ }
90
+
91
+ if (maxFileSize && maxFileSize > 0) {
92
+ for (let f = 0; f < fl; f++) {
93
+ const file = files[f];
94
+ if (file.size > maxFileSize) {
95
+ if (onFileInvalid) onFileInvalid([maxFileSize, file.size], file);
96
+ return;
97
+ }
98
+ }
99
+ }
100
+
101
+ onUploadFiles(files);
102
+ };
103
+
59
104
  // Layout
60
105
  return (
61
- <Button component="label" {...rest}>
62
- {children}
63
- <input
64
- type="file"
65
- hidden={true}
66
- onChange={(event) => {
67
- if (onChange) onChange(event);
68
- if (event.isDefaultPrevented()) return;
69
-
70
- if (onUploadFiles) {
106
+ <HBox
107
+ alignItems="center"
108
+ flexWrap="wrap"
109
+ border={(theme) =>
110
+ dragOver ? "1px dashed " + theme.palette.warning.main : undefined
111
+ }
112
+ spacing={0.5}
113
+ {...(dropFilesLabel == null
114
+ ? undefined
115
+ : {
116
+ onDrop: handleDrop,
117
+ onDragOver: handleDragOver,
118
+ onDragLeave: handleDragLeave
119
+ })}
120
+ >
121
+ {dropFilesLabel &&
122
+ (typeof dropFilesLabel === "string" ? (
123
+ <Typography variant="body2">{dropFilesLabel}</Typography>
124
+ ) : (
125
+ dropFilesLabel
126
+ ))}
127
+ <Button component="label" sx={{ textTransform: "none" }} {...rest}>
128
+ {children}
129
+ <input
130
+ type="file"
131
+ hidden={true}
132
+ onChange={(event) => {
133
+ if (onChange) onChange(event);
134
+ if (event.isDefaultPrevented()) return;
135
+
71
136
  const files = event.target.files;
72
137
  if (files == null) return;
73
138
 
74
139
  const fl = files.length;
75
140
  if (fl === 0) return;
76
141
 
77
- if (maxFiles && maxFiles > 0 && fl > maxFiles) {
78
- if (onFileInvalid) onFileInvalid([maxFiles, fl]);
79
- return;
80
- }
81
-
82
- if (maxFileSize && maxFileSize > 0) {
83
- for (let f = 0; f < fl; f++) {
84
- const file = files[f];
85
- if (file.size > maxFileSize) {
86
- if (onFileInvalid)
87
- onFileInvalid([maxFileSize, file.size], file);
88
- return;
89
- }
90
- }
91
- }
92
-
93
- onUploadFiles(files);
94
- }
95
- }}
96
- {...inputProps}
97
- />
98
- </Button>
142
+ validateFiles(files);
143
+ }}
144
+ {...inputProps}
145
+ />
146
+ </Button>
147
+ </HBox>
99
148
  );
100
149
  }
@@ -40,12 +40,13 @@ function getItemField<T extends object>(
40
40
  app: ReactAppType,
41
41
  field: ViewPageFieldTypeNarrow<T>,
42
42
  data: T
43
- ): [React.ReactNode, React.ReactNode, GridProps, ViewPageItemSize] {
43
+ ): [React.ReactNode, React.ReactNode, GridProps, ViewPageItemSize, boolean?] {
44
44
  // Item data and label
45
45
  let itemData: React.ReactNode,
46
46
  itemLabel: React.ReactNode,
47
47
  gridProps: GridProps = {},
48
- size: ViewPageItemSize;
48
+ size: ViewPageItemSize,
49
+ isHorizontal: boolean | undefined;
49
50
 
50
51
  if (Array.isArray(field)) {
51
52
  const [fieldData, fieldType, renderProps, singleRow = "small"] = field;
@@ -61,9 +62,13 @@ function getItemField<T extends object>(
61
62
  label: fieldLabel,
62
63
  renderProps,
63
64
  singleRow = "default",
65
+ horizontal,
64
66
  ...rest
65
67
  } = field;
66
68
 
69
+ // Horizontal or not
70
+ isHorizontal = horizontal;
71
+
67
72
  // Size
68
73
  size = getResp(singleRow);
69
74
 
@@ -96,7 +101,7 @@ function getItemField<T extends object>(
96
101
  gridProps = { size };
97
102
  }
98
103
 
99
- return [itemData, itemLabel, gridProps, size];
104
+ return [itemData, itemLabel, gridProps, size, isHorizontal];
100
105
  }
101
106
 
102
107
  function getItemSize(bp: Breakpoint, size: ViewPageItemSize) {
@@ -180,6 +185,7 @@ export type ViewPageGridItemProps = GridProps & {
180
185
  data: React.ReactNode;
181
186
  label?: React.ReactNode;
182
187
  singleRow?: ViewPageRowType;
188
+ horizontal?: boolean;
183
189
  };
184
190
 
185
191
  /**
@@ -189,7 +195,7 @@ export type ViewPageGridItemProps = GridProps & {
189
195
  */
190
196
  export function ViewPageGridItem(props: ViewPageGridItemProps) {
191
197
  // Destruct
192
- const { data, label, singleRow, ...gridProps } = props;
198
+ const { data, label, singleRow, horizontal = false, ...gridProps } = props;
193
199
 
194
200
  // Default options
195
201
  let options = {};
@@ -203,12 +209,16 @@ export function ViewPageGridItem(props: ViewPageGridItemProps) {
203
209
  return (
204
210
  <Grid {...gridProps} {...options}>
205
211
  {label != null && (
206
- <Typography variant="caption" component="div">
212
+ <Typography variant="caption" component={horizontal ? "span" : "div"}>
207
213
  {label}:
208
214
  </Typography>
209
215
  )}
210
216
  {typeof data === "object" ? (
211
217
  data
218
+ ) : horizontal ? (
219
+ <Typography variant="subtitle2" component="span" marginLeft={0.5}>
220
+ {data}
221
+ </Typography>
212
222
  ) : (
213
223
  <Typography variant="subtitle2">{data}</Typography>
214
224
  )}
@@ -240,6 +250,11 @@ export interface ViewPageField<T extends object> extends GridProps {
240
250
  */
241
251
  singleRow?: ViewPageRowType;
242
252
 
253
+ /**
254
+ * Render as horizontal or not
255
+ */
256
+ horizontal?: boolean;
257
+
243
258
  /**
244
259
  * Render props
245
260
  */
@@ -352,11 +367,8 @@ export function ViewContainer<T extends DataTypes.StringRecord>(
352
367
  oneItem = createdResult;
353
368
  }
354
369
  } else {
355
- const [itemData, itemLabel, gridProps, size] = getItemField(
356
- app,
357
- field,
358
- data
359
- );
370
+ const [itemData, itemLabel, gridProps, size, horizontal] =
371
+ getItemField(app, field, data);
360
372
 
361
373
  // Some callback function may return '' instead of undefined
362
374
  if (itemData == null || itemData === "") continue;
@@ -368,6 +380,7 @@ export function ViewContainer<T extends DataTypes.StringRecord>(
368
380
  key={i}
369
381
  data={itemData}
370
382
  label={itemLabel}
383
+ horizontal={horizontal}
371
384
  />
372
385
  );
373
386
  }
package/tsconfig.cjs.json CHANGED
@@ -5,6 +5,8 @@
5
5
  "module": "NodeNext",
6
6
  "moduleResolution": "NodeNext",
7
7
  "isolatedModules": true,
8
+ "allowJs": false,
9
+ "rootDir": "./src",
8
10
  "outDir": "./lib/cjs",
9
11
  "noEmit": false,
10
12
  "declaration": true,
package/tsconfig.json CHANGED
@@ -6,6 +6,7 @@
6
6
  "moduleResolution": "bundler",
7
7
  "allowJs": false,
8
8
  "isolatedModules": true,
9
+ "rootDir": "./src",
9
10
  "outDir": "./lib/mjs",
10
11
  "noEmit": false,
11
12
  "declaration": true,
package/' DELETED
File without changes