@etsoo/materialui 1.6.1 → 1.6.3

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.
@@ -73,6 +73,7 @@ export type AutocompleteExtendedProps<T extends object, D extends DataTypes.Keys
73
73
  /**
74
74
  * Value change handler
75
75
  * @param value New value
76
+ * @param input Input element
76
77
  */
77
- onValueChange?: (value: T | null) => void;
78
+ onValueChange?: (value: T | null, input?: HTMLInputElement | null) => void;
78
79
  };
@@ -56,7 +56,7 @@ function ComboBox(props) {
56
56
  if (localValue != null && localValue != stateValue) {
57
57
  setStateValue(localValue);
58
58
  if (onValueChange)
59
- onValueChange(localValue);
59
+ onValueChange(localValue, inputRef.current);
60
60
  }
61
61
  }, [localValue]);
62
62
  // Add readOnly
@@ -131,7 +131,7 @@ function ComboBox(props) {
131
131
  if (onChange != null)
132
132
  onChange(event, value, reason, details);
133
133
  if (onValueChange)
134
- onValueChange(value);
134
+ onValueChange(value, inputRef.current);
135
135
  }, openOnFocus: openOnFocus, sx: sx, renderInput: (params) => search ? ((0, jsx_runtime_1.jsx)(SearchField_1.SearchField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })) : ((0, jsx_runtime_1.jsx)(InputField_1.InputField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })), options: localOptions, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, getOptionKey: getOptionKey, ...rest }), onAdd && ((0, jsx_runtime_1.jsx)(IconButton_1.default, { size: "small", onClick: () => {
136
136
  onAdd(doLoadData);
137
137
  }, title: addLabel, children: (0, jsx_runtime_1.jsx)(Add_1.default, {}) }))] })] }));
@@ -13,14 +13,25 @@ const InputField_1 = require("./InputField");
13
13
  const Box_1 = __importDefault(require("@mui/material/Box"));
14
14
  const InputAdornment_1 = __importDefault(require("@mui/material/InputAdornment"));
15
15
  const IconButton_1 = __importDefault(require("@mui/material/IconButton"));
16
+ const react_2 = require("@etsoo/react");
16
17
  /**
17
18
  * Integer input field (controlled)
18
19
  */
19
20
  function IntInputField(props) {
20
21
  // Destruct
21
- const { min = 0, step = 1, max = 9999999, inputStyle = { textAlign: "right" }, boxProps, buttons, endSymbol, symbol, value, changeDelay = [600], onChangeDelay, onChange, onFocus = (event) => event.currentTarget.select(), onValueChange, required, ...rest } = props;
22
+ const { min = 0, step = 1, max = 9999999, inputRef, inputStyle = { textAlign: "right" }, boxProps, buttons, endSymbol, symbol, value, changeDelay = [600], onChangeDelay, onChange, onFocus = (event) => event.currentTarget.select(), onValueChange, required, ...rest } = props;
23
+ const isControlled = value !== undefined;
22
24
  // State
23
- const [localValue, setLocalValue] = react_1.default.useState();
25
+ const [localValue, setInnerLocalValue] = react_1.default.useState();
26
+ const localRef = react_1.default.useRef(null);
27
+ function setLocalValue(value) {
28
+ if (isControlled) {
29
+ setInnerLocalValue(value);
30
+ }
31
+ else if (localRef.current) {
32
+ localRef.current.value = value?.toString() ?? "";
33
+ }
34
+ }
24
35
  const setValue = (value, source, init = false) => {
25
36
  if (onValueChange) {
26
37
  const newValue = onValueChange(value, source, init);
@@ -40,10 +51,17 @@ function IntInputField(props) {
40
51
  }
41
52
  };
42
53
  react_1.default.useEffect(() => {
43
- setValue(value, undefined, true);
44
- }, [value]);
54
+ if (isControlled)
55
+ setValue(value, undefined, true);
56
+ }, [value, isControlled]);
45
57
  // Layout
