@etsoo/react 1.1.80 → 1.1.84

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.
package/lib/index.d.ts CHANGED
@@ -27,11 +27,13 @@ export * from './mu/DataGridEx';
27
27
  export * from './mu/DataGridRenderers';
28
28
  export * from './mu/DialogButton';
29
29
  export * from './mu/DraggablePaperComponent';
30
+ export * from './mu/EmailInput';
30
31
  export * from './mu/FabBox';
31
32
  export * from './mu/FlexBox';
32
33
  export * from './mu/IconButtonLink';
33
34
  export * from './mu/InputField';
34
35
  export * from './mu/ItemList';
36
+ export * from './mu/LoadingButton';
35
37
  export * from './mu/MoreFab';
36
38
  export * from './mu/MUGlobal';
37
39
  export * from './mu/NotifierMU';
package/lib/index.js CHANGED
@@ -30,11 +30,13 @@ export * from './mu/DataGridEx';
30
30
  export * from './mu/DataGridRenderers';
31
31
  export * from './mu/DialogButton';
32
32
  export * from './mu/DraggablePaperComponent';
33
+ export * from './mu/EmailInput';
33
34
  export * from './mu/FabBox';
34
35
  export * from './mu/FlexBox';
35
36
  export * from './mu/IconButtonLink';
36
37
  export * from './mu/InputField';
37
38
  export * from './mu/ItemList';
39
+ export * from './mu/LoadingButton';
38
40
  export * from './mu/MoreFab';
39
41
  export * from './mu/MUGlobal';
40
42
  export * from './mu/NotifierMU';
@@ -0,0 +1,11 @@
1
+ /// <reference types="react" />
2
+ import { TextFieldProps } from '@mui/material';
3
+ /**
4
+ * Email input props
5
+ */
6
+ export declare type EmailInputProps = Omit<TextFieldProps, 'type'> & {};
7
+ /**
8
+ * Email input
9
+ * @param props Props
10
+ */
11
+ export declare function EmailInput(props: EmailInputProps): JSX.Element;
@@ -0,0 +1,15 @@
1
+ import { TextField } from '@mui/material';
2
+ import React from 'react';
3
+ /**
4
+ * Email input
5
+ * @param props Props
6
+ */
7
+ export function EmailInput(props) {
8
+ var _a;
9
+ // Destruct
10
+ const { inputProps = {}, ...rest } = props;
11
+ // Default max length
12
+ (_a = inputProps.maxLength) !== null && _a !== void 0 ? _a : (inputProps.maxLength = 128);
13
+ // Layout
14
+ return (React.createElement(TextField, { type: "email", fullWidth: true, inputProps: inputProps, ...rest }));
15
+ }
@@ -0,0 +1,16 @@
1
+ /// <reference types="react" />
2
+ import { ButtonProps, CircularProgressProps } from '@mui/material';
3
+ /**
4
+ * Loading button props
5
+ */
6
+ export declare type LoadingButtonProps = ButtonProps & {
7
+ /**
8
+ * Loading icon props
9
+ */
10
+ loadingIconProps?: CircularProgressProps;
11
+ };
12
+ /**
13
+ * Loading button
14
+ * @param props Props
15
+ */
16
+ export declare function LoadingButton(props: LoadingButtonProps): JSX.Element;
@@ -0,0 +1,45 @@
1
+ import { Button, CircularProgress } from '@mui/material';
2
+ import React from 'react';
3
+ /**
4
+ * Loading button
5
+ * @param props Props
6
+ */
7
+ export function LoadingButton(props) {
8
+ var _a;
9
+ // Destruct
10
+ const { endIcon, loadingIconProps = {}, onClick, ...rest } = props;
11
+ // Default size
12
+ (_a = loadingIconProps.size) !== null && _a !== void 0 ? _a : (loadingIconProps.size = 12);
13
+ // State
14
+ // https://stackoverflow.com/questions/55265255/react-usestate-hook-event-handler-using-initial-state
15
+ const [loading, setLoading] = React.useState(false);
16
+ // Icon
17
+ const localEndIcon = loading ? (React.createElement(CircularProgress, { ...loadingIconProps })) : (endIcon);
18
+ // Check if the component is mounted
19
+ const isMounted = React.useRef(true);
20
+ React.useEffect(() => {
21
+ return () => {
22
+ isMounted.current = false;
23
+ };
24
+ }, []);
25
+ // Layout
26
+ return (React.createElement(Button, { disabled: loading, endIcon: localEndIcon, onClick: async (event) => {
27
+ if (onClick) {
28
+ // Update state
29
+ setLoading(true);
30
+ // const AsyncFunction = (async () => {}).constructor;
31
+ // onClick instanceof AsyncFunction
32
+ if (onClick.constructor.name === 'AsyncFunction') {
33
+ // May long time running
34
+ await onClick(event);
35
+ }
36
+ else {
37
+ onClick(event);
38
+ }
39
+ // Warning: Can't perform a React state update on an unmounted component
40
+ // It's necessary to check the component is mounted now
41
+ if (isMounted.current)
42
+ setLoading(false);
43
+ }
44
+ }, ...rest }));
45
+ }
@@ -5,6 +5,7 @@ import React from 'react';
5
5
  import { Labels } from '../app/Labels';
