@etsoo/materialui 1.6.19 → 1.6.21

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.
@@ -32,6 +32,7 @@ function ComboBoxMultiple(props) {
32
32
  const { search = false, autoAddBlankItem = search, idField = "id", idValue, idValues, inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, defaultValue, label, labelField = "label", loadData, onLoadData, name, inputAutoComplete = "off", options, dataReadonly = true, readOnly, onChange, openOnFocus = true, value, disableCloseOnSelect = true, renderOption = ({ key, ...restProps }, option, { selected }) => ((0, jsx_runtime_1.jsxs)("li", { ...restProps, children: [(0, jsx_runtime_1.jsx)(Checkbox_1.default, { icon: icon, checkedIcon: checkedIcon, style: { marginRight: 8 }, checked: selected }), `${option[labelField]}`] }, key)), getOptionLabel = (option) => `${option[labelField]}`, getOptionKey = (option) => `${option[idField]}`, sx = { minWidth: "150px" }, noOptionsText = labels?.noOptions, loadingText = labels?.loading, disabled, ...rest } = props;
33
33
  // Value input ref
34
34
  const inputRef = react_1.default.createRef();
35
+ const localRef = react_1.default.useRef(undefined);
35
36
  // Options state
36
37
  const [localOptions, setOptions] = react_1.default.useState(options ?? []);
37
38
  const isMounted = react_1.default.useRef(true);
@@ -44,6 +45,11 @@ function ComboBoxMultiple(props) {
44
45
  // State
45
46
  // null for controlled
46
47
  const [stateValue, setStateValue] = react_1.default.useState(null);
48
+ const selectedCount = stateValue?.length ?? 0;
49
+ react_1.default.useEffect(() => {
50
+ if (localRef.current && inputRequired)
51
+ localRef.current.required = selectedCount === 0;
52
+ }, [inputRequired, selectedCount]);
47
53
  react_1.default.useEffect(() => {
48
54
  const localValue = idValue != null
49
55
  ? localOptions.filter((o) => o[idField] === idValue)
@@ -58,11 +64,6 @@ function ComboBoxMultiple(props) {
58
64
  Object.assign(params, { readOnly });
59
65
  }
60
66
  Object.assign(params.inputProps, { "data-reset": inputReset });
61
- params.inputProps.onInvalid = (event) => {
62
- if (inputRequired && stateValue != null && stateValue.length > 0) {
63
- event.preventDefault();
64
- }
65
- };
66
67
  if (dataReadonly) {
67
68
  params.inputProps.onKeyDown = (event) => {
68
69
  if (shared_1.Keyboard.isTypingContent(event.key)) {
@@ -124,5 +125,5 @@ function ComboBoxMultiple(props) {
124
125
  // Custom
125
126
  if (onChange != null)
126
127
  onChange(event, value, reason, details);
127
- }, 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, renderOption: renderOption, noOptionsText: noOptionsText, loadingText: loadingText, ...rest })] }));
128
+ }, 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, inputRef: localRef })) : ((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, inputRef: localRef })), options: localOptions, renderOption: renderOption, noOptionsText: noOptionsText, loadingText: loadingText, ...rest })] }));
128
129
  }
@@ -1,4 +1,5 @@
1
- import { CustomFieldData } from "@etsoo/appscript";
1
+ import { CustomFieldData, CustomFieldRef } from "@etsoo/appscript";
2
+ import React from "react";
2
3
  /**
3
4
  * CustomFieldUI component props
4
5
  */
@@ -7,6 +8,10 @@ export type CustomFieldUIProps<D extends CustomFieldData = CustomFieldData> = {
7
8
  * Custom fields
8
9
  */
9
10
  fields: D[];
11
+ /**
12
+ * Initial value
13
+ */
14
+ initialValue?: Record<string, unknown>;
10
15
  /**
11
16
  * Change event
12
17
  * @param data Current data collection
@@ -15,9 +20,9 @@ export type CustomFieldUIProps<D extends CustomFieldData = CustomFieldData> = {
15
20
  */
16
21
  onChange?: (data: Record<string, unknown>, name: string, value: unknown) => void;
17
22
  /**
18
- * Initial value
23
+ * Methods reference
19
24
  */
20
- value?: Record<string, unknown>;
25
+ mref: React.Ref<CustomFieldRef<Record<string, unknown>>>;
21
26
  };