46
- const layout = ((0, jsx_runtime_1.jsx)(InputField_1.InputField, { type: "number", value: localValue == null ? (required ? min : "") : localValue, slotProps: {
58
+ const layout = ((0, jsx_runtime_1.jsx)(InputField_1.InputField, { type: "number", inputRef: (0, react_2.useCombinedRefs)(inputRef, localRef), value: isControlled
59
+ ? localValue == null
60
+ ? required
61
+ ? min
62
+ : ""
63
+ : localValue
64
+ : undefined, slotProps: {
47
65
  input: {
48
66
  startAdornment: symbol ? ((0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: (0, jsx_runtime_1.jsx)(InputAdornment_1.default, { position: "start", children: symbol }) })) : undefined,
49
67
  endAdornment: endSymbol ? ((0, jsx_runtime_1.jsx)(InputAdornment_1.default, { position: "end", children: endSymbol })) : undefined
@@ -113,7 +113,7 @@ function Tiplist(props) {
113
113
  if (id && options && onValueChange) {
114
114
  const option = options.find((o) => o[idField] === id);
115
115
  if (option)
116
- onValueChange(option);
116
+ onValueChange(option, inputRef.current);
117
117
  }
118
118
  // Indicates loading completed
119
119
  stateUpdate({
@@ -183,7 +183,7 @@ function Tiplist(props) {
183
183
  if (onChange != null)
184
184
  onChange(event, value, reason, details);
185
185
  if (onValueChange)
186
- onValueChange(value);
186
+ onValueChange(value, inputRef.current);
187
187
  // For clear case
188
188
  if (reason === "clear") {
189
189
  stateUpdate({ options: [], open: event.type === "click" });
@@ -73,6 +73,7 @@ export type AutocompleteExtendedProps<T extends object, D extends DataTypes.Keys
73
73
  /**
74
74
  * Value change handler
75
75
  * @param value New value
76
+ * @param input Input element
76
77
  */
77
- onValueChange?: (value: T | null) => void;
78
+ onValueChange?: (value: T | null, input?: HTMLInputElement | null) => void;
78
79
  };
@@ -50,7 +50,7 @@ export function ComboBox(props) {
50
50
  if (localValue != null && localValue != stateValue) {
51
51
  setStateValue(localValue);
52
52
  if (onValueChange)
53
- onValueChange(localValue);
53
+ onValueChange(localValue, inputRef.current);
54
54
  }
55
55
  }, [localValue]);
56
56
  // Add readOnly
@@ -125,7 +125,7 @@ export function ComboBox(props) {
125
125
  if (onChange != null)
126
126
  onChange(event, value, reason, details);
127
127
  if (onValueChange)
128
- onValueChange(value);
128
+ onValueChange(value, inputRef.current);
129
129
  }, openOnFocus: openOnFocus, sx: sx, renderInput: (params) => search ? (_jsx(SearchField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })) : (_jsx(InputField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })), options: localOptions, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, getOptionKey: getOptionKey, ...rest }), onAdd && (_jsx(IconButton, { size: "small", onClick: () => {
130
130
  onAdd(doLoadData);
131
131
  }, title: addLabel, children: _jsx(AddIcon, {}) }))] })] }));
@@ -7,14 +7,25 @@ import { InputField } from "./InputField";
7
7
  import Box from "@mui/material/Box";
8
8
  import InputAdornment from "@mui/material/InputAdornment";
9
9
  import IconButton from "@mui/material/IconButton";
10
+ import { useCombinedRefs } from "@etsoo/react";
10
11
  /**
11
12
  * Integer input field (controlled)
12
13
  */