6
6
  import { NotificationReact, NotifierReact } from '../notifier/Notifier';
7
7
  import { DraggablePaperComponent } from './DraggablePaperComponent';
8
+ import { LoadingButton } from './LoadingButton';
8
9
  // Custom icon dialog title bar
9
10
  const IconDialogTitle = styled(DialogTitle) `
10
11
  ${({ theme }) => `
@@ -106,12 +107,13 @@ export class NotificationMU extends NotificationReact {
106
107
  const labels = Labels.NotificationMU;
107
108
  const title = (_a = this.title) !== null && _a !== void 0 ? _a : labels.promptTitle;
108
109
  const { cancelLabel = labels.promptCancel, okLabel = labels.promptOK, inputs, type, ...rest } = this.inputProps;
109
- const handleSubmit = (event) => {
110
- event.preventDefault();
110
+ const handleSubmit = async (event) => {
111
+ // Result
112
+ let result = undefined;
111
113
  if (this.onReturn) {
112
114
  // Inputs case, no HTMLForm set to value, set the current form
113
115
  if (inputs && value == null)
114
- value = event.currentTarget;
116
+ value = event.currentTarget.form;
115
117
  if (inputRef.current) {
116
118
  if (type === 'date') {
117
119
  const dateValue = inputRef.current.valueAsDate;
@@ -119,8 +121,7 @@ export class NotificationMU extends NotificationReact {
119
121
  inputRef.current.focus();
120
122
  return;
121
123
  }
122
- if (this.onReturn(dateValue) === false)
123
- return;
124
+ result = this.onReturn(dateValue);
124
125
  }
125
126
  else if (type === 'number') {
126
127
  const numberValue = inputRef.current.valueAsNumber;
@@ -128,34 +129,35 @@ export class NotificationMU extends NotificationReact {
128
129
  inputRef.current.focus();
129
130
  return;
130
131
  }
131
- if (this.onReturn(numberValue) === false)
132
- return;
132
+ result = this.onReturn(numberValue);
133
133
  }
134
134
  else if (type === 'switch') {
135
135
  const boolValue = inputRef.current.value == 'true';
136
- if (this.onReturn(boolValue) === false)
137
- return;
136
+ result = this.onReturn(boolValue);
138
137
  }
139
138
  else {
140
- const textValue = inputRef.current.value;
141
- if (textValue) {
142
- if (this.onReturn(textValue) === false)
143
- return;
139
+ const textValue = inputRef.current.value.trim();
140
+ if (textValue === '') {
141
+ inputRef.current.focus();
142
+ return;
144
143
  }
145
- inputRef.current.focus();
144
+ result = this.onReturn(textValue);
146
145
  }
147
146
  }
148
147
  else if (value != null) {
149
- if (this.onReturn(value) === false)
150
- return;
148
+ result = this.onReturn(value);
151
149
  }
152
150
  }
151
+ // Get the value
152
+ // returns false to prevent default dismiss
153
+ const v = await result;
154
+ if (v === false)
155
+ return;
153
156
  this.dismiss();
154
157
  };
155
158
  let localInputs;
156
159
  let inputRef = React.createRef();
157
160
  let value = undefined;
158
- let formChangeHandler;
159
161
  if (inputs == null) {
160
162
  if (type === 'switch') {
161
163
  localInputs = (React.createElement(Switch, { inputRef: inputRef, ...rest, value: "true", autoFocus: true }));
@@ -169,12 +171,9 @@ export class NotificationMU extends NotificationReact {
169
171
  }
170
172
  else {
171
173
  localInputs = inputs;
172
- formChangeHandler = (event) => {
173
- value = event.currentTarget;
174
- };
175
174
  }
176
175
  return (React.createElement(Dialog, { key: this.id, open: this.open, PaperComponent: DraggablePaperComponent, className: className },
177
- React.createElement("form", { onSubmit: handleSubmit, onChange: formChangeHandler },
176
+ React.createElement("form", null,
178
177
  React.createElement(IconDialogTitle, { className: classes.iconTitle, id: "draggable-dialog-title" },
179
178
  React.createElement(Info, { color: "primary" }),
180
179
  React.createElement("span", { className: "dialogTitle" }, title)),
@@ -183,7 +182,7 @@ export class NotificationMU extends NotificationReact {
183
182
  localInputs),
184
183
  React.createElement(DialogActions, null,
185
184
  React.createElement(Button, { color: "secondary", onClick: () => this.dismiss() }, cancelLabel),
186
- React.createElement(Button, { type: "submit", color: "primary", autoFocus: true }, okLabel)))));
185
+ React.createElement(LoadingButton, { color: "primary", autoFocus: true, onClick: handleSubmit }, okLabel)))));
187
186
  }
188
187
  // Create loading
189
188
  createLoading(_props, className, _classes) {
@@ -11,6 +11,11 @@ export interface SearchBarProps {
11
11
  * Fields
12
12
  */
13
13
  fields: React.ReactElement[];
14
+ /**
15
+ * Inner height
16
+ * @default 40
17
+ */
18
+ innerHeight?: number;
14
19
  /**
15
20
  * On submit callback
16
21
  */
@@ -53,7 +53,7 @@ const setChildState = (child, enabled) => {
53
53
  */
54
54
  export function SearchBar(props) {
55
55
  // Destruct
56
- const { className, fields, onSubmit } = props;
56
+ const { className, fields, innerHeight = 40, onSubmit } = props;
57
57
  // Labels
58
58
  const labels = Labels.CommonPage;
59
59
  // Spacing
@@ -235,7 +235,7 @@ export function SearchBar(props) {
235
235
  if (form)
236
236
  forms.form = form;
237
237
  } },
238
- React.createElement(Stack, { ref: dimensions[0][0], justifyContent: "center", alignItems: "center", direction: "row", spacing: 1, sx: {
238
+ React.createElement(Stack, { ref: dimensions[0][0], justifyContent: "center", alignItems: "center", direction: "row", spacing: 1, height: innerHeight, sx: {
239
239
  '& > :not(style)': {
240
240
  flexBasis: 'auto',
241
241
  flexGrow: 0,
@@ -15,7 +15,7 @@ import { CommonPage } from './CommonPage';
15
15
  export function DataGridPage(props) {
16
16
  var _a, _b;
17
17
  // Destruct
18
- const { adjustHeight, fields, height, loadData, mRef, pageProps = {}, ...rest } = props;
18
+ const { adjustHeight, fields, height, loadData, mRef, sizeReadyMiliseconds = 100, pageProps = {}, ...rest } = props;
19
19
  (_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
20
20
  // States
21
21
  const [states, setStates] = React.useReducer((currentState, newState) => {
@@ -38,7 +38,7 @@ export function DataGridPage(props) {
38
38
  return loadData({ ...json, ...rest });
39
39
  };
40
40
  // Watch container
41
- const { dimensions } = useDimensions(1, undefined, 50);
41
+ const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
42
42
  const rect = dimensions[0][2];
43
43
  React.useEffect(() => {
44
44
  if (rect != null && rect.height > 50 && height == null) {
@@ -15,7 +15,7 @@ import { CommonPage } from './CommonPage';
15
15
  export function FixedListPage(props) {
16
16
  var _a;
17
17
  // Destruct
18
- const { adjustHeight, fields, loadData, mRef, pageProps = {}, ...rest } = props;
18
+ const { adjustHeight, fields, loadData, mRef, sizeReadyMiliseconds = 100, pageProps = {}, ...rest } = props;
19
19
  (_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
20
20
  // States
21
21
  const [states] = React.useState({});
@@ -44,7 +44,7 @@ export function FixedListPage(props) {
44
44
  return loadData({ ...json, ...rest });
45
45
  };
46
46
  // Watch container
47
- const { dimensions } = useDimensions(1, undefined, 100);
47
+ const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
48
48
  const rect = dimensions[0][2];
49
49
  const list = React.useMemo(() => {
50
50
  if (rect != null && rect.height > 50) {
@@ -16,7 +16,7 @@ import { CommonPage } from './CommonPage';
16
16
  export function ResponsivePage(props) {
17
17
  var _a, _b;
18
18
  // Destruct
19
- const { adjustHeight, columns, dataGridMinWidth = DataGridExCalColumns(columns).total, fields, height, loadData, innerItemRenderer, itemSize, mRef, pageProps = {}, ...rest } = props;
19
+ const { adjustHeight, columns, dataGridMinWidth = DataGridExCalColumns(columns).total, fields, height, loadData, innerItemRenderer, itemSize, mRef, sizeReadyMiliseconds = 100, pageProps = {}, ...rest } = props;
20
20
  (_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
21
21
  // States
22
22
  const [states, setStates] = React.useReducer((currentState, newState) => {
@@ -39,7 +39,7 @@ export function ResponsivePage(props) {
39
39
  setStates({ data });
40
40
  };
41
41
  // Watch container
42
- const { dimensions } = useDimensions(1, undefined, 50);
42
+ const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
43
43
  const rect = dimensions[0][2];
44
44
  const showDataGrid = ((_b = rect === null || rect === void 0 ? void 0 : rect.width) !== null && _b !== void 0 ? _b : 0) >= dataGridMinWidth;
45
45
  React.useEffect(() => {
@@ -17,4 +17,9 @@ export interface SearchPageProps<T> extends Omit<GridLoader<T>, 'loadData'> {
17
17
  * Page props
18
18
  */
19
19
  pageProps?: CommonPageProps;
20
+ /**
21
+ * Size ready to read miliseconds span
22
+ * @default 100
23
+ */
24
+ sizeReadyMiliseconds?: number;
20
25
  }
@@ -15,7 +15,7 @@ import { CommonPage, CommonPagePullContainer, CommonPageScrollContainer } from '
15
15
  export function TablePage(props) {
16
16
  var _a;
17
17
  // Destruct
18
- const { columns, fields, loadData, mRef, pageProps = {}, ...rest } = props;
18
+ const { columns, fields, loadData, mRef, sizeReadyMiliseconds = 100, pageProps = {}, ...rest } = props;
19
19
  (_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
20
20
  // States
21
21
  const [states] = React.useState({});
@@ -47,7 +47,7 @@ export function TablePage(props) {
47
47
  return previousValue + ((_a = width !== null && width !== void 0 ? width : minWidth) !== null && _a !== void 0 ? _a : TableExMinWidth);
48
48
  }, 0), [columns]);
49
49
  // Watch container
50
- const { dimensions } = useDimensions(1, undefined, 100);
50
+ const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
51
51
  const rect = dimensions[0][2];
52
52
  const list = React.useMemo(() => {
53
53
  if (rect != null && rect.height > 50 && rect.width >= totalWidth) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.1.80",
3
+ "version": "1.1.84",
4
4
  "description": "TypeScript ReactJs framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -44,8 +44,8 @@
44
44
  "@emotion/react": "^11.4.1",
45
45
  "@emotion/style": "^0.8.0",
46
46
  "@emotion/styled": "^11.3.0",
47
- "@etsoo/appscript": "^1.0.86",
48
- "@etsoo/notificationbase": "^1.0.77",
47
+ "@etsoo/appscript": "^1.0.87",
48
+ "@etsoo/notificationbase": "^1.0.78",
49
49
  "@etsoo/shared": "^1.0.41",
50
50
  "@mui/icons-material": "^5.0.0-rc.0",
51
51
  "@mui/material": "^5.0.0-rc.0",
package/src/index.ts CHANGED
@@ -32,11 +32,13 @@ export * from './mu/DataGridEx';
32
32
  export * from './mu/DataGridRenderers';
33
33
  export * from './mu/DialogButton';
34
34
  export * from './mu/DraggablePaperComponent';
35
+ export * from './mu/EmailInput';
35
36
  export * from './mu/FabBox';
36
37
  export * from './mu/FlexBox';
37
38
  export * from './mu/IconButtonLink';
38
39
  export * from './mu/InputField';
39
40
  export * from './mu/ItemList';
41
+ export * from './mu/LoadingButton';
40
42
  export * from './mu/MoreFab';
41
43
  export * from './mu/MUGlobal';
42
44
  export * from './mu/NotifierMU';
@@ -0,0 +1,24 @@
1
+ import { TextField, TextFieldProps } from '@mui/material';
2
+ import React from 'react';
3
+
4
+ /**
5
+ * Email input props
6
+ */
7
+ export type EmailInputProps = Omit<TextFieldProps, 'type'> & {};
8
+
9
+ /**
10
+ * Email input
11
+ * @param props Props
12
+ */
13
+ export function EmailInput(props: EmailInputProps) {
14
+ // Destruct
15
+ const { inputProps = {}, ...rest } = props;
16
+
17
+ // Default max length
18
+ inputProps.maxLength ??= 128;
19
+
20
+ // Layout
21
+ return (
22
+ <TextField type="email" fullWidth inputProps={inputProps} {...rest} />
23
+ );
24
+ }
@@ -0,0 +1,77 @@
1
+ import {
2
+ Button,
3
+ ButtonProps,
4
+ CircularProgress,
5
+ CircularProgressProps
6
+ } from '@mui/material';
7
+ import React from 'react';
8
+
9
+ /**
10
+ * Loading button props
11
+ */
12
+ export type LoadingButtonProps = ButtonProps & {
13
+ /**
14
+ * Loading icon props
15
+ */
16
+ loadingIconProps?: CircularProgressProps;
17
+ };
18
+
19
+ /**
20
+ * Loading button
21
+ * @param props Props
22
+ */
23
+ export function LoadingButton(props: LoadingButtonProps) {
24
+ // Destruct
25
+ const { endIcon, loadingIconProps = {}, onClick, ...rest } = props;
26
+
27
+ // Default size
28
+ loadingIconProps.size ??= 12;
29
+
30
+ // State
31
+ // https://stackoverflow.com/questions/55265255/react-usestate-hook-event-handler-using-initial-state
32
+ const [loading, setLoading] = React.useState(false);
33
+
34
+ // Icon
35
+ const localEndIcon = loading ? (
36
+ <CircularProgress {...loadingIconProps} />
37
+ ) : (
38
+ endIcon
39
+ );
40
+
41
+ // Check if the component is mounted
42
+ const isMounted = React.useRef(true);
43
+
44
+ React.useEffect(() => {
45
+ return () => {
46
+ isMounted.current = false;
47
+ };
48
+ }, []);
49
+
50
+ // Layout
51
+ return (
52
+ <Button
53
+ disabled={loading}
54
+ endIcon={localEndIcon}
55
+ onClick={async (event) => {
56
+ if (onClick) {
57
+ // Update state
58
+ setLoading(true);
59
+
60
+ // const AsyncFunction = (async () => {}).constructor;
61
+ // onClick instanceof AsyncFunction
62
+ if (onClick.constructor.name === 'AsyncFunction') {
63
+ // May long time running
64
+ await onClick(event);
65
+ } else {
66
+ onClick(event);
67
+ }
68
+
69
+ // Warning: Can't perform a React state update on an unmounted component
70
+ // It's necessary to check the component is mounted now
71
+ if (isMounted.current) setLoading(false);
72
+ }
73
+ }}
74
+ {...rest}
75
+ />
76
+ );
77
+ }
@@ -39,6 +39,7 @@ import {
39
39
  } from '../notifier/Notifier';
40
40
  import { DraggablePaperComponent } from './DraggablePaperComponent';
41
41
  import { NotifierPromptProps } from './NotifierPromptProps';
42
+ import { LoadingButton } from './LoadingButton';
42
43
 
43
44
  // Custom icon dialog title bar
44
45
  const IconDialogTitle = styled(DialogTitle)`
@@ -220,12 +221,16 @@ export class NotificationMU extends NotificationReact {
220
221
  ...rest
221
222
  } = this.inputProps as NotifierPromptProps;
222
223
 
223
- const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
224
- event.preventDefault();
224
+ const handleSubmit = async (
225
+ event: React.MouseEvent<HTMLButtonElement>
226
+ ) => {
227
+ // Result
228
+ let result: boolean | void | PromiseLike<boolean | void> =
229
+ undefined;
225
230
 
226
231
  if (this.onReturn) {
227
232
  // Inputs case, no HTMLForm set to value, set the current form
228
- if (inputs && value == null) value = event.currentTarget;
233
+ if (inputs && value == null) value = event.currentTarget.form;
229
234
 
230
235
  if (inputRef.current) {
231
236
  if (type === 'date') {
@@ -234,29 +239,35 @@ export class NotificationMU extends NotificationReact {
234
239
  inputRef.current.focus();
235
240
  return;
236
241
  }
237
- if (this.onReturn(dateValue) === false) return;
242
+ result = this.onReturn(dateValue);
238
243
  } else if (type === 'number') {
239
244
  const numberValue = inputRef.current.valueAsNumber;
240
245
  if (isNaN(numberValue)) {
241
246
  inputRef.current.focus();
242
247
  return;
243
248
  }
244
- if (this.onReturn(numberValue) === false) return;
249
+ result = this.onReturn(numberValue);
245
250
  } else if (type === 'switch') {
246
251
  const boolValue = inputRef.current.value == 'true';
247
- if (this.onReturn(boolValue) === false) return;
252
+ result = this.onReturn(boolValue);
248
253
  } else {
249
- const textValue = inputRef.current.value;
250
- if (textValue) {
251
- if (this.onReturn(textValue) === false) return;
254
+ const textValue = inputRef.current.value.trim();
255
+ if (textValue === '') {
256
+ inputRef.current.focus();
257
+ return;
252
258
  }
253
- inputRef.current.focus();
259
+ result = this.onReturn(textValue);
254
260
  }
255
261
  } else if (value != null) {
256
- if (this.onReturn(value) === false) return;
262
+ result = this.onReturn(value);
257
263
  }
258
264
  }
259
265
 
266
+ // Get the value
267
+ // returns false to prevent default dismiss
268
+ const v = await result;
269
+ if (v === false) return;
270
+
260
271
  this.dismiss();
261
272
  };
262
273
 
@@ -264,10 +275,6 @@ export class NotificationMU extends NotificationReact {
264
275
  let inputRef = React.createRef<HTMLInputElement>();
265
276
  let value: any = undefined;
266
277
 
267
- let formChangeHandler:
268
- | React.FormEventHandler<HTMLFormElement>
269
- | undefined;
270
-
271
278
  if (inputs == null) {
272
279
  if (type === 'switch') {
273
280
  localInputs = (
@@ -293,9 +300,6 @@ export class NotificationMU extends NotificationReact {
293
300
  }
294
301
  } else {
295
302
  localInputs = inputs;
296
- formChangeHandler = (event) => {
297
- value = event.currentTarget;
298
- };
299
303
  }
300
304
 
301
305
  return (
@@ -305,7 +309,7 @@ export class NotificationMU extends NotificationReact {
305
309
  PaperComponent={DraggablePaperComponent}
306
310
  className={className}
307
311
  >
308
- <form onSubmit={handleSubmit} onChange={formChangeHandler}>
312
+ <form>
309
313
  <IconDialogTitle
310
314
  className={classes.iconTitle}
311
315
  id="draggable-dialog-title"
@@ -324,9 +328,13 @@ export class NotificationMU extends NotificationReact {
324
328
  >
325
329
  {cancelLabel}
326
330
  </Button>
327
- <Button type="submit" color="primary" autoFocus>
331
+ <LoadingButton
332
+ color="primary"
333
+ autoFocus
334
+ onClick={handleSubmit}
335
+ >
328
336
  {okLabel}
329
- </Button>
337
+ </LoadingButton>
330
338
  </DialogActions>
331
339
  </form>
332
340
  </Dialog>
@@ -20,6 +20,12 @@ export interface SearchBarProps {
20
20
  */
21
21
  fields: React.ReactElement[];
22
22
 
23
+ /**
24
+ * Inner height
25
+ * @default 40
26
+ */
27
+ innerHeight?: number;
28
+
23
29
  /**
24
30
  * On submit callback
25
31
  */
@@ -78,7 +84,7 @@ const setChildState = (child: Element, enabled: boolean) => {
78
84
  */
79
85
  export function SearchBar(props: SearchBarProps) {
80
86
  // Destruct
81
- const { className, fields, onSubmit } = props;
87
+ const { className, fields, innerHeight = 40, onSubmit } = props;
82
88
 
83
89
  // Labels
84
90
  const labels = Labels.CommonPage;
@@ -316,6 +322,7 @@ export function SearchBar(props: SearchBarProps) {
316
322
  alignItems="center"
317
323
  direction="row"
318
324
  spacing={1}
325
+ height={innerHeight}
319
326
  sx={{
320
327
  '& > :not(style)': {
321
328
  flexBasis: 'auto',
@@ -30,6 +30,7 @@ export function DataGridPage<T>(props: DataGridPageProps<T>) {
30
30
  height,
31
31
  loadData,
32
32
  mRef,
33
+ sizeReadyMiliseconds = 100,
33
34
  pageProps = {},
34
35
  ...rest
35
36
  } = props;
@@ -63,7 +64,7 @@ export function DataGridPage<T>(props: DataGridPageProps<T>) {
63
64
  };
64
65
 
65
66
  // Watch container
66
- const { dimensions } = useDimensions(1, undefined, 50);
67
+ const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
67
68
  const rect = dimensions[0][2];
68
69
 
69
70
  React.useEffect(() => {
@@ -30,6 +30,7 @@ export function FixedListPage<T>(
30
30
  fields,
31
31
  loadData,
32
32
  mRef,
33
+ sizeReadyMiliseconds = 100,
33
34
  pageProps = {},
34
35
  ...rest
35
36
  } = props;
@@ -74,7 +75,7 @@ export function FixedListPage<T>(
74
75
  };
75
76
 
76
77
  // Watch container
77
- const { dimensions } = useDimensions(1, undefined, 100);
78
+ const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
78
79
  const rect = dimensions[0][2];
79
80
  const list = React.useMemo(() => {
80
81
  if (rect != null && rect.height > 50) {
@@ -35,6 +35,7 @@ export function ResponsivePage<T>(props: ResponsePageProps<T>) {
35
35
  innerItemRenderer,
36
36
  itemSize,
37
37
  mRef,
38
+ sizeReadyMiliseconds = 100,
38
39
  pageProps = {},
39
40
  ...rest
40
41
  } = props;
@@ -68,7 +69,7 @@ export function ResponsivePage<T>(props: ResponsePageProps<T>) {
68
69
  };
69
70
 
70
71
  // Watch container
71
- const { dimensions } = useDimensions(1, undefined, 50);
72
+ const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
72
73
  const rect = dimensions[0][2];
73
74
  const showDataGrid = (rect?.width ?? 0) >= dataGridMinWidth;
74
75
 
@@ -19,4 +19,10 @@ export interface SearchPageProps<T> extends Omit<GridLoader<T>, 'loadData'> {
19
19
  * Page props
20
20
  */
21
21
  pageProps?: CommonPageProps;
22
+
23
+ /**
24
+ * Size ready to read miliseconds span
25
+ * @default 100
26
+ */
27
+ sizeReadyMiliseconds?: number;
22
28
  }
@@ -20,7 +20,15 @@ import { TablePageProps } from './TablePageProps';
20
20
  */
21
21
  export function TablePage<T>(props: TablePageProps<T>) {
22
22
  // Destruct
23
- const { columns, fields, loadData, mRef, pageProps = {}, ...rest } = props;
23
+ const {
24
+ columns,
25
+ fields,
26
+ loadData,
27
+ mRef,
28
+ sizeReadyMiliseconds = 100,
29
+ pageProps = {},
30
+ ...rest
31
+ } = props;
24
32
 
25
33
  pageProps.paddings ??= MUGlobal.pagePaddings;
26
34
 
@@ -66,7 +74,7 @@ export function TablePage<T>(props: TablePageProps<T>) {
66
74
  );
67
75
 
68
76
  // Watch container
69
- const { dimensions } = useDimensions(1, undefined, 100);
77
+ const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
70
78
  const rect = dimensions[0][2];
71
79
  const list = React.useMemo(() => {
72
80
  if (rect != null && rect.height > 50 && rect.width >= totalWidth) {