@etsoo/react 1.5.80 → 1.5.81

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 (257) 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/uses/useWindowScroll.d.ts +10 -0
  13. package/lib/uses/useWindowScroll.js +46 -0
  14. package/lib/uses/useWindowSize.js +11 -5
  15. package/package.json +3 -15
  16. package/src/{mu → components}/DnDList.tsx +11 -34
  17. package/src/components/GridMethodRef.ts +12 -0
  18. package/src/components/ScrollerGrid.tsx +3 -3
  19. package/src/components/ScrollerList.tsx +5 -3
  20. package/src/index.ts +2 -78
  21. package/src/notifier/Notifier.ts +2 -3
  22. package/src/uses/useWindowScroll.ts +60 -0
  23. package/src/uses/useWindowSize.ts +14 -5
  24. package/__tests__/mu/ComboBox.tsx +0 -30
  25. package/__tests__/mu/MUGlobalTests.tsx +0 -58
  26. package/__tests__/mu/NotifierMUTests.tsx +0 -213
  27. package/__tests__/mu/SelectEx.tsx +0 -26
  28. package/lib/app/CommonApp.d.ts +0 -39
  29. package/lib/app/CommonApp.js +0 -149
  30. package/lib/app/IServiceAppSettings.d.ts +0 -11
  31. package/lib/app/IServiceAppSettings.js +0 -1
  32. package/lib/app/IServicePage.d.ts +0 -6
  33. package/lib/app/IServicePage.js +0 -1
  34. package/lib/app/IServiceUser.d.ts +0 -14
  35. package/lib/app/IServiceUser.js +0 -1
  36. package/lib/app/ISmartERPUser.d.ts +0 -14
  37. package/lib/app/ISmartERPUser.js +0 -1
  38. package/lib/app/Labels.d.ts +0 -65
  39. package/lib/app/Labels.js +0 -62
  40. package/lib/app/ReactApp.d.ts +0 -194
  41. package/lib/app/ReactApp.js +0 -298
  42. package/lib/app/ServiceApp.d.ts +0 -78
  43. package/lib/app/ServiceApp.js +0 -244
  44. package/lib/components/ShowDataComparison.d.ts +0 -20
  45. package/lib/components/ShowDataComparison.js +0 -60
  46. package/lib/mu/AuditDisplay.d.ts +0 -33
  47. package/lib/mu/AuditDisplay.js +0 -52
  48. package/lib/mu/AutocompleteExtendedProps.d.ts +0 -64
  49. package/lib/mu/AutocompleteExtendedProps.js +0 -1
  50. package/lib/mu/BackButton.d.ts +0 -13
  51. package/lib/mu/BackButton.js +0 -33
  52. package/lib/mu/BridgeCloseButton.d.ts +0 -23
  53. package/lib/mu/BridgeCloseButton.js +0 -32
  54. package/lib/mu/ButtonLink.d.ts +0 -17
  55. package/lib/mu/ButtonLink.js +0 -19
  56. package/lib/mu/ComboBox.d.ts +0 -38
  57. package/lib/mu/ComboBox.js +0 -108
  58. package/lib/mu/CountdownButton.d.ts +0 -23
  59. package/lib/mu/CountdownButton.js +0 -81
  60. package/lib/mu/CustomFabProps.d.ts +0 -27
  61. package/lib/mu/CustomFabProps.js +0 -1
  62. package/lib/mu/DataGridEx.d.ts +0 -96
  63. package/lib/mu/DataGridEx.js +0 -331
  64. package/lib/mu/DataGridRenderers.d.ts +0 -22
  65. package/lib/mu/DataGridRenderers.js +0 -99
  66. package/lib/mu/DialogButton.d.ts +0 -54
  67. package/lib/mu/DialogButton.js +0 -45
  68. package/lib/mu/DraggablePaperComponent.d.ts +0 -8
  69. package/lib/mu/DraggablePaperComponent.js +0 -12
  70. package/lib/mu/EmailInput.d.ts +0 -11
  71. package/lib/mu/EmailInput.js +0 -15
  72. package/lib/mu/FabBox.d.ts +0 -21
  73. package/lib/mu/FabBox.js +0 -31
  74. package/lib/mu/FlexBox.d.ts +0 -14
  75. package/lib/mu/FlexBox.js +0 -18
  76. package/lib/mu/GridDataFormat.d.ts +0 -10
  77. package/lib/mu/GridDataFormat.js +0 -43
  78. package/lib/mu/GridMethodRef.d.ts +0 -11
  79. package/lib/mu/IconButtonLink.d.ts +0 -17
  80. package/lib/mu/IconButtonLink.js +0 -16
  81. package/lib/mu/InputField.d.ts +0 -21
  82. package/lib/mu/InputField.js +0 -39
  83. package/lib/mu/ItemList.d.ts +0 -56
  84. package/lib/mu/ItemList.js +0 -69
  85. package/lib/mu/ListItemRightIcon.d.ts +0 -4
  86. package/lib/mu/ListItemRightIcon.js +0 -8
  87. package/lib/mu/ListMoreDisplay.d.ts +0 -35
  88. package/lib/mu/ListMoreDisplay.js +0 -99
  89. package/lib/mu/LoadingButton.d.ts +0 -16
  90. package/lib/mu/LoadingButton.js +0 -41
  91. package/lib/mu/MUGlobal.d.ts +0 -102
  92. package/lib/mu/MUGlobal.js +0 -184
  93. package/lib/mu/MaskInput.d.ts +0 -34
  94. package/lib/mu/MaskInput.js +0 -43
  95. package/lib/mu/MobileListItemRenderer.d.ts +0 -17
  96. package/lib/mu/MobileListItemRenderer.js +0 -35
  97. package/lib/mu/MoreFab.d.ts +0 -45
  98. package/lib/mu/MoreFab.js +0 -95
  99. package/lib/mu/NotifierMU.d.ts +0 -47
  100. package/lib/mu/NotifierMU.js +0 -387
  101. package/lib/mu/NotifierPromptProps.d.ts +0 -22
  102. package/lib/mu/NotifierPromptProps.js +0 -1
  103. package/lib/mu/OptionGroup.d.ts +0 -58
  104. package/lib/mu/OptionGroup.js +0 -81
  105. package/lib/mu/PList.d.ts +0 -15
  106. package/lib/mu/PList.js +0 -12
  107. package/lib/mu/ProgressCount.d.ts +0 -44
  108. package/lib/mu/ProgressCount.js +0 -79
  109. package/lib/mu/PullToRefreshUI.d.ts +0 -9
  110. package/lib/mu/PullToRefreshUI.js +0 -18
  111. package/lib/mu/RLink.d.ts +0 -14
  112. package/lib/mu/RLink.js +0 -37
  113. package/lib/mu/ResponsibleContainer.d.ts +0 -89
  114. package/lib/mu/ResponsibleContainer.js +0 -159
  115. package/lib/mu/ScrollTopFab.d.ts +0 -7
  116. package/lib/mu/ScrollTopFab.js +0 -25
  117. package/lib/mu/ScrollerListEx.d.ts +0 -81
  118. package/lib/mu/ScrollerListEx.js +0 -167
  119. package/lib/mu/SearchBar.d.ts +0 -29
  120. package/lib/mu/SearchBar.js +0 -262
  121. package/lib/mu/SearchField.d.ts +0 -21
  122. package/lib/mu/SearchField.js +0 -39
  123. package/lib/mu/SearchOptionGroup.d.ts +0 -9
  124. package/lib/mu/SearchOptionGroup.js +0 -14
  125. package/lib/mu/SelectBool.d.ts +0 -13
  126. package/lib/mu/SelectBool.js +0 -22
  127. package/lib/mu/SelectEx.d.ts +0 -50
  128. package/lib/mu/SelectEx.js +0 -156
  129. package/lib/mu/Switch.d.ts +0 -29
  130. package/lib/mu/Switch.js +0 -34
  131. package/lib/mu/SwitchAnt.d.ts +0 -25
  132. package/lib/mu/SwitchAnt.js +0 -40
  133. package/lib/mu/TabBox.d.ts +0 -54
  134. package/lib/mu/TabBox.js +0 -31
  135. package/lib/mu/TableEx.d.ts +0 -66
  136. package/lib/mu/TableEx.js +0 -271
  137. package/lib/mu/TextFieldEx.d.ts +0 -101
  138. package/lib/mu/TextFieldEx.js +0 -127
  139. package/lib/mu/Tiplist.d.ts +0 -18
  140. package/lib/mu/Tiplist.js +0 -158
  141. package/lib/mu/TooltipClick.d.ts +0 -15
  142. package/lib/mu/TooltipClick.js +0 -40
  143. package/lib/mu/UserAvatar.d.ts +0 -24
  144. package/lib/mu/UserAvatar.js +0 -25
  145. package/lib/mu/UserAvatarEditor.d.ts +0 -53
  146. package/lib/mu/UserAvatarEditor.js +0 -129
  147. package/lib/mu/pages/CommonPage.d.ts +0 -11
  148. package/lib/mu/pages/CommonPage.js +0 -60
  149. package/lib/mu/pages/CommonPageProps.d.ts +0 -60
  150. package/lib/mu/pages/CommonPageProps.js +0 -1
  151. package/lib/mu/pages/DataGridPage.d.ts +0 -9
  152. package/lib/mu/pages/DataGridPage.js +0 -81
  153. package/lib/mu/pages/DataGridPageProps.d.ts +0 -17
  154. package/lib/mu/pages/DataGridPageProps.js +0 -1
  155. package/lib/mu/pages/EditPage.d.ts +0 -33
  156. package/lib/mu/pages/EditPage.js +0 -29
  157. package/lib/mu/pages/FixedListPage.d.ts +0 -15
  158. package/lib/mu/pages/FixedListPage.js +0 -72
  159. package/lib/mu/pages/ListPage.d.ts +0 -9
  160. package/lib/mu/pages/ListPage.js +0 -51
  161. package/lib/mu/pages/ListPageProps.d.ts +0 -7
  162. package/lib/mu/pages/ListPageProps.js +0 -1
  163. package/lib/mu/pages/ResponsivePage.d.ts +0 -9
  164. package/lib/mu/pages/ResponsivePage.js +0 -45
  165. package/lib/mu/pages/ResponsivePageProps.d.ts +0 -39
  166. package/lib/mu/pages/ResponsivePageProps.js +0 -1
  167. package/lib/mu/pages/SearchPageProps.d.ts +0 -30
  168. package/lib/mu/pages/SearchPageProps.js +0 -1
  169. package/lib/mu/pages/TablePage.d.ts +0 -9
  170. package/lib/mu/pages/TablePage.js +0 -71
  171. package/lib/mu/pages/TablePageProps.d.ts +0 -7
  172. package/lib/mu/pages/TablePageProps.js +0 -1
  173. package/lib/mu/pages/ViewPage.d.ts +0 -66
  174. package/lib/mu/pages/ViewPage.js +0 -105
  175. package/lib/mu/texts/DateText.d.ts +0 -34
  176. package/lib/mu/texts/DateText.js +0 -25
  177. package/lib/mu/texts/MoneyText.d.ts +0 -21
  178. package/lib/mu/texts/MoneyText.js +0 -14
  179. package/lib/mu/texts/NumberText.d.ts +0 -25
  180. package/lib/mu/texts/NumberText.js +0 -14
  181. package/src/app/CommonApp.ts +0 -225
  182. package/src/app/IServiceAppSettings.ts +0 -13
  183. package/src/app/IServicePage.ts +0 -6
  184. package/src/app/IServiceUser.ts +0 -17
  185. package/src/app/ISmartERPUser.ts +0 -16
  186. package/src/app/Labels.ts +0 -77
  187. package/src/app/ReactApp.ts +0 -500
  188. package/src/app/ServiceApp.ts +0 -353
  189. package/src/components/ShowDataComparison.tsx +0 -108
  190. package/src/mu/AuditDisplay.tsx +0 -117
  191. package/src/mu/AutocompleteExtendedProps.ts +0 -83
  192. package/src/mu/BackButton.tsx +0 -55
  193. package/src/mu/BridgeCloseButton.tsx +0 -69
  194. package/src/mu/ButtonLink.tsx +0 -32
  195. package/src/mu/ComboBox.tsx +0 -251
  196. package/src/mu/CountdownButton.tsx +0 -119
  197. package/src/mu/CustomFabProps.ts +0 -32
  198. package/src/mu/DataGridEx.tsx +0 -712
  199. package/src/mu/DataGridRenderers.tsx +0 -140
  200. package/src/mu/DialogButton.tsx +0 -163
  201. package/src/mu/DraggablePaperComponent.tsx +0 -19
  202. package/src/mu/EmailInput.tsx +0 -24
  203. package/src/mu/FabBox.tsx +0 -51
  204. package/src/mu/FlexBox.tsx +0 -20
  205. package/src/mu/GridDataFormat.tsx +0 -77
  206. package/src/mu/GridMethodRef.ts +0 -12
  207. package/src/mu/IconButtonLink.tsx +0 -29
  208. package/src/mu/InputField.tsx +0 -82
  209. package/src/mu/ItemList.tsx +0 -204
  210. package/src/mu/ListItemRightIcon.tsx +0 -9
  211. package/src/mu/ListMoreDisplay.tsx +0 -205
  212. package/src/mu/LoadingButton.tsx +0 -75
  213. package/src/mu/MUGlobal.ts +0 -220
  214. package/src/mu/MaskInput.tsx +0 -107
  215. package/src/mu/MobileListItemRenderer.tsx +0 -79
  216. package/src/mu/MoreFab.tsx +0 -211
  217. package/src/mu/NotifierMU.tsx +0 -654
  218. package/src/mu/NotifierPromptProps.ts +0 -26
  219. package/src/mu/OptionGroup.tsx +0 -223
  220. package/src/mu/PList.tsx +0 -27
  221. package/src/mu/ProgressCount.tsx +0 -166
  222. package/src/mu/PullToRefreshUI.tsx +0 -21
  223. package/src/mu/RLink.tsx +0 -64
  224. package/src/mu/ResponsibleContainer.tsx +0 -394
  225. package/src/mu/ScrollTopFab.tsx +0 -34
  226. package/src/mu/ScrollerListEx.tsx +0 -387
  227. package/src/mu/SearchBar.tsx +0 -398
  228. package/src/mu/SearchField.tsx +0 -82
  229. package/src/mu/SearchOptionGroup.tsx +0 -31
  230. package/src/mu/SelectBool.tsx +0 -33
  231. package/src/mu/SelectEx.tsx +0 -290
  232. package/src/mu/Switch.tsx +0 -94
  233. package/src/mu/SwitchAnt.tsx +0 -95
  234. package/src/mu/TabBox.tsx +0 -118
  235. package/src/mu/TableEx.tsx +0 -560
  236. package/src/mu/TextFieldEx.tsx +0 -250
  237. package/src/mu/Tiplist.tsx +0 -304
  238. package/src/mu/TooltipClick.tsx +0 -84
  239. package/src/mu/UserAvatar.tsx +0 -64
  240. package/src/mu/UserAvatarEditor.tsx +0 -287
  241. package/src/mu/pages/CommonPage.tsx +0 -128
  242. package/src/mu/pages/CommonPageProps.ts +0 -71
  243. package/src/mu/pages/DataGridPage.tsx +0 -137
  244. package/src/mu/pages/DataGridPageProps.ts +0 -24
  245. package/src/mu/pages/EditPage.tsx +0 -114
  246. package/src/mu/pages/FixedListPage.tsx +0 -135
  247. package/src/mu/pages/ListPage.tsx +0 -87
  248. package/src/mu/pages/ListPageProps.ts +0 -12
  249. package/src/mu/pages/ResponsivePage.tsx +0 -68
  250. package/src/mu/pages/ResponsivePageProps.ts +0 -57
  251. package/src/mu/pages/SearchPageProps.ts +0 -39
  252. package/src/mu/pages/TablePage.tsx +0 -120
  253. package/src/mu/pages/TablePageProps.ts +0 -12
  254. package/src/mu/pages/ViewPage.tsx +0 -285
  255. package/src/mu/texts/DateText.tsx +0 -74
  256. package/src/mu/texts/MoneyText.tsx +0 -49
  257. 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
- }