@etsoo/react 1.5.80 → 1.5.83

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 (259) hide show
  1. package/README.md +7 -2
  2. package/__tests__/ReactUtils.ts +6 -0
  3. package/lib/{mu → components}/DnDList.d.ts +1 -14
  4. package/lib/{mu → components}/DnDList.js +1 -24
  5. package/lib/components/GridMethodRef.d.ts +11 -0
  6. package/lib/{mu → components}/GridMethodRef.js +0 -0
  7. package/lib/components/ScrollerGrid.d.ts +3 -3
  8. package/lib/components/ScrollerList.d.ts +3 -3
  9. package/lib/index.d.ts +2 -74
  10. package/lib/index.js +2 -75
  11. package/lib/notifier/Notifier.d.ts +2 -3
  12. package/lib/states/UserState.d.ts +1 -1
  13. package/lib/uses/useWindowScroll.d.ts +10 -0
  14. package/lib/uses/useWindowScroll.js +46 -0
  15. package/lib/uses/useWindowSize.js +11 -5
  16. package/package.json +4 -16
  17. package/src/{mu → components}/DnDList.tsx +11 -34
  18. package/src/components/GridMethodRef.ts +12 -0
  19. package/src/components/ScrollerGrid.tsx +3 -3
  20. package/src/components/ScrollerList.tsx +5 -3
  21. package/src/index.ts +2 -78
  22. package/src/notifier/Notifier.ts +2 -3
  23. package/src/states/UserState.ts +7 -2
  24. package/src/uses/useWindowScroll.ts +60 -0
  25. package/src/uses/useWindowSize.ts +14 -5
  26. package/__tests__/mu/ComboBox.tsx +0 -30
  27. package/__tests__/mu/MUGlobalTests.tsx +0 -58
  28. package/__tests__/mu/NotifierMUTests.tsx +0 -213
  29. package/__tests__/mu/SelectEx.tsx +0 -26
  30. package/lib/app/CommonApp.d.ts +0 -39
  31. package/lib/app/CommonApp.js +0 -149
  32. package/lib/app/IServiceAppSettings.d.ts +0 -11
  33. package/lib/app/IServiceAppSettings.js +0 -1
  34. package/lib/app/IServicePage.d.ts +0 -6
  35. package/lib/app/IServicePage.js +0 -1
  36. package/lib/app/IServiceUser.d.ts +0 -14
  37. package/lib/app/IServiceUser.js +0 -1
  38. package/lib/app/ISmartERPUser.d.ts +0 -14
  39. package/lib/app/ISmartERPUser.js +0 -1
  40. package/lib/app/Labels.d.ts +0 -65
  41. package/lib/app/Labels.js +0 -62
  42. package/lib/app/ReactApp.d.ts +0 -194
  43. package/lib/app/ReactApp.js +0 -298
  44. package/lib/app/ServiceApp.d.ts +0 -78
  45. package/lib/app/ServiceApp.js +0 -244
  46. package/lib/components/ShowDataComparison.d.ts +0 -20
  47. package/lib/components/ShowDataComparison.js +0 -60
  48. package/lib/mu/AuditDisplay.d.ts +0 -33
  49. package/lib/mu/AuditDisplay.js +0 -52
  50. package/lib/mu/AutocompleteExtendedProps.d.ts +0 -64
  51. package/lib/mu/AutocompleteExtendedProps.js +0 -1
  52. package/lib/mu/BackButton.d.ts +0 -13
  53. package/lib/mu/BackButton.js +0 -33
  54. package/lib/mu/BridgeCloseButton.d.ts +0 -23
  55. package/lib/mu/BridgeCloseButton.js +0 -32
  56. package/lib/mu/ButtonLink.d.ts +0 -17
  57. package/lib/mu/ButtonLink.js +0 -19
  58. package/lib/mu/ComboBox.d.ts +0 -38
  59. package/lib/mu/ComboBox.js +0 -108
  60. package/lib/mu/CountdownButton.d.ts +0 -23
  61. package/lib/mu/CountdownButton.js +0 -81
  62. package/lib/mu/CustomFabProps.d.ts +0 -27
  63. package/lib/mu/CustomFabProps.js +0 -1
  64. package/lib/mu/DataGridEx.d.ts +0 -96
  65. package/lib/mu/DataGridEx.js +0 -331
  66. package/lib/mu/DataGridRenderers.d.ts +0 -22
  67. package/lib/mu/DataGridRenderers.js +0 -99
  68. package/lib/mu/DialogButton.d.ts +0 -54
  69. package/lib/mu/DialogButton.js +0 -45
  70. package/lib/mu/DraggablePaperComponent.d.ts +0 -8
  71. package/lib/mu/DraggablePaperComponent.js +0 -12
  72. package/lib/mu/EmailInput.d.ts +0 -11
  73. package/lib/mu/EmailInput.js +0 -15
  74. package/lib/mu/FabBox.d.ts +0 -21
  75. package/lib/mu/FabBox.js +0 -31
  76. package/lib/mu/FlexBox.d.ts +0 -14
  77. package/lib/mu/FlexBox.js +0 -18
  78. package/lib/mu/GridDataFormat.d.ts +0 -10
  79. package/lib/mu/GridDataFormat.js +0 -43
  80. package/lib/mu/GridMethodRef.d.ts +0 -11
  81. package/lib/mu/IconButtonLink.d.ts +0 -17
  82. package/lib/mu/IconButtonLink.js +0 -16
  83. package/lib/mu/InputField.d.ts +0 -21
  84. package/lib/mu/InputField.js +0 -39
  85. package/lib/mu/ItemList.d.ts +0 -56
  86. package/lib/mu/ItemList.js +0 -69
  87. package/lib/mu/ListItemRightIcon.d.ts +0 -4
  88. package/lib/mu/ListItemRightIcon.js +0 -8
  89. package/lib/mu/ListMoreDisplay.d.ts +0 -35
  90. package/lib/mu/ListMoreDisplay.js +0 -99
  91. package/lib/mu/LoadingButton.d.ts +0 -16
  92. package/lib/mu/LoadingButton.js +0 -41
  93. package/lib/mu/MUGlobal.d.ts +0 -102
  94. package/lib/mu/MUGlobal.js +0 -184
  95. package/lib/mu/MaskInput.d.ts +0 -34
  96. package/lib/mu/MaskInput.js +0 -43
  97. package/lib/mu/MobileListItemRenderer.d.ts +0 -17
  98. package/lib/mu/MobileListItemRenderer.js +0 -35
  99. package/lib/mu/MoreFab.d.ts +0 -45
  100. package/lib/mu/MoreFab.js +0 -95
  101. package/lib/mu/NotifierMU.d.ts +0 -47
  102. package/lib/mu/NotifierMU.js +0 -387
  103. package/lib/mu/NotifierPromptProps.d.ts +0 -22
  104. package/lib/mu/NotifierPromptProps.js +0 -1
  105. package/lib/mu/OptionGroup.d.ts +0 -58
  106. package/lib/mu/OptionGroup.js +0 -81
  107. package/lib/mu/PList.d.ts +0 -15
  108. package/lib/mu/PList.js +0 -12
  109. package/lib/mu/ProgressCount.d.ts +0 -44
  110. package/lib/mu/ProgressCount.js +0 -79
  111. package/lib/mu/PullToRefreshUI.d.ts +0 -9
  112. package/lib/mu/PullToRefreshUI.js +0 -18
  113. package/lib/mu/RLink.d.ts +0 -14
  114. package/lib/mu/RLink.js +0 -37
  115. package/lib/mu/ResponsibleContainer.d.ts +0 -89
  116. package/lib/mu/ResponsibleContainer.js +0 -159
  117. package/lib/mu/ScrollTopFab.d.ts +0 -7
  118. package/lib/mu/ScrollTopFab.js +0 -25
  119. package/lib/mu/ScrollerListEx.d.ts +0 -81
  120. package/lib/mu/ScrollerListEx.js +0 -167
  121. package/lib/mu/SearchBar.d.ts +0 -29
  122. package/lib/mu/SearchBar.js +0 -262
  123. package/lib/mu/SearchField.d.ts +0 -21
  124. package/lib/mu/SearchField.js +0 -39
  125. package/lib/mu/SearchOptionGroup.d.ts +0 -9
  126. package/lib/mu/SearchOptionGroup.js +0 -14
  127. package/lib/mu/SelectBool.d.ts +0 -13
  128. package/lib/mu/SelectBool.js +0 -22
  129. package/lib/mu/SelectEx.d.ts +0 -50
  130. package/lib/mu/SelectEx.js +0 -156
  131. package/lib/mu/Switch.d.ts +0 -29
  132. package/lib/mu/Switch.js +0 -34
  133. package/lib/mu/SwitchAnt.d.ts +0 -25
  134. package/lib/mu/SwitchAnt.js +0 -40
  135. package/lib/mu/TabBox.d.ts +0 -54
  136. package/lib/mu/TabBox.js +0 -31
  137. package/lib/mu/TableEx.d.ts +0 -66
  138. package/lib/mu/TableEx.js +0 -271
  139. package/lib/mu/TextFieldEx.d.ts +0 -101
  140. package/lib/mu/TextFieldEx.js +0 -127
  141. package/lib/mu/Tiplist.d.ts +0 -18
  142. package/lib/mu/Tiplist.js +0 -158
  143. package/lib/mu/TooltipClick.d.ts +0 -15
  144. package/lib/mu/TooltipClick.js +0 -40
  145. package/lib/mu/UserAvatar.d.ts +0 -24
  146. package/lib/mu/UserAvatar.js +0 -25
  147. package/lib/mu/UserAvatarEditor.d.ts +0 -53
  148. package/lib/mu/UserAvatarEditor.js +0 -129
  149. package/lib/mu/pages/CommonPage.d.ts +0 -11
  150. package/lib/mu/pages/CommonPage.js +0 -60
  151. package/lib/mu/pages/CommonPageProps.d.ts +0 -60
  152. package/lib/mu/pages/CommonPageProps.js +0 -1
  153. package/lib/mu/pages/DataGridPage.d.ts +0 -9
  154. package/lib/mu/pages/DataGridPage.js +0 -81
  155. package/lib/mu/pages/DataGridPageProps.d.ts +0 -17
  156. package/lib/mu/pages/DataGridPageProps.js +0 -1
  157. package/lib/mu/pages/EditPage.d.ts +0 -33
  158. package/lib/mu/pages/EditPage.js +0 -29
  159. package/lib/mu/pages/FixedListPage.d.ts +0 -15
  160. package/lib/mu/pages/FixedListPage.js +0 -72
  161. package/lib/mu/pages/ListPage.d.ts +0 -9
  162. package/lib/mu/pages/ListPage.js +0 -51
  163. package/lib/mu/pages/ListPageProps.d.ts +0 -7
  164. package/lib/mu/pages/ListPageProps.js +0 -1
  165. package/lib/mu/pages/ResponsivePage.d.ts +0 -9
  166. package/lib/mu/pages/ResponsivePage.js +0 -45
  167. package/lib/mu/pages/ResponsivePageProps.d.ts +0 -39
  168. package/lib/mu/pages/ResponsivePageProps.js +0 -1
  169. package/lib/mu/pages/SearchPageProps.d.ts +0 -30
  170. package/lib/mu/pages/SearchPageProps.js +0 -1
  171. package/lib/mu/pages/TablePage.d.ts +0 -9
  172. package/lib/mu/pages/TablePage.js +0 -71
  173. package/lib/mu/pages/TablePageProps.d.ts +0 -7
  174. package/lib/mu/pages/TablePageProps.js +0 -1
  175. package/lib/mu/pages/ViewPage.d.ts +0 -66
  176. package/lib/mu/pages/ViewPage.js +0 -105
  177. package/lib/mu/texts/DateText.d.ts +0 -34
  178. package/lib/mu/texts/DateText.js +0 -25
  179. package/lib/mu/texts/MoneyText.d.ts +0 -21
  180. package/lib/mu/texts/MoneyText.js +0 -14
  181. package/lib/mu/texts/NumberText.d.ts +0 -25
  182. package/lib/mu/texts/NumberText.js +0 -14
  183. package/src/app/CommonApp.ts +0 -225
  184. package/src/app/IServiceAppSettings.ts +0 -13
  185. package/src/app/IServicePage.ts +0 -6
  186. package/src/app/IServiceUser.ts +0 -17
  187. package/src/app/ISmartERPUser.ts +0 -16
  188. package/src/app/Labels.ts +0 -77
  189. package/src/app/ReactApp.ts +0 -500
  190. package/src/app/ServiceApp.ts +0 -353
  191. package/src/components/ShowDataComparison.tsx +0 -108
  192. package/src/mu/AuditDisplay.tsx +0 -117
  193. package/src/mu/AutocompleteExtendedProps.ts +0 -83
  194. package/src/mu/BackButton.tsx +0 -55
  195. package/src/mu/BridgeCloseButton.tsx +0 -69
  196. package/src/mu/ButtonLink.tsx +0 -32
  197. package/src/mu/ComboBox.tsx +0 -251
  198. package/src/mu/CountdownButton.tsx +0 -119
  199. package/src/mu/CustomFabProps.ts +0 -32
  200. package/src/mu/DataGridEx.tsx +0 -712
  201. package/src/mu/DataGridRenderers.tsx +0 -140
  202. package/src/mu/DialogButton.tsx +0 -163
  203. package/src/mu/DraggablePaperComponent.tsx +0 -19
  204. package/src/mu/EmailInput.tsx +0 -24
  205. package/src/mu/FabBox.tsx +0 -51
  206. package/src/mu/FlexBox.tsx +0 -20
  207. package/src/mu/GridDataFormat.tsx +0 -77
  208. package/src/mu/GridMethodRef.ts +0 -12
  209. package/src/mu/IconButtonLink.tsx +0 -29
  210. package/src/mu/InputField.tsx +0 -82
  211. package/src/mu/ItemList.tsx +0 -204
  212. package/src/mu/ListItemRightIcon.tsx +0 -9
  213. package/src/mu/ListMoreDisplay.tsx +0 -205
  214. package/src/mu/LoadingButton.tsx +0 -75
  215. package/src/mu/MUGlobal.ts +0 -220
  216. package/src/mu/MaskInput.tsx +0 -107
  217. package/src/mu/MobileListItemRenderer.tsx +0 -79
  218. package/src/mu/MoreFab.tsx +0 -211
  219. package/src/mu/NotifierMU.tsx +0 -654
  220. package/src/mu/NotifierPromptProps.ts +0 -26
  221. package/src/mu/OptionGroup.tsx +0 -223
  222. package/src/mu/PList.tsx +0 -27
  223. package/src/mu/ProgressCount.tsx +0 -166
  224. package/src/mu/PullToRefreshUI.tsx +0 -21
  225. package/src/mu/RLink.tsx +0 -64
  226. package/src/mu/ResponsibleContainer.tsx +0 -394
  227. package/src/mu/ScrollTopFab.tsx +0 -34
  228. package/src/mu/ScrollerListEx.tsx +0 -387
  229. package/src/mu/SearchBar.tsx +0 -398
  230. package/src/mu/SearchField.tsx +0 -82
  231. package/src/mu/SearchOptionGroup.tsx +0 -31
  232. package/src/mu/SelectBool.tsx +0 -33
  233. package/src/mu/SelectEx.tsx +0 -290
  234. package/src/mu/Switch.tsx +0 -94
  235. package/src/mu/SwitchAnt.tsx +0 -95
  236. package/src/mu/TabBox.tsx +0 -118
  237. package/src/mu/TableEx.tsx +0 -560
  238. package/src/mu/TextFieldEx.tsx +0 -250
  239. package/src/mu/Tiplist.tsx +0 -304
  240. package/src/mu/TooltipClick.tsx +0 -84
  241. package/src/mu/UserAvatar.tsx +0 -64
  242. package/src/mu/UserAvatarEditor.tsx +0 -287
  243. package/src/mu/pages/CommonPage.tsx +0 -128
  244. package/src/mu/pages/CommonPageProps.ts +0 -71
  245. package/src/mu/pages/DataGridPage.tsx +0 -137
  246. package/src/mu/pages/DataGridPageProps.ts +0 -24
  247. package/src/mu/pages/EditPage.tsx +0 -114
  248. package/src/mu/pages/FixedListPage.tsx +0 -135
  249. package/src/mu/pages/ListPage.tsx +0 -87
  250. package/src/mu/pages/ListPageProps.ts +0 -12
  251. package/src/mu/pages/ResponsivePage.tsx +0 -68
  252. package/src/mu/pages/ResponsivePageProps.ts +0 -57
  253. package/src/mu/pages/SearchPageProps.ts +0 -39
  254. package/src/mu/pages/TablePage.tsx +0 -120
  255. package/src/mu/pages/TablePageProps.ts +0 -12
  256. package/src/mu/pages/ViewPage.tsx +0 -285
  257. package/src/mu/texts/DateText.tsx +0 -74
  258. package/src/mu/texts/MoneyText.tsx +0 -49
  259. package/src/mu/texts/NumberText.tsx +0 -40