22
27
  /**
23
28
  * CustomFieldUI component
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.CustomFieldUI = CustomFieldUI;
7
+ const react_1 = __importDefault(require("react"));
4
8
  const CustomFieldUtils_1 = require("./CustomFieldUtils");
5
9
  /**
6
10
  * CustomFieldUI component
@@ -9,14 +13,28 @@ const CustomFieldUtils_1 = require("./CustomFieldUtils");
9
13
  */
10
14
  function CustomFieldUI(props) {
11
15
  // Destruct
12
- const { fields, onChange, value = {} } = props;
16
+ const { fields, initialValue, mref, onChange } = props;
17
+ // Field component collections
18
+ const collections = {};
19
+ // Value reference
20
+ const valueRef = react_1.default.useRef({ ...initialValue });
21
+ // Methods
22
+ react_1.default.useImperativeHandle(mref, () => ({
23
+ getValue: () => valueRef.current,
24
+ setValue: (value) => {
25
+ if (!!value && typeof value === "object") {
26
+ valueRef.current = { ...value };
27
+ CustomFieldUtils_1.CustomFieldUtils.updateValues(collections, valueRef.current);
28
+ }
29
+ }
30
+ }), []);
13
31
  // Layout
14
- return CustomFieldUtils_1.CustomFieldUtils.create(fields, {}, (field) => {
32
+ return CustomFieldUtils_1.CustomFieldUtils.create(fields, collections, (field) => {
15
33
  if (!field.name)
16
34
  return undefined;
17
- return value[field.name];
35
+ return valueRef.current[field.name];
18
36
  }, (name, fieldValue) => {
19
- value[name] = fieldValue;
20
- onChange?.(value, name, fieldValue);
37
+ valueRef.current[name] = fieldValue;
38
+ onChange?.(valueRef.current, name, fieldValue);
21
39
  });
22
40
  }
@@ -53,4 +53,10 @@ export declare namespace CustomFieldUtils {
53
53
  * @param globalCallback Global callback
54
54
  */
55
55
  function updateProperties(input: object, globalCallback: (input: string) => string): void;
56
+ /**
57
+ * Update values for all fields
58
+ * @param collections Field component collections
59
+ * @param value New value
60
+ */
61
+ function updateValues<D extends CustomFieldData = CustomFieldData>(collections: CustomFieldReactCollection<D>, value: Record<string, unknown>): void;
56
62
  }
@@ -150,4 +150,21 @@ var CustomFieldUtils;
150
150
  }
151
151
  }
152
152
  CustomFieldUtils.updateProperties = updateProperties;
153
+ /**
154
+ * Update values for all fields
155
+ * @param collections Field component collections
156
+ * @param value New value
157
+ */
158
+ function updateValues(collections, value) {
159
+ for (const key in collections) {
160
+ const c = collections[key];
161
+ if (c == null)
162
+ continue;
163
+ const [ref, data] = c;
164
+ if (ref.current == null || !data.name)
165
+ continue;
166
+ ref.current.setValue(value[data.name]);
167
+ }
168
+ }
169
+ CustomFieldUtils.updateValues = updateValues;
153
170
  })(CustomFieldUtils || (exports.CustomFieldUtils = CustomFieldUtils = {}));