13
14
  export function IntInputField(props) {
14
15
  // Destruct
15
- const { min = 0, step = 1, max = 9999999, inputStyle = { textAlign: "right" }, boxProps, buttons, endSymbol, symbol, value, changeDelay = [600], onChangeDelay, onChange, onFocus = (event) => event.currentTarget.select(), onValueChange, required, ...rest } = props;
16
+ const { min = 0, step = 1, max = 9999999, inputRef, inputStyle = { textAlign: "right" }, boxProps, buttons, endSymbol, symbol, value, changeDelay = [600], onChangeDelay, onChange, onFocus = (event) => event.currentTarget.select(), onValueChange, required, ...rest } = props;
17
+ const isControlled = value !== undefined;
16
18
  // State
17
- const [localValue, setLocalValue] = React.useState();
19
+ const [localValue, setInnerLocalValue] = React.useState();
20
+ const localRef = React.useRef(null);
21
+ function setLocalValue(value) {
22
+ if (isControlled) {
23
+ setInnerLocalValue(value);
24
+ }
25
+ else if (localRef.current) {
26
+ localRef.current.value = value?.toString() ?? "";
27
+ }
28
+ }
18
29
  const setValue = (value, source, init = false) => {
19
30
  if (onValueChange) {
20
31
  const newValue = onValueChange(value, source, init);
@@ -34,10 +45,17 @@ export function IntInputField(props) {
34
45
  }
35
46
  };
36
47
  React.useEffect(() => {
37
- setValue(value, undefined, true);
38
- }, [value]);
48
+ if (isControlled)
49
+ setValue(value, undefined, true);
50
+ }, [value, isControlled]);
39
51
  // Layout
