@etsoo/react 1.5.79 → 1.5.82

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