@@ -26,6 +26,7 @@ export function ComboBoxMultiple(props) {
26
26
  const { search = false, autoAddBlankItem = search, idField = "id", idValue, idValues, inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, defaultValue, label, labelField = "label", loadData, onLoadData, name, inputAutoComplete = "off", options, dataReadonly = true, readOnly, onChange, openOnFocus = true, value, disableCloseOnSelect = true, renderOption = ({ key, ...restProps }, option, { selected }) => (_jsxs("li", { ...restProps, children: [_jsx(Checkbox, { icon: icon, checkedIcon: checkedIcon, style: { marginRight: 8 }, checked: selected }), `${option[labelField]}`] }, key)), getOptionLabel = (option) => `${option[labelField]}`, getOptionKey = (option) => `${option[idField]}`, sx = { minWidth: "150px" }, noOptionsText = labels?.noOptions, loadingText = labels?.loading, disabled, ...rest } = props;
27
27
  // Value input ref
28
28
  const inputRef = React.createRef();
29
+ const localRef = React.useRef(undefined);
29
30
  // Options state
30
31
  const [localOptions, setOptions] = React.useState(options ?? []);
31
32
  const isMounted = React.useRef(true);
@@ -38,6 +39,11 @@ export function ComboBoxMultiple(props) {
38
39
  // State
39
40
  // null for controlled
40
41
  const [stateValue, setStateValue] = React.useState(null);
42
+ const selectedCount = stateValue?.length ?? 0;
43
+ React.useEffect(() => {
44
+ if (localRef.current && inputRequired)
45
+ localRef.current.required = selectedCount === 0;
46
+ }, [inputRequired, selectedCount]);
41
47
  React.useEffect(() => {
42
48
  const localValue = idValue != null
43
49
  ? localOptions.filter((o) => o[idField] === idValue)
@@ -52,11 +58,6 @@ export function ComboBoxMultiple(props) {
52
58
  Object.assign(params, { readOnly });
53
59
  }
54
60
  Object.assign(params.inputProps, { "data-reset": inputReset });
55
- params.inputProps.onInvalid = (event) => {
56
- if (inputRequired && stateValue != null && stateValue.length > 0) {
57
- event.preventDefault();
58
- }
59
- };
60
61
  if (dataReadonly) {
61
62
  params.inputProps.onKeyDown = (event) => {
62
63
  if (Keyboard.isTypingContent(event.key)) {
@@ -118,5 +119,5 @@ export function ComboBoxMultiple(props) {
118
119
  // Custom
119
120
  if (onChange != null)
120
121
  onChange(event, value, reason, details);
121
- }, 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, renderOption: renderOption, noOptionsText: noOptionsText, loadingText: loadingText, ...rest })] }));
122
+ }, 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, inputRef: localRef })) : (_jsx(InputField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText, inputRef: localRef })), options: localOptions, renderOption: renderOption, noOptionsText: noOptionsText, loadingText: loadingText, ...rest })] }));
122
123
  }
@@ -1,4 +1,5 @@
1
- import { CustomFieldData } from "@etsoo/appscript";
1
+ import { CustomFieldData, CustomFieldRef } from "@etsoo/appscript";
2
+ import React from "react";
2
3
  /**
3
4
  * CustomFieldUI component props
4
5
  */
@@ -7,6 +8,10 @@ export type CustomFieldUIProps<D extends CustomFieldData = CustomFieldData> = {
7
8
  * Custom fields
8
9
  */
9
10
  fields: D[];
11
+ /**
12
+ * Initial value
13
+ */
14
+ initialValue?: Record<string, unknown>;
10
15
  /**
11
16
  * Change event
12
17
  * @param data Current data collection
@@ -15,9 +20,9 @@ export type CustomFieldUIProps<D extends CustomFieldData = CustomFieldData> = {
15
20
  */
16
21
  onChange?: (data: Record<string, unknown>, name: string, value: unknown) => void;
17
22
  /**
18
- * Initial value
23
+ * Methods reference
19
24
  */
20
- value?: Record<string, unknown>;
25
+ mref: React.Ref<CustomFieldRef<Record<string, unknown>>>;
21
26
  };
22
27
  /**
23
28
  * CustomFieldUI component
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  import { CustomFieldUtils } from "./CustomFieldUtils";
2
3
  /**
3
4
  * CustomFieldUI component
@@ -6,14 +7,28 @@ import { CustomFieldUtils } from "./CustomFieldUtils";
6
7
  */
