@etsoo/react 1.2.55 → 1.2.59

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.
@@ -9,20 +9,29 @@ import { SearchField } from './SearchField';
9
9
  * @returns Component
10
10
  */
11
11
  export function ComboBox(props) {
12
- var _a, _b;
13
12
  // Destruct
14
- const { search = false, idField = 'id', idValue, inputAutoComplete = 'new-region', inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputVariant, defaultValue, label, labelField = 'label', loadData, onLoadData, name, options = [], readOnly = true, onChange, value, getOptionLabel = (option) => String(Reflect.get(option, labelField)), sx = { minWidth: '150px' }, ...rest } = props;
13
+ const { search = false, idField = 'id', idValue, inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputVariant, defaultValue, label, labelField = 'label', loadData, onLoadData, name, inputAutoComplete = 'off', options = [], readOnly = true, onChange, value, getOptionLabel = (option) => String(Reflect.get(option, labelField)), sx = { minWidth: '150px' }, ...rest } = props;
15
14
  // Value input ref
16
15
  const inputRef = React.createRef();
17
16
  // Options state
18
17
  const [localOptions, setOptions] = React.useState(options);
19
18
  const isMounted = React.useRef(true);
20
19
  // Local default value
21
- const localValue = (_a = (idValue != null
20
+ let localValue = idValue != null
22
21
  ? localOptions.find((o) => Reflect.get(o, idField) === idValue)
23
- : defaultValue !== null && defaultValue !== void 0 ? defaultValue : value)) !== null && _a !== void 0 ? _a : { [idField]: '', [labelField]: '' };
22
+ : defaultValue !== null && defaultValue !== void 0 ? defaultValue : value;
23
+ if (localValue === undefined)
24
+ localValue = null;
24
25
  // Current id value
25
- const localIdValue = Reflect.get(localValue, idField);
26
+ // One time calculation for input's default value (uncontrolled)
27
+ const localIdValue = localValue && Reflect.get(localValue, idField);
28
+ // State
29
+ // null for controlled
30
+ const [stateValue, setStateValue] = React.useState(null);
31
+ React.useEffect(() => {
32
+ if (localValue != null)
33
+ setStateValue(localValue);
34
+ }, [localValue]);
26
35
  // Add readOnly
27
36
  const addReadOnly = (params) => {
28
37
  if (readOnly != null) {
@@ -36,6 +45,22 @@ export function ComboBox(props) {
36
45
  Object.assign(params.inputProps, { autoComplete: inputAutoComplete });
37
46
  return params;
38
47
  };
48
+ const setInputValue = (value) => {
49
+ // Set state
50
+ setStateValue(value);
51
+ // Input value
52
+ const input = inputRef.current;
53
+ if (input) {
54
+ // Update value
55
+ const newValue = value != null && idField in value
56
+ ? `${Reflect.get(value, idField)}`
57
+ : '';
58
+ if (newValue !== input.value) {
59
+ // Different value, trigger change event
60
+ Utils.triggerChange(input, newValue, false);
61
+ }
62
+ }
63
+ };
39
64
  React.useEffect(() => {
40
65
  if (loadData) {
41
66
  loadData().then((result) => {
@@ -52,20 +77,10 @@ export function ComboBox(props) {
52
77
  }, []);
53
78
  // Layout
54
79
  return (React.createElement("div", null,
55
- React.createElement("input", { ref: inputRef, "data-reset": "true", type: "text", style: { display: 'none' }, name: name, value: (_b = Utils.formatInputValue(localIdValue)) !== null && _b !== void 0 ? _b : '', onChange: inputOnChange }),
56
- React.createElement(Autocomplete, { value: localValue, getOptionLabel: getOptionLabel, isOptionEqualToValue: (option, value) => Reflect.get(option, idField) === Reflect.get(value, idField), onChange: (event, value, reason, details) => {
57
- // Input value
58
- const input = inputRef.current;
59
- if (input) {
60
- // Update value
61
- const newValue = value != null && idField in value
62
- ? `${Reflect.get(value, idField)}`
63
- : '';
64
- if (newValue !== input.value) {
65
- // Different value, trigger change event
66
- Utils.triggerChange(input, newValue, false);
67
- }
68
- }
80
+ React.createElement("input", { ref: inputRef, "data-reset": "true", type: "text", style: { display: 'none' }, name: name, defaultValue: localIdValue, onChange: inputOnChange }),
81
+ React.createElement(Autocomplete, { value: stateValue, getOptionLabel: getOptionLabel, isOptionEqualToValue: (option, value) => Reflect.get(option, idField) === Reflect.get(value, idField), onChange: (event, value, reason, details) => {
82
+ // Set value
83
+ setInputValue(value);
69
84
  // Custom
70
85
  if (onChange != null)
71
86
  onChange(event, value, reason, details);
@@ -9,11 +9,13 @@ import { useIMask } from 'react-imask';
9
9
  * @returns Component
10
10
  */
11
11
  export function MaskInput(props) {
12
+ var _a;
12
13
  // Destruct
13
- const { mask, InputLabelProps = {}, InputProps = {}, readOnly, search = false, size = search ? MUGlobal.searchFieldSize : MUGlobal.inputFieldSize, variant = search
14
+ const { defaultValue, mask, InputLabelProps = {}, InputProps = {}, readOnly, search = false, size = search ? MUGlobal.searchFieldSize : MUGlobal.inputFieldSize, value, variant = search
14
15
  ? MUGlobal.searchFieldVariant
15
16
  : MUGlobal.inputFieldVariant, ...rest } = props;
16
- const { ref } = useIMask(mask);
17
+ const { ref, maskRef } = useIMask(mask);
18
+ const localValue = (_a = defaultValue !== null && defaultValue !== void 0 ? defaultValue : value) !== null && _a !== void 0 ? _a : '';
17
19
  // Shrink
18
20
  InputLabelProps.shrink = search
19
21
  ? MUGlobal.searchFieldShrink
@@ -22,6 +24,9 @@ export function MaskInput(props) {
22
24
  if (readOnly != null)
23
25
  InputProps.readOnly = readOnly;
24
26
  InputProps.inputRef = ref;
27
+ React.useEffect(() => {
28
+ maskRef.current.value = String(localValue);
29
+ }, [localValue]);
25
30
  // Layout
26
31
  return (React.createElement(TextField, { InputLabelProps: InputLabelProps, InputProps: InputProps, size: size, variant: variant, ...rest }));
27
32
  }
@@ -4,7 +4,7 @@ import { IdLabelDto } from '@etsoo/appscript';
4
4
  /**
5
5
  * Extended select component props
6
6
  */
7
- export interface SelectExProps<T extends Record<string, any> = IdLabelDto> extends Omit<SelectProps, 'labelId' | 'input' | 'native'> {
7
+ export interface SelectExProps<T extends {}> extends Omit<SelectProps, 'labelId' | 'input' | 'native'> {
8
8
  /**
9
9
  * Id field, default is id
10
10
  */
@@ -43,4 +43,4 @@ export interface SelectExProps<T extends Record<string, any> = IdLabelDto> exten
43
43
  * @param props Props
44
44
  * @returns Component
45
45
  */
46
- export declare function SelectEx<T extends Record<string, any> = IdLabelDto>(props: SelectExProps<T>): JSX.Element;
46
+ export declare function SelectEx<T extends {} = IdLabelDto>(props: SelectExProps<T>): JSX.Element;
@@ -28,7 +28,11 @@ export function SelectEx(props) {
28
28
  localValue = valueSource;
29
29
  }
30
30
  // Value state
31
- const [valueState, setValueState] = React.useState(localValue);
31
+ const [valueState, setValueState] = React.useState(null);
32
+ React.useEffect(() => {
33
+ if (localValue != null)
34
+ setValueState(localValue);
35
+ }, [localValue]);
32
36
  // Label id
33
37
  const labelId = `selectex-label-${name}`;
34
38
  // Item checked or not
package/lib/mu/Tiplist.js CHANGED
@@ -9,14 +9,16 @@ import { SearchField } from './SearchField';
9
9
  * @returns Component
10
10
  */
11
11
  export function Tiplist(props) {
12
- var _a;
13
12
  // Destruct
14
13
  const { search = false, idField = 'id', idValue, inputAutoComplete = 'off', inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputVariant, label, loadData, defaultValue, value, name, readOnly, onChange, sx = { minWidth: '180px' }, ...rest } = props;
15
14
  // Value input ref
16
15
  const inputRef = React.createRef();
17
16
  // Local value
18
- const localValue = (_a = value !== null && value !== void 0 ? value : defaultValue) !== null && _a !== void 0 ? _a : { [idField]: '', label: '' };
19
- const localIdValue = idValue !== null && idValue !== void 0 ? idValue : Reflect.get(localValue, idField);
17
+ let localValue = value !== null && value !== void 0 ? value : defaultValue;
18
+ if (localValue === undefined)
19
+ localValue = null;
20
+ // One time calculation for input's default value (uncontrolled)
21
+ const localIdValue = idValue !== null && idValue !== void 0 ? idValue : (localValue && Reflect.get(localValue, idField));
20
22
  // Changable states
21
23
  const [states, stateUpdate] = React.useReducer((currentState, newState) => {
22
24
  return { ...currentState, ...newState };
@@ -24,8 +26,12 @@ export function Tiplist(props) {
24
26
  // Loading unknown
25
27
  open: false,
26
28
  options: [],
27
- value: localValue
29
+ value: null
28
30
  });
31
+ React.useEffect(() => {
32
+ if (localValue != null)
33
+ stateUpdate({ value: localValue });
34
+ }, [localValue]);
29
35
  // State
30
36
  const [state] = React.useState({});
31
37
  const isMounted = React.useRef(true);
@@ -127,7 +133,7 @@ export function Tiplist(props) {
127
133
  }, []);
128
134
  // Layout
129
135
  return (React.createElement("div", null,
130
- React.createElement("input", { ref: inputRef, "data-reset": "true", type: "text", style: { display: 'none' }, name: name, value: localIdValue, onChange: inputOnChange }),
136
+ React.createElement("input", { ref: inputRef, "data-reset": "true", type: "text", style: { display: 'none' }, name: name, defaultValue: localIdValue, onChange: inputOnChange }),
131
137
  React.createElement(Autocomplete, { filterOptions: (options, _state) => options, value: states.value, options: states.options, onChange: (event, value, reason, details) => {
132
138
  // Set value
133
139
  setInputValue(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.2.55",
3
+ "version": "1.2.59",
4
4
  "description": "TypeScript ReactJs framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -50,9 +50,9 @@
50
50
  "@emotion/react": "^11.5.0",
51
51
  "@emotion/style": "^0.8.0",
52
52
  "@emotion/styled": "^11.3.0",
53
- "@etsoo/appscript": "^1.1.17",
53
+ "@etsoo/appscript": "^1.1.18",
54
54
  "@etsoo/notificationbase": "^1.0.88",
55
- "@etsoo/shared": "^1.0.55",
55
+ "@etsoo/shared": "^1.0.56",
56
56
  "@mui/icons-material": "^5.0.4",
57
57
  "@mui/material": "^5.0.4",
58
58
  "@reach/router": "^1.3.4",
@@ -43,7 +43,6 @@ export function ComboBox<T extends {} = IdLabelDto>(props: ComboBoxProps<T>) {
43
43
  search = false,
44
44
  idField = 'id',
45
45
  idValue,
46
- inputAutoComplete = 'new-region',
47
46
  inputError,
48
47
  inputHelperText,
49
48
  inputMargin,
@@ -56,6 +55,7 @@ export function ComboBox<T extends {} = IdLabelDto>(props: ComboBoxProps<T>) {
56
55
  loadData,
57
56
  onLoadData,
58
57
  name,
58
+ inputAutoComplete = 'off',
59
59
  options = [],
60
60
  readOnly = true,
61
61
  onChange,
@@ -73,14 +73,24 @@ export function ComboBox<T extends {} = IdLabelDto>(props: ComboBoxProps<T>) {
73
73
  const isMounted = React.useRef(true);
74
74
 
75
75
  // Local default value
76
- const localValue =
77
- (idValue != null
76
+ let localValue =
77
+ idValue != null
78
78
  ? localOptions.find((o) => Reflect.get(o, idField) === idValue)
79
- : defaultValue ?? value) ??
80
- ({ [idField]: '', [labelField]: '' } as T);
79
+ : defaultValue ?? value;
80
+
81
+ if (localValue === undefined) localValue = null;
81
82
 
82
83
  // Current id value
83
- const localIdValue = Reflect.get(localValue, idField);
84
+ // One time calculation for input's default value (uncontrolled)
85
+ const localIdValue = localValue && Reflect.get(localValue, idField);
86
+
87
+ // State
88
+ // null for controlled
89
+ const [stateValue, setStateValue] = React.useState<T | null>(null);
90
+
91
+ React.useEffect(() => {
92
+ if (localValue != null) setStateValue(localValue);
93
+ }, [localValue]);
84
94
 
85
95
  // Add readOnly
86
96
  const addReadOnly = (params: AutocompleteRenderInputParams) => {
@@ -99,6 +109,26 @@ export function ComboBox<T extends {} = IdLabelDto>(props: ComboBoxProps<T>) {
99
109
  return params;
100
110
  };
101
111
 
112
+ const setInputValue = (value: T | null) => {
113
+ // Set state
114
+ setStateValue(value);
115
+
116
+ // Input value
117
+ const input = inputRef.current;
118
+ if (input) {
119
+ // Update value
120
+ const newValue =
121
+ value != null && idField in value
122
+ ? `${Reflect.get(value, idField)}`
123
+ : '';
124
+
125
+ if (newValue !== input.value) {
126
+ // Different value, trigger change event
127
+ Utils.triggerChange(input, newValue, false);
128
+ }
129
+ }
130
+ };
131
+
102
132
  React.useEffect(() => {
103
133
  if (loadData) {
104
134
  loadData().then((result) => {
@@ -122,31 +152,19 @@ export function ComboBox<T extends {} = IdLabelDto>(props: ComboBoxProps<T>) {
122
152
  type="text"
123
153
  style={{ display: 'none' }}
124
154
  name={name}
125
- value={Utils.formatInputValue(localIdValue) ?? ''}
155
+ defaultValue={localIdValue}
126
156
  onChange={inputOnChange}
127
157
  />
128
158
  {/* Previous input will reset first with "disableClearable = false", next input trigger change works */}
129
159
  <Autocomplete
130
- value={localValue}
160
+ value={stateValue}
131
161
  getOptionLabel={getOptionLabel}
132
162
  isOptionEqualToValue={(option: T, value: T) =>
133
163
  Reflect.get(option, idField) === Reflect.get(value, idField)
134
164
  }
135
165
  onChange={(event, value, reason, details) => {
136
- // Input value
137
- const input = inputRef.current;
138
- if (input) {
139
- // Update value
140
- const newValue =
141
- value != null && idField in value
142
- ? `${Reflect.get(value, idField)}`
143
- : '';
144
-
145
- if (newValue !== input.value) {
146
- // Different value, trigger change event
147
- Utils.triggerChange(input, newValue, false);
148
- }
149
- }
166
+ // Set value
167
+ setInputValue(value);
150
168
 
151
169
  // Custom
152
170
  if (onChange != null)
@@ -32,19 +32,22 @@ export type MaskInputProps = TextFieldProps & {
32
32
  export function MaskInput(props: MaskInputProps) {
33
33
  // Destruct
34
34
  const {
35
+ defaultValue,
35
36
  mask,
36
37
  InputLabelProps = {},
37
38
  InputProps = {},
38
39
  readOnly,
39
40
  search = false,
40
41
  size = search ? MUGlobal.searchFieldSize : MUGlobal.inputFieldSize,
42
+ value,
41
43
  variant = search
42
44
  ? MUGlobal.searchFieldVariant
43
45
  : MUGlobal.inputFieldVariant,
44
46
  ...rest
45
47
  } = props;
46
48
 
47
- const { ref } = useIMask(mask);
49
+ const { ref, maskRef } = useIMask(mask);
50
+ const localValue = defaultValue ?? value ?? '';
48
51
 
49
52
  // Shrink
50
53
  InputLabelProps.shrink = search
@@ -55,6 +58,10 @@ export function MaskInput(props: MaskInputProps) {
55
58
  if (readOnly != null) InputProps.readOnly = readOnly;
56
59
  InputProps.inputRef = ref;
57
60
 
61
+ React.useEffect(() => {
62
+ maskRef.current.value = String(localValue);
63
+ }, [localValue]);
64
+
58
65
  // Layout
59
66
  return (
60
67
  <TextField
@@ -18,7 +18,7 @@ import { ListItemRightIcon } from './ListItemRightIcon';
18
18
  /**
19
19
  * Extended select component props
20
20
  */
21
- export interface SelectExProps<T extends Record<string, any> = IdLabelDto>
21
+ export interface SelectExProps<T extends {}>
22
22
  extends Omit<SelectProps, 'labelId' | 'input' | 'native'> {
23
23
  /**
24
24
  * Id field, default is id
@@ -66,9 +66,7 @@ export interface SelectExProps<T extends Record<string, any> = IdLabelDto>
66
66
  * @param props Props
67
67
  * @returns Component
68
68
  */
69
- export function SelectEx<T extends Record<string, any> = IdLabelDto>(
70
- props: SelectExProps<T>
71
- ) {
69
+ export function SelectEx<T extends {} = IdLabelDto>(props: SelectExProps<T>) {
72
70
  // Destruct
73
71
  const {
74
72
  defaultValue,
@@ -103,7 +101,11 @@ export function SelectEx<T extends Record<string, any> = IdLabelDto>(
103
101
  }
104
102
 
105
103
  // Value state
106
- const [valueState, setValueState] = React.useState(localValue);
104
+ const [valueState, setValueState] = React.useState<unknown | null>(null);
105
+
106
+ React.useEffect(() => {
107
+ if (localValue != null) setValueState(localValue);
108
+ }, [localValue]);
107
109
 
108
110
  // Label id
109
111
  const labelId = `selectex-label-${name}`;
@@ -62,9 +62,12 @@ export function Tiplist<T extends {} = IdLabelDto>(props: TiplistProps<T>) {
62
62
  const inputRef = React.createRef<HTMLInputElement>();
63
63
 
64
64
  // Local value
65
- const localValue =
66
- value ?? defaultValue ?? ({ [idField]: '', label: '' } as unknown as T);
67
- const localIdValue = idValue ?? Reflect.get(localValue, idField);
65
+ let localValue = value ?? defaultValue;
66
+ if (localValue === undefined) localValue = null;
67
+
68
+ // One time calculation for input's default value (uncontrolled)
69
+ const localIdValue =
70
+ idValue ?? (localValue && Reflect.get(localValue, idField));
68
71
 
69
72
  // Changable states
70
73
  const [states, stateUpdate] = React.useReducer(
@@ -75,10 +78,14 @@ export function Tiplist<T extends {} = IdLabelDto>(props: TiplistProps<T>) {
75
78
  // Loading unknown
76
79
  open: false,
77
80
  options: [],
78
- value: localValue
81
+ value: null
79
82
  }
80
83
  );
81
84
 
85
+ React.useEffect(() => {
86
+ if (localValue != null) stateUpdate({ value: localValue });
87
+ }, [localValue]);
88
+
82
89
  // State
83
90
  const [state] = React.useState<{
84
91
  loadDataSeed?: number;
@@ -214,7 +221,7 @@ export function Tiplist<T extends {} = IdLabelDto>(props: TiplistProps<T>) {
214
221
  type="text"
215
222
  style={{ display: 'none' }}
216
223
  name={name}
217
- value={localIdValue}
224
+ defaultValue={localIdValue}
218
225
  onChange={inputOnChange}
219
226
  />
220
227
  {/* Previous input will reset first with "disableClearable = false", next input trigger change works */}