@etsoo/react 1.2.54 → 1.2.58

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.
@@ -1,11 +1,10 @@
1
1
  /// <reference types="react" />
2
2
  import { IdLabelDto } from '@etsoo/appscript';
3
- import { DataTypes } from '@etsoo/shared';
4
3
  import { AutocompleteExtendedProps } from './AutocompleteExtendedProps';
5
4
  /**
6
5
  * ComboBox props
7
6
  */
8
- export interface ComboBoxProps<T extends DataTypes.StringRecord> extends AutocompleteExtendedProps<T> {
7
+ export interface ComboBoxProps<T extends {}> extends AutocompleteExtendedProps<T> {
9
8
  /**
10
9
  * Label field
11
10
  */
@@ -28,4 +27,4 @@ export interface ComboBoxProps<T extends DataTypes.StringRecord> extends Autocom
28
27
  * @param props Props
29
28
  * @returns Component
30
29
  */
31
- export declare function ComboBox<T extends DataTypes.StringRecord = IdLabelDto>(props: ComboBoxProps<T>): JSX.Element;
30
+ export declare function ComboBox<T extends {} = IdLabelDto>(props: ComboBoxProps<T>): JSX.Element;
@@ -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(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
22
- ? localOptions.find((o) => o[idField] === idValue)
23
- : defaultValue !== null && defaultValue !== void 0 ? defaultValue : value)) !== null && _a !== void 0 ? _a : { [idField]: '', [labelField]: '' };
20
+ let localValue = idValue != null
21
+ ? localOptions.find((o) => Reflect.get(o, idField) === idValue)
22
+ : defaultValue !== null && defaultValue !== void 0 ? defaultValue : value;
23
+ if (localValue === undefined)
24
+ localValue = null;
24
25
  // Current id value
25
- const localIdValue = 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) => option[idField] === 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
- ? `${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);
@@ -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
@@ -5,7 +5,7 @@ import { AutocompleteExtendedProps } from './AutocompleteExtendedProps';
5
5
  /**
6
6
  * Tiplist props
7
7
  */
8
- export interface TiplistProps<T extends DataTypes.StringRecord> extends Omit<AutocompleteExtendedProps<T>, 'open'> {
8
+ export interface TiplistProps<T extends {}> extends Omit<AutocompleteExtendedProps<T>, 'open'> {
9
9
  /**
10
10
  * Load data callback
11
11
  */
@@ -16,4 +16,4 @@ export interface TiplistProps<T extends DataTypes.StringRecord> extends Omit<Aut
16
16
  * @param props Props
17
17
  * @returns Component
18
18
  */
19
- export declare function Tiplist<T extends DataTypes.StringRecord = IdLabelDto>(props: TiplistProps<T>): JSX.Element;
19
+ export declare function Tiplist<T extends {} = IdLabelDto>(props: TiplistProps<T>): JSX.Element;
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 : 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);
@@ -93,7 +99,9 @@ export function Tiplist(props) {
93
99
  const input = inputRef.current;
94
100
  if (input) {
95
101
  // Update value
96
- const newValue = value != null && idField in value ? `${value[idField]}` : '';
102
+ const newValue = value != null && idField in value
103
+ ? `${Reflect.get(value, idField)}`
104
+ : '';
97
105
  if (newValue !== input.value) {
98
106
  // Different value, trigger change event
99
107
  Utils.triggerChange(input, newValue, false);
@@ -125,7 +133,7 @@ export function Tiplist(props) {
125
133
  }, []);
126
134
  // Layout
127
135
  return (React.createElement("div", null,
128
- 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 }),
129
137
  React.createElement(Autocomplete, { filterOptions: (options, _state) => options, value: states.value, options: states.options, onChange: (event, value, reason, details) => {
130
138
  // Set value
131
139
  setInputValue(value);
@@ -147,7 +155,7 @@ export function Tiplist(props) {
147
155
  if (loading)
148
156
  loadDataDirect(undefined, states.value == null
149
157
  ? undefined
150
- : states.value[idField]);
158
+ : Reflect.get(states.value, idField));
151
159
  }, onClose: () => {
152
160
  stateUpdate({
153
161
  open: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.2.54",
3
+ "version": "1.2.58",
4
4
  "description": "TypeScript ReactJs framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -1,5 +1,4 @@
1
1
  import { IdLabelDto } from '@etsoo/appscript';
2
- import { DataTypes } from '@etsoo/shared';
3
2
  import { Autocomplete, AutocompleteRenderInputParams } from '@mui/material';
4
3
  import React from 'react';
5
4
  import { Utils } from '../app/Utils';
@@ -10,7 +9,7 @@ import { SearchField } from './SearchField';
10
9
  /**
11
10
  * ComboBox props
12
11
  */
13
- export interface ComboBoxProps<T extends DataTypes.StringRecord>
12
+ export interface ComboBoxProps<T extends {}>
14
13
  extends AutocompleteExtendedProps<T> {
15
14
  /**
16
15
  * Label field
@@ -38,15 +37,12 @@ export interface ComboBoxProps<T extends DataTypes.StringRecord>
38
37
  * @param props Props
39
38
  * @returns Component
40
39
  */
41
- export function ComboBox<T extends DataTypes.StringRecord = IdLabelDto>(
42
- props: ComboBoxProps<T>
43
- ) {
40
+ export function ComboBox<T extends {} = IdLabelDto>(props: ComboBoxProps<T>) {
44
41
  // Destruct
45
42
  const {
46
43
  search = false,
47
44
  idField = 'id',
48
45
  idValue,
49
- inputAutoComplete = 'new-region',
50
46
  inputError,
51
47
  inputHelperText,
52
48
  inputMargin,
@@ -59,11 +55,12 @@ export function ComboBox<T extends DataTypes.StringRecord = IdLabelDto>(
59
55
  loadData,
60
56
  onLoadData,
61
57
  name,
58
+ inputAutoComplete = 'off',
62
59
  options = [],
63
60
  readOnly = true,
64
61
  onChange,
65
62
  value,
66
- getOptionLabel = (option: T) => String(option[labelField]),
63
+ getOptionLabel = (option: T) => String(Reflect.get(option, labelField)),
67
64
  sx = { minWidth: '150px' },
68
65
  ...rest
69
66
  } = props;
@@ -76,14 +73,24 @@ export function ComboBox<T extends DataTypes.StringRecord = IdLabelDto>(
76
73
  const isMounted = React.useRef(true);
77
74
 
78
75
  // Local default value
79
- const localValue =
80
- (idValue != null
81
- ? localOptions.find((o) => o[idField] === idValue)
82
- : defaultValue ?? value) ??
83
- ({ [idField]: '', [labelField]: '' } as T);
76
+ let localValue =
77
+ idValue != null
78
+ ? localOptions.find((o) => Reflect.get(o, idField) === idValue)
79
+ : defaultValue ?? value;
80
+
81
+ if (localValue === undefined) localValue = null;
84
82
 
85
83
  // Current id value
86
- const localIdValue = 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]);
87
94
 
88
95
  // Add readOnly
89
96
  const addReadOnly = (params: AutocompleteRenderInputParams) => {
@@ -102,6 +109,26 @@ export function ComboBox<T extends DataTypes.StringRecord = IdLabelDto>(
102
109
  return params;
103
110
  };
104
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
+
105
132
  React.useEffect(() => {
106
133
  if (loadData) {
107
134
  loadData().then((result) => {
@@ -125,31 +152,19 @@ export function ComboBox<T extends DataTypes.StringRecord = IdLabelDto>(
125
152
  type="text"
126
153
  style={{ display: 'none' }}
127
154
  name={name}
128
- value={Utils.formatInputValue(localIdValue) ?? ''}
155
+ defaultValue={localIdValue}
129
156
  onChange={inputOnChange}
130
157
  />
131
158
  {/* Previous input will reset first with "disableClearable = false", next input trigger change works */}
132
159
  <Autocomplete
133
- value={localValue}
160
+ value={stateValue}
134
161
  getOptionLabel={getOptionLabel}
135
162
  isOptionEqualToValue={(option: T, value: T) =>
136
- option[idField] === value[idField]
163
+ Reflect.get(option, idField) === Reflect.get(value, idField)
137
164
  }
138
165
  onChange={(event, value, reason, details) => {
139
- // Input value
140
- const input = inputRef.current;
141
- if (input) {
142
- // Update value
143
- const newValue =
144
- value != null && idField in value
145
- ? `${value[idField]}`
146
- : '';
147
-
148
- if (newValue !== input.value) {
149
- // Different value, trigger change event
150
- Utils.triggerChange(input, newValue, false);
151
- }
152
- }
166
+ // Set value
167
+ setInputValue(value);
153
168
 
154
169
  // Custom
155
170
  if (onChange != null)
@@ -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}`;
@@ -10,7 +10,7 @@ import { SearchField } from './SearchField';
10
10
  /**
11
11
  * Tiplist props
12
12
  */