7
8
  export function CustomFieldUI(props) {
8
9
  // Destruct
9
- const { fields, onChange, value = {} } = props;
10
+ const { fields, initialValue, mref, onChange } = props;
11
+ // Field component collections
12
+ const collections = {};
13
+ // Value reference
14
+ const valueRef = React.useRef({ ...initialValue });
15
+ // Methods
16
+ React.useImperativeHandle(mref, () => ({
17
+ getValue: () => valueRef.current,
18
+ setValue: (value) => {
19
+ if (!!value && typeof value === "object") {
20
+ valueRef.current = { ...value };
21
+ CustomFieldUtils.updateValues(collections, valueRef.current);
22
+ }
23
+ }
24
+ }), []);
10
25
  // Layout
11
- return CustomFieldUtils.create(fields, {}, (field) => {
26
+ return CustomFieldUtils.create(fields, collections, (field) => {
12
27
  if (!field.name)
13
28
  return undefined;
14
- return value[field.name];
29
+ return valueRef.current[field.name];
15
30
  }, (name, fieldValue) => {
16
- value[name] = fieldValue;
17
- onChange?.(value, name, fieldValue);
31
+ valueRef.current[name] = fieldValue;
32
+ onChange?.(valueRef.current, name, fieldValue);
18
33
  });
19
34
  }
@@ -53,4 +53,10 @@ export declare namespace CustomFieldUtils {
53
53
  * @param globalCallback Global callback
54
54
  */
55
55
  function updateProperties(input: object, globalCallback: (input: string) => string): void;
56
+ /**
57
+ * Update values for all fields
58
+ * @param collections Field component collections
59
+ * @param value New value
60
+ */
61
+ function updateValues<D extends CustomFieldData = CustomFieldData>(collections: CustomFieldReactCollection<D>, value: Record<string, unknown>): void;
56
62
  }
@@ -144,4 +144,21 @@ export var CustomFieldUtils;
144
144
  }
145
145
  }
146
146
  CustomFieldUtils.updateProperties = updateProperties;
