@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.
- package/lib/cjs/ComboBoxMultiple.js +7 -6
- package/lib/cjs/custom/CustomFieldUI.d.ts +8 -3
- package/lib/cjs/custom/CustomFieldUI.js +23 -5
- package/lib/cjs/custom/CustomFieldUtils.d.ts +6 -0
- package/lib/cjs/custom/CustomFieldUtils.js +17 -0
- package/lib/mjs/ComboBoxMultiple.js +7 -6
- package/lib/mjs/custom/CustomFieldUI.d.ts +8 -3
- package/lib/mjs/custom/CustomFieldUI.js +20 -5
- package/lib/mjs/custom/CustomFieldUtils.d.ts +6 -0
- package/lib/mjs/custom/CustomFieldUtils.js +17 -0
- package/package.json +1 -1
- package/src/ComboBoxMultiple.tsx +9 -6
- package/src/custom/CustomFieldUI.tsx +36 -8
- package/src/custom/CustomFieldUtils.tsx +20 -0
|
@@ -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
|
-
*
|
|
23
|
+
* Methods reference
|
|
19
24
|
*/
|
|
20
|
-
|
|
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,
|
|
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,
|
|
32
|
+
return CustomFieldUtils_1.CustomFieldUtils.create(fields, collections, (field) => {
|
|
15
33
|
if (!field.name)
|
|
16
34
|
return undefined;
|
|
17
|
-
return
|
|
35
|
+
return valueRef.current[field.name];
|
|
18
36
|
}, (name, fieldValue) => {
|
|
19
|
-
|
|
20
|
-
onChange?.(
|
|
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
|
-
*
|
|
23
|
+
* Methods reference
|
|
19
24
|
*/
|
|
20
|
-
|
|
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,
|
|
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,
|
|
26
|
+
return CustomFieldUtils.create(fields, collections, (field) => {
|
|
12
27
|
if (!field.name)
|
|
13
28
|
return undefined;
|
|
14
|
-
return
|
|
29
|
+
return valueRef.current[field.name];
|
|
15
30
|
}, (name, fieldValue) => {
|
|
16
|
-
|
|
17
|
-
onChange?.(
|
|
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
package/src/ComboBoxMultiple.tsx
CHANGED
|
@@ -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
|
-
*
|
|
33
|
+
* Methods reference
|
|
27
34
|
*/
|
|
28
|
-
|
|
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,
|
|
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
|
|
76
|
+
return valueRef.current[field.name];
|
|
49
77
|
},
|
|
50
78
|
(name, fieldValue) => {
|
|
51
|
-
|
|
52
|
-
onChange?.(
|
|
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
|
}
|