@gravity-ui/dynamic-forms 1.2.0 → 1.4.0
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/CHANGELOG.md +21 -0
- package/README.md +34 -5
- package/build/cjs/lib/core/components/Form/Controller.js +9 -3
- package/build/cjs/lib/core/components/Form/DynamicField.js +11 -4
- package/build/cjs/lib/core/components/Form/hooks/index.js +3 -0
- package/build/cjs/lib/core/components/Form/hooks/useControllerMirror.js +19 -0
- package/build/cjs/lib/core/components/Form/hooks/useDynamicFieldMirror.js +22 -0
- package/build/cjs/lib/core/components/Form/hooks/useField.js +1 -1
- package/build/cjs/lib/core/components/Form/hooks/useIntegrationFF.js +46 -0
- package/build/cjs/lib/core/components/Form/hooks/useSearchStore.js +5 -2
- package/build/cjs/lib/core/components/Form/hooks/useStore.js +3 -35
- package/build/cjs/lib/core/components/Form/types/index.js +2 -0
- package/build/cjs/lib/core/components/Form/types/mirror.js +2 -0
- package/build/cjs/lib/core/components/Form/types/store.js +2 -0
- package/build/cjs/lib/core/components/View/ViewController.js +2 -2
- package/build/cjs/lib/core/components/View/hooks/useComponents.js +1 -3
- package/build/cjs/lib/kit/components/Inputs/FileInput/FileInput.css +20 -0
- package/build/cjs/lib/kit/components/Inputs/FileInput/FileInput.js +50 -0
- package/build/cjs/lib/kit/components/Inputs/FileInput/index.js +4 -0
- package/build/cjs/lib/kit/components/Inputs/FileInput/utils.js +16 -0
- package/build/cjs/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +3 -2
- package/build/cjs/lib/kit/components/Inputs/TextLink/TextLink.js +20 -0
- package/build/cjs/lib/kit/components/Inputs/TextLink/index.js +4 -0
- package/build/cjs/lib/kit/components/Inputs/index.js +2 -0
- package/build/cjs/lib/kit/components/Layouts/Row/Row.css +18 -10
- package/build/cjs/lib/kit/components/Layouts/Row/Row.js +4 -5
- package/build/cjs/lib/kit/components/Views/FileInputView/FileInputView.js +12 -0
- package/build/cjs/lib/kit/components/Views/FileInputView/index.js +4 -0
- package/build/cjs/lib/kit/components/Views/TextLinkView/TextLinkView.js +17 -0
- package/build/cjs/lib/kit/components/Views/TextLinkView/index.js +4 -0
- package/build/cjs/lib/kit/components/Views/index.js +2 -0
- package/build/cjs/lib/kit/constants/config.js +8 -0
- package/build/cjs/lib/kit/i18n/en.json +3 -1
- package/build/cjs/lib/kit/i18n/ru.json +3 -1
- package/build/cjs/lib/kit/utils/common.js +1 -26
- package/build/cjs/lib/kit/validators/validators.js +8 -8
- package/build/esm/lib/core/components/Form/Controller.js +9 -3
- package/build/esm/lib/core/components/Form/DynamicField.d.ts +2 -1
- package/build/esm/lib/core/components/Form/DynamicField.js +12 -5
- package/build/esm/lib/core/components/Form/hooks/index.d.ts +3 -0
- package/build/esm/lib/core/components/Form/hooks/index.js +3 -0
- package/build/esm/lib/core/components/Form/hooks/useControllerMirror.d.ts +2 -0
- package/build/esm/lib/core/components/Form/hooks/useControllerMirror.js +14 -0
- package/build/esm/lib/core/components/Form/hooks/useDynamicFieldMirror.d.ts +2 -0
- package/build/esm/lib/core/components/Form/hooks/useDynamicFieldMirror.js +17 -0
- package/build/esm/lib/core/components/Form/hooks/useField.d.ts +2 -2
- package/build/esm/lib/core/components/Form/hooks/useField.js +1 -1
- package/build/esm/lib/core/components/Form/hooks/useIntegrationFF.d.ts +2 -0
- package/build/esm/lib/core/components/Form/hooks/useIntegrationFF.js +41 -0
- package/build/esm/lib/core/components/Form/hooks/useSearchStore.d.ts +2 -4
- package/build/esm/lib/core/components/Form/hooks/useSearchStore.js +5 -2
- package/build/esm/lib/core/components/Form/hooks/useStore.d.ts +2 -8
- package/build/esm/lib/core/components/Form/hooks/useStore.js +5 -37
- package/build/esm/lib/core/components/Form/types/context.d.ts +2 -1
- package/build/esm/lib/core/components/Form/types/index.d.ts +2 -0
- package/build/esm/lib/core/components/Form/types/index.js +2 -0
- package/build/esm/lib/core/components/Form/types/mirror.d.ts +17 -0
- package/build/esm/lib/core/components/Form/types/mirror.js +1 -0
- package/build/esm/lib/core/components/Form/types/store.d.ts +7 -0
- package/build/esm/lib/core/components/Form/types/store.js +1 -0
- package/build/esm/lib/core/components/View/ViewController.js +2 -2
- package/build/esm/lib/core/components/View/hooks/useComponents.d.ts +2 -2
- package/build/esm/lib/core/components/View/hooks/useComponents.js +1 -3
- package/build/esm/lib/core/constants.d.ts +1 -0
- package/build/esm/lib/core/types/specs.d.ts +6 -1
- package/build/esm/lib/kit/components/Inputs/FileInput/FileInput.css +20 -0
- package/build/esm/lib/kit/components/Inputs/FileInput/FileInput.d.ts +4 -0
- package/build/esm/lib/kit/components/Inputs/FileInput/FileInput.js +46 -0
- package/build/esm/lib/kit/components/Inputs/FileInput/index.d.ts +1 -0
- package/build/esm/lib/kit/components/Inputs/FileInput/index.js +1 -0
- package/build/esm/lib/kit/components/Inputs/FileInput/utils.d.ts +2 -0
- package/build/esm/lib/kit/components/Inputs/FileInput/utils.js +12 -0
- package/build/esm/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +3 -2
- package/build/esm/lib/kit/components/Inputs/TextLink/TextLink.d.ts +2 -0
- package/build/esm/lib/kit/components/Inputs/TextLink/TextLink.js +15 -0
- package/build/esm/lib/kit/components/Inputs/TextLink/index.d.ts +1 -0
- package/build/esm/lib/kit/components/Inputs/TextLink/index.js +1 -0
- package/build/esm/lib/kit/components/Inputs/index.d.ts +2 -0
- package/build/esm/lib/kit/components/Inputs/index.js +2 -0
- package/build/esm/lib/kit/components/Layouts/Row/Row.css +18 -10
- package/build/esm/lib/kit/components/Layouts/Row/Row.js +4 -5
- package/build/esm/lib/kit/components/Views/FileInputView/FileInputView.d.ts +3 -0
- package/build/esm/lib/kit/components/Views/FileInputView/FileInputView.js +7 -0
- package/build/esm/lib/kit/components/Views/FileInputView/index.d.ts +1 -0
- package/build/esm/lib/kit/components/Views/FileInputView/index.js +1 -0
- package/build/esm/lib/kit/components/Views/TextLinkView/TextLinkView.d.ts +2 -0
- package/build/esm/lib/kit/components/Views/TextLinkView/TextLinkView.js +12 -0
- package/build/esm/lib/kit/components/Views/TextLinkView/index.d.ts +1 -0
- package/build/esm/lib/kit/components/Views/TextLinkView/index.js +1 -0
- package/build/esm/lib/kit/components/Views/index.d.ts +2 -0
- package/build/esm/lib/kit/components/Views/index.js +2 -0
- package/build/esm/lib/kit/constants/config.js +9 -1
- package/build/esm/lib/kit/i18n/en.json +3 -1
- package/build/esm/lib/kit/i18n/ru.json +3 -1
- package/build/esm/lib/kit/utils/common.d.ts +0 -2
- package/build/esm/lib/kit/utils/common.js +0 -24
- package/build/esm/lib/kit/validators/validators.d.ts +2 -0
- package/build/esm/lib/kit/validators/validators.js +8 -8
- package/package.json +12 -4
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TextLinkView = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
6
|
+
const core_1 = require("../../../../core");
|
|
7
|
+
const TEXT_LINK_PROPERTY_NAME = 'text';
|
|
8
|
+
const TextLinkView = ({ value, spec, name }) => {
|
|
9
|
+
const specProperties = spec.properties;
|
|
10
|
+
const preparedSpec = react_1.default.useMemo(() => {
|
|
11
|
+
var _a;
|
|
12
|
+
return specProperties && specProperties[TEXT_LINK_PROPERTY_NAME]
|
|
13
|
+
? Object.assign(Object.assign({}, specProperties[TEXT_LINK_PROPERTY_NAME]), { viewSpec: Object.assign(Object.assign({}, (_a = specProperties[TEXT_LINK_PROPERTY_NAME]) === null || _a === void 0 ? void 0 : _a.viewSpec), { link: value === null || value === void 0 ? void 0 : value.link }) }) : undefined;
|
|
14
|
+
}, [specProperties, value === null || value === void 0 ? void 0 : value.link]);
|
|
15
|
+
return preparedSpec ? (react_1.default.createElement(core_1.ViewController, { spec: preparedSpec, name: `${name}.${TEXT_LINK_PROPERTY_NAME}` })) : null;
|
|
16
|
+
};
|
|
17
|
+
exports.TextLinkView = TextLinkView;
|
|
@@ -4,6 +4,7 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
tslib_1.__exportStar(require("./ArrayBaseView"), exports);
|
|
5
5
|
tslib_1.__exportStar(require("./BaseView"), exports);
|
|
6
6
|
tslib_1.__exportStar(require("./CardOneOfView"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./FileInputView"), exports);
|
|
7
8
|
tslib_1.__exportStar(require("./MonacoInputView"), exports);
|
|
8
9
|
tslib_1.__exportStar(require("./MultiSelectView"), exports);
|
|
9
10
|
tslib_1.__exportStar(require("./NumberWithScaleView"), exports);
|
|
@@ -12,3 +13,4 @@ tslib_1.__exportStar(require("./OneOfCardView"), exports);
|
|
|
12
13
|
tslib_1.__exportStar(require("./OneOfView"), exports);
|
|
13
14
|
tslib_1.__exportStar(require("./TableArrayView"), exports);
|
|
14
15
|
tslib_1.__exportStar(require("./TextAreaView"), exports);
|
|
16
|
+
tslib_1.__exportStar(require("./TextLinkView"), exports);
|
|
@@ -60,6 +60,7 @@ exports.dynamicConfig = {
|
|
|
60
60
|
card_oneof: { Component: components_1.CardOneOf, independent: true },
|
|
61
61
|
secret: { Component: components_1.Secret, independent: true },
|
|
62
62
|
base: { Component: components_1.ObjectBase, independent: true },
|
|
63
|
+
text_link: { Component: components_1.TextLink, independent: true },
|
|
63
64
|
},
|
|
64
65
|
layouts: {
|
|
65
66
|
row: components_1.Row,
|
|
@@ -83,6 +84,7 @@ exports.dynamicConfig = {
|
|
|
83
84
|
textarea: { Component: components_1.TextArea },
|
|
84
85
|
select: { Component: components_1.Select },
|
|
85
86
|
base: { Component: components_1.Text },
|
|
87
|
+
file_input: { Component: components_1.FileInput },
|
|
86
88
|
number_with_scale: { Component: components_1.NumberWithScale },
|
|
87
89
|
monaco_input: { Component: components_1.MonacoInput },
|
|
88
90
|
text_content: { Component: components_1.TextContent, independent: true },
|
|
@@ -155,6 +157,7 @@ exports.dynamicCardConfig = {
|
|
|
155
157
|
oneof: { Component: components_1.OneOfCard, independent: true },
|
|
156
158
|
secret: { Component: components_1.Secret, independent: true },
|
|
157
159
|
base: { Component: components_1.ObjectBase, independent: true },
|
|
160
|
+
text_link: { Component: components_1.TextLink, independent: true },
|
|
158
161
|
},
|
|
159
162
|
layouts: {
|
|
160
163
|
row: components_1.Row2,
|
|
@@ -175,6 +178,7 @@ exports.dynamicCardConfig = {
|
|
|
175
178
|
textarea: { Component: components_1.TextArea },
|
|
176
179
|
select: { Component: components_1.Select },
|
|
177
180
|
base: { Component: components_1.Text },
|
|
181
|
+
file_input: { Component: components_1.FileInput },
|
|
178
182
|
number_with_scale: { Component: components_1.NumberWithScale },
|
|
179
183
|
monaco_input: { Component: components_1.MonacoInputCard },
|
|
180
184
|
text_content: { Component: components_1.TextContent, independent: true },
|
|
@@ -239,6 +243,7 @@ exports.dynamicViewConfig = {
|
|
|
239
243
|
card_oneof: { Component: components_1.CardOneOfView, independent: true },
|
|
240
244
|
secret: undefined,
|
|
241
245
|
base: { Component: components_1.ObjectBaseView, independent: true },
|
|
246
|
+
text_link: { Component: components_1.TextLinkView, independent: true },
|
|
242
247
|
},
|
|
243
248
|
layouts: {
|
|
244
249
|
row: components_1.ViewRow,
|
|
@@ -258,6 +263,7 @@ exports.dynamicViewConfig = {
|
|
|
258
263
|
textarea: { Component: components_1.TextAreaView },
|
|
259
264
|
select: { Component: components_1.BaseView },
|
|
260
265
|
base: { Component: components_1.BaseView },
|
|
266
|
+
file_input: { Component: components_1.FileInputView },
|
|
261
267
|
number_with_scale: { Component: components_1.NumberWithScaleView },
|
|
262
268
|
monaco_input: { Component: components_1.MonacoView },
|
|
263
269
|
text_content: undefined,
|
|
@@ -316,6 +322,7 @@ exports.dynamicViewCardConfig = {
|
|
|
316
322
|
oneof: { Component: components_1.OneOfCardView, independent: true },
|
|
317
323
|
secret: undefined,
|
|
318
324
|
base: { Component: components_1.ObjectBaseView, independent: true },
|
|
325
|
+
text_link: { Component: components_1.TextLinkView, independent: true },
|
|
319
326
|
},
|
|
320
327
|
layouts: {
|
|
321
328
|
row: components_1.ViewRow2,
|
|
@@ -333,6 +340,7 @@ exports.dynamicViewCardConfig = {
|
|
|
333
340
|
textarea: { Component: components_1.TextAreaView },
|
|
334
341
|
select: { Component: components_1.BaseView },
|
|
335
342
|
base: { Component: components_1.BaseView },
|
|
343
|
+
file_input: { Component: components_1.FileInputView },
|
|
336
344
|
number_with_scale: { Component: components_1.NumberWithScaleView },
|
|
337
345
|
monaco_input: { Component: components_1.MonacoViewCard },
|
|
338
346
|
text_content: undefined,
|
|
@@ -42,5 +42,7 @@
|
|
|
42
42
|
"label_error-zero-start": "Value must not start with a zero",
|
|
43
43
|
"label_error-dot-end": "Value must not end with a dot",
|
|
44
44
|
"label_delete": "Delete",
|
|
45
|
-
"button_cancel": "Close"
|
|
45
|
+
"button_cancel": "Close",
|
|
46
|
+
"button-upload_file": "Upload file",
|
|
47
|
+
"label-data_loaded": "Data uploaded"
|
|
46
48
|
}
|
|
@@ -42,5 +42,7 @@
|
|
|
42
42
|
"label_error-zero-start": "Значение не должно начинаться с нуля",
|
|
43
43
|
"label_error-dot-end": "Значение не должно заканчиваться точкой",
|
|
44
44
|
"label_delete": "Удалить",
|
|
45
|
-
"button_cancel": "Закрыть"
|
|
45
|
+
"button_cancel": "Закрыть",
|
|
46
|
+
"button-upload_file": "Загрузить файл",
|
|
47
|
+
"label-data_loaded": "Данные загружены"
|
|
46
48
|
}
|
|
@@ -1,36 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isCorrectSizeParams = exports.prepareSpec = exports.isNotEmptyValue =
|
|
3
|
+
exports.isCorrectSizeParams = exports.prepareSpec = exports.isNotEmptyValue = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const final_form_1 = require("final-form");
|
|
6
5
|
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
7
6
|
const core_1 = require("../../core");
|
|
8
7
|
const helpers_1 = require("../validators/helpers");
|
|
9
8
|
const bigIntMath_1 = require("./bigIntMath");
|
|
10
|
-
const getChildError = (name, errors, head) => {
|
|
11
|
-
const error = lodash_1.default.get(errors, name);
|
|
12
|
-
if (!head && (error === null || error === void 0 ? void 0 : error[final_form_1.ARRAY_ERROR])) {
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
else if (lodash_1.default.isArray(error)) {
|
|
16
|
-
return error.some((itemError, idx) => {
|
|
17
|
-
if (lodash_1.default.isArray(itemError) || lodash_1.default.isObjectLike(itemError)) {
|
|
18
|
-
return (0, exports.getChildError)(`${name}[${idx}]`, errors);
|
|
19
|
-
}
|
|
20
|
-
return Boolean(itemError);
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
else if (lodash_1.default.isObjectLike(error)) {
|
|
24
|
-
return Object.keys(error).some((key) => {
|
|
25
|
-
if (lodash_1.default.isArray(error[key]) || lodash_1.default.isObjectLike(error[key])) {
|
|
26
|
-
return (0, exports.getChildError)(`${name}.${key}`, errors);
|
|
27
|
-
}
|
|
28
|
-
return Boolean(error[key]);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
return false;
|
|
32
|
-
};
|
|
33
|
-
exports.getChildError = getChildError;
|
|
34
9
|
const isNotEmptyValue = (value, spec) => {
|
|
35
10
|
var _a;
|
|
36
11
|
if (lodash_1.default.isNil(value)) {
|
|
@@ -37,7 +37,7 @@ const getBooleanValidator = (params = {}) => {
|
|
|
37
37
|
};
|
|
38
38
|
exports.getBooleanValidator = getBooleanValidator;
|
|
39
39
|
const getNumberValidator = (params = {}) => {
|
|
40
|
-
const { ignoreRequiredCheck, ignoreSpaceStartCheck, ignoreSpaceEndCheck, ignoreNumberCheck, ignoreMaximumCheck, ignoreMinimumCheck, ignoreIntCheck, } = params;
|
|
40
|
+
const { ignoreRequiredCheck, ignoreSpaceStartCheck, ignoreSpaceEndCheck, ignoreNumberCheck, ignoreMaximumCheck, ignoreMinimumCheck, ignoreIntCheck, ignoreDotEnd, ignoreZeroStart, } = params;
|
|
41
41
|
return (spec, value = '') => {
|
|
42
42
|
const stringValue = String(value);
|
|
43
43
|
if (!ignoreRequiredCheck && spec.required && !stringValue.length) {
|
|
@@ -50,16 +50,17 @@ const getNumberValidator = (params = {}) => {
|
|
|
50
50
|
if (!ignoreSpaceEndCheck && !stringValue[stringValue.length - 1].trim()) {
|
|
51
51
|
return validators_1.ErrorMessages.SPACE_END;
|
|
52
52
|
}
|
|
53
|
-
if (stringValue[stringValue.length - 1] === '.') {
|
|
53
|
+
if (!ignoreDotEnd && stringValue[stringValue.length - 1] === '.') {
|
|
54
54
|
return validators_1.ErrorMessages.DOT_END;
|
|
55
55
|
}
|
|
56
56
|
if (!ignoreNumberCheck && !(0, helpers_1.isFloat)(stringValue)) {
|
|
57
57
|
return validators_1.ErrorMessages.NUMBER;
|
|
58
58
|
}
|
|
59
|
-
if (
|
|
60
|
-
(stringValue.length >
|
|
61
|
-
stringValue.
|
|
62
|
-
|
|
59
|
+
if (!ignoreZeroStart &&
|
|
60
|
+
((stringValue.length > 1 && stringValue[0] === '0' && stringValue[1] !== '.') ||
|
|
61
|
+
(stringValue.length > 2 &&
|
|
62
|
+
stringValue.substring(0, 2) === '-0' &&
|
|
63
|
+
stringValue[2] !== '.'))) {
|
|
63
64
|
return validators_1.ErrorMessages.ZERO_START;
|
|
64
65
|
}
|
|
65
66
|
}
|
|
@@ -71,8 +72,7 @@ const getNumberValidator = (params = {}) => {
|
|
|
71
72
|
}
|
|
72
73
|
if (!ignoreMinimumCheck &&
|
|
73
74
|
lodash_1.default.isNumber(spec.minimum) &&
|
|
74
|
-
stringValue.length &&
|
|
75
|
-
spec.minimum > Number(stringValue)) {
|
|
75
|
+
((stringValue.length && spec.minimum > Number(stringValue)) || !stringValue.length)) {
|
|
76
76
|
return validators_1.ErrorMessages.minNumber(spec.minimum);
|
|
77
77
|
}
|
|
78
78
|
if (lodash_1.default.isString(spec.format) && stringValue.length) {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import { isCorrectSpec } from '../../helpers';
|
|
3
|
-
import { useComponents, useDynamicFormsCtx, useField, useRender, useValidate } from './hooks';
|
|
4
|
-
import { useSearch } from './hooks/useSearch';
|
|
3
|
+
import { useComponents, useControllerMirror, useDynamicFormsCtx, useField, useRender, useSearch, useValidate, } from './hooks';
|
|
5
4
|
export const Controller = ({ spec, name, initialValue, parentOnChange, parentOnUnmount, }) => {
|
|
6
|
-
const { tools } = useDynamicFormsCtx();
|
|
5
|
+
const { tools, __mirror } = useDynamicFormsCtx();
|
|
7
6
|
const { inputEntity, Layout } = useComponents(spec);
|
|
8
7
|
const render = useRender({ name, spec, inputEntity, Layout });
|
|
9
8
|
const validate = useValidate(spec);
|
|
@@ -17,6 +16,13 @@ export const Controller = ({ spec, name, initialValue, parentOnChange, parentOnU
|
|
|
17
16
|
parentOnUnmount,
|
|
18
17
|
});
|
|
19
18
|
const withSearch = useSearch(spec, renderProps.input.value, name);
|
|
19
|
+
useControllerMirror(name, {
|
|
20
|
+
useComponents: { inputEntity, Layout },
|
|
21
|
+
useRender: render,
|
|
22
|
+
useValidate: validate,
|
|
23
|
+
useField: renderProps,
|
|
24
|
+
useSearch: withSearch,
|
|
25
|
+
}, __mirror);
|
|
20
26
|
if (_.isString(name) && isCorrectSpec(spec)) {
|
|
21
27
|
return withSearch(render(renderProps));
|
|
22
28
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { MonacoEditorProps } from 'react-monaco-editor/lib/types';
|
|
3
3
|
import { Spec } from '../../types';
|
|
4
|
-
import { DynamicFormConfig, FieldValue } from './types';
|
|
4
|
+
import { DynamicFormConfig, FieldValue, WonderMirror } from './types';
|
|
5
5
|
export interface DynamicFieldProps {
|
|
6
6
|
name: string;
|
|
7
7
|
spec: Spec;
|
|
8
8
|
config: DynamicFormConfig;
|
|
9
9
|
Monaco?: React.ComponentType<MonacoEditorProps>;
|
|
10
10
|
search?: string | ((spec: Spec, input: FieldValue, name: string) => boolean);
|
|
11
|
+
__mirror?: WonderMirror;
|
|
11
12
|
}
|
|
12
13
|
export declare const DynamicField: React.FC<DynamicFieldProps>;
|
|
@@ -3,18 +3,20 @@ import _ from 'lodash';
|
|
|
3
3
|
import { isValidElementType } from 'react-is';
|
|
4
4
|
import { isCorrectSpec } from '../../helpers';
|
|
5
5
|
import { Controller } from './Controller';
|
|
6
|
-
import { useCreateContext, useCreateSearchContext, useSearchStore, useStore } from './hooks';
|
|
6
|
+
import { useCreateContext, useCreateSearchContext, useDynamicFieldMirror, useIntegrationFF, useSearchStore, useStore, } from './hooks';
|
|
7
7
|
import { getDefaultSearchFunction, isCorrectConfig } from './utils';
|
|
8
|
-
export const DynamicField = ({ name, spec, config, Monaco, search }) => {
|
|
8
|
+
export const DynamicField = ({ name, spec, config, Monaco, search, __mirror, }) => {
|
|
9
9
|
const DynamicFormsCtx = useCreateContext();
|
|
10
10
|
const SearchContext = useCreateSearchContext();
|
|
11
|
-
const { tools,
|
|
12
|
-
const
|
|
11
|
+
const { tools, store } = useStore(name);
|
|
12
|
+
const watcher = useIntegrationFF(store);
|
|
13
|
+
const { store: searchStore, setField, removeField, isHiddenField } = useSearchStore();
|
|
13
14
|
const context = React.useMemo(() => ({
|
|
14
15
|
config,
|
|
15
16
|
Monaco: isValidElementType(Monaco) ? Monaco : undefined,
|
|
16
17
|
tools,
|
|
17
|
-
|
|
18
|
+
__mirror,
|
|
19
|
+
}), [tools, config, Monaco, __mirror]);
|
|
18
20
|
const searchContext = React.useMemo(() => ({
|
|
19
21
|
setField,
|
|
20
22
|
removeField,
|
|
@@ -22,6 +24,11 @@ export const DynamicField = ({ name, spec, config, Monaco, search }) => {
|
|
|
22
24
|
searchFunction: _.isFunction(search) ? search : getDefaultSearchFunction(search),
|
|
23
25
|
}), [isHiddenField, removeField, search, setField]);
|
|
24
26
|
const correctParams = React.useMemo(() => _.isString(name) && isCorrectSpec(spec) && isCorrectConfig(config), [name, spec, config]);
|
|
27
|
+
useDynamicFieldMirror({
|
|
28
|
+
useStore: { tools, store },
|
|
29
|
+
useIntegrationFF: watcher,
|
|
30
|
+
useSearchStore: { store: searchStore, setField, removeField, isHiddenField },
|
|
31
|
+
}, __mirror);
|
|
25
32
|
if (correctParams) {
|
|
26
33
|
return (React.createElement(DynamicFormsCtx.Provider, { value: context },
|
|
27
34
|
React.createElement(SearchContext.Provider, { value: searchContext },
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export * from './useComponents';
|
|
2
|
+
export * from './useControllerMirror';
|
|
2
3
|
export * from './useCreateContext';
|
|
4
|
+
export * from './useDynamicFieldMirror';
|
|
3
5
|
export * from './useDynamicFormsCtx';
|
|
4
6
|
export * from './useField';
|
|
7
|
+
export * from './useIntegrationFF';
|
|
5
8
|
export * from './useRender';
|
|
6
9
|
export * from './useStore';
|
|
7
10
|
export * from './useValidate';
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export * from './useComponents';
|
|
2
|
+
export * from './useControllerMirror';
|
|
2
3
|
export * from './useCreateContext';
|
|
4
|
+
export * from './useDynamicFieldMirror';
|
|
3
5
|
export * from './useDynamicFormsCtx';
|
|
4
6
|
export * from './useField';
|
|
7
|
+
export * from './useIntegrationFF';
|
|
5
8
|
export * from './useRender';
|
|
6
9
|
export * from './useStore';
|
|
7
10
|
export * from './useValidate';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export const useControllerMirror = (name, params, __mirror) => {
|
|
3
|
+
if (__mirror === null || __mirror === void 0 ? void 0 : __mirror.controller) {
|
|
4
|
+
__mirror.controller[name] = params;
|
|
5
|
+
}
|
|
6
|
+
React.useEffect(() => {
|
|
7
|
+
return () => {
|
|
8
|
+
var _a;
|
|
9
|
+
if ((_a = __mirror === null || __mirror === void 0 ? void 0 : __mirror.controller) === null || _a === void 0 ? void 0 : _a[name]) {
|
|
10
|
+
delete __mirror.controller[name];
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}, []);
|
|
14
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export const useDynamicFieldMirror = (params, __mirror) => {
|
|
3
|
+
if (__mirror === null || __mirror === void 0 ? void 0 : __mirror.field) {
|
|
4
|
+
__mirror.field.useStore = params.useStore;
|
|
5
|
+
__mirror.field.useIntegrationFF = params.useIntegrationFF;
|
|
6
|
+
__mirror.field.useSearchStore = params.useSearchStore;
|
|
7
|
+
}
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
return () => {
|
|
10
|
+
if (__mirror === null || __mirror === void 0 ? void 0 : __mirror.field) {
|
|
11
|
+
delete __mirror.field.useStore;
|
|
12
|
+
delete __mirror.field.useIntegrationFF;
|
|
13
|
+
delete __mirror.field.useSearchStore;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}, []);
|
|
17
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Spec } from '../../../types';
|
|
2
2
|
import { DynamicFormsContext, FieldRenderProps, FieldValue, ValidateError } from '../types';
|
|
3
|
-
export interface
|
|
3
|
+
export interface UseFieldProps<Value extends FieldValue, SpecType extends Spec> {
|
|
4
4
|
name: string;
|
|
5
5
|
spec: SpecType;
|
|
6
6
|
initialValue: Value;
|
|
@@ -9,4 +9,4 @@ export interface FieldProps<Value extends FieldValue, SpecType extends Spec> {
|
|
|
9
9
|
parentOnChange: ((childName: string, childValue: FieldValue, childErrors: Record<string, ValidateError>) => void) | null;
|
|
10
10
|
parentOnUnmount: ((childName: string) => void) | null;
|
|
11
11
|
}
|
|
12
|
-
export declare const useField: <Value extends FieldValue, SpecType extends Spec>({ name, spec, initialValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount, }:
|
|
12
|
+
export declare const useField: <Value extends FieldValue, SpecType extends Spec>({ name, spec, initialValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount, }: UseFieldProps<Value, SpecType>) => FieldRenderProps<Value>;
|
|
@@ -122,7 +122,7 @@ export const useField = ({ name, spec, initialValue, validate: propsValidate, to
|
|
|
122
122
|
onDrop,
|
|
123
123
|
]);
|
|
124
124
|
React.useEffect(() => {
|
|
125
|
-
if (!firstRenderRef.current || !_.isEqual(initialValue, state.value)) {
|
|
125
|
+
if (!firstRenderRef.current || !_.isEqual(initialValue, state.value) || state.error) {
|
|
126
126
|
(parentOnChange ? parentOnChange : tools.onChange)(name, state.value, Object.assign(Object.assign({}, state.childErrors), { [name]: state.error }));
|
|
127
127
|
}
|
|
128
128
|
}, [state.value]);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
import debounce from 'lodash/debounce';
|
|
4
|
+
import { Field as FinalFormField, useForm } from 'react-final-form';
|
|
5
|
+
import { transformArrOut } from '../utils';
|
|
6
|
+
export const useIntegrationFF = (store) => {
|
|
7
|
+
const form = useForm();
|
|
8
|
+
const watcher = React.useMemo(() => {
|
|
9
|
+
const props = {
|
|
10
|
+
name: store.name,
|
|
11
|
+
render: () => null,
|
|
12
|
+
subscription: {},
|
|
13
|
+
validate: () => {
|
|
14
|
+
const asyncErrors = [];
|
|
15
|
+
let error;
|
|
16
|
+
_.values(store.errors).forEach((err) => {
|
|
17
|
+
if (err) {
|
|
18
|
+
if (_.isFunction(err === null || err === void 0 ? void 0 : err.then)) {
|
|
19
|
+
asyncErrors.push(err);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
error = err;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (asyncErrors.length) {
|
|
27
|
+
return Promise.all(asyncErrors).then((r) => r[0]);
|
|
28
|
+
}
|
|
29
|
+
return error;
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
return React.createElement(FinalFormField, Object.assign({}, props));
|
|
33
|
+
}, [store.name, store.errors]);
|
|
34
|
+
const change = React.useCallback(debounce((value) => {
|
|
35
|
+
form.change(store.name, _.get(transformArrOut(value), store.name));
|
|
36
|
+
}, 100), [form.change, store.name]);
|
|
37
|
+
React.useEffect(() => {
|
|
38
|
+
change(store.values);
|
|
39
|
+
}, [store.values]);
|
|
40
|
+
return watcher;
|
|
41
|
+
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
export declare const useSearchStore: (
|
|
2
|
-
store:
|
|
3
|
-
[x: string]: boolean;
|
|
4
|
-
};
|
|
1
|
+
export declare const useSearchStore: () => {
|
|
2
|
+
store: Record<string, boolean>;
|
|
5
3
|
setField: (name: string, search: boolean) => void;
|
|
6
4
|
removeField: (name: string) => void;
|
|
7
5
|
isHiddenField: (name: string) => boolean;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import _ from 'lodash';
|
|
3
3
|
import { getParentName } from '../';
|
|
4
|
-
export const useSearchStore = (
|
|
5
|
-
const [store, setStore] = React.useState({
|
|
4
|
+
export const useSearchStore = () => {
|
|
5
|
+
const [store, setStore] = React.useState({});
|
|
6
6
|
const isHiddenField = React.useCallback((name) => {
|
|
7
7
|
const selfFlag = store[name];
|
|
8
8
|
if (selfFlag === false) {
|
|
@@ -20,6 +20,9 @@ export const useSearchStore = (name) => {
|
|
|
20
20
|
return false;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
if (_.isUndefined(selfFlag)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
23
26
|
return true;
|
|
24
27
|
}, [store]);
|
|
25
28
|
return {
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import { FieldObjectValue, FieldValue, ValidateError } from '../types';
|
|
2
|
-
export interface DynamicFieldStore {
|
|
3
|
-
name: string;
|
|
4
|
-
initialValue: FieldObjectValue;
|
|
5
|
-
values: FieldObjectValue;
|
|
6
|
-
errors: Record<string, ValidateError>;
|
|
7
|
-
}
|
|
1
|
+
import { DynamicFieldStore, FieldObjectValue, FieldValue, ValidateError } from '../types';
|
|
8
2
|
export declare const useStore: (name: string) => {
|
|
9
3
|
tools: {
|
|
10
4
|
initialValue: FieldObjectValue;
|
|
@@ -12,5 +6,5 @@ export declare const useStore: (name: string) => {
|
|
|
12
6
|
onUnmount: (name: string) => void;
|
|
13
7
|
submitFailed: boolean;
|
|
14
8
|
};
|
|
15
|
-
|
|
9
|
+
store: DynamicFieldStore;
|
|
16
10
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import {
|
|
4
|
-
import { transformArrIn
|
|
3
|
+
import { useForm } from 'react-final-form';
|
|
4
|
+
import { transformArrIn } from '../utils';
|
|
5
5
|
export const useStore = (name) => {
|
|
6
6
|
const form = useForm();
|
|
7
7
|
const firstRenderRef = React.useRef(true);
|
|
@@ -17,44 +17,12 @@ export const useStore = (name) => {
|
|
|
17
17
|
};
|
|
18
18
|
});
|
|
19
19
|
const submitFailed = form.getState().submitFailed;
|
|
20
|
-
const watcher = React.useMemo(() => {
|
|
21
|
-
const props = {
|
|
22
|
-
name: store.name,
|
|
23
|
-
render: () => null,
|
|
24
|
-
subscription: {},
|
|
25
|
-
validate: () => {
|
|
26
|
-
const asyncErrors = [];
|
|
27
|
-
let error;
|
|
28
|
-
_.values(store.errors).forEach((err) => {
|
|
29
|
-
if (err) {
|
|
30
|
-
if (_.isFunction(err === null || err === void 0 ? void 0 : err.then)) {
|
|
31
|
-
asyncErrors.push(err);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
error = err;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
if (asyncErrors.length) {
|
|
39
|
-
return Promise.all(asyncErrors).then((r) => r[0]);
|
|
40
|
-
}
|
|
41
|
-
return error;
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
return React.createElement(FinalFormField, Object.assign({}, props));
|
|
45
|
-
}, [store.name, store.errors]);
|
|
46
20
|
const tools = React.useMemo(() => ({
|
|
47
21
|
initialValue: store.initialValue,
|
|
48
|
-
onChange: (name, value, errors) => setStore((store) => (Object.assign(Object.assign({}, store), { values: _.set(Object.assign({}, store.values), name, value), errors: errors || {} }))),
|
|
49
|
-
onUnmount: (name) => setStore((store) => (Object.assign(Object.assign({}, store), { errors: _.omit(store.errors, Object.keys(store.errors).filter((key) => key.startsWith(name))) }))),
|
|
22
|
+
onChange: (name, value, errors) => setStore((store) => (Object.assign(Object.assign({}, store), { values: _.set(Object.assign({}, store.values), name, _.clone(value)), errors: errors || {} }))),
|
|
23
|
+
onUnmount: (name) => setStore((store) => (Object.assign(Object.assign({}, store), { values: _.omit(store.values, name), errors: _.omit(store.errors, Object.keys(store.errors).filter((key) => key.startsWith(name))) }))),
|
|
50
24
|
submitFailed,
|
|
51
25
|
}), [store.initialValue, setStore, submitFailed]);
|
|
52
|
-
const change = React.useCallback(_.debounce((value) => {
|
|
53
|
-
form.change(store.name, _.get(transformArrOut(value), store.name));
|
|
54
|
-
}, 100), [form.change, store.name]);
|
|
55
|
-
React.useEffect(() => {
|
|
56
|
-
change(store.values);
|
|
57
|
-
}, [store.values]);
|
|
58
26
|
React.useEffect(() => {
|
|
59
27
|
if (!firstRenderRef.current) {
|
|
60
28
|
const initialValue = transformArrIn({
|
|
@@ -71,5 +39,5 @@ export const useStore = (name) => {
|
|
|
71
39
|
React.useEffect(() => {
|
|
72
40
|
firstRenderRef.current = false;
|
|
73
41
|
}, []);
|
|
74
|
-
return { tools,
|
|
42
|
+
return { tools, store };
|
|
75
43
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { MonacoEditorProps } from 'react-monaco-editor/lib/types';
|
|
3
|
-
import { DynamicFormConfig, FieldObjectValue, FieldValue, ValidateError } from './';
|
|
3
|
+
import { DynamicFormConfig, FieldObjectValue, FieldValue, ValidateError, WonderMirror } from './';
|
|
4
4
|
export interface DynamicFormsContext {
|
|
5
5
|
config: DynamicFormConfig;
|
|
6
6
|
Monaco?: React.ComponentType<MonacoEditorProps>;
|
|
@@ -10,4 +10,5 @@ export interface DynamicFormsContext {
|
|
|
10
10
|
onUnmount: (name: string) => void;
|
|
11
11
|
submitFailed: boolean;
|
|
12
12
|
};
|
|
13
|
+
__mirror?: WonderMirror;
|
|
13
14
|
}
|
|
@@ -5,8 +5,10 @@ export * from './context';
|
|
|
5
5
|
export * from './field';
|
|
6
6
|
export * from './input';
|
|
7
7
|
export * from './layout';
|
|
8
|
+
export * from './mirror';
|
|
8
9
|
export * from './number';
|
|
9
10
|
export * from './object';
|
|
11
|
+
export * from './store';
|
|
10
12
|
export * from './string';
|
|
11
13
|
export * from './validators';
|
|
12
14
|
export * from './value';
|
|
@@ -5,8 +5,10 @@ export * from './context';
|
|
|
5
5
|
export * from './field';
|
|
6
6
|
export * from './input';
|
|
7
7
|
export * from './layout';
|
|
8
|
+
export * from './mirror';
|
|
8
9
|
export * from './number';
|
|
9
10
|
export * from './object';
|
|
11
|
+
export * from './store';
|
|
10
12
|
export * from './string';
|
|
11
13
|
export * from './validators';
|
|
12
14
|
export * from './value';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useComponents, useField, useIntegrationFF, useRender, useSearch, useSearchStore, useStore, useValidate } from '../hooks';
|
|
2
|
+
export interface ControllerMirror {
|
|
3
|
+
useComponents?: ReturnType<typeof useComponents>;
|
|
4
|
+
useRender?: ReturnType<typeof useRender>;
|
|
5
|
+
useValidate?: ReturnType<typeof useValidate>;
|
|
6
|
+
useField?: ReturnType<typeof useField>;
|
|
7
|
+
useSearch?: ReturnType<typeof useSearch>;
|
|
8
|
+
}
|
|
9
|
+
export interface DynamicFieldMirror {
|
|
10
|
+
useStore?: ReturnType<typeof useStore>;
|
|
11
|
+
useIntegrationFF?: ReturnType<typeof useIntegrationFF>;
|
|
12
|
+
useSearchStore?: ReturnType<typeof useSearchStore>;
|
|
13
|
+
}
|
|
14
|
+
export interface WonderMirror {
|
|
15
|
+
field: DynamicFieldMirror;
|
|
16
|
+
controller: Record<string, ControllerMirror | undefined>;
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useComponents, useDynamicFormsCtx, useRender } from './hooks';
|
|
3
3
|
export const ViewController = ({ spec, name, }) => {
|
|
4
|
-
const { value, Link } = useDynamicFormsCtx();
|
|
5
|
-
const { viewEntity, Layout } = useComponents(spec);
|
|
4
|
+
const { config, value, Link } = useDynamicFormsCtx();
|
|
5
|
+
const { viewEntity, Layout } = useComponents(spec, config);
|
|
6
6
|
const render = useRender({ name, value, spec, viewEntity, Layout, Link });
|
|
7
7
|
return React.createElement(React.Fragment, null, render);
|
|
8
8
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FormValue, Spec } from '../../../types';
|
|
2
|
-
import { IndependentViewEntity, ViewEntity, ViewLayoutType } from '../types';
|
|
3
|
-
export declare const useComponents: <Value extends FormValue, SpecType extends Spec>(spec: SpecType) => {
|
|
2
|
+
import { DynamicViewConfig, IndependentViewEntity, ViewEntity, ViewLayoutType } from '../types';
|
|
3
|
+
export declare const useComponents: <Value extends FormValue, SpecType extends Spec>(spec: SpecType, config: DynamicViewConfig) => {
|
|
4
4
|
viewEntity: ViewEntity<Value, SpecType> | IndependentViewEntity<Value, SpecType> | undefined;
|
|
5
5
|
Layout: ViewLayoutType<Value, SpecType> | undefined;
|
|
6
6
|
};
|