40
- const layout = (_jsx(InputField, { type: "number", value: localValue == null ? (required ? min : "") : localValue, slotProps: {
52
+ const layout = (_jsx(InputField, { type: "number", inputRef: useCombinedRefs(inputRef, localRef), value: isControlled
53
+ ? localValue == null
54
+ ? required
55
+ ? min
56
+ : ""
57
+ : localValue
58
+ : undefined, slotProps: {
41
59
  input: {
42
60
  startAdornment: symbol ? (_jsx(React.Fragment, { children: _jsx(InputAdornment, { position: "start", children: symbol }) })) : undefined,
43
61
  endAdornment: endSymbol ? (_jsx(InputAdornment, { position: "end", children: endSymbol })) : undefined
@@ -107,7 +107,7 @@ export function Tiplist(props) {
107
107
  if (id && options && onValueChange) {
108
108
  const option = options.find((o) => o[idField] === id);
109
109
  if (option)
110
- onValueChange(option);
110
+ onValueChange(option, inputRef.current);
111
111
  }
112
112
  // Indicates loading completed
113
113
  stateUpdate({
@@ -177,7 +177,7 @@ export function Tiplist(props) {
177
177
  if (onChange != null)
178
178
  onChange(event, value, reason, details);
179
179
  if (onValueChange)
180
- onValueChange(value);
180
+ onValueChange(value, inputRef.current);
181
181
  // For clear case
182
182
  if (reason === "clear") {
183
183
  stateUpdate({ options: [], open: event.type === "click" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -40,9 +40,9 @@
40
40
  "@dnd-kit/sortable": "^10.0.0",
41
41
  "@emotion/react": "^11.14.0",
42
42
  "@emotion/styled": "^11.14.1",
43
- "@etsoo/appscript": "^1.6.52",
43
+ "@etsoo/appscript": "^1.6.53",
44
44
  "@etsoo/notificationbase": "^1.1.66",
45
- "@etsoo/react": "^1.8.69",
45
+ "@etsoo/react": "^1.8.70",
46
46
  "@etsoo/shared": "^1.2.80",
47
47
  "@mui/icons-material": "^7.3.7",
48
48
  "@mui/material": "^7.3.7",
@@ -75,7 +75,7 @@
75
75
  "@testing-library/react": "^16.3.1",
76
76
  "@types/pica": "^9.0.5",
77
77
  "@types/pulltorefreshjs": "^0.1.7",
78
- "@types/react": "^19.2.7",
78
+ "@types/react": "^19.2.8",
79
79
  "@types/react-avatar-editor": "^13.0.4",
80
80
  "@types/react-dom": "^19.2.3",
81
81
  "@types/react-input-mask": "^3.0.6",
@@ -96,6 +96,7 @@ export type AutocompleteExtendedProps<
96
96
  /**
97
97
  * Value change handler
98
98
  * @param value New value
99
+ * @param input Input element
99
100
  */
100
- onValueChange?: (value: T | null) => void;
101
+ onValueChange?: (value: T | null, input?: HTMLInputElement | null) => void;
101
102
  };
package/src/ComboBox.tsx CHANGED
@@ -160,7 +160,7 @@ export function ComboBox<
160
160
  React.useEffect(() => {
161
161
  if (localValue != null && localValue != stateValue) {
162
162
  setStateValue(localValue);
163
- if (onValueChange) onValueChange(localValue);
163
+ if (onValueChange) onValueChange(localValue, inputRef.current);
164
164
  }
165
165
  }, [localValue]);
166
166
 
@@ -266,7 +266,7 @@ export function ComboBox<
266
266
  // Custom
267
267
  if (onChange != null) onChange(event, value, reason, details);
268
268
 
269
- if (onValueChange) onValueChange(value);
269
+ if (onValueChange) onValueChange(value, inputRef.current);
270
270
  }}
271
271
  openOnFocus={openOnFocus}
272
272
  sx={sx}
@@ -6,6 +6,7 @@ import { InputField, InputFieldProps } from "./InputField";
6
6
  import Box, { BoxProps } from "@mui/material/Box";
7
7
  import InputAdornment from "@mui/material/InputAdornment";
8
8
  import IconButton from "@mui/material/IconButton";
9
+ import { useCombinedRefs } from "@etsoo/react";
9
10
 
10
11
  /**
11
12
  * Integer input field props
@@ -81,6 +82,7 @@ export function IntInputField(props: IntInputFieldProps) {
81
82
  min = 0,
82
83
  step = 1,
83
84
  max = 9999999,
85
+ inputRef,
84
86
  inputStyle = { textAlign: "right" },
85
87
  boxProps,
86
88
  buttons,
@@ -96,8 +98,20 @@ export function IntInputField(props: IntInputFieldProps) {
96
98
  ...rest
97
99
  } = props;
98
100
 
101
+ const isControlled = value !== undefined;
102
+
99
103
  // State
100
- const [localValue, setLocalValue] = React.useState<number | string>();
104
+ const [localValue, setInnerLocalValue] = React.useState<number | string>();
105
+
106
+ const localRef = React.useRef<HTMLInputElement>(null);
107
+
108
+ function setLocalValue(value: number | string | undefined) {
109
+ if (isControlled) {
110
+ setInnerLocalValue(value);
111
+ } else if (localRef.current) {
112
+ localRef.current.value = value?.toString() ?? "";
113
+ }
114
+ }
101
115
 
102
116
  const setValue = (
103
117
  value: number | undefined,
@@ -121,14 +135,23 @@ export function IntInputField(props: IntInputFieldProps) {
121
135
  };
122
136
 
123
137
  React.useEffect(() => {
124
- setValue(value, undefined, true);
125
- }, [value]);
138
+ if (isControlled) setValue(value, undefined, true);
139
+ }, [value, isControlled]);
126
140
 
127
141
  // Layout
128
142
  const layout = (
129
143
  <InputField
130
144
  type="number"
131
- value={localValue == null ? (required ? min : "") : localValue}
145
+ inputRef={useCombinedRefs(inputRef, localRef)}
146
+ value={
147
+ isControlled
148
+ ? localValue == null
149
+ ? required
150
+ ? min
151
+ : ""
152
+ : localValue
153
+ : undefined
154
+ }
132
155
  slotProps={{
133
156
  input: {
134
157
  startAdornment: symbol ? (
package/src/Tiplist.tsx CHANGED
@@ -220,7 +220,7 @@ export function Tiplist<
220
220
 
221
221
  if (id && options && onValueChange) {
222
222
  const option = options.find((o) => o[idField] === id);
223
- if (option) onValueChange(option);
223
+ if (option) onValueChange(option, inputRef.current);
224
224
  }
225
225
 
226
226
  // Indicates loading completed
@@ -318,7 +318,7 @@ export function Tiplist<
318
318
  // Custom
319
319
  if (onChange != null) onChange(event, value, reason, details);
320
320
 
321
- if (onValueChange) onValueChange(value);
321
+ if (onValueChange) onValueChange(value, inputRef.current);
322
322
 
323
323
  // For clear case
324
324
  if (reason === "clear") {