@@ -1,250 +0,0 @@
1
- import React from 'react';
2
- import {
3
- IconButton,
4
- InputAdornment,
5
- TextField,
6
- TextFieldProps
7
- } from '@mui/material';
8
- import { MUGlobal } from './MUGlobal';
9
- import { Clear, Visibility } from '@mui/icons-material';
10
- import useCombinedRefs from '../uses/useCombinedRefs';
11
- import { Keyboard } from '@etsoo/shared';
12
- import { useDelayedExecutor } from '../uses/useDelayedExecutor';
13
-
14
- /**
15
- * Extended text field props
16
- */
17
- export type TextFieldExProps = TextFieldProps & {
18
- /**
19
- * Change delay (ms) to avoid repeatly dispatch onChange
20
- */
21
- changeDelay?: number;
22
-
23
- /**
24
- * On enter click
25
- */
26
- onEnter?: React.KeyboardEventHandler<HTMLDivElement>;
27
-
28
- /**
29
- * Is the field read only?
30
- */
31
- readOnly?: boolean;
32
-
33
- /**
34
- * Show clear button
35
- */
36
- showClear?: boolean;
37
-
38
- /**
39
- * Show password button
40
- */
41
- showPassword?: boolean;
42
- };
43
-
44
- /**
45
- * Extended text field methods
46
- */
47
- export interface TextFieldExMethods {
48
- /**
49
- * Set error
50
- * @param error Error
51
- */
52
- setError(error: React.ReactNode): void;
53
- }
54
-
55
- export const TextFieldEx = React.forwardRef<
56
- TextFieldExMethods,
57
- TextFieldExProps
58
- >((props, ref) => {
59
- // Destructure
60
- const {
61
- changeDelay,
62
- error,
63
- fullWidth = true,
64
- helperText,
65
- InputProps = {},
66
- onChange,
67
- onKeyPress,
68
- onEnter,
69
- inputRef,
70
- readOnly,
71
- showClear,
72
- showPassword,
73
- type,
74
- variant = MUGlobal.textFieldVariant,
75
- ...rest
76
- } = props;
77
-
78
- // State
79
- const [errorText, updateErrorText] = React.useState<React.ReactNode>();
80
- const [empty, updateEmpty] = React.useState<boolean>(true);
81
-
82
- // Read only
83
- if (readOnly != null) InputProps.readOnly = readOnly;
84
-
85
- // Calculate
86
- let errorEx = error;
87
- let helperTextEx = helperText;
88
- if (errorText != null) {
89
- errorEx = true;
90
- helperTextEx = errorText;
91
- }
92
-
93
- let typeEx = showPassword ? 'password' : type;
94
-
95
- let input: HTMLInputElement | undefined;
96
- const localRef = (ref: HTMLInputElement) => {
97
- input = ref;
98
-
99
- if (input.value !== '') {
100
- updateEmpty(false);
101
- }
102
- };
103
-
104
- const clearClick = () => {
105
- if (input != null) {
106
- input.value = '';
107
- input.focus();
108
- }
109
-
110
- if (errorText != null) {
111
- // Reset
112
- updateErrorText(undefined);
113
- }
114
-
115
- updateEmpty(true);
116
- };
117
-
118
- const preventDefault = (e: React.TouchEvent | React.MouseEvent) => {
119
- // Prevent long press
120
- if (e.isPropagationStopped()) e.stopPropagation();
121
-
122
- if (e.isDefaultPrevented()) e.preventDefault();
123
- };
124
-
125
- const touchStart = (e: React.TouchEvent | React.MouseEvent) => {
126
- // Show the password
127
- if (input) {
128
- input.blur();
129
- input.type = 'text';
130
- }
131
- preventDefault(e);
132
- };
133
-
134
- const touchEnd = (e: React.TouchEvent | React.MouseEvent) => {
135
- // Show the password
136
- if (input) input.type = 'password';
137
- preventDefault(e);
138
- };
139
-
140
- // Show password and/or clear button
141
- if (!empty && (showPassword || showClear)) {
142
- InputProps.endAdornment = (
143
- <InputAdornment position="end">
144
- {showPassword && (
145
- <IconButton
146
- tabIndex={-1}
147
- onContextMenu={(event) => event.preventDefault()}
148
- onMouseDown={touchStart}
149
- onMouseUp={touchEnd}
150
- onTouchStart={touchStart}
151
- onTouchCancel={touchEnd}
152
- onTouchEnd={touchEnd}
153
- >
154
- <Visibility />
155
- </IconButton>
156
- )}
157
- {showClear && (
158
- <IconButton onClick={clearClick} tabIndex={-1}>
159
- <Clear />
160
- </IconButton>
161
- )}
162
- </InputAdornment>
163
- );
164
- }
165
-
166
- // Extend key precess
167
- const onKeyPressEx =
168
- onEnter == null
169
- ? onKeyPress
170
- : (e: React.KeyboardEvent<HTMLDivElement>) => {
171
- if (e.key === Keyboard.Keys.Enter) {
172
- // Enter press callback
173
- onEnter(e);
174
- }
175
-
176
- if (!e.isDefaultPrevented && onKeyPress != null) {
177
- // Common press callback
178
- onKeyPress(e);
179
- }
180
- };
181
-
182
- React.useImperativeHandle(
183
- ref,
184
- () => ({
185
- /**
186
- * Set error
187
- * @param error Error
188
- */
189
- setError(error: React.ReactNode): void {
190
- updateErrorText(error);
191
- }
192
- }),
193
- []
194
- );
195
-
196
- const isMounted = React.useRef(true);
197
- const delayed =
198
- onChange != null && changeDelay != null && changeDelay >= 1
199
- ? useDelayedExecutor(onChange, changeDelay)
200
- : undefined;
201
-
202
- const onChangeEx = (
203
- event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
204
- ) => {
205
- if (errorText != null) {
206
- // Reset
207
- updateErrorText(undefined);
208
- }
209
-
210
- if (showClear || showPassword) {
211
- if (event.target.value === '') {
212
- updateEmpty(true);
213
- } else if (empty) {
214
- updateEmpty(false);
215
- }
216
- }
217
-
218
- if (onChange == null) return;
219
-
220
- if (changeDelay == null || changeDelay < 1) {
221
- onChange(event);
222
- return;
223
- }
224
-
225
- delayed?.call(undefined, event);
226
- };
227
-
228
- React.useEffect(() => {
229
- return () => {
230
- isMounted.current = false;
231
- delayed?.clear();
232
- };
233
- }, []);
234
-
235
- // Textfield
236
- return (
237
- <TextField
238
- error={errorEx}
239
- fullWidth={fullWidth}
240
- helperText={helperTextEx}
241
- inputRef={useCombinedRefs(inputRef, localRef)}
242
- InputProps={InputProps}
243
- onChange={onChangeEx}
244
- onKeyPress={onKeyPressEx}
245
- type={typeEx}
246
- variant={variant}
247
- {...rest}
248
- />
249
- );
250
- });
@@ -1,304 +0,0 @@
1
- import { DataTypes, IdDefaultType, ListType } from '@etsoo/shared';
2
- import { Autocomplete, AutocompleteRenderInputParams } from '@mui/material';
3
- import React from 'react';
4
- import { ReactUtils } from '../app/ReactUtils';
5
- import { useDelayedExecutor } from '../uses/useDelayedExecutor';
6
- import { AutocompleteExtendedProps } from './AutocompleteExtendedProps';
7
- import { InputField } from './InputField';
8
- import { SearchField } from './SearchField';
9
-
10
- /**
11
- * Tiplist props
12
- */
13
- export type TiplistProps<T extends object, D extends DataTypes.Keys<T>> = Omit<
14
- AutocompleteExtendedProps<T, D>,
15
- 'open'
16
- > & {
17
- /**
18
- * Load data callback
19
- */
20
- loadData: (
21
- keyword?: string,
22
- id?: T[D]
23
- ) => PromiseLike<T[] | null | undefined>;
24
- };
25
-
26
- // Multiple states
27
- interface States<T extends object> {
28
- open: boolean;
29
- options: T[];
30
- value?: T | null;
31
- loading?: boolean;
32
- }
33
-
34
- /**
35
- * Tiplist
36
- * @param props Props
37
- * @returns Component
38
- */
39
- export function Tiplist<
40
- T extends object = ListType,
41
- D extends DataTypes.Keys<T> = IdDefaultType<T>
42
- >(props: TiplistProps<T, D>) {
43
- // Destruct
44
- const {
45
- search = false,
46
- idField = 'id' as D,
47
- idValue,
48
- inputAutoComplete = 'off',
49
- inputError,
50
- inputHelperText,
51
- inputMargin,
52
- inputOnChange,
53
- inputRequired,
54
- inputVariant,
55
- label,
56
- loadData,
57
- defaultValue,
58
- value,
59
- name,
60
- readOnly,
61
- onChange,
62
- openOnFocus = true,
63
- sx = { minWidth: '180px' },
64
- ...rest
65
- } = props;
66
-
67
- // Value input ref
68
- const inputRef = React.createRef<HTMLInputElement>();
69
-
70
- // Local value
71
- let localValue = value ?? defaultValue;
72
-
73
- // One time calculation for input's default value (uncontrolled)
74
- const localIdValue =
75
- idValue ?? DataTypes.getValue(localValue, idField as any);
76
-
77
- // Changable states
78
- const [states, stateUpdate] = React.useReducer(
79
- (currentState: States<T>, newState: Partial<States<T>>) => {
80
- return { ...currentState, ...newState };
81
- },
82
- {
83
- // Loading unknown
84
- open: false,
85
- options: [],
86
- value: null
87
- }
88
- );
89
-
90
- // Input value
91
- const inputValue = React.useMemo(
92
- () => states.value && states.value[idField],
93
- [states.value]
94
- );
95
-
96
- React.useEffect(() => {
97
- if (localValue != null) stateUpdate({ value: localValue });
98
- }, [localValue]);
99
-
100
- // State
101
- const [state] = React.useState<{
102
- idLoaded?: boolean;
103
- idSet?: boolean;
104
- }>({});
105
- const isMounted = React.useRef(true);
106
-
107
- // Add readOnly
108
- const addReadOnly = (params: AutocompleteRenderInputParams) => {
109
- if (readOnly != null) {
110
- Object.assign(params, { readOnly });
111
- }
112
-
113
- // https://stackoverflow.com/questions/15738259/disabling-chrome-autofill
114
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html
115
- Object.assign(params.inputProps, { autoComplete: inputAutoComplete });
116
-
117
- return params;
118
- };
119
-
120
- // Change handler
121
- const changeHandle = (event: React.ChangeEvent<HTMLInputElement>) => {
122
- // Stop processing with auto trigger event
123
- if (event.nativeEvent.cancelable && !event.nativeEvent.composed) {
124
- stateUpdate({ options: [] });
125
- return;
126
- }
127
-
128
- // Stop bubble
129
- event.stopPropagation();
130
-
131
- // Call with delay
132
- delayed.call(undefined, event.currentTarget.value);
133
- };
134
-
135
- // Directly load data
136
- const loadDataDirect = (keyword?: string, id?: T[D]) => {
137
- // Reset options
138
- // setOptions([]);
139
-
140
- if (id == null) {
141
- // Reset real value
142
- const input = inputRef.current;
143
-
144
- if (input && input.value !== '') {
145
- // Different value, trigger change event
146
- ReactUtils.triggerChange(input, '', false);
147
- }
148
-
149
- if (states.options.length > 0) {
150
- // Reset options
151
- stateUpdate({ options: [] });
152
- }
153
- }
154
-
155
- // Loading indicator
156
- if (!states.loading) stateUpdate({ loading: true });
157
-
158
- // Load list
159
- loadData(keyword, id).then((options) => {
160
- if (!isMounted.current) return;
161
-
162
- // Indicates loading completed
163
- stateUpdate({
164
- loading: false,
165
- ...(options != null && { options })
166
- });
167
- });
168
- };
169
-
170
- const delayed = useDelayedExecutor(loadDataDirect, 480);
171
-
172
- const setInputValue = (value: T | null) => {
173
- stateUpdate({ value });
174
-
175
- // Input value
176
- const input = inputRef.current;
177
- if (input) {
178
- // Update value
179
- const newValue = DataTypes.getStringValue(value, idField) ?? '';
180
- if (newValue !== input.value) {
181
- // Different value, trigger change event
182
- ReactUtils.triggerChange(input, newValue, false);
183
- }
184
- }
185
- };
186
-
187
- if (localIdValue != null && (localIdValue as any) !== '') {
188
- if (state.idLoaded) {
189
- // Set default
190
- if (!state.idSet && states.options.length == 1) {
191
- stateUpdate({ value: states.options[0] });
192
- state.idSet = true;
193
- }
194
- } else {
195
- // Load id data
196
- loadDataDirect(undefined, localIdValue);
197
- state.idLoaded = true;
198
- }
199
- }
200
-
201
- React.useEffect(() => {
202
- return () => {
203
- isMounted.current = false;
204
- delayed.clear();
205
- };
206
- }, []);
207
-
208
- // Layout
209
- return (
210
- <div>
211
- <input
212
- ref={inputRef}
213
- data-reset="true"
214
- type="text"
215
- style={{ display: 'none' }}
216
- name={name}
217
- value={`${inputValue ?? ''}`}
218
- readOnly
219
- onChange={inputOnChange}
220
- />
221
- {/* Previous input will reset first with "disableClearable = false", next input trigger change works */}
222
- <Autocomplete<T, undefined, false, false>
223
- filterOptions={(options, _state) => options}
224
- value={states.value}
225
- options={states.options}
226
- onChange={(event, value, reason, details) => {
227
- // Set value
228
- setInputValue(value);
229
-
230
- // Custom
231
- if (onChange != null)
232
- onChange(event, value, reason, details);
233
-
234
- // For clear case
235
- if (reason === 'clear') {
236
- stateUpdate({ options: [] });
237
- loadDataDirect();
238
- }
239
- }}
240
- open={states.open}
241
- openOnFocus={openOnFocus}
242
- onOpen={() => {
243
- // Should load
244
- const loading = states.loading
245
- ? true
246
- : states.options.length === 0;
247
-
248
- stateUpdate({ open: true, loading });
249
-
250
- // If not loading
251
- if (loading)
252
- loadDataDirect(
253
- undefined,
254
- states.value == null
255
- ? undefined
256
- : states.value[idField]
257
- );
258
- }}
259
- onClose={() => {
260
- stateUpdate({
261
- open: false,
262
- ...(!states.value && { options: [] })
263
- });
264
- }}
265
- loading={states.loading}
266
- sx={sx}
267
- renderInput={(params) =>
268
- search ? (
269
- <SearchField
270
- onChange={changeHandle}
271
- {...params}
272
- readOnly={readOnly}
273
- label={label}
274
- name={name + 'Input'}
275
- margin={inputMargin}
276
- variant={inputVariant}
277
- required={inputRequired}
278
- autoComplete={inputAutoComplete}
279
- error={inputError}
280
- helperText={inputHelperText}
281
- />
282
- ) : (
283
- <InputField
284
- onChange={changeHandle}
285
- {...addReadOnly(params)}
286
- label={label}
287
- name={name + 'Input'}
288
- margin={inputMargin}
289
- variant={inputVariant}
290
- required={inputRequired}
291
- autoComplete={inputAutoComplete}
292
- error={inputError}
293
- helperText={inputHelperText}
294
- />
295
- )
296
- }
297
- isOptionEqualToValue={(option: T, value: T) =>
298
- option[idField] === value[idField]
299
- }
300
- {...rest}
301
- />
302
- </div>
303
- );
304
- }
@@ -1,84 +0,0 @@
1
- import { ClickAwayListener, Tooltip, TooltipProps } from '@mui/material';
2
- import React from 'react';
3
- import { useDelayedExecutor } from '../uses/useDelayedExecutor';
4
-
5
- /**
6
- * Tooltip with click visibility props
7
- */
8
- export interface TooltipClickProps
9
- extends Omit<
10
- TooltipProps,
11
- 'children' | 'open' | 'disableFocusListener' | 'disableTouchListener'
12
- > {
13
- children: (
14
- openTooltip: (newTitle?: string) => void
15
- ) => React.ReactElement<any, any>;
16
-
17
- disableHoverListener?: boolean;
18
- }
19
-
20
- /**
21
- * Tooltip with click visibility
22
- * @param props Props
23
- * @returns Component
24
- */
25
- export function TooltipClick(props: TooltipClickProps) {
26
- // Destruct
27
- // leaveDelay set to 5 seconds to hide the tooltip automatically
28
- const {
29
- children,
30
- disableHoverListener = true,
31
- leaveDelay = 5000,
32
- onClose,
33
- title,
34
- ...rest
35
- } = props;
36
-
37
- // State
38
- const [localTitle, setTitle] = React.useState(title);
39
- const [open, setOpen] = React.useState(false);
40
-
41
- const delayed =
42
- leaveDelay > 0
43
- ? useDelayedExecutor(() => setOpen(false), leaveDelay)
44
- : undefined;
45
-
46
- // Callback for open the tooltip
47
- const openTooltip = (newTitle?: string) => {
48
- setOpen(true);
49
- if (newTitle) setTitle(newTitle);
50
- delayed?.call();
51
- };
52
-
53
- React.useEffect(() => {
54
- return () => {
55
- delayed?.clear();
56
- };
57
- }, []);
58
-
59
- // Layout
60
- return (
61
- <ClickAwayListener onClickAway={() => setOpen(false)}>
62
- <Tooltip
63
- PopperProps={{
64
- disablePortal: true
65
- }}
66
- onClose={(event) => {
67
- setOpen(false);
68
- if (onClose) onClose(event);
69
- }}
70
- title={localTitle}
71
- open={open}
72
- disableFocusListener
73
- disableTouchListener
74
- disableHoverListener={disableHoverListener}
75
- onMouseOver={
76
- disableHoverListener ? undefined : () => setOpen(true)
77
- }
78
- {...rest}
79
- >
80
- {children(openTooltip)}
81
- </Tooltip>
82
- </ClickAwayListener>
83
- );
84
- }
@@ -1,64 +0,0 @@
1
- import React from 'react';
2
- import { Avatar } from '@mui/material';
3
- import { BusinessUtils } from '@etsoo/appscript';
4
- import { globalApp } from '../app/ReactApp';
5
-
6
- /**
7
- * User avatar props
8
- */
9
- export interface UserAvatarProps {
10
- /**
11
- * Photo src
12
- */
13
- src?: string;
14
-
15
- /**
16
- * Format title
17
- */
18
- formatTitle?: (title?: string) => string;
19
-
20
- /**
21
- * Title of the user
22
- */
23
- title?: string;
24
- }
25
-
26
- /**
27
- * User avatar
28
- * @param props Props
29
- * @returns Component
30
- */
31
- export function UserAvatar(props: UserAvatarProps) {
32
- // Destruct
33
- const {
34
- src,
35
- title,
36
- formatTitle = (title?: string) => {
37
- return BusinessUtils.formatAvatarTitle(
38
- title,
39
- 3,
40
- typeof globalApp === 'undefined'
41
- ? 'ME'
42
- : globalApp.get<string>('me')
43
- );
44
- }
45
- } = props;
46
-
47
- // Format
48
- const fTitle = formatTitle(title);
49
- const count = fTitle.length;
50
-
51
- return (
52
- <Avatar
53
- title={title}
54
- src={src}
55
- sx={{
56
- width: 48,
57
- height: 32,
58
- fontSize: count <= 2 ? '15px' : '12px'
59
- }}
60
- >
61
- {fTitle}
62
- </Avatar>
63
- );
64
- }