@etsoo/materialui 1.6.30 → 1.6.32

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,7 +4,14 @@ import {
4
4
  } from "@etsoo/notificationbase";
5
5
  import React, { act } from "react";
6
6
  import { createRoot } from "react-dom/client";
7
- import { NotifierMU } from "../src";
7
+ import {
8
+ NotificationMUDataMethods,
9
+ NotificationMUDataProps,
10
+ NotifierMU,
11
+ VBox
12
+ } from "../src";
13
+ import TextField from "@mui/material/TextField";
14
+ import { screen } from "@testing-library/react";
8
15
 
9
16
  // Without it will popup error:
10
17
  // The current testing environment is not configured to support act
@@ -15,11 +22,11 @@ const root = document.body;
15
22
  const container: HTMLElement = document.createElement("div");
16
23
  root.append(container);
17
24
 
18
- // The state provider
19
- const Provider = NotifierMU.setup();
20
- const reactRoot = createRoot(container);
21
-
22
25
  act(() => {
26
+ // The state provider
27
+ const Provider = NotifierMU.setup();
28
+ const reactRoot = createRoot(container);
29
+
23
30
  // Concorrent renderer needs act block
24
31
  reactRoot.render(<Provider />);
25
32
  });
@@ -137,6 +144,77 @@ test("Prompt tests", async () => {
137
144
  vi.runOnlyPendingTimers();
138
145
  });
139
146
 
147
+ type DataType = {
148
+ name: string;
149
+ age: number;
150
+ };
151
+
152
+ function DataCollector(props: NotificationMUDataProps) {
153
+ const { mRef } = props;
154
+ const nameRef = React.createRef<HTMLInputElement>();
155
+ const ageRef = React.createRef<HTMLInputElement>();
156
+
157
+ function getValue(): DataType | undefined {
158
+ if (!nameRef.current?.value) {
159
+ nameRef.current?.focus();
160
+ return undefined;
161
+ }
162
+
163
+ if (!ageRef.current?.valueAsNumber) {
164
+ ageRef.current?.focus();
165
+ return undefined;
166
+ }
167
+
168
+ return {
169
+ name: nameRef.current.value,
170
+ age: ageRef.current.valueAsNumber
171
+ };
172
+ }
173
+
174
+ React.useImperativeHandle(mRef, () => ({
175
+ getValue
176
+ }));
177
+
178
+ return (
179
+ <VBox>
180
+ <TextField name="name" required inputRef={nameRef} />
181
+ <TextField name="age" type="number" required inputRef={ageRef} />
182
+ </VBox>
183
+ );
184
+ }
185
+
186
+ test("Data tests", async () => {
187
+ const name = "John Doe";
188
+ const age = 30;
189
+
190
+ act(() => {
191
+ // Add the notification
192
+ notifier.data<DataType>(
193
+ <DataCollector mRef={React.createRef<NotificationMUDataMethods>()} />,
194
+ (result) => {
195
+ expect(result).toEqual({ name, age });
196
+ return true;
197
+ },
198
+ "Data Modal"
199
+ );
200
+ });
201
+
202
+ const button = screen.getByText("OK");
203
+ expect(button).toBeInTheDocument();
204
+
205
+ const nameInput = root.querySelector<HTMLInputElement>('input[name="name"]');
206
+ expect(nameInput).not.toBeNull();
207
+ nameInput!.value = name;
208
+
209
+ const ageInput = root.querySelector<HTMLInputElement>('input[name="age"]');
210
+ expect(ageInput).not.toBeNull();
211
+ ageInput!.value = age.toString();
212
+
213
+ await act(async () => {
214
+ button.click();
215
+ });
216
+ });
217
+
140
218
  test("Prompt tests with form submit", async () => {
141
219
  // Click
142
220
  const handleClick = vi.fn((result: boolean) => {
@@ -151,17 +229,14 @@ test("Prompt tests with form submit", async () => {
151
229
  });
152
230
  });
153
231
 
232
+ const button = screen.getByText("OK");
233
+ expect(button).toBeInTheDocument();
234
+
154
235
  await act(async () => {
155
- (
156
- root
157
- .getElementsByTagName("form")[0]
158
- .elements.namedItem("okButton") as HTMLButtonElement
159
- )?.click();
236
+ button.click();
160
237
  });
161
238
 
162
239
  expect(handleClick).toHaveBeenCalled();
163
-
164
- vi.runOnlyPendingTimers();
165
240
  });