147
+ /**
148
+ * Update values for all fields
149
+ * @param collections Field component collections
150
+ * @param value New value
151
+ */
152
+ function updateValues(collections, value) {
153
+ for (const key in collections) {
154
+ const c = collections[key];
155
+ if (c == null)
156
+ continue;
157
+ const [ref, data] = c;
158
+ if (ref.current == null || !data.name)
159
+ continue;
160
+ ref.current.setValue(value[data.name]);
161
+ }
162
+ }
163
+ CustomFieldUtils.updateValues = updateValues;
147
164
  })(CustomFieldUtils || (CustomFieldUtils = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.6.19",
3
+ "version": "1.6.21",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -132,6 +132,7 @@ export function ComboBoxMultiple<
132
132
 
133
133
  // Value input ref
134
134
  const inputRef = React.createRef<HTMLInputElement>();
135
+ const localRef = React.useRef<HTMLInputElement>(undefined);
135
136
 
136
137
  // Options state
137
138
  const [localOptions, setOptions] = React.useState(options ?? []);
@@ -148,6 +149,12 @@ export function ComboBoxMultiple<
148
149
  // null for controlled
149
150
  const [stateValue, setStateValue] = React.useState<T[] | null>(null);
150
151
 
152
+ const selectedCount = stateValue?.length ?? 0;
153
+ React.useEffect(() => {
154
+ if (localRef.current && inputRequired)
155
+ localRef.current.required = selectedCount === 0;
156
+ }, [inputRequired, selectedCount]);
157
+
151
158
  React.useEffect(() => {
152
159
  const localValue: T[] | null | undefined =
153
160
  idValue != null
@@ -167,12 +174,6 @@ export function ComboBoxMultiple<
167
174
 
168
175
  Object.assign(params.inputProps, { "data-reset": inputReset });
169
176
 
170
- params.inputProps.onInvalid = (event) => {
171
- if (inputRequired && stateValue != null && stateValue.length > 0) {
172
- event.preventDefault();
173
- }
174
- };
175
-
176
177
  if (dataReadonly) {
177
178
  params.inputProps.onKeyDown = (event) => {
178
179
  if (Keyboard.isTypingContent(event.key)) {
@@ -279,6 +280,7 @@ export function ComboBoxMultiple<
279
280
  required={inputRequired}
280
281
  error={inputError}
281
282
  helperText={inputHelperText}
283
+ inputRef={localRef}
282
284
  />
283
285
  ) : (
284
286
  <InputField
@@ -290,6 +292,7 @@ export function ComboBoxMultiple<
290
292
  required={inputRequired}
291
293
  error={inputError}
292
294
  helperText={inputHelperText}
295
+ inputRef={localRef}
293
296
  />
294
297
  )
295
298
  }
@@ -1,4 +1,6 @@
1
- import { CustomFieldData } from "@etsoo/appscript";
1
+ import { CustomFieldData, CustomFieldRef } from "@etsoo/appscript";
2
+ import { CustomFieldReactCollection } from "@etsoo/react";
3
+ import React from "react";
2
4
  import { CustomFieldUtils } from "./CustomFieldUtils";
3
5
 
4
6
  /**
@@ -10,6 +12,11 @@ export type CustomFieldUIProps<D extends CustomFieldData = CustomFieldData> = {
10
12
  */
11
13
  fields: D[];
12
14
 
15
+ /**
16
+ * Initial value
17
+ */
18
+ initialValue?: Record<string, unknown>;
19
+
13
20
  /**
14
21
  * Change event
15
22
  * @param data Current data collection
@@ -23,9 +30,9 @@ export type CustomFieldUIProps<D extends CustomFieldData = CustomFieldData> = {
23
30
  ) => void;
24
31
 
25
32
  /**
26
- * Initial value
33
+ * Methods reference
27
34
  */
28
- value?: Record<string, unknown>;
35
+ mref: React.Ref<CustomFieldRef<Record<string, unknown>>>;
29
36
  };
30
37
 
31
38
  /**
@@ -37,19 +44,40 @@ export function CustomFieldUI<D extends CustomFieldData = CustomFieldData>(
37
44
  props: CustomFieldUIProps<D>
38
45
  ) {
39
46
  // Destruct
40
- const { fields, onChange, value = {} } = props;
47
+ const { fields, initialValue, mref, onChange } = props;
48
+
49
+ // Field component collections
50
+ const collections: CustomFieldReactCollection<D> = {};
51
+
52
+ // Value reference
53
+ const valueRef = React.useRef<Record<string, unknown>>({ ...initialValue });
54
+
55
+ // Methods
56
+ React.useImperativeHandle(
57
+ mref,
58
+ () => ({
59
+ getValue: () => valueRef.current,
60
+ setValue: (value) => {
61
+ if (!!value && typeof value === "object") {
62
+ valueRef.current = { ...value };
63
+ CustomFieldUtils.updateValues(collections, valueRef.current);
64
+ }
65
+ }
66
+ }),
67
+ []
68
+ );
41
69
 
42
70
  // Layout
43
71
  return CustomFieldUtils.create(
44
72
  fields,
45
- {},
73
+ collections,
46
74
  (field) => {
47
75
  if (!field.name) return undefined;
48
- return value[field.name];
76
+ return valueRef.current[field.name];
49
77
  },
50
78
  (name, fieldValue) => {
51
- value[name] = fieldValue;
52
- onChange?.(value, name, fieldValue);
79
+ valueRef.current[name] = fieldValue;
80
+ onChange?.(valueRef.current, name, fieldValue);
53
81
  }
54
82
  );
55
83
  }
@@ -199,4 +199,24 @@ export namespace CustomFieldUtils {
199
199
  }
200
200
  }
201
201
  }
202
+
203
+ /**
204
+ * Update values for all fields
205
+ * @param collections Field component collections
206
+ * @param value New value
207
+ */
208
+ export function updateValues<D extends CustomFieldData = CustomFieldData>(
209
+ collections: CustomFieldReactCollection<D>,
210
+ value: Record<string, unknown>
211
+ ) {
212
+ for (const key in collections) {
213
+ const c = collections[key];
214
+ if (c == null) continue;
215
+
216
+ const [ref, data] = c;
217
+ if (ref.current == null || !data.name) continue;
218
+
219
+ ref.current.setValue(value[data.name]);
220
+ }
221
+ }
202
222
  }