@etsoo/materialui 1.3.55 → 1.3.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/ReactAppTests.tsx +107 -0
- package/lib/TextFieldEx.d.ts +2 -2
- package/lib/TextFieldEx.js +19 -17
- package/package.json +5 -5
- package/src/TextFieldEx.tsx +237 -234
- package/src/app/ReactApp.ts +1 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AddressUtils,
|
|
3
|
+
ApiAuthorizationScheme,
|
|
4
|
+
ExternalSettings,
|
|
5
|
+
en,
|
|
6
|
+
zhHans
|
|
7
|
+
} from "@etsoo/appscript";
|
|
8
|
+
import { ReactApp } from "../src";
|
|
9
|
+
import { DataTypes, DomUtils, IActionResult, Utils } from "@etsoo/shared";
|
|
10
|
+
import React, { act } from "react";
|
|
11
|
+
import { createRoot } from "react-dom/client";
|
|
12
|
+
|
|
13
|
+
// Without it will popup error:
|
|
14
|
+
// The current testing environment is not configured to support act
|
|
15
|
+
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
|
|
16
|
+
|
|
17
|
+
// Detected country or region
|
|
18
|
+
const { detectedCountry } = DomUtils;
|
|
19
|
+
|
|
20
|
+
// Detected culture
|
|
21
|
+
const { detectedCulture } = DomUtils;
|
|
22
|
+
|
|
23
|
+
// Supported cultures
|
|
24
|
+
const supportedCultures: DataTypes.CultureDefinition[] = [zhHans({}), en({})];
|
|
25
|
+
|
|
26
|
+
// Supported regions
|
|
27
|
+
const supportedRegions = ["CN"];
|
|
28
|
+
|
|
29
|
+
const settings = ExternalSettings.format({
|
|
30
|
+
/**
|
|
31
|
+
* Endpoint of the API service
|
|
32
|
+
*/
|
|
33
|
+
endpoint: "http://{hostname}/com.etsoo.SmartERPApi/api/",
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* App root url
|
|
37
|
+
*/
|
|
38
|
+
homepage: "/cms",
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Web url of the cloud
|
|
42
|
+
*/
|
|
43
|
+
webUrl: "http://localhost",
|
|
44
|
+
|
|
45
|
+
// Authorization scheme
|
|
46
|
+
authScheme: ApiAuthorizationScheme.Bearer,
|
|
47
|
+
|
|
48
|
+
// Detected culture
|
|
49
|
+
detectedCulture,
|
|
50
|
+
|
|
51
|
+
// Supported cultures
|
|
52
|
+
cultures: supportedCultures,
|
|
53
|
+
|
|
54
|
+
// Supported regions
|
|
55
|
+
regions: supportedRegions,
|
|
56
|
+
|
|
57
|
+
// Browser's time zone
|
|
58
|
+
timeZone: Utils.getTimeZone(),
|
|
59
|
+
|
|
60
|
+
// Current country or region
|
|
61
|
+
currentRegion: AddressUtils.getRegion(
|
|
62
|
+
supportedRegions,
|
|
63
|
+
detectedCountry,
|
|
64
|
+
detectedCulture
|
|
65
|
+
),
|
|
66
|
+
|
|
67
|
+
// Current culture
|
|
68
|
+
currentCulture: DomUtils.getCulture(supportedCultures, detectedCulture)![0]
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const app = new ReactApp(settings, "test");
|
|
72
|
+
|
|
73
|
+
// Root
|
|
74
|
+
const root = document.body;
|
|
75
|
+
const container: HTMLElement = document.createElement("div");
|
|
76
|
+
root.append(container);
|
|
77
|
+
|
|
78
|
+
// The state provider
|
|
79
|
+
const Provider = ReactApp.notifierProvider;
|
|
80
|
+
const reactRoot = createRoot(container);
|
|
81
|
+
|
|
82
|
+
act(() => {
|
|
83
|
+
// Concorrent renderer needs act block
|
|
84
|
+
reactRoot.render(<Provider />);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("Test for properties", () => {
|
|
88
|
+
const result: IActionResult = {
|
|
89
|
+
ok: false,
|
|
90
|
+
type: "https://tools.ietf.org/html/rfc9110#section-15.5.1",
|
|
91
|
+
title: "One or more validation errors occurred.",
|
|
92
|
+
status: 400,
|
|
93
|
+
errors: {
|
|
94
|
+
$: [
|
|
95
|
+
"JSON deserialization for type \u0027com.etsoo.CMS.RQ.User.UserCreateRQ\u0027 was missing required properties, including the following: password"
|
|
96
|
+
],
|
|
97
|
+
rq: ["The rq field is required."]
|
|
98
|
+
},
|
|
99
|
+
traceId: "00-ed96a4f0c83f066594ecc69b77da9803-df770e3cd714fedd-00"
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
act(() => {
|
|
103
|
+
app.alertResult(result);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(root.innerHTML).toContain(result.title);
|
|
107
|
+
});
|
package/lib/TextFieldEx.d.ts
CHANGED
package/lib/TextFieldEx.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { IconButton, InputAdornment, TextField } from
|
|
3
|
-
import { MUGlobal } from
|
|
4
|
-
import { Clear, Visibility } from
|
|
5
|
-
import { Keyboard } from
|
|
6
|
-
import { useCombinedRefs, useDelayedExecutor } from
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { IconButton, InputAdornment, TextField } from "@mui/material";
|
|
3
|
+
import { MUGlobal } from "./MUGlobal";
|
|
4
|
+
import { Clear, Visibility } from "@mui/icons-material";
|
|
5
|
+
import { Keyboard } from "@etsoo/shared";
|
|
6
|
+
import { useCombinedRefs, useDelayedExecutor } from "@etsoo/react";
|
|
7
7
|
export const TextFieldEx = React.forwardRef((props, ref) => {
|
|
8
8
|
// Destructure
|
|
9
|
-
const { changeDelay, error, fullWidth = true, helperText, InputProps = {}, onChange,
|
|
9
|
+
const { changeDelay, error, fullWidth = true, helperText, InputLabelProps = {}, InputProps = {}, onChange, onKeyDown, onEnter, onVisibility, inputRef, readOnly, showClear, showPassword, type, variant = MUGlobal.textFieldVariant, ...rest } = props;
|
|
10
|
+
// Shrink
|
|
11
|
+
InputLabelProps.shrink ?? (InputLabelProps.shrink = MUGlobal.searchFieldShrink);
|
|
10
12
|
// State
|
|
11
13
|
const [errorText, updateErrorText] = React.useState();
|
|
12
14
|
const [empty, updateEmpty] = React.useState(true);
|
|
@@ -20,17 +22,17 @@ export const TextFieldEx = React.forwardRef((props, ref) => {
|
|
|
20
22
|
errorEx = true;
|
|
21
23
|
helperTextEx = errorText;
|
|
22
24
|
}
|
|
23
|
-
let typeEx = showPassword ?
|
|
25
|
+
let typeEx = showPassword ? "password" : type;
|
|
24
26
|
let input;
|
|
25
27
|
const localRef = (ref) => {
|
|
26
28
|
input = ref;
|
|
27
|
-
if (input.value !==
|
|
29
|
+
if (input.value !== "") {
|
|
28
30
|
updateEmpty(false);
|
|
29
31
|
}
|
|
30
32
|
};
|
|
31
33
|
const clearClick = () => {
|
|
32
34
|
if (input != null) {
|
|
33
|
-
input.value =
|
|
35
|
+
input.value = "";
|
|
34
36
|
input.focus();
|
|
35
37
|
}
|
|
36
38
|
if (errorText != null) {
|
|
@@ -55,7 +57,7 @@ export const TextFieldEx = React.forwardRef((props, ref) => {
|
|
|
55
57
|
return;
|
|
56
58
|
}
|
|
57
59
|
input.blur();
|
|
58
|
-
input.type =
|
|
60
|
+
input.type = "text";
|
|
59
61
|
}
|
|
60
62
|
preventDefault(e);
|
|
61
63
|
};
|
|
@@ -64,7 +66,7 @@ export const TextFieldEx = React.forwardRef((props, ref) => {
|
|
|
64
66
|
if (input) {
|
|
65
67
|
if (onVisibility)
|
|
66
68
|
return;
|
|
67
|
-
input.type =
|
|
69
|
+
input.type = "password";
|
|
68
70
|
}
|
|
69
71
|
preventDefault(e);
|
|
70
72
|
};
|
|
@@ -78,15 +80,15 @@ export const TextFieldEx = React.forwardRef((props, ref) => {
|
|
|
78
80
|
}
|
|
79
81
|
// Extend key precess
|
|
80
82
|
const onKeyPressEx = onEnter == null
|
|
81
|
-
?
|
|
83
|
+
? onKeyDown
|
|
82
84
|
: (e) => {
|
|
83
85
|
if (e.key === Keyboard.Keys.Enter) {
|
|
84
86
|
// Enter press callback
|
|
85
87
|
onEnter(e);
|
|
86
88
|
}
|
|
87
|
-
if (!e.isDefaultPrevented &&
|
|
89
|
+
if (!e.isDefaultPrevented && onKeyDown != null) {
|
|
88
90
|
// Common press callback
|
|
89
|
-
|
|
91
|
+
onKeyDown(e);
|
|
90
92
|
}
|
|
91
93
|
};
|
|
92
94
|
React.useImperativeHandle(ref, () => ({
|
|
@@ -108,7 +110,7 @@ export const TextFieldEx = React.forwardRef((props, ref) => {
|
|
|
108
110
|
updateErrorText(undefined);
|
|
109
111
|
}
|
|
110
112
|
if (showClear || showPassword) {
|
|
111
|
-
if (event.target.value ===
|
|
113
|
+
if (event.target.value === "") {
|
|
112
114
|
updateEmpty(true);
|
|
113
115
|
}
|
|
114
116
|
else if (empty) {
|
|
@@ -130,5 +132,5 @@ export const TextFieldEx = React.forwardRef((props, ref) => {
|
|
|
130
132
|
};
|
|
131
133
|
}, []);
|
|
132
134
|
// Textfield
|
|
133
|
-
return (React.createElement(TextField, { error: errorEx, fullWidth: fullWidth, helperText: helperTextEx, inputRef: useCombinedRefs(inputRef, localRef), InputProps: InputProps, onChange: onChangeEx,
|
|
135
|
+
return (React.createElement(TextField, { error: errorEx, fullWidth: fullWidth, helperText: helperTextEx, inputRef: useCombinedRefs(inputRef, localRef), InputProps: InputProps, InputLabelProps: InputLabelProps, onChange: onChangeEx, onKeyDown: onKeyPressEx, type: typeEx, variant: variant, ...rest }));
|
|
134
136
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/materialui",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.57",
|
|
4
4
|
"description": "TypeScript Material-UI Implementation",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -50,13 +50,13 @@
|
|
|
50
50
|
"@emotion/css": "^11.11.2",
|
|
51
51
|
"@emotion/react": "^11.11.4",
|
|
52
52
|
"@emotion/styled": "^11.11.5",
|
|
53
|
-
"@etsoo/appscript": "^1.4.
|
|
53
|
+
"@etsoo/appscript": "^1.4.89",
|
|
54
54
|
"@etsoo/notificationbase": "^1.1.42",
|
|
55
|
-
"@etsoo/react": "^1.7.
|
|
55
|
+
"@etsoo/react": "^1.7.43",
|
|
56
56
|
"@etsoo/shared": "^1.2.40",
|
|
57
57
|
"@mui/icons-material": "^5.15.17",
|
|
58
58
|
"@mui/material": "^5.15.17",
|
|
59
|
-
"@mui/x-data-grid": "^7.
|
|
59
|
+
"@mui/x-data-grid": "^7.4.0",
|
|
60
60
|
"chart.js": "^4.4.2",
|
|
61
61
|
"chartjs-plugin-datalabels": "^2.2.0",
|
|
62
62
|
"eventemitter3": "^5.0.1",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"@types/jest": "^29.5.12",
|
|
83
83
|
"@types/pica": "^9.0.4",
|
|
84
84
|
"@types/pulltorefreshjs": "^0.1.7",
|
|
85
|
-
"@types/react": "^18.3.
|
|
85
|
+
"@types/react": "^18.3.2",
|
|
86
86
|
"@types/react-avatar-editor": "^13.0.2",
|
|
87
87
|
"@types/react-dom": "^18.3.0",
|
|
88
88
|
"@types/react-input-mask": "^3.0.5",
|
package/src/TextFieldEx.tsx
CHANGED
|
@@ -1,268 +1,271 @@
|
|
|
1
|
-
import React from
|
|
1
|
+
import React from "react";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from
|
|
8
|
-
import { MUGlobal } from
|
|
9
|
-
import { Clear, Visibility } from
|
|
10
|
-
import { Keyboard } from
|
|
11
|
-
import { useCombinedRefs, useDelayedExecutor } from
|
|
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 { Keyboard } from "@etsoo/shared";
|
|
11
|
+
import { useCombinedRefs, useDelayedExecutor } from "@etsoo/react";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Extended text field props
|
|
15
15
|
*/
|
|
16
16
|
export type TextFieldExProps = TextFieldProps & {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
*/
|
|
49
|
-
showPassword?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Change delay (ms) to avoid repeatly dispatch onChange
|
|
19
|
+
*/
|
|
20
|
+
changeDelay?: number;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* On enter click
|
|
24
|
+
*/
|
|
25
|
+
onEnter?: React.KeyboardEventHandler<HTMLDivElement>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* On visibility
|
|
29
|
+
* @param input HTML input
|
|
30
|
+
* @returns Result
|
|
31
|
+
*/
|
|
32
|
+
onVisibility?: (input: HTMLInputElement) => void | boolean | Promise<boolean>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Is the field read only?
|
|
36
|
+
*/
|
|
37
|
+
readOnly?: boolean;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Show clear button
|
|
41
|
+
*/
|
|
42
|
+
showClear?: boolean;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Show password button
|
|
46
|
+
*/
|
|
47
|
+
showPassword?: boolean;
|
|
50
48
|
};
|
|
51
49
|
|
|
52
50
|
/**
|
|
53
51
|
* Extended text field methods
|
|
54
52
|
*/
|
|
55
53
|
export interface TextFieldExMethods {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Set error
|
|
56
|
+
* @param error Error
|
|
57
|
+
*/
|
|
58
|
+
setError(error: React.ReactNode): void;
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
export const TextFieldEx = React.forwardRef<
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
TextFieldExMethods,
|
|
63
|
+
TextFieldExProps
|
|
66
64
|
>((props, ref) => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
65
|
+
// Destructure
|
|
66
|
+
const {
|
|
67
|
+
changeDelay,
|
|
68
|
+
error,
|
|
69
|
+
fullWidth = true,
|
|
70
|
+
helperText,
|
|
71
|
+
InputLabelProps = {},
|
|
72
|
+
InputProps = {},
|
|
73
|
+
onChange,
|
|
74
|
+
onKeyDown,
|
|
75
|
+
onEnter,
|
|
76
|
+
onVisibility,
|
|
77
|
+
inputRef,
|
|
78
|
+
readOnly,
|
|
79
|
+
showClear,
|
|
80
|
+
showPassword,
|
|
81
|
+
type,
|
|
82
|
+
variant = MUGlobal.textFieldVariant,
|
|
83
|
+
...rest
|
|
84
|
+
} = props;
|
|
85
|
+
|
|
86
|
+
// Shrink
|
|
87
|
+
InputLabelProps.shrink ??= MUGlobal.searchFieldShrink;
|
|
88
|
+
|
|
89
|
+
// State
|
|
90
|
+
const [errorText, updateErrorText] = React.useState<React.ReactNode>();
|
|
91
|
+
const [empty, updateEmpty] = React.useState<boolean>(true);
|
|
92
|
+
|
|
93
|
+
// Read only
|
|
94
|
+
if (readOnly != null) InputProps.readOnly = readOnly;
|
|
95
|
+
|
|
96
|
+
// Calculate
|
|
97
|
+
let errorEx = error;
|
|
98
|
+
let helperTextEx = helperText;
|
|
99
|
+
if (errorText != null) {
|
|
100
|
+
errorEx = true;
|
|
101
|
+
helperTextEx = errorText;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let typeEx = showPassword ? "password" : type;
|
|
105
|
+
|
|
106
|
+
let input: HTMLInputElement | undefined;
|
|
107
|
+
const localRef = (ref: HTMLInputElement) => {
|
|
108
|
+
input = ref;
|
|
109
|
+
|
|
110
|
+
if (input.value !== "") {
|
|
111
|
+
updateEmpty(false);
|
|
100
112
|
}
|
|
113
|
+
};
|
|
101
114
|
|
|
102
|
-
|
|
115
|
+
const clearClick = () => {
|
|
116
|
+
if (input != null) {
|
|
117
|
+
input.value = "";
|
|
118
|
+
input.focus();
|
|
119
|
+
}
|
|
103
120
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
121
|
+
if (errorText != null) {
|
|
122
|
+
// Reset
|
|
123
|
+
updateErrorText(undefined);
|
|
124
|
+
}
|
|
107
125
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
};
|
|
126
|
+
updateEmpty(true);
|
|
127
|
+
};
|
|
112
128
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
input.focus();
|
|
117
|
-
}
|
|
129
|
+
const preventDefault = (e: React.TouchEvent | React.MouseEvent) => {
|
|
130
|
+
// Prevent long press
|
|
131
|
+
if (e.isPropagationStopped()) e.stopPropagation();
|
|
118
132
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
updateErrorText(undefined);
|
|
122
|
-
}
|
|
133
|
+
if (e.isDefaultPrevented()) e.preventDefault();
|
|
134
|
+
};
|
|
123
135
|
|
|
124
|
-
|
|
125
|
-
|
|
136
|
+
const touchStart = async (e: React.TouchEvent | React.MouseEvent) => {
|
|
137
|
+
// Show the password
|
|
138
|
+
if (input) {
|
|
139
|
+
if (onVisibility) {
|
|
140
|
+
const result = await onVisibility(input);
|
|
141
|
+
if (result === false) return;
|
|
142
|
+
}
|
|
126
143
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
144
|
+
input.blur();
|
|
145
|
+
input.type = "text";
|
|
146
|
+
}
|
|
147
|
+
preventDefault(e);
|
|
148
|
+
};
|
|
130
149
|
|
|
131
|
-
|
|
132
|
-
|
|
150
|
+
const touchEnd = (e: React.TouchEvent | React.MouseEvent) => {
|
|
151
|
+
// Show the password
|
|
152
|
+
if (input) {
|
|
153
|
+
if (onVisibility) return;
|
|
133
154
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
155
|
+
input.type = "password";
|
|
156
|
+
}
|
|
157
|
+
preventDefault(e);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// Show password and/or clear button
|
|
161
|
+
if (!empty && (showPassword || showClear)) {
|
|
162
|
+
InputProps.endAdornment = (
|
|
163
|
+
<InputAdornment position="end">
|
|
164
|
+
{showPassword && (
|
|
165
|
+
<IconButton
|
|
166
|
+
tabIndex={-1}
|
|
167
|
+
onContextMenu={(event) => event.preventDefault()}
|
|
168
|
+
onMouseDown={touchStart}
|
|
169
|
+
onMouseUp={touchEnd}
|
|
170
|
+
onTouchStart={touchStart}
|
|
171
|
+
onTouchCancel={touchEnd}
|
|
172
|
+
onTouchEnd={touchEnd}
|
|
173
|
+
>
|
|
174
|
+
<Visibility />
|
|
175
|
+
</IconButton>
|
|
176
|
+
)}
|
|
177
|
+
{showClear && (
|
|
178
|
+
<IconButton onClick={clearClick} tabIndex={-1}>
|
|
179
|
+
<Clear />
|
|
180
|
+
</IconButton>
|
|
181
|
+
)}
|
|
182
|
+
</InputAdornment>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Extend key precess
|
|
187
|
+
const onKeyPressEx =
|
|
188
|
+
onEnter == null
|
|
189
|
+
? onKeyDown
|
|
190
|
+
: (e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
191
|
+
if (e.key === Keyboard.Keys.Enter) {
|
|
192
|
+
// Enter press callback
|
|
193
|
+
onEnter(e);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (!e.isDefaultPrevented && onKeyDown != null) {
|
|
197
|
+
// Common press callback
|
|
198
|
+
onKeyDown(e);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
147
201
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
202
|
+
React.useImperativeHandle(
|
|
203
|
+
ref,
|
|
204
|
+
() => ({
|
|
205
|
+
/**
|
|
206
|
+
* Set error
|
|
207
|
+
* @param error Error
|
|
208
|
+
*/
|
|
209
|
+
setError(error: React.ReactNode): void {
|
|
210
|
+
updateErrorText(error);
|
|
211
|
+
}
|
|
212
|
+
}),
|
|
213
|
+
[]
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const isMounted = React.useRef(true);
|
|
217
|
+
const delayed =
|
|
218
|
+
onChange != null && changeDelay != null && changeDelay >= 1
|
|
219
|
+
? useDelayedExecutor(onChange, changeDelay)
|
|
220
|
+
: undefined;
|
|
221
|
+
|
|
222
|
+
const onChangeEx = (
|
|
223
|
+
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
|
224
|
+
) => {
|
|
225
|
+
if (errorText != null) {
|
|
226
|
+
// Reset
|
|
227
|
+
updateErrorText(undefined);
|
|
228
|
+
}
|
|
152
229
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
230
|
+
if (showClear || showPassword) {
|
|
231
|
+
if (event.target.value === "") {
|
|
232
|
+
updateEmpty(true);
|
|
233
|
+
} else if (empty) {
|
|
234
|
+
updateEmpty(false);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
157
237
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
<IconButton
|
|
164
|
-
tabIndex={-1}
|
|
165
|
-
onContextMenu={(event) => event.preventDefault()}
|
|
166
|
-
onMouseDown={touchStart}
|
|
167
|
-
onMouseUp={touchEnd}
|
|
168
|
-
onTouchStart={touchStart}
|
|
169
|
-
onTouchCancel={touchEnd}
|
|
170
|
-
onTouchEnd={touchEnd}
|
|
171
|
-
>
|
|
172
|
-
<Visibility />
|
|
173
|
-
</IconButton>
|
|
174
|
-
)}
|
|
175
|
-
{showClear && (
|
|
176
|
-
<IconButton onClick={clearClick} tabIndex={-1}>
|
|
177
|
-
<Clear />
|
|
178
|
-
</IconButton>
|
|
179
|
-
)}
|
|
180
|
-
</InputAdornment>
|
|
181
|
-
);
|
|
238
|
+
if (onChange == null) return;
|
|
239
|
+
|
|
240
|
+
if (changeDelay == null || changeDelay < 1) {
|
|
241
|
+
onChange(event);
|
|
242
|
+
return;
|
|
182
243
|
}
|
|
183
244
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
onEnter == null
|
|
187
|
-
? onKeyPress
|
|
188
|
-
: (e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
189
|
-
if (e.key === Keyboard.Keys.Enter) {
|
|
190
|
-
// Enter press callback
|
|
191
|
-
onEnter(e);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (!e.isDefaultPrevented && onKeyPress != null) {
|
|
195
|
-
// Common press callback
|
|
196
|
-
onKeyPress(e);
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
React.useImperativeHandle(
|
|
201
|
-
ref,
|
|
202
|
-
() => ({
|
|
203
|
-
/**
|
|
204
|
-
* Set error
|
|
205
|
-
* @param error Error
|
|
206
|
-
*/
|
|
207
|
-
setError(error: React.ReactNode): void {
|
|
208
|
-
updateErrorText(error);
|
|
209
|
-
}
|
|
210
|
-
}),
|
|
211
|
-
[]
|
|
212
|
-
);
|
|
245
|
+
delayed?.call(undefined, event);
|
|
246
|
+
};
|
|
213
247
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
: undefined;
|
|
219
|
-
|
|
220
|
-
const onChangeEx = (
|
|
221
|
-
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
|
222
|
-
) => {
|
|
223
|
-
if (errorText != null) {
|
|
224
|
-
// Reset
|
|
225
|
-
updateErrorText(undefined);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (showClear || showPassword) {
|
|
229
|
-
if (event.target.value === '') {
|
|
230
|
-
updateEmpty(true);
|
|
231
|
-
} else if (empty) {
|
|
232
|
-
updateEmpty(false);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (onChange == null) return;
|
|
237
|
-
|
|
238
|
-
if (changeDelay == null || changeDelay < 1) {
|
|
239
|
-
onChange(event);
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
delayed?.call(undefined, event);
|
|
248
|
+
React.useEffect(() => {
|
|
249
|
+
return () => {
|
|
250
|
+
isMounted.current = false;
|
|
251
|
+
delayed?.clear();
|
|
244
252
|
};
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
type={typeEx}
|
|
264
|
-
variant={variant}
|
|
265
|
-
{...rest}
|
|
266
|
-
/>
|
|
267
|
-
);
|
|
253
|
+
}, []);
|
|
254
|
+
|
|
255
|
+
// Textfield
|
|
256
|
+
return (
|
|
257
|
+
<TextField
|
|
258
|
+
error={errorEx}
|
|
259
|
+
fullWidth={fullWidth}
|
|
260
|
+
helperText={helperTextEx}
|
|
261
|
+
inputRef={useCombinedRefs(inputRef, localRef)}
|
|
262
|
+
InputProps={InputProps}
|
|
263
|
+
InputLabelProps={InputLabelProps}
|
|
264
|
+
onChange={onChangeEx}
|
|
265
|
+
onKeyDown={onKeyPressEx}
|
|
266
|
+
type={typeEx}
|
|
267
|
+
variant={variant}
|
|
268
|
+
{...rest}
|
|
269
|
+
/>
|
|
270
|
+
);
|
|
268
271
|
});
|