@etsoo/react 1.5.12 → 1.5.16

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.
Files changed (46) hide show
  1. package/lib/app/Labels.d.ts +1 -0
  2. package/lib/app/Labels.js +1 -0
  3. package/lib/app/ReactApp.d.ts +0 -13
  4. package/lib/app/ReactApp.js +6 -31
  5. package/lib/app/{Utils.d.ts → ReactUtils.d.ts} +7 -2
  6. package/lib/app/{Utils.js → ReactUtils.js} +20 -10
  7. package/lib/app/ServiceApp.d.ts +6 -5
  8. package/lib/app/ServiceApp.js +14 -7
  9. package/lib/index.d.ts +2 -1
  10. package/lib/index.js +2 -1
  11. package/lib/mu/BackButton.d.ts +13 -0
  12. package/lib/mu/BackButton.js +32 -0
  13. package/lib/mu/BridgeCloseButton.d.ts +5 -1
  14. package/lib/mu/BridgeCloseButton.js +5 -9
  15. package/lib/mu/ButtonLink.js +2 -2
  16. package/lib/mu/ComboBox.js +2 -2
  17. package/lib/mu/IconButtonLink.js +2 -2
  18. package/lib/mu/ResponsibleContainer.js +2 -2
  19. package/lib/mu/SearchBar.js +2 -2
  20. package/lib/mu/SelectEx.js +2 -2
  21. package/lib/mu/Tiplist.js +3 -3
  22. package/lib/mu/pages/CommonPage.js +4 -2
  23. package/lib/mu/pages/CommonPageProps.d.ts +5 -1
  24. package/lib/mu/pages/EditPage.d.ts +5 -0
  25. package/lib/mu/pages/EditPage.js +4 -2
  26. package/lib/mu/pages/ViewPage.d.ts +4 -0
  27. package/lib/mu/pages/ViewPage.js +13 -3
  28. package/package.json +2 -2
  29. package/src/app/Labels.ts +1 -0
  30. package/src/app/ReactApp.ts +9 -36
  31. package/src/app/{Utils.ts → ReactUtils.ts} +20 -4
  32. package/src/app/ServiceApp.ts +16 -7
  33. package/src/index.ts +2 -1
  34. package/src/mu/BackButton.tsx +53 -0
  35. package/src/mu/BridgeCloseButton.tsx +17 -16
  36. package/src/mu/ButtonLink.tsx +3 -2
  37. package/src/mu/ComboBox.tsx +2 -2
  38. package/src/mu/IconButtonLink.tsx +2 -2
  39. package/src/mu/ResponsibleContainer.tsx +2 -2
  40. package/src/mu/SearchBar.tsx +2 -2
  41. package/src/mu/SelectEx.tsx +2 -2
  42. package/src/mu/Tiplist.tsx +3 -3
  43. package/src/mu/pages/CommonPage.tsx +5 -0
  44. package/src/mu/pages/CommonPageProps.ts +6 -1
  45. package/src/mu/pages/EditPage.tsx +9 -0
  46. package/src/mu/pages/ViewPage.tsx +36 -1