13
- export interface TiplistProps<T extends DataTypes.StringRecord>
13
+ export interface TiplistProps<T extends {}>
14
14
  extends Omit<AutocompleteExtendedProps<T>, 'open'> {
15
15
  /**
16
16
  * Load data callback
@@ -22,7 +22,7 @@ export interface TiplistProps<T extends DataTypes.StringRecord>
22
22
  }
23
23
 
24
24
  // Multiple states
25
- interface States<T extends DataTypes.StringRecord> {
25
+ interface States<T extends {}> {
26
26
  open: boolean;
27
27
  options: T[];
28
28
  value?: T | null;
@@ -34,9 +34,7 @@ interface States<T extends DataTypes.StringRecord> {
34
34
  * @param props Props
35
35
  * @returns Component
36
36
  */
37
- export function Tiplist<T extends DataTypes.StringRecord = IdLabelDto>(
38
- props: TiplistProps<T>
39
- ) {
37
+ export function Tiplist<T extends {} = IdLabelDto>(props: TiplistProps<T>) {
40
38
  // Destruct
41
39
  const {
42
40
  search = false,
@@ -64,9 +62,12 @@ export function Tiplist<T extends DataTypes.StringRecord = IdLabelDto>(
64
62
  const inputRef = React.createRef<HTMLInputElement>();
65
63
 
66
64
  // Local value
67
- const localValue =
68
- value ?? defaultValue ?? ({ [idField]: '', label: '' } as unknown as T);
69
- const localIdValue = idValue ?? (localValue[idField] as DataTypes.IdType);
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));
70
71
 
71
72
  // Changable states
72
73
  const [states, stateUpdate] = React.useReducer(
@@ -77,10 +78,14 @@ export function Tiplist<T extends DataTypes.StringRecord = IdLabelDto>(
77
78
  // Loading unknown
78
79
  open: false,
79
80
  options: [],
80
- value: localValue
81
+ value: null
81
82
  }
82
83
  );
83
84
 
85
+ React.useEffect(() => {
86
+ if (localValue != null) stateUpdate({ value: localValue });
87
+ }, [localValue]);
88
+
84
89
  // State
85
90
  const [state] = React.useState<{
86
91
  loadDataSeed?: number;
@@ -172,7 +177,9 @@ export function Tiplist<T extends DataTypes.StringRecord = IdLabelDto>(
172
177
  if (input) {
173
178
  // Update value
174
179
  const newValue =
175
- value != null && idField in value ? `${value[idField]}` : '';
180
+ value != null && idField in value
181
+ ? `${Reflect.get(value, idField)}`
182
+ : '';
176
183
  if (newValue !== input.value) {
177
184
  // Different value, trigger change event
178
185
  Utils.triggerChange(input, newValue, false);
@@ -214,7 +221,7 @@ export function Tiplist<T extends DataTypes.StringRecord = IdLabelDto>(
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 */}
@@ -251,7 +258,7 @@ export function Tiplist<T extends DataTypes.StringRecord = IdLabelDto>(
251
258
  undefined,
252
259
  states.value == null
253
260
  ? undefined
254
- : (states.value[idField] as DataTypes.IdType)
261
+ : Reflect.get(states.value, idField)
255
262
  );
256
263
  }}
257
264
  onClose={() => {