166
241
 
167
242
  test("Message tests", () => {
@@ -1,6 +1,18 @@
1
1
  import { NotificationAlign, NotificationRenderProps } from "@etsoo/notificationbase";
2
2
  import React from "react";
3
3
  import { INotificationBaseReact, INotificationReact, NotificationReact, NotifierReact } from "@etsoo/react";
4
+ /**
5
+ * MU notification data methods
6
+ */
7
+ export interface NotificationMUDataMethods {
8
+ getValue(): unknown;
9
+ }
10
+ /**
11
+ * MU notification data props
12
+ */
13
+ export type NotificationMUDataProps = {
14
+ mRef: React.RefObject<NotificationMUDataMethods | null>;
15
+ };
4
16
  /**
5
17
  * MU notification
6
18
  */
@@ -9,6 +21,7 @@ export declare class NotificationMU extends NotificationReact {
9
21
  private createConfirm;
10
22
  private createMessageColor;
11
23
  private createMessage;
24
+ private createData;
12
25
  private createPrompt;
13
26
  private createPopup;
14
27
  private createLoading;
@@ -59,6 +59,14 @@ const IconDialogTitle = (0, styles_1.styled)(DialogTitle_1.default, {
59
59
  }
60
60
  `}
61
61
  `;
62
+ function isFunctionComponentElement(node) {
63
+ return (react_1.default.isValidElement(node) &&
64
+ typeof node.type === "function" &&
65
+ !(node.type.prototype && node.type.prototype.isReactComponent) &&
66
+ node.props != null &&
67
+ typeof node.props === "object" &&
68
+ "mRef" in node.props);
69
+ }
62
70
  /**
63
71
  * MU notification
64
72
  */
@@ -134,6 +142,53 @@ class NotificationMU extends react_2.NotificationReact {
134
142
  const options = this.renderSetup ? this.renderSetup(setupProps) : undefined;
135
143
  return ((0, jsx_runtime_1.jsx)(Fade_1.default, { in: true, children: (0, jsx_runtime_1.jsxs)(Alert_1.default, { ...setupProps, ...options, action: closable ? ((0, jsx_runtime_1.jsx)(IconButton_1.default, { size: "small", onClick: () => this.returnValue("CLOSE"), children: (0, jsx_runtime_1.jsx)(Close_1.default, {}) })) : undefined, onClose: () => this.dismiss(), className: className, children: [this.title && (0, jsx_runtime_1.jsx)(AlertTitle_1.default, { children: this.title }), this.content] }) }, this.id));
136
144
  }
145
+ // Create data collector
146
+ createData(_props, className) {
147
+ const labels = Labels_1.Labels.NotificationMU;
148
+ const title = this.title ?? labels.promptTitle;
149
+ const { buttons, cancelLabel = labels.promptCancel, okLabel = labels.promptOK, cancelButton = true, inputs,
150
+ // type, not used
151
+ fullScreen, fullWidth = true, maxWidth, primaryButton = true, primaryButtonProps, inputProps, closable = false, draggable = fullScreen === true ? false : true } = this.inputProps ?? {};
152
+ const content = inputs ?? this.content;
153
+ if (!isFunctionComponentElement(content) || content.props.mRef == null) {
154
+ throw new Error("Data collector content must be a function component with mRef prop");
155
+ }
156
+ const mRef = content.props.mRef;
157
+ const errorRef = react_1.default.createRef();
158
+ const setError = (error) => {
159
+ if (errorRef.current == null)
160
+ return;
161
+ errorRef.current.innerText = error ?? "";
162
+ };
163
+ // Setup callback
164
+ const options = this.renderSetup ? this.renderSetup({}) : undefined;
165
+ const handleSubmit = async () => {
166
+ if (this.onReturn) {
167
+ // Get the value
168
+ const value = mRef.current?.getValue();
169
+ if (value == null) {
170
+ return false;
171
+ }
172
+ const result = this.onReturn(value);
173
+ // returns false to prevent default dismiss
174
+ const v = await result;
175
+ if (v === false) {
176
+ return false;
177
+ }
178
+ if (typeof v === "string") {
179
+ setError(v);
180
+ return false;
181
+ }
182
+ }
183
+ this.dismiss();
184
+ return true;
185
+ };
186
+ return ((0, jsx_runtime_1.jsxs)(Dialog_1.default, { open: this.open, PaperComponent: draggable ? DraggablePaperComponent_1.DraggablePaperComponent : undefined, className: className, fullWidth: fullWidth, maxWidth: maxWidth, fullScreen: fullScreen, ...options, children: [(0, jsx_runtime_1.jsxs)(IconDialogTitle, { draggable: draggable, className: draggable ? "dialog-title draggable-dialog-title" : "dialog-title", children: [(0, jsx_runtime_1.jsx)(Info_1.default, { color: "primary" }), (0, jsx_runtime_1.jsx)("span", { className: "dialogTitle", children: title }), closable && ((0, jsx_runtime_1.jsx)(IconButton_1.default, { className: "MuiDialogContent-root-close-button", size: "small", onClick: () => this.returnValue("CLOSE"), children: (0, jsx_runtime_1.jsx)(Close_1.default, {}) }))] }), (0, jsx_runtime_1.jsxs)(DialogContent_1.default, { ...inputProps, children: [content, (0, jsx_runtime_1.jsx)(Typography_1.default, { variant: "caption", display: "block", ref: errorRef, color: "error" })] }), (0, jsx_runtime_1.jsx)(DialogActions_1.default, { children: buttons ? (buttons(this, handleSubmit)) : ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [cancelButton && ((0, jsx_runtime_1.jsx)(Button_1.default, { color: "secondary", onClick: () => {
187
+ if (this.onReturn)
188
+ this.onReturn(undefined);
189
+ this.dismiss();
190
+ }, children: cancelLabel })), primaryButton && ((0, jsx_runtime_1.jsx)(LoadingButton_1.LoadingButton, { color: "primary", autoFocus: true, onClick: handleSubmit, name: "okButton", ...primaryButtonProps, children: okLabel }))] })) })] }, this.id));
191
+ }
137
192
  // Create prompt
138
193
  createPrompt(_props, className) {
139
194
  const labels = Labels_1.Labels.NotificationMU;
@@ -147,13 +202,13 @@ class NotificationMU extends react_2.NotificationReact {
147
202
  errorRef.current.innerText = error ?? "";
148
203
  };
149
204
  const handleSubmit = async (event) => {
150
- // Result
151
- let result = undefined;
152
205
  const input = inputRef.current;
153
206
  if (this.onReturn) {
154
207
  // Inputs case, no HTMLForm set to value, set the current form
155
208
  if (inputs && value == null)
156
209
  value = event.currentTarget.form;
210
+ // Result
211
+ let result = undefined;
157
212
  if (input) {
158
213
  if (type === "switch") {
159
214
  const boolValue = input.value === "true";
@@ -171,18 +226,18 @@ class NotificationMU extends react_2.NotificationReact {
171
226
  else if (value != null) {
172
227
  result = this.onReturn(value);
173
228
  }
174
- }
175
- // Get the value
176
- // returns false to prevent default dismiss
177
- const v = await result;
178
- if (v === false) {
179
- input?.focus();
180
- return false;
181
- }
182
- if (typeof v === "string") {
183
- setError(v);
184
- input?.focus();
185
- return false;
229
+ // Get the value
230
+ // returns false to prevent default dismiss
231
+ const v = await result;
232
+ if (v === false) {
233
+ input?.focus();
234
+ return false;
235
+ }
236
+ if (typeof v === "string") {
237
+ setError(v);
238
+ input?.focus();
239
+ return false;
240
+ }
186
241
  }
187
242
  this.dismiss();
188
243
  return true;
@@ -259,6 +314,9 @@ class NotificationMU extends react_2.NotificationReact {
259
314
  else if (this.type === notificationbase_1.NotificationType.Confirm) {
260
315
  return this.createConfirm(props, className);
261
316
  }
317
+ else if (this.type === notificationbase_1.NotificationType.Data) {
318
+ return this.createData(props, className);
319
+ }
262
320
  else if (this.type === notificationbase_1.NotificationType.Prompt) {
263
321
  return this.createPrompt(props, className);
264
322
  }
@@ -1,6 +1,18 @@
1
1
  import { NotificationAlign, NotificationRenderProps } from "@etsoo/notificationbase";
2
2
  import React from "react";
3
3
  import { INotificationBaseReact, INotificationReact, NotificationReact, NotifierReact } from "@etsoo/react";
4
+ /**
5
+ * MU notification data methods
6
+ */
7
+ export interface NotificationMUDataMethods {
8
+ getValue(): unknown;
9
+ }
10
+ /**
11
+ * MU notification data props
12
+ */
13
+ export type NotificationMUDataProps = {
14
+ mRef: React.RefObject<NotificationMUDataMethods | null>;
15
+ };
4
16
  /**
5
17
  * MU notification
6
18
  */
@@ -9,6 +21,7 @@ export declare class NotificationMU extends NotificationReact {
9
21
  private createConfirm;
10
22
  private createMessageColor;
11
23
  private createMessage;
24
+ private createData;
12
25
  private createPrompt;
13
26
  private createPopup;
14
27
  private createLoading;
@@ -53,6 +53,14 @@ const IconDialogTitle = styled(DialogTitle, {
53
53
  }
54
54
  `}
55
55
  `;
56
+ function isFunctionComponentElement(node) {
57
+ return (React.isValidElement(node) &&
58
+ typeof node.type === "function" &&
59
+ !(node.type.prototype && node.type.prototype.isReactComponent) &&
60
+ node.props != null &&
61
+ typeof node.props === "object" &&
62
+ "mRef" in node.props);
63
+ }
56
64
  /**
57
65
  * MU notification
58
66
  */
@@ -128,6 +136,53 @@ export class NotificationMU extends NotificationReact {
128
136
  const options = this.renderSetup ? this.renderSetup(setupProps) : undefined;
129
137
  return (_jsx(Fade, { in: true, children: _jsxs(Alert, { ...setupProps, ...options, action: closable ? (_jsx(IconButton, { size: "small", onClick: () => this.returnValue("CLOSE"), children: _jsx(CloseIcon, {}) })) : undefined, onClose: () => this.dismiss(), className: className, children: [this.title && _jsx(AlertTitle, { children: this.title }), this.content] }) }, this.id));
130
138
  }
139
+ // Create data collector
140
+ createData(_props, className) {
141
+ const labels = Labels.NotificationMU;
142
+ const title = this.title ?? labels.promptTitle;
143
+ const { buttons, cancelLabel = labels.promptCancel, okLabel = labels.promptOK, cancelButton = true, inputs,
144
+ // type, not used
145
+ fullScreen, fullWidth = true, maxWidth, primaryButton = true, primaryButtonProps, inputProps, closable = false, draggable = fullScreen === true ? false : true } = this.inputProps ?? {};
146
+ const content = inputs ?? this.content;
147
+ if (!isFunctionComponentElement(content) || content.props.mRef == null) {
148
+ throw new Error("Data collector content must be a function component with mRef prop");
149
+ }
150
+ const mRef = content.props.mRef;
151
+ const errorRef = React.createRef();
152
+ const setError = (error) => {
153
+ if (errorRef.current == null)
154
+ return;
155
+ errorRef.current.innerText = error ?? "";
156
+ };
157
+ // Setup callback
158
+ const options = this.renderSetup ? this.renderSetup({}) : undefined;
159
+ const handleSubmit = async () => {
160
+ if (this.onReturn) {
161
+ // Get the value
162
+ const value = mRef.current?.getValue();
163
+ if (value == null) {
164
+ return false;
165
+ }
166
+ const result = this.onReturn(value);
167
+ // returns false to prevent default dismiss
168
+ const v = await result;
169
+ if (v === false) {
170
+ return false;
171
+ }
172
+ if (typeof v === "string") {
173
+ setError(v);
174
+ return false;
175
+ }
176
+ }
177
+ this.dismiss();
178
+ return true;
179
+ };
180
+ return (_jsxs(Dialog, { open: this.open, PaperComponent: draggable ? DraggablePaperComponent : undefined, className: className, fullWidth: fullWidth, maxWidth: maxWidth, fullScreen: fullScreen, ...options, children: [_jsxs(IconDialogTitle, { draggable: draggable, className: draggable ? "dialog-title draggable-dialog-title" : "dialog-title", children: [_jsx(InfoIcon, { color: "primary" }), _jsx("span", { className: "dialogTitle", children: title }), closable && (_jsx(IconButton, { className: "MuiDialogContent-root-close-button", size: "small", onClick: () => this.returnValue("CLOSE"), children: _jsx(CloseIcon, {}) }))] }), _jsxs(DialogContent, { ...inputProps, children: [content, _jsx(Typography, { variant: "caption", display: "block", ref: errorRef, color: "error" })] }), _jsx(DialogActions, { children: buttons ? (buttons(this, handleSubmit)) : (_jsxs(React.Fragment, { children: [cancelButton && (_jsx(Button, { color: "secondary", onClick: () => {
181
+ if (this.onReturn)
182
+ this.onReturn(undefined);
183
+ this.dismiss();
184
+ }, children: cancelLabel })), primaryButton && (_jsx(LoadingButton, { color: "primary", autoFocus: true, onClick: handleSubmit, name: "okButton", ...primaryButtonProps, children: okLabel }))] })) })] }, this.id));
185
+ }
131
186
  // Create prompt
132
187
  createPrompt(_props, className) {
133
188
  const labels = Labels.NotificationMU;
@@ -141,13 +196,13 @@ export class NotificationMU extends NotificationReact {
141
196
  errorRef.current.innerText = error ?? "";
142
197
  };
143
198
  const handleSubmit = async (event) => {
144
- // Result
145
- let result = undefined;
146
199
  const input = inputRef.current;
147
200
  if (this.onReturn) {
148
201
  // Inputs case, no HTMLForm set to value, set the current form
149
202
  if (inputs && value == null)
150
203
  value = event.currentTarget.form;
204
+ // Result
205
+ let result = undefined;
151
206
  if (input) {
152
207
  if (type === "switch") {
153
208
  const boolValue = input.value === "true";
@@ -165,18 +220,18 @@ export class NotificationMU extends NotificationReact {
165
220
  else if (value != null) {
166
221
  result = this.onReturn(value);
167
222
  }
168
- }
169
- // Get the value
170
- // returns false to prevent default dismiss
171
- const v = await result;
172
- if (v === false) {
173
- input?.focus();
174
- return false;
175
- }
176
- if (typeof v === "string") {
177
- setError(v);
178
- input?.focus();
179
- return false;
223
+ // Get the value
224
+ // returns false to prevent default dismiss
225
+ const v = await result;
226
+ if (v === false) {
227
+ input?.focus();
228
+ return false;
229
+ }
230
+ if (typeof v === "string") {
231
+ setError(v);
232
+ input?.focus();
233
+ return false;
234
+ }
180
235
  }
181
236
  this.dismiss();
182
237
  return true;
@@ -253,6 +308,9 @@ export class NotificationMU extends NotificationReact {
253
308
  else if (this.type === NotificationType.Confirm) {
254
309
  return this.createConfirm(props, className);
255
310
  }
311
+ else if (this.type === NotificationType.Data) {
312
+ return this.createData(props, className);
313
+ }
256
314
  else if (this.type === NotificationType.Prompt) {
257
315
  return this.createPrompt(props, className);
258
316
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.6.30",
3
+ "version": "1.6.32",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -36,20 +36,20 @@
36
36
  },
37
37
  "homepage": "https://github.com/ETSOO/ReactMU#readme",
38
38
  "dependencies": {
39
- "@base-ui/react": "^1.2.0",
39
+ "@base-ui/react": "^1.3.0",
40
40
  "@dnd-kit/react": "^0.3.2",
41
41
  "@emotion/react": "^11.14.0",
42
42
  "@emotion/styled": "^11.14.1",
43
- "@etsoo/appscript": "^1.6.56",
44
- "@etsoo/notificationbase": "^1.1.66",
45
- "@etsoo/react": "^1.8.80",
43
+ "@etsoo/appscript": "^1.6.57",
44
+ "@etsoo/notificationbase": "^1.1.67",
45
+ "@etsoo/react": "^1.8.81",
46
46
  "@etsoo/shared": "^1.2.80",
47
47
  "@mui/icons-material": "^7.3.9",
48
48
  "@mui/material": "^7.3.9",
49
- "@mui/x-data-grid": "^8.27.4",
49
+ "@mui/x-data-grid": "^8.27.5",
50
50
  "chart.js": "^4.5.1",
51
51
  "chartjs-plugin-datalabels": "^2.2.0",
52
- "dompurify": "^3.3.2",
52
+ "dompurify": "^3.3.3",
53
53
  "eventemitter3": "^5.0.4",
54
54
  "pica": "^9.0.1",
55
55
  "pulltorefreshjs": "^0.1.22",
@@ -71,6 +71,7 @@
71
71
  "@babel/preset-react": "^7.28.5",
72
72
  "@babel/preset-typescript": "^7.28.5",
73
73
  "@babel/runtime-corejs3": "^7.29.0",
74
+ "@testing-library/jest-dom": "^6.9.1",
74
75
  "@testing-library/react": "^16.3.2",
75
76
  "@types/pica": "^9.0.5",
76
77
  "@types/pulltorefreshjs": "^0.1.7",
@@ -78,9 +79,9 @@
78
79
  "@types/react-avatar-editor": "^13.0.4",
79
80
  "@types/react-dom": "^19.2.3",
80
81
  "@types/react-input-mask": "^3.0.6",
81
- "@vitejs/plugin-react": "^5.1.4",
82
- "jsdom": "^28.1.0",
82
+ "@vitejs/plugin-react": "^6.0.1",
83
+ "jsdom": "^29.0.0",
83
84
  "typescript": "^5.9.3",
84
- "vitest": "^4.0.18"
85
+ "vitest": "^4.1.0"
85
86
  }
86
87
  }
package/setupTests.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { MockResizeObserver, NodeStorage } from "@etsoo/shared";
2
2
  import { vi } from "vitest";
3
+ import "@testing-library/jest-dom";
3
4
 
4
5
  (globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
5
6
 
@@ -70,6 +70,36 @@ const IconDialogTitle = styled(DialogTitle, {
70
70
  `}
71
71
  `;
72
72
 
73
+ /**
74
+ * MU notification data methods
75
+ */
76
+ export interface NotificationMUDataMethods {
77
+ getValue(): unknown;
78
+ }
79
+
80
+ /**
81
+ * MU notification data props
82
+ */
83
+ export type NotificationMUDataProps = {
84
+ mRef: React.RefObject<NotificationMUDataMethods | null>;
85
+ };
86
+
87
+ function isFunctionComponentElement(
88
+ node: React.ReactNode
89
+ ): node is React.ReactElement<
90
+ NotificationMUDataProps,
91
+ React.FunctionComponent<NotificationMUDataProps>
92
+ > {
93
+ return (
94
+ React.isValidElement(node) &&
95
+ typeof node.type === "function" &&
96
+ !(node.type.prototype && node.type.prototype.isReactComponent) &&
97
+ node.props != null &&
98
+ typeof node.props === "object" &&
99
+ "mRef" in node.props
100
+ );
101
+ }
102
+
73
103
  /**
74
104
  * MU notification
75
105
  */
@@ -319,6 +349,145 @@ export class NotificationMU extends NotificationReact {
319
349
  );
320
350
  }
321
351
 
352
+ // Create data collector
353
+ private createData(_props: NotificationRenderProps, className?: string) {
354
+ const labels = Labels.NotificationMU;
355
+ const title = this.title ?? labels.promptTitle;
356
+
357
+ const {
358
+ buttons,
359
+ cancelLabel = labels.promptCancel,
360
+ okLabel = labels.promptOK,
361
+ cancelButton = true,
362
+ inputs,
363
+ // type, not used
364
+ fullScreen,
365
+ fullWidth = true,
366
+ maxWidth,
367
+ primaryButton = true,
368
+ primaryButtonProps,
369
+ inputProps,
370
+ closable = false,
371
+ draggable = fullScreen === true ? false : true
372
+ } = this.inputProps ?? {};
373
+
374
+ const content = inputs ?? this.content;
375
+ if (!isFunctionComponentElement(content) || content.props.mRef == null) {
376
+ throw new Error(
377
+ "Data collector content must be a function component with mRef prop"
378
+ );
379
+ }
380
+
381
+ const mRef = content.props.mRef;
382
+
383
+ const errorRef = React.createRef<HTMLSpanElement>();
384
+
385
+ const setError = (error?: string) => {
386
+ if (errorRef.current == null) return;
387
+ errorRef.current.innerText = error ?? "";
388
+ };
389
+
390
+ // Setup callback
391
+ const options = this.renderSetup ? this.renderSetup({}) : undefined;
392
+
393
+ const handleSubmit = async () => {
394
+ if (this.onReturn) {
395
+ // Get the value
396
+ const value = mRef.current?.getValue();
397
+ if (value == null) {
398
+ return false;
399
+ }
400
+
401
+ const result = this.onReturn(value);
402
+
403
+ // returns false to prevent default dismiss
404
+ const v = await result;
405
+ if (v === false) {
406
+ return false;
407
+ }
408
+
409
+ if (typeof v === "string") {
410
+ setError(v);
411
+ return false;
412
+ }
413
+ }
414
+
415
+ this.dismiss();
416
+ return true;
417
+ };
418
+
419
+ return (
420
+ <Dialog
421
+ key={this.id}
422
+ open={this.open}
423
+ PaperComponent={draggable ? DraggablePaperComponent : undefined}
424
+ className={className}
425
+ fullWidth={fullWidth}
426
+ maxWidth={maxWidth}
427
+ fullScreen={fullScreen}
428
+ {...options}
429
+ >
430
+ <IconDialogTitle
431
+ draggable={draggable}
432
+ className={
433
+ draggable ? "dialog-title draggable-dialog-title" : "dialog-title"
434
+ }
435
+ >
436
+ <InfoIcon color="primary" />
437
+ <span className="dialogTitle">{title}</span>
438
+ {closable && (
439
+ <IconButton
440
+ className="MuiDialogContent-root-close-button"
441
+ size="small"
442
+ onClick={() => this.returnValue("CLOSE")}
443
+ >
444
+ <CloseIcon />
445
+ </IconButton>
446
+ )}
447
+ </IconDialogTitle>
448
+ <DialogContent {...inputProps}>
449
+ {content}
450
+ <Typography
451
+ variant="caption"
452
+ display="block"
453
+ ref={errorRef}
454
+ color="error"
455
+ />
456
+ </DialogContent>
457
+ <DialogActions>
458
+ {buttons ? (
459
+ buttons(this, handleSubmit)
460
+ ) : (
461
+ <React.Fragment>
462
+ {cancelButton && (
463
+ <Button
464
+ color="secondary"
465
+ onClick={() => {
466
+ if (this.onReturn) this.onReturn(undefined);
467
+ this.dismiss();
468
+ }}
469
+ >
470
+ {cancelLabel}
471
+ </Button>
472
+ )}
473
+ {primaryButton && (
474
+ <LoadingButton
475
+ color="primary"
476
+ autoFocus
477
+ onClick={handleSubmit}
478
+ name="okButton"
479
+ {...primaryButtonProps}
480
+ >
481
+ {okLabel}
482
+ </LoadingButton>
483
+ )}
484
+ </React.Fragment>
485
+ )}
486
+ </DialogActions>
487
+ </Dialog>
488
+ );
489
+ }
490
+
322
491
  // Create prompt
323
492
  private createPrompt(_props: NotificationRenderProps, className?: string) {
324
493
  const labels = Labels.NotificationMU;
@@ -350,19 +519,19 @@ export class NotificationMU extends NotificationReact {
350
519
  };
351
520
 
352
521
  const handleSubmit = async (event: React.MouseEvent<HTMLButtonElement>) => {
353
- // Result
354
- let result:
355
- | boolean
356
- | string
357
- | void
358
- | PromiseLike<boolean | string | void> = undefined;
359
-
360
522
  const input = inputRef.current;
361
523
 
362
524
  if (this.onReturn) {
363
525
  // Inputs case, no HTMLForm set to value, set the current form
364
526
  if (inputs && value == null) value = event.currentTarget.form;
365
527
 
528
+ // Result
529
+ let result:
530
+ | boolean
531
+ | string
532
+ | void
533
+ | PromiseLike<boolean | string | void> = undefined;
534
+
366
535
  if (input) {
367
536
  if (type === "switch") {
368
537
  const boolValue = input.value === "true";
@@ -378,19 +547,20 @@ export class NotificationMU extends NotificationReact {
378
547
  } else if (value != null) {
379
548
  result = this.onReturn(value);
380
549
  }
381
- }
382
550
 
383
- // Get the value
384
- // returns false to prevent default dismiss
385
- const v = await result;
386
- if (v === false) {
387
- input?.focus();
388
- return false;
389
- }
390
- if (typeof v === "string") {
391
- setError(v);
392
- input?.focus();
393
- return false;
551
+ // Get the value
552
+ // returns false to prevent default dismiss
553
+ const v = await result;
554
+ if (v === false) {
555
+ input?.focus();
556
+ return false;
557
+ }
558
+
559
+ if (typeof v === "string") {
560
+ setError(v);
561
+ input?.focus();
562
+ return false;
563
+ }
394
564
  }
395
565
 
396
566
  this.dismiss();
@@ -606,6 +776,8 @@ export class NotificationMU extends NotificationReact {
606
776
  return this.createLoading(props, className);
607
777
  } else if (this.type === NotificationType.Confirm) {
608
778
  return this.createConfirm(props, className);
779
+ } else if (this.type === NotificationType.Data) {
780
+ return this.createData(props, className);
609
781
  } else if (this.type === NotificationType.Prompt) {
610
782
  return this.createPrompt(props, className);
611
783
  } else if (this.type === NotificationType.Popup) {