@@ -8,6 +8,7 @@ export declare namespace Labels {
8
8
  */
9
9
  const CommonPage: {
10
10
  add: string;
11
+ back: string;
11
12
  delete: string;
12
13
  more: string;
13
14
  pullToRefresh: string;
package/lib/app/Labels.js CHANGED
@@ -9,6 +9,7 @@ export var Labels;
9
9
  */
10
10
  Labels.CommonPage = {
11
11
  add: 'Add',
12
+ back: 'Back',
12
13
  delete: 'Delete',
13
14
  more: 'More',
14
15
  pullToRefresh: 'Pull down to refresh',
@@ -108,19 +108,6 @@ export declare class ReactApp<S extends IAppSettings, D extends IUser, P extends
108
108
  * @param name Application name
109
109
  */
110
110
  constructor(settings: S, name: string);
111
- /**
112
- * Get parsed Url under bridge host
113
- * @param url Url
114
- * @returns Parsed Url
115
- */
116
- protected getHostUrl(url: string): string;
117
- /**
118
- * Get parsed Url under bridge host
119
- * @param url Url
120
- * @param name App name in the host environment
121
- * @returns Parsed Url
122
- */
123
- protected getHostUrlBase(url: string, name: string): string;
124
111
  /**
125
112
  * Override alert action result
126
113
  * @param result Action result
@@ -8,7 +8,7 @@ import { CultureState } from '../states/CultureState';
8
8
  import { PageActionType, PageState } from '../states/PageState';
9
9
  import { UserActionType, UserState } from '../states/UserState';
10
10
  import { Labels } from './Labels';
11
- import { Utils } from './Utils';
11
+ import { ReactUtils } from './ReactUtils';
12
12
  /**
13
13
  * Global application
14
14
  */
@@ -26,8 +26,8 @@ export function ReactAppStateDetector(props) {
26
26
  // Destruct
27
27
  const { targetFields, update } = props;
28
28
  // Context
29
- const { state } = globalApp == null
30
- ? { state: {} }
29
+ const { state = {} } = globalApp == null
30
+ ? {}
31
31
  : React.useContext(globalApp.userState.context);
32
32
  // Ready
33
33
  React.useEffect(() => {
@@ -66,9 +66,9 @@ export class ReactApp extends CoreApp {
66
66
  */
67
67
  this.userState = new UserState();
68
68
  this.history =
69
- window.location.hostname === ''
70
- ? Utils.getMemoryHistory(this.getHostUrl(window.location.href))
71
- : undefined;
69
+ BridgeUtils.host == null
70
+ ? undefined
71
+ : ReactUtils.getMemoryHistory(BridgeUtils.host.getStartUrl());
72
72
  this.cultureState = new CultureState(settings.currentCulture);
73
73
  this.pageState = new PageState();
74
74
  globalApp = this;
@@ -91,31 +91,6 @@ export class ReactApp extends CoreApp {
91
91
  ReactApp._notifierProvider = NotifierMU.setup();
92
92
  return NotifierMU.instance;
93
93
  }
94
- /**
95
- * Get parsed Url under bridge host
96
- * @param url Url
97
- * @returns Parsed Url
98
- */
99
- getHostUrl(url) {
100
- return this.getHostUrlBase(url, 'core');
101
- }
102
- /**
103
- * Get parsed Url under bridge host
104
- * @param url Url
105
- * @param name App name in the host environment
106
- * @returns Parsed Url
107
- */
108
- getHostUrlBase(url, name) {
109
- if (url.startsWith('/'))
110
- return url;
111
- const identifier = `/${name}/`;
112
- const pos = url.indexOf(identifier);
113
- if (pos === -1)
114
- return '/';
115
- return url
116
- .substring(pos + identifier.length - 1)
117
- .replace('/index.html', '/'); // Router take / as start
118
- }
119
94
  /**
120
95
  * Override alert action result
121
96
  * @param result Action result
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  /**
4
4
  * React utils
5
5
  */
6
- export declare namespace Utils {
6
+ export declare namespace ReactUtils {
7
7
  /**
8
8
  * Format input value
9
9
  * @param value Input value
@@ -15,7 +15,12 @@ export declare namespace Utils {
15
15
  * @param initialPath Initial path
16
16
  * @returns History
17
17
  */
18
- function getMemoryHistory(initialPath?: string): History;
18
+ function getMemoryHistory(initialPath?: string | null): History;
19
+ /**
20
+ * Get navigate function, works with memory history
21
+ * @returns NavigateFn
22
+ */
23
+ function getNavigateFn(): import("@reach/router").NavigateFn;
19
24
  /**
20
25
  * Is safe click
21
26
  * @param event Mouse event
@@ -1,9 +1,9 @@
1
- import { createHistory, createMemorySource } from '@reach/router';
1
+ import { createHistory, createMemorySource, navigate } from '@reach/router';
2
2
  /**
3
3
  * React utils
4
4
  */
5
- export var Utils;
6
- (function (Utils) {
5
+ export var ReactUtils;
6
+ (function (ReactUtils) {
7
7
  // Memory history
8
8
  // https://github.com/reach/router/issues/225
9
9
  let memoryHistory;
@@ -23,19 +23,29 @@ export var Utils;
23
23
  return value;
24
24
  return String(value);
25
25
  }
26
- Utils.formatInputValue = formatInputValue;
26
+ ReactUtils.formatInputValue = formatInputValue;
27
27
  /**
28
28
  * Get memory history
29
29
  * @param initialPath Initial path
30
30
  * @returns History
31
31
  */
32
- function getMemoryHistory(initialPath = '/') {
32
+ function getMemoryHistory(initialPath) {
33
33
  if (memoryHistory == null) {
34
- memoryHistory = createHistory(createMemorySource(initialPath));
34
+ memoryHistory = createHistory(createMemorySource(initialPath !== null && initialPath !== void 0 ? initialPath : '/'));
35
35
  }
36
36
  return memoryHistory;
37
37
  }
38
- Utils.getMemoryHistory = getMemoryHistory;
38
+ ReactUtils.getMemoryHistory = getMemoryHistory;
39
+ /**
40
+ * Get navigate function, works with memory history
41
+ * @returns NavigateFn
42
+ */
43
+ function getNavigateFn() {
44
+ if (memoryHistory == null)
45
+ return navigate;
46
+ return memoryHistory.navigate;
47
+ }
48
+ ReactUtils.getNavigateFn = getNavigateFn;
39
49
  /**
40
50
  * Is safe click
41
51
  * @param event Mouse event
@@ -61,7 +71,7 @@ export var Utils;
61
71
  }
62
72
  return true;
63
73
  }
64
- Utils.isSafeClick = isSafeClick;
74
+ ReactUtils.isSafeClick = isSafeClick;
65
75
  /**
66
76
  * Trigger input change event
67
77
  * @param input Form input
@@ -99,5 +109,5 @@ export var Utils;
99
109
  input.dispatchEvent(inputEvent);
100
110
  }
101
111
  }
102
- Utils.triggerChange = triggerChange;
103
- })(Utils || (Utils = {}));
112
+ ReactUtils.triggerChange = triggerChange;
113
+ })(ReactUtils || (ReactUtils = {}));
@@ -33,11 +33,9 @@ export declare class ServiceApp<U extends IServiceUser = IServiceUser, P extends
33
33
  */
34
34
  constructor(settings: S, name: string);
35
35
  /**
36
- * Get parsed Url under bridge host
37
- * @param url Url
38
- * @returns Parsed Url
36
+ * Load SmartERP core
39
37
  */
40
- protected getHostUrl(url: string): string;
38
+ loadSmartERP(): void;
41
39
  /**
42
40
  * Go to the login page
43
41
  * @param tryLogin Try to login again
@@ -66,8 +64,11 @@ export declare class ServiceApp<U extends IServiceUser = IServiceUser, P extends
66
64
  serviceEncrypt(message: string, passphrase?: string, iterations?: number): string;
67
65
  /**
68
66
  * Try login
67
+ * @param data Additional data
68
+ * @param showLoading Show loading bar or not
69
+ * @returns Result
69
70
  */
70
- tryLogin<D extends {} = {}>(data?: D): Promise<boolean>;
71
+ tryLogin<D extends {} = {}>(data?: D, showLoading?: boolean): Promise<boolean>;
71
72
  /**
72
73
  * User login extended
73
74
  * @param user Core system user
@@ -40,12 +40,15 @@ export class ServiceApp extends ReactApp {
40
40
  this._serviceUser = value;
41
41
  }
42
42
  /**
43
- * Get parsed Url under bridge host
44
- * @param url Url
45
- * @returns Parsed Url
43
+ * Load SmartERP core
46
44
  */
47
- getHostUrl(url) {
48
- return this.getHostUrlBase(url, 's' + this.settings.serviceId);
45
+ loadSmartERP() {
46
+ if (BridgeUtils.host == null) {
47
+ window.location.href = this.settings.webUrl;
48
+ }
49
+ else {
50
+ BridgeUtils.host.loadApp('core');
51
+ }
49
52
  }
50
53
  /**
51
54
  * Go to the login page
@@ -206,10 +209,13 @@ export class ServiceApp extends ReactApp {
206
209
  }
207
210
  /**
208
211
  * Try login
212
+ * @param data Additional data
213
+ * @param showLoading Show loading bar or not
214
+ * @returns Result
209
215
  */
210
- async tryLogin(data) {
216
+ async tryLogin(data, showLoading) {
211
217
  // Reset user state
212
- const result = await super.tryLogin(data);
218
+ const result = await super.tryLogin(data, showLoading);
213
219
  if (!result)
214
220
  return false;
215
221
  // Refresh token
@@ -228,6 +234,7 @@ export class ServiceApp extends ReactApp {
228
234
  });
229
235
  },
230
236
  data,
237
+ showLoading,
231
238
  relogin: true
232
239
  });
233
240
  }
package/lib/index.d.ts CHANGED
@@ -6,9 +6,9 @@ export * from './app/IServiceUser';
6
6
  export * from './app/ISmartERPUser';
7
7
  export * from './app/Labels';
8
8
  export * from './app/ReactApp';
9
+ export * from './app/ReactUtils';
9
10
  export * from './app/RefreshTokenRQ';
10
11
  export * from './app/ServiceApp';
11
- export * from './app/Utils';
12
12
  export * from './components/GridColumn';
13
13
  export * from './components/GridLoader';
14
14
  export * from './components/ListItemReact';
@@ -31,6 +31,7 @@ export * from './mu/texts/DateText';
31
31
  export * from './mu/texts/MoneyText';
32
32
  export * from './mu/texts/NumberText';
33
33
  export * from './mu/AuditDisplay';
34
+ export * from './mu/BackButton';
34
35
  export * from './mu/BridgeCloseButton';
35
36
  export * from './mu/ButtonLink';
36
37
  export * from './mu/ComboBox';
package/lib/index.js CHANGED
@@ -7,9 +7,9 @@ export * from './app/IServiceUser';
7
7
  export * from './app/ISmartERPUser';
8
8
  export * from './app/Labels';
9
9
  export * from './app/ReactApp';
10
+ export * from './app/ReactUtils';
10
11
  export * from './app/RefreshTokenRQ';
11
12
  export * from './app/ServiceApp';
12
- export * from './app/Utils';
13
13
  // components
14
14
  export * from './components/GridColumn';
15
15
  export * from './components/GridLoader';
@@ -34,6 +34,7 @@ export * from './mu/texts/DateText';
34
34
  export * from './mu/texts/MoneyText';
35
35
  export * from './mu/texts/NumberText';
36
36
  export * from './mu/AuditDisplay';
37
+ export * from './mu/BackButton';
37
38
  export * from './mu/BridgeCloseButton';
38
39
  export * from './mu/ButtonLink';
39
40
  export * from './mu/ComboBox';
@@ -0,0 +1,13 @@
1
+ /// <reference types="react" />
2
+ import { IconButtonProps } from '@mui/material';
3
+ /**
4
+ * BackButton props
5
+ */
6
+ export interface BackButtonProps extends IconButtonProps {
7
+ }
8
+ /**
9
+ * BackButton
10
+ * @param props Props
11
+ * @returns Component
12
+ */
13
+ export declare function BackButton(props: BackButtonProps): JSX.Element;
@@ -0,0 +1,32 @@
1
+ import { IconButton, useTheme } from '@mui/material';
2
+ import ArrowBackIcon from '@mui/icons-material/ArrowBack';
3
+ import React from 'react';
4
+ import { ReactUtils } from '../app/ReactUtils';
5
+ /**
6
+ * BackButton
7
+ * @param props Props
8
+ * @returns Component
9
+ */
10
+ export function BackButton(props) {
11
+ // Destruct
12
+ const { color = 'primary', size = 'small', onClick, ...rest } = props;
13
+ // Navigate
14
+ const navigate = ReactUtils.getNavigateFn();
15
+ // Theme
16
+ const theme = useTheme();
17
+ // Color
18
+ const pColor = color != 'inherit' && color != 'default' && color in theme.palette
19
+ ? theme.palette[color]
20
+ : theme.palette.primary;
21
+ // Click handler
22
+ const onClickLocal = (event) => {
23
+ if (onClick)
24
+ onClick(event);
25
+ navigate(-1);
26
+ };
27
+ return (React.createElement(IconButton, { "aria-label": "Back", color: color, size: size, onClick: onClickLocal, sx: {
28
+ backgroundColor: pColor.contrastText,
29
+ border: `1px solid ${pColor.light}`
30
+ }, ...rest },
31
+ React.createElement(ArrowBackIcon, null)));
32
+ }
@@ -1,10 +1,14 @@
1
1
  /// <reference types="react" />
2
2
  import { IBridgeHost } from '@etsoo/appscript';
3
- import { IconButtonProps } from '@mui/material';
3
+ import { BoxProps, IconButtonProps } from '@mui/material';
4
4
  /**
5
5
  * Bridge close button props
6
6
  */
7
7
  export interface BridgeCloseButtonProps extends IconButtonProps {
8
+ /**
9
+ * Box props
10
+ */
11
+ boxProps?: BoxProps;
8
12
  /**
9
13
  * Validate the host
10
14
  * @param host Host
@@ -1,6 +1,6 @@
1
1
  import { BridgeUtils } from '@etsoo/appscript';
2
2
  import CloseIcon from '@mui/icons-material/Close';
3
- import { IconButton } from '@mui/material';
3
+ import { Box, IconButton } from '@mui/material';
4
4
  import React from 'react';
5
5
  import { globalApp } from '../app/ReactApp';
6
6
  /**
@@ -10,7 +10,7 @@ import { globalApp } from '../app/ReactApp';
10
10
  */
11
11
  export function BridgeCloseButton(props) {
12
12
  // Destruct
13
- const { onClick, title = typeof globalApp === 'undefined'
13
+ const { boxProps, onClick, title = typeof globalApp === 'undefined'
14
14
  ? 'Close'
15
15
  : globalApp.get('close'), validate, ...rest } = props;
16
16
  // Host
@@ -24,11 +24,7 @@ export function BridgeCloseButton(props) {
24
24
  onClick(event);
25
25
  host.exit();
26
26
  };
27
- return (React.createElement(IconButton, { "aria-label": "close", color: "secondary", onClick: onClickLocal, title: title, sx: {
28
- position: 'absolute',
29
- zIndex: (theme) => theme.zIndex.appBar + 1,
30
- top: (theme) => theme.spacing(0.5),
31
- right: (theme) => theme.spacing(0.5)
32
- }, ...rest },
33
- React.createElement(CloseIcon, null)));
27
+ return (React.createElement(Box, { ...boxProps },
28
+ React.createElement(IconButton, { "aria-label": "close", onClick: onClickLocal, title: title, ...rest },
29
+ React.createElement(CloseIcon, null))));
34
30
  }
@@ -1,6 +1,6 @@
1
1
  import { Button } from '@mui/material';
2
- import { useNavigate } from '@reach/router';
3
2
  import React from 'react';
3
+ import { ReactUtils } from '../app/ReactUtils';
4
4
  /**
5
5
  * ButtonLink
6
6
  * @param props Props
@@ -10,7 +10,7 @@ export function ButtonLink(props) {
10
10
  // Destruct
11
11
  const { href, ...rest } = props;
12
12
  // Navigate
13
- const navigate = useNavigate();
13
+ const navigate = ReactUtils.getNavigateFn();
14
14
  const onClick = href.includes('://')
15
15
  ? () => window.open(href, '_blank')
16
16
  : () => navigate(href);
@@ -1,10 +1,10 @@
1
1
  import { Keyboard } from '@etsoo/shared';
2
2
  import { Autocomplete } from '@mui/material';
3
3
  import React from 'react';
4
- import { Utils } from '../app/Utils';
5
4
  import { Utils as SharedUtils } from '@etsoo/shared';
6
5
  import { InputField } from './InputField';
7
6
  import { SearchField } from './SearchField';
7
+ import { ReactUtils } from '../app/ReactUtils';
8
8
  /**
9
9
  * ComboBox
10
10
  * @param props Props
@@ -71,7 +71,7 @@ export function ComboBox(props) {
71
71
  const newValue = value != null ? `${Reflect.get(value, idField)}` : '';
72
72
  if (newValue !== input.value) {
73
73
  // Different value, trigger change event
74
- Utils.triggerChange(input, newValue, false);
74
+ ReactUtils.triggerChange(input, newValue, false);
75
75
  }
76
76
  }
77
77
  };
@@ -1,6 +1,6 @@
1
1
  import { IconButton } from '@mui/material';
2
- import { useNavigate } from '@reach/router';
3
2
  import React from 'react';
3
+ import { ReactUtils } from '../app/ReactUtils';
4
4
  /**
5
5
  * IconButtonLink
6
6
  * @param props Props
@@ -10,7 +10,7 @@ export function IconButtonLink(props) {
10
10
  // Destruct
11
11
  const { href, ...rest } = props;
12
12
  // Navigate
13
- const navigate = useNavigate();
13
+ const navigate = ReactUtils.getNavigateFn();
14
14
  // Layout
15
15
  return React.createElement(IconButton, { ...rest, onClick: () => navigate(href) });
16
16
  }
@@ -1,7 +1,7 @@
1
1
  import { Box, Stack } from '@mui/material';
2
2
  import React from 'react';
3
3
  import { Labels } from '../app/Labels';
4
- import { Utils } from '../app/Utils';
4
+ import { ReactUtils } from '../app/ReactUtils';
5
5
  import { GridDataGet } from '../components/GridLoader';
6
6
  import useCombinedRefs from '../uses/useCombinedRefs';
7
7
  import { useDimensions } from '../uses/useDimensions';
@@ -126,7 +126,7 @@ export function ResponsibleContainer(props) {
126
126
  return [
127
127
  React.createElement(Box, { className: "ListBox", sx: { height: heightLocal } },
128
128
  React.createElement(ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, mRef: mRefs, onClick: (event, data) => quickAction &&
129
- Utils.isSafeClick(event) &&
129
+ ReactUtils.isSafeClick(event) &&
130
130
  quickAction(data), oRef: (element) => {
131
131
  if (element != null && elementReady)
132
132
  elementReady(element, false);
@@ -2,9 +2,9 @@ import { Button, Drawer, IconButton, Stack, useTheme } from '@mui/material';
2
2
  import React from 'react';
3
3
  import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
4
4
  import { useDimensions } from '../uses/useDimensions';
5
- import { Utils as AppUtils } from '../app/Utils';
6
5
  import { DomUtils } from '@etsoo/shared';
7
6
  import { Labels } from '../app/Labels';
7
+ import { ReactUtils } from '../app/ReactUtils';
8
8
  // Cached width attribute name
9
9
  const cachedWidthName = 'data-cached-width';
10
10
  // Reset form
@@ -20,7 +20,7 @@ const resetForm = (form) => {
20
20
  continue;
21
21
  // Ignore readOnly without data-reset=true inputs
22
22
  if (!input.readOnly || input.dataset.reset === 'true') {
23
- AppUtils.triggerChange(input, '', true);
23
+ ReactUtils.triggerChange(input, '', true);
24
24
  }
25
25
  continue;
26
26
  }
@@ -1,9 +1,9 @@
1
- import { Utils as AppUtils } from '../app/Utils';
2
1
  import { Checkbox, FormControl, InputLabel, ListItemText, MenuItem, OutlinedInput, Select } from '@mui/material';
3
2
  import React from 'react';
4
3
  import { MUGlobal } from './MUGlobal';
5
4
  import { ListItemRightIcon } from './ListItemRightIcon';
6
5
  import { Utils } from '@etsoo/shared';
6
+ import { ReactUtils } from '../app/ReactUtils';
7
7
  /**
8
8
  * Extended select component
9
9
  * @param props Props
@@ -65,7 +65,7 @@ export function SelectEx(props) {
65
65
  const input = (_a = divRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('input');
66
66
  if (input) {
67
67
  // Different value, trigger change event
68
- AppUtils.triggerChange(input, id, false);
68
+ ReactUtils.triggerChange(input, id, false);
69
69
  }
70
70
  }
71
71
  };
package/lib/mu/Tiplist.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { DataTypes } from '@etsoo/shared';
2
2
  import { Autocomplete } from '@mui/material';
3
3
  import React from 'react';
4
- import { Utils } from '../app/Utils';
4
+ import { ReactUtils } from '../app/ReactUtils';
5
5
  import { InputField } from './InputField';
6
6
  import { SearchField } from './SearchField';
7
7
  /**
@@ -75,7 +75,7 @@ export function Tiplist(props) {
75
75
  const input = inputRef.current;
76
76
  if (input && input.value !== '') {
77
77
  // Different value, trigger change event
78
- Utils.triggerChange(input, '', false);
78
+ ReactUtils.triggerChange(input, '', false);
79
79
  }
80
80
  if (states.options.length > 0) {
81
81
  // Reset options
@@ -106,7 +106,7 @@ export function Tiplist(props) {
106
106
  const newValue = (_a = DataTypes.getStringValue(value, idField)) !== null && _a !== void 0 ? _a : '';
107
107
  if (newValue !== input.value) {
108
108
  // Different value, trigger change event
109
- Utils.triggerChange(input, newValue, false);
109
+ ReactUtils.triggerChange(input, newValue, false);
110
110
  }
111
111
  }
112
112
  };
@@ -7,6 +7,7 @@ import { MoreFab } from '../MoreFab';
7
7
  import { ReactAppStateDetector } from '../../app/ReactApp';
8
8
  import { Container, Fab } from '@mui/material';
9
9
  import RefreshIcon from '@mui/icons-material/Refresh';
10
+ import { BackButton } from '../BackButton';
10
11
  /**
11
12
  * Default scroll container
12
13
  */
@@ -17,7 +18,7 @@ export const CommonPageScrollContainer = global;
17
18
  */
18
19
  export function CommonPage(props) {
19
20
  // Destruct
20
- const { children, disableGutters = true, fabButtons, fabColumnDirection, fabPaddingAdjust = 1.5, fabSize = 'small', maxWidth = false, moreActions, onRefresh, onUpdate, onUpdateAll, paddings = MUGlobal.pagePaddings, scrollContainer, targetFields, sx = {}, ...rest } = props;
21
+ const { children, disableGutters = true, fabButtons, fabColumnDirection, fabPaddingAdjust = 1.5, fabSize = 'small', maxWidth = false, moreActions, onRefresh, onUpdate, onUpdateAll, paddings = MUGlobal.pagePaddings, scrollContainer, supportBack = false, targetFields, sx = {}, ...rest } = props;
21
22
  // Merge style
22
23
  Object.assign(sx, {
23
24
  padding: paddings
@@ -53,6 +54,7 @@ export function CommonPage(props) {
53
54
  fabButtons,
54
55
  onRefresh != null && (React.createElement(Fab, { title: labels.refresh, size: fabSize, onClick: onRefresh, sx: { display: { xs: 'none', md: 'inherit' } } },
55
56
  React.createElement(RefreshIcon, null))),
56
- React.createElement(MoreFab, { size: fabSize, title: labels.more, actions: moreActions })),
57
+ React.createElement(MoreFab, { size: fabSize, title: labels.more, actions: moreActions }),
58
+ supportBack && (React.createElement(BackButton, { title: labels.back, size: fabSize }))),
57
59
  children)));
58
60
  }
@@ -18,7 +18,7 @@ export interface CommonPageProps extends Omit<ContainerProps, 'id'> {
18
18
  */
19
19
  fabSize?: CustomFabSize;
20
20
  /**
21
- * Fab flex column direction?
21
+ * Fab flex column direction, undefined to hide it
22
22
  */
23
23
  fabColumnDirection?: boolean;
24
24
  /**
@@ -49,6 +49,10 @@ export interface CommonPageProps extends Omit<ContainerProps, 'id'> {
49
49
  * Scroll container
50
50
  */
51
51
  scrollContainer?: HTMLElement | object;
52
+ /**
53
+ * Support back click
54
+ */
55
+ supportBack?: boolean;
52
56
  /**
53
57
  * State last changed fields
54
58
  */
@@ -16,6 +16,11 @@ export interface EditPageProps extends Omit<CommonPageProps, 'onSubmit'> {
16
16
  * On delete callback
17
17
  */
18
18
  onDelete?: () => Promise<void> | void;
19
+ /**
20
+ * Support back click
21
+ * @default true
22
+ */
23
+ supportBack?: boolean;
19
24
  }
20
25
  /**
21
26
  * Add / Edit page
@@ -5,13 +5,14 @@ import { MUGlobal } from '../MUGlobal';
5
5
  import { CommonPage, CommonPageScrollContainer } from './CommonPage';
6
6
  import SaveIcon from '@mui/icons-material/Save';
7
7
  import DeleteIcon from '@mui/icons-material/Delete';
8
+ import { BackButton } from '../BackButton';
8
9
  /**
9
10
  * Add / Edit page
10
11
  * @param props Props
11
12
  */
12
13
  export function EditPage(props) {
13
14
  // Destruct
14
- const { children, isEditing, onDelete, onSubmit, paddings = MUGlobal.pagePaddings, scrollContainer = CommonPageScrollContainer, ...rest } = props;
15
+ const { children, isEditing, onDelete, onSubmit, paddings = MUGlobal.pagePaddings, scrollContainer = CommonPageScrollContainer, supportBack = true, ...rest } = props;
15
16
  // Labels
16
17
  const labels = Labels.CommonPage;
17
18
  return (React.createElement(CommonPage, { paddings: paddings, scrollContainer: scrollContainer, ...rest },
@@ -23,5 +24,6 @@ export function EditPage(props) {
23
24
  paddingTop: paddings
24
25
  } },
25
26
  isEditing && onDelete && (React.createElement(Button, { color: "primary", variant: "outlined", onClick: () => onDelete(), startIcon: React.createElement(DeleteIcon, { color: "warning" }) }, labels.delete)),
26
- React.createElement(Button, { variant: "contained", type: "submit", startIcon: React.createElement(SaveIcon, null), sx: { flexGrow: 1 } }, labels.save)))));
27
+ React.createElement(Button, { variant: "contained", type: "submit", startIcon: React.createElement(SaveIcon, null), sx: { flexGrow: 1 } }, labels.save),
28
+ supportBack && React.createElement(BackButton, { title: labels.back })))));
27
29
  }
@@ -48,6 +48,10 @@ export interface ViewPageProps<T extends {}> extends Exclude<CommonPageProps, 'c
48
48
  * Load data
49
49
  */
50
50
  loadData: () => PromiseLike<T | undefined>;
51
+ /**
52
+ * Pull to refresh data
53
+ */
54
+ pullToRefresh?: boolean;
51
55
  /**
52
56
  * Support refresh
53
57
  */