@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.
Files changed (99) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +34 -5
  3. package/build/cjs/lib/core/components/Form/Controller.js +9 -3
  4. package/build/cjs/lib/core/components/Form/DynamicField.js +11 -4
  5. package/build/cjs/lib/core/components/Form/hooks/index.js +3 -0
  6. package/build/cjs/lib/core/components/Form/hooks/useControllerMirror.js +19 -0
  7. package/build/cjs/lib/core/components/Form/hooks/useDynamicFieldMirror.js +22 -0
  8. package/build/cjs/lib/core/components/Form/hooks/useField.js +1 -1
  9. package/build/cjs/lib/core/components/Form/hooks/useIntegrationFF.js +46 -0
  10. package/build/cjs/lib/core/components/Form/hooks/useSearchStore.js +5 -2
  11. package/build/cjs/lib/core/components/Form/hooks/useStore.js +3 -35
  12. package/build/cjs/lib/core/components/Form/types/index.js +2 -0
  13. package/build/cjs/lib/core/components/Form/types/mirror.js +2 -0
  14. package/build/cjs/lib/core/components/Form/types/store.js +2 -0
  15. package/build/cjs/lib/core/components/View/ViewController.js +2 -2
  16. package/build/cjs/lib/core/components/View/hooks/useComponents.js +1 -3
  17. package/build/cjs/lib/kit/components/Inputs/FileInput/FileInput.css +20 -0
  18. package/build/cjs/lib/kit/components/Inputs/FileInput/FileInput.js +50 -0
  19. package/build/cjs/lib/kit/components/Inputs/FileInput/index.js +4 -0
  20. package/build/cjs/lib/kit/components/Inputs/FileInput/utils.js +16 -0
  21. package/build/cjs/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +3 -2
  22. package/build/cjs/lib/kit/components/Inputs/TextLink/TextLink.js +20 -0
  23. package/build/cjs/lib/kit/components/Inputs/TextLink/index.js +4 -0
  24. package/build/cjs/lib/kit/components/Inputs/index.js +2 -0
  25. package/build/cjs/lib/kit/components/Layouts/Row/Row.css +18 -10
  26. package/build/cjs/lib/kit/components/Layouts/Row/Row.js +4 -5
  27. package/build/cjs/lib/kit/components/Views/FileInputView/FileInputView.js +12 -0
  28. package/build/cjs/lib/kit/components/Views/FileInputView/index.js +4 -0
  29. package/build/cjs/lib/kit/components/Views/TextLinkView/TextLinkView.js +17 -0
  30. package/build/cjs/lib/kit/components/Views/TextLinkView/index.js +4 -0
  31. package/build/cjs/lib/kit/components/Views/index.js +2 -0
  32. package/build/cjs/lib/kit/constants/config.js +8 -0
  33. package/build/cjs/lib/kit/i18n/en.json +3 -1
  34. package/build/cjs/lib/kit/i18n/ru.json +3 -1
  35. package/build/cjs/lib/kit/utils/common.js +1 -26
  36. package/build/cjs/lib/kit/validators/validators.js +8 -8
  37. package/build/esm/lib/core/components/Form/Controller.js +9 -3
  38. package/build/esm/lib/core/components/Form/DynamicField.d.ts +2 -1
  39. package/build/esm/lib/core/components/Form/DynamicField.js +12 -5
  40. package/build/esm/lib/core/components/Form/hooks/index.d.ts +3 -0
  41. package/build/esm/lib/core/components/Form/hooks/index.js +3 -0
  42. package/build/esm/lib/core/components/Form/hooks/useControllerMirror.d.ts +2 -0
  43. package/build/esm/lib/core/components/Form/hooks/useControllerMirror.js +14 -0
  44. package/build/esm/lib/core/components/Form/hooks/useDynamicFieldMirror.d.ts +2 -0
  45. package/build/esm/lib/core/components/Form/hooks/useDynamicFieldMirror.js +17 -0
  46. package/build/esm/lib/core/components/Form/hooks/useField.d.ts +2 -2
  47. package/build/esm/lib/core/components/Form/hooks/useField.js +1 -1
  48. package/build/esm/lib/core/components/Form/hooks/useIntegrationFF.d.ts +2 -0
  49. package/build/esm/lib/core/components/Form/hooks/useIntegrationFF.js +41 -0
  50. package/build/esm/lib/core/components/Form/hooks/useSearchStore.d.ts +2 -4
  51. package/build/esm/lib/core/components/Form/hooks/useSearchStore.js +5 -2
  52. package/build/esm/lib/core/components/Form/hooks/useStore.d.ts +2 -8
  53. package/build/esm/lib/core/components/Form/hooks/useStore.js +5 -37
  54. package/build/esm/lib/core/components/Form/types/context.d.ts +2 -1
  55. package/build/esm/lib/core/components/Form/types/index.d.ts +2 -0
  56. package/build/esm/lib/core/components/Form/types/index.js +2 -0
  57. package/build/esm/lib/core/components/Form/types/mirror.d.ts +17 -0
  58. package/build/esm/lib/core/components/Form/types/mirror.js +1 -0
  59. package/build/esm/lib/core/components/Form/types/store.d.ts +7 -0
  60. package/build/esm/lib/core/components/Form/types/store.js +1 -0
  61. package/build/esm/lib/core/components/View/ViewController.js +2 -2
  62. package/build/esm/lib/core/components/View/hooks/useComponents.d.ts +2 -2
  63. package/build/esm/lib/core/components/View/hooks/useComponents.js +1 -3
  64. package/build/esm/lib/core/constants.d.ts +1 -0
  65. package/build/esm/lib/core/types/specs.d.ts +6 -1
  66. package/build/esm/lib/kit/components/Inputs/FileInput/FileInput.css +20 -0
  67. package/build/esm/lib/kit/components/Inputs/FileInput/FileInput.d.ts +4 -0
  68. package/build/esm/lib/kit/components/Inputs/FileInput/FileInput.js +46 -0
  69. package/build/esm/lib/kit/components/Inputs/FileInput/index.d.ts +1 -0
  70. package/build/esm/lib/kit/components/Inputs/FileInput/index.js +1 -0
  71. package/build/esm/lib/kit/components/Inputs/FileInput/utils.d.ts +2 -0
  72. package/build/esm/lib/kit/components/Inputs/FileInput/utils.js +12 -0
  73. package/build/esm/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +3 -2
  74. package/build/esm/lib/kit/components/Inputs/TextLink/TextLink.d.ts +2 -0
  75. package/build/esm/lib/kit/components/Inputs/TextLink/TextLink.js +15 -0
  76. package/build/esm/lib/kit/components/Inputs/TextLink/index.d.ts +1 -0
  77. package/build/esm/lib/kit/components/Inputs/TextLink/index.js +1 -0
  78. package/build/esm/lib/kit/components/Inputs/index.d.ts +2 -0
  79. package/build/esm/lib/kit/components/Inputs/index.js +2 -0
  80. package/build/esm/lib/kit/components/Layouts/Row/Row.css +18 -10
  81. package/build/esm/lib/kit/components/Layouts/Row/Row.js +4 -5
  82. package/build/esm/lib/kit/components/Views/FileInputView/FileInputView.d.ts +3 -0
  83. package/build/esm/lib/kit/components/Views/FileInputView/FileInputView.js +7 -0
  84. package/build/esm/lib/kit/components/Views/FileInputView/index.d.ts +1 -0
  85. package/build/esm/lib/kit/components/Views/FileInputView/index.js +1 -0
  86. package/build/esm/lib/kit/components/Views/TextLinkView/TextLinkView.d.ts +2 -0
  87. package/build/esm/lib/kit/components/Views/TextLinkView/TextLinkView.js +12 -0
  88. package/build/esm/lib/kit/components/Views/TextLinkView/index.d.ts +1 -0
  89. package/build/esm/lib/kit/components/Views/TextLinkView/index.js +1 -0
  90. package/build/esm/lib/kit/components/Views/index.d.ts +2 -0
  91. package/build/esm/lib/kit/components/Views/index.js +2 -0
  92. package/build/esm/lib/kit/constants/config.js +9 -1
  93. package/build/esm/lib/kit/i18n/en.json +3 -1
  94. package/build/esm/lib/kit/i18n/ru.json +3 -1
  95. package/build/esm/lib/kit/utils/common.d.ts +0 -2
  96. package/build/esm/lib/kit/utils/common.js +0 -24
  97. package/build/esm/lib/kit/validators/validators.d.ts +2 -0
  98. package/build/esm/lib/kit/validators/validators.js +8 -8
  99. 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;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./TextLinkView"), exports);
@@ -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 = exports.getChildError = void 0;
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 ((stringValue.length > 1 && stringValue[0] === '0' && stringValue[1] !== '.') ||
60
- (stringValue.length > 2 &&
61
- stringValue.substring(0, 2) === '-0' &&
62
- stringValue[2] !== '.')) {
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, watcher } = useStore(name);
12
- const { setField, removeField, isHiddenField } = useSearchStore(name);
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
- }), [tools, config, Monaco]);
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,2 @@
1
+ import { ControllerMirror, WonderMirror } from '../types';
2
+ export declare const useControllerMirror: (name: string, params: ControllerMirror, __mirror?: WonderMirror) => void;
@@ -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,2 @@
1
+ import { DynamicFieldMirror, WonderMirror } from '../types';
2
+ export declare const useDynamicFieldMirror: (params: DynamicFieldMirror, __mirror?: WonderMirror) => void;
@@ -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 FieldProps<Value extends FieldValue, SpecType extends Spec> {
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, }: FieldProps<Value, SpecType>) => FieldRenderProps<Value>;
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,2 @@
1
+ import { DynamicFieldStore } from '../types';
2
+ export declare const useIntegrationFF: (store: DynamicFieldStore) => JSX.Element;
@@ -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: (name: string) => {
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 = (name) => {
5
- const [store, setStore] = React.useState({ [name]: false });
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
- watcher: JSX.Element;
9
+ store: DynamicFieldStore;
16
10
  };
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import _ from 'lodash';
3
- import { Field as FinalFormField, useForm } from 'react-final-form';
4
- import { transformArrIn, transformArrOut } from '../utils';
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, watcher };
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,7 @@
1
+ import { FieldObjectValue, ValidateError } from '../types';
2
+ export interface DynamicFieldStore {
3
+ name: string;
4
+ initialValue: FieldObjectValue;
5
+ values: FieldObjectValue;
6
+ errors: Record<string, ValidateError>;
7
+ }
@@ -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
  };