@gravity-ui/dynamic-forms 3.0.1 → 3.2.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 (53) hide show
  1. package/build/cjs/lib/core/components/Form/Controller.js +12 -2
  2. package/build/cjs/lib/core/components/Form/DynamicField.js +6 -3
  3. package/build/cjs/lib/core/components/Form/constants.js +2 -1
  4. package/build/cjs/lib/core/components/Form/hooks/index.js +3 -0
  5. package/build/cjs/lib/core/components/Form/hooks/useField.js +33 -6
  6. package/build/cjs/lib/core/components/Form/hooks/useMutateDFState.js +6 -0
  7. package/build/cjs/lib/core/components/Form/hooks/useMutators.js +23 -0
  8. package/build/cjs/lib/core/components/Form/hooks/useStore.js +6 -6
  9. package/build/cjs/lib/core/components/Form/hooks/useStoreValue.js +6 -0
  10. package/build/cjs/lib/core/components/Form/index.js +4 -0
  11. package/build/cjs/lib/core/components/Form/types/index.js +1 -0
  12. package/build/cjs/lib/core/components/Form/types/mutators.js +2 -0
  13. package/build/cjs/lib/core/components/Form/utils/common.js +5 -1
  14. package/build/cjs/lib/core/components/View/DynamicView.js +1 -2
  15. package/build/cjs/lib/kit/components/Inputs/Text/Text.js +16 -31
  16. package/build/cjs/lib/kit/components/ViewLayouts/ViewAccordeon/ViewAccordeon.js +2 -1
  17. package/build/cjs/lib/kit/components/ViewLayouts/ViewCardAccordeon.js +2 -1
  18. package/build/esm/lib/core/components/Form/Controller.d.ts +1 -1
  19. package/build/esm/lib/core/components/Form/Controller.js +12 -2
  20. package/build/esm/lib/core/components/Form/DynamicField.d.ts +2 -1
  21. package/build/esm/lib/core/components/Form/DynamicField.js +7 -4
  22. package/build/esm/lib/core/components/Form/constants.d.ts +1 -0
  23. package/build/esm/lib/core/components/Form/constants.js +1 -0
  24. package/build/esm/lib/core/components/Form/hooks/index.d.ts +3 -0
  25. package/build/esm/lib/core/components/Form/hooks/index.js +3 -0
  26. package/build/esm/lib/core/components/Form/hooks/useField.d.ts +3 -2
  27. package/build/esm/lib/core/components/Form/hooks/useField.js +35 -8
  28. package/build/esm/lib/core/components/Form/hooks/useMutateDFState.d.ts +1 -0
  29. package/build/esm/lib/core/components/Form/hooks/useMutateDFState.js +2 -0
  30. package/build/esm/lib/core/components/Form/hooks/useMutators.d.ts +5 -0
  31. package/build/esm/lib/core/components/Form/hooks/useMutators.js +18 -0
  32. package/build/esm/lib/core/components/Form/hooks/useStore.js +7 -7
  33. package/build/esm/lib/core/components/Form/hooks/useStoreValue.d.ts +1 -0
  34. package/build/esm/lib/core/components/Form/hooks/useStoreValue.js +2 -0
  35. package/build/esm/lib/core/components/Form/index.d.ts +1 -0
  36. package/build/esm/lib/core/components/Form/index.js +1 -0
  37. package/build/esm/lib/core/components/Form/types/context.d.ts +4 -1
  38. package/build/esm/lib/core/components/Form/types/index.d.ts +1 -0
  39. package/build/esm/lib/core/components/Form/types/index.js +1 -0
  40. package/build/esm/lib/core/components/Form/types/mutators.d.ts +7 -0
  41. package/build/esm/lib/core/components/Form/types/mutators.js +1 -0
  42. package/build/esm/lib/core/components/Form/utils/common.d.ts +3 -0
  43. package/build/esm/lib/core/components/Form/utils/common.js +2 -0
  44. package/build/esm/lib/core/components/View/DynamicView.d.ts +2 -2
  45. package/build/esm/lib/core/components/View/DynamicView.js +1 -2
  46. package/build/esm/lib/core/components/View/types/context.d.ts +2 -2
  47. package/build/esm/lib/kit/components/Inputs/Text/Text.d.ts +1 -2
  48. package/build/esm/lib/kit/components/Inputs/Text/Text.js +17 -33
  49. package/build/esm/lib/kit/components/ViewLayouts/ViewAccordeon/ViewAccordeon.js +2 -1
  50. package/build/esm/lib/kit/components/ViewLayouts/ViewCardAccordeon.js +2 -1
  51. package/package.json +6 -6
  52. package/build/cjs/lib/kit/components/Inputs/Text/Text.css +0 -6
  53. package/build/esm/lib/kit/components/Inputs/Text/Text.css +0 -6
@@ -2,10 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Controller = void 0;
4
4
  const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
5
6
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
7
+ const constants_1 = require("./constants");
6
8
  const hooks_1 = require("./hooks");
7
- const Controller = ({ spec, name, value, parentOnChange, parentOnUnmount, }) => {
8
- const { tools, __mirror } = (0, hooks_1.useDynamicFormsCtx)();
9
+ const Controller = ({ spec: _spec, name, value, parentOnChange, parentOnUnmount, }) => {
10
+ const { tools, mutators, __mirror } = (0, hooks_1.useDynamicFormsCtx)();
11
+ const spec = react_1.default.useMemo(() => {
12
+ const specMutator = lodash_1.default.get(mutators.spec, name, constants_1.EMPTY_MUTATOR);
13
+ if (specMutator !== constants_1.EMPTY_MUTATOR) {
14
+ return lodash_1.default.merge(_spec, specMutator);
15
+ }
16
+ return _spec;
17
+ }, [_spec, mutators.spec, name]);
9
18
  const { inputEntity, Layout } = (0, hooks_1.useComponents)(spec);
10
19
  const render = (0, hooks_1.useRender)({ name, spec, inputEntity, Layout });
11
20
  const validate = (0, hooks_1.useValidate)(spec);
@@ -18,6 +27,7 @@ const Controller = ({ spec, name, value, parentOnChange, parentOnUnmount, }) =>
18
27
  tools,
19
28
  parentOnChange,
20
29
  parentOnUnmount,
30
+ mutators,
21
31
  });
22
32
  const withSearch = (0, hooks_1.useSearch)(spec, renderProps.input.value, name);
23
33
  (0, hooks_1.useControllerMirror)(name, {
@@ -9,19 +9,22 @@ const helpers_1 = require("../../helpers");
9
9
  const Controller_1 = require("./Controller");
10
10
  const hooks_1 = require("./hooks");
11
11
  const utils_1 = require("./utils");
12
- const DynamicField = ({ name, spec, config, Monaco, generateRandomValue, search, withoutInsertFFDebounce, __mirror, }) => {
12
+ const DynamicField = ({ name, spec, config, Monaco, generateRandomValue, search, withoutInsertFFDebounce, mutators: externalMutators, __mirror, }) => {
13
13
  const DynamicFormsCtx = (0, hooks_1.useCreateContext)();
14
14
  const SearchContext = (0, hooks_1.useCreateSearchContext)();
15
15
  const { tools, store } = (0, hooks_1.useStore)(name);
16
16
  const watcher = (0, hooks_1.useIntegrationFF)(store, withoutInsertFFDebounce);
17
+ const { mutators, mutateDFState } = (0, hooks_1.useMutators)(externalMutators);
17
18
  const { store: searchStore, setField, removeField, isHiddenField } = (0, hooks_1.useSearchStore)();
18
19
  const context = react_1.default.useMemo(() => ({
19
20
  config,
20
21
  Monaco: (0, react_is_1.isValidElementType)(Monaco) ? Monaco : undefined,
21
22
  generateRandomValue,
22
- tools,
23
+ tools: Object.assign(Object.assign({}, tools), { mutateDFState }),
24
+ store,
25
+ mutators,
23
26
  __mirror,
24
- }), [tools, config, Monaco, __mirror, generateRandomValue]);
27
+ }), [tools, config, Monaco, __mirror, generateRandomValue, mutators, mutateDFState, store]);
25
28
  const searchContext = react_1.default.useMemo(() => ({
26
29
  setField,
27
30
  removeField,
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SPEC_TYPE_FOR_GENERATE_BUTTON = exports.OBJECT_ARRAY_CNT = exports.OBJECT_ARRAY_FLAG = void 0;
3
+ exports.EMPTY_MUTATOR = exports.SPEC_TYPE_FOR_GENERATE_BUTTON = exports.OBJECT_ARRAY_CNT = exports.OBJECT_ARRAY_FLAG = void 0;
4
4
  exports.OBJECT_ARRAY_FLAG = '____arr-obj';
5
5
  exports.OBJECT_ARRAY_CNT = '____arr-obj-cnt';
6
6
  exports.SPEC_TYPE_FOR_GENERATE_BUTTON = ['base', 'password', 'textarea'];
7
+ exports.EMPTY_MUTATOR = '____empty-mutator';
@@ -9,8 +9,11 @@ tslib_1.__exportStar(require("./useDynamicFormsCtx"), exports);
9
9
  tslib_1.__exportStar(require("./useField"), exports);
10
10
  tslib_1.__exportStar(require("./useGenerateRandomValue"), exports);
11
11
  tslib_1.__exportStar(require("./useIntegrationFF"), exports);
12
+ tslib_1.__exportStar(require("./useMutateDFState"), exports);
13
+ tslib_1.__exportStar(require("./useMutators"), exports);
12
14
  tslib_1.__exportStar(require("./useRender"), exports);
13
15
  tslib_1.__exportStar(require("./useStore"), exports);
16
+ tslib_1.__exportStar(require("./useStoreValue"), exports);
14
17
  tslib_1.__exportStar(require("./useValidate"), exports);
15
18
  tslib_1.__exportStar(require("./useMonaco"), exports);
16
19
  tslib_1.__exportStar(require("./useSearchStore"), exports);
@@ -7,11 +7,15 @@ const lodash_1 = tslib_1.__importDefault(require("lodash"));
7
7
  const helpers_1 = require("../../../helpers");
8
8
  const constants_1 = require("../constants");
9
9
  const utils_1 = require("../utils");
10
- const useField = ({ name, spec, initialValue, value: externalValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount: externalParentOnUnmount, }) => {
10
+ const useField = ({ name, spec, initialValue, value: externalValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount: externalParentOnUnmount, mutators, }) => {
11
11
  const firstRenderRef = react_1.default.useRef(true);
12
12
  const validate = react_1.default.useCallback((value) => propsValidate === null || propsValidate === void 0 ? void 0 : propsValidate((0, utils_1.transformArrOut)(value)), [propsValidate]);
13
13
  const [state, setState] = react_1.default.useState(() => {
14
+ const valueMutator = lodash_1.default.get(mutators.values, name, constants_1.EMPTY_MUTATOR);
14
15
  let value = lodash_1.default.cloneDeep(externalValue);
16
+ if ((0, utils_1.isValueMutatorCorrect)(valueMutator, spec) && valueMutator !== constants_1.EMPTY_MUTATOR) {
17
+ value = valueMutator;
18
+ }
15
19
  if (lodash_1.default.isNil(value)) {
16
20
  if (spec.defaultValue) {
17
21
  value = (0, utils_1.transformArrIn)(spec.defaultValue);
@@ -27,7 +31,11 @@ const useField = ({ name, spec, initialValue, value: externalValue, validate: pr
27
31
  }
28
32
  }
29
33
  }
30
- const error = validate === null || validate === void 0 ? void 0 : validate(value);
34
+ let errorMutator = lodash_1.default.get(mutators.errors, name);
35
+ if (!(0, utils_1.isErrorMutatorCorrect)(errorMutator)) {
36
+ errorMutator = undefined;
37
+ }
38
+ const error = (validate === null || validate === void 0 ? void 0 : validate(value)) || errorMutator;
31
39
  const dirty = !lodash_1.default.isEqual(value, initialValue);
32
40
  return {
33
41
  active: false,
@@ -43,11 +51,11 @@ const useField = ({ name, spec, initialValue, value: externalValue, validate: pr
43
51
  childErrors: {},
44
52
  };
45
53
  });
46
- const { onChange, onDrop } = react_1.default.useMemo(() => {
47
- const onChange = (valOrSetter, childErrors) => {
54
+ const { onChange, onLocalChange, onDrop } = react_1.default.useMemo(() => {
55
+ const onLocalChange = (valOrSetter, childErrors, errorMutator) => {
48
56
  setState((state) => {
49
57
  const _value = lodash_1.default.isFunction(valOrSetter) ? valOrSetter(state.value) : valOrSetter;
50
- const error = validate === null || validate === void 0 ? void 0 : validate(_value);
58
+ const error = (validate === null || validate === void 0 ? void 0 : validate(_value)) || errorMutator;
51
59
  let value = (0, utils_1.transformArrIn)(_value);
52
60
  if ((0, helpers_1.isNumberSpec)(spec) && !error) {
53
61
  value = (value ? Number(value) : undefined);
@@ -63,6 +71,7 @@ const useField = ({ name, spec, initialValue, value: externalValue, validate: pr
63
71
  return Object.assign(Object.assign({}, state), { dirty: !lodash_1.default.isEqual(value, initialValue), error, invalid: Boolean(error), modified: true, pristine: value === initialValue, touched: true, valid: !error, value, visited: true, childErrors: newChildErrors });
64
72
  });
65
73
  };
74
+ const onChange = (valOrSetter, childErrors) => onLocalChange(valOrSetter, childErrors);
66
75
  const onDrop = () => {
67
76
  if ((0, utils_1.isArrayItem)(name)) {
68
77
  (externalParentOnUnmount ? externalParentOnUnmount : tools.onUnmount)(name);
@@ -71,7 +80,7 @@ const useField = ({ name, spec, initialValue, value: externalValue, validate: pr
71
80
  onChange(undefined, { [name]: false });
72
81
  }
73
82
  };
74
- return { onChange, onDrop };
83
+ return { onChange, onLocalChange, onDrop };
75
84
  }, [initialValue, setState, name, validate, spec, externalParentOnUnmount, tools.onUnmount]);
76
85
  const onBlur = react_1.default.useCallback(() => {
77
86
  setState((state) => (Object.assign(Object.assign({}, state), { active: false, touched: true })));
@@ -138,6 +147,24 @@ const useField = ({ name, spec, initialValue, value: externalValue, validate: pr
138
147
  (parentOnChange ? parentOnChange : tools.onChange)(name, state.value, Object.assign(Object.assign({}, state.childErrors), { [name]: state.error }));
139
148
  }
140
149
  }, [state.value]);
150
+ react_1.default.useEffect(() => {
151
+ if (!firstRenderRef.current) {
152
+ const valueMutator = lodash_1.default.get(mutators.values, name, constants_1.EMPTY_MUTATOR);
153
+ let errorMutator = lodash_1.default.get(mutators.errors, name);
154
+ if (!(0, utils_1.isErrorMutatorCorrect)(errorMutator)) {
155
+ errorMutator = undefined;
156
+ }
157
+ if ((0, utils_1.isValueMutatorCorrect)(valueMutator, spec) &&
158
+ valueMutator !== state.value &&
159
+ valueMutator !== constants_1.EMPTY_MUTATOR) {
160
+ onLocalChange(valueMutator, undefined, errorMutator);
161
+ }
162
+ else if (state.error !== errorMutator && !(state.error && !errorMutator)) {
163
+ setState(Object.assign(Object.assign({}, state), { error: errorMutator }));
164
+ (parentOnChange ? parentOnChange : tools.onChange)(name, state.value, Object.assign(Object.assign({}, state.childErrors), { [name]: errorMutator }));
165
+ }
166
+ }
167
+ }, [mutators]);
141
168
  react_1.default.useEffect(() => {
142
169
  firstRenderRef.current = false;
143
170
  return () => {
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useMutateDFState = void 0;
4
+ const useDynamicFormsCtx_1 = require("./useDynamicFormsCtx");
5
+ const useMutateDFState = () => (0, useDynamicFormsCtx_1.useDynamicFormsCtx)().tools.mutateDFState;
6
+ exports.useMutateDFState = useMutateDFState;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useMutators = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
7
+ const useMutators = (externalMutators) => {
8
+ const firstRenderRef = react_1.default.useRef(true);
9
+ const [store, setStore] = react_1.default.useState(externalMutators || {});
10
+ const mutateDFState = react_1.default.useCallback((mutators) => {
11
+ setStore((store) => (Object.assign(Object.assign(Object.assign(Object.assign({}, store), (mutators.errors ? { errors: lodash_1.default.merge(store.errors, mutators.errors) } : {})), (mutators.values ? { values: lodash_1.default.merge(store.values, mutators.values) } : {})), (mutators.spec ? { spec: lodash_1.default.merge(store.spec, mutators.spec) } : {}))));
12
+ }, [setStore]);
13
+ react_1.default.useEffect(() => {
14
+ if (firstRenderRef.current) {
15
+ firstRenderRef.current = false;
16
+ }
17
+ else if (externalMutators) {
18
+ mutateDFState(externalMutators);
19
+ }
20
+ }, [externalMutators]);
21
+ return { mutators: store, mutateDFState };
22
+ };
23
+ exports.useMutators = useMutators;
@@ -7,14 +7,14 @@ const lodash_1 = tslib_1.__importDefault(require("lodash"));
7
7
  const react_final_form_1 = require("react-final-form");
8
8
  const utils_1 = require("../utils");
9
9
  const useStore = (name) => {
10
- const form = (0, react_final_form_1.useForm)();
10
+ const formState = (0, react_final_form_1.useFormState)();
11
11
  const firstRenderRef = react_1.default.useRef(true);
12
12
  const [store, setStore] = react_1.default.useState(() => {
13
13
  const values = (0, utils_1.transformArrIn)({
14
- [name]: lodash_1.default.get(form.getState().values, name),
14
+ [name]: lodash_1.default.get(formState.values, name),
15
15
  });
16
16
  const initialValue = (0, utils_1.transformArrIn)({
17
- [name]: lodash_1.default.get(form.getState().initialValues, name),
17
+ [name]: lodash_1.default.get(formState.initialValues, name),
18
18
  });
19
19
  return {
20
20
  name,
@@ -23,7 +23,7 @@ const useStore = (name) => {
23
23
  errors: {},
24
24
  };
25
25
  });
26
- const submitFailed = form.getState().submitFailed;
26
+ const submitFailed = formState.submitFailed;
27
27
  const tools = react_1.default.useMemo(() => ({
28
28
  initialValue: store.initialValue,
29
29
  onChange: (name, value, errors) => setStore((store) => (Object.assign(Object.assign({}, store), { values: lodash_1.default.set(Object.assign({}, store.values), name, lodash_1.default.clone(value)), errors: errors || {} }))),
@@ -33,10 +33,10 @@ const useStore = (name) => {
33
33
  react_1.default.useEffect(() => {
34
34
  if (!firstRenderRef.current) {
35
35
  const values = (0, utils_1.transformArrIn)({
36
- [name]: lodash_1.default.get(form.getState().values, name),
36
+ [name]: lodash_1.default.get(formState.values, name),
37
37
  });
38
38
  const initialValue = (0, utils_1.transformArrIn)({
39
- [name]: lodash_1.default.get(form.getState().initialValues, name),
39
+ [name]: lodash_1.default.get(formState.initialValues, name),
40
40
  });
41
41
  setStore({
42
42
  name: name,
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useStoreValue = void 0;
4
+ const useDynamicFormsCtx_1 = require("./useDynamicFormsCtx");
5
+ const useStoreValue = () => (0, useDynamicFormsCtx_1.useDynamicFormsCtx)().store;
6
+ exports.useStoreValue = useStoreValue;
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useStoreValue = exports.useMutateDFState = void 0;
3
4
  const tslib_1 = require("tslib");
4
5
  tslib_1.__exportStar(require("./constants"), exports);
5
6
  tslib_1.__exportStar(require("./Controller"), exports);
6
7
  tslib_1.__exportStar(require("./DynamicField"), exports);
8
+ var hooks_1 = require("./hooks");
9
+ Object.defineProperty(exports, "useMutateDFState", { enumerable: true, get: function () { return hooks_1.useMutateDFState; } });
10
+ Object.defineProperty(exports, "useStoreValue", { enumerable: true, get: function () { return hooks_1.useStoreValue; } });
7
11
  tslib_1.__exportStar(require("./types"), exports);
8
12
  tslib_1.__exportStar(require("./utils"), exports);
@@ -9,6 +9,7 @@ tslib_1.__exportStar(require("./field"), exports);
9
9
  tslib_1.__exportStar(require("./input"), exports);
10
10
  tslib_1.__exportStar(require("./layout"), exports);
11
11
  tslib_1.__exportStar(require("./mirror"), exports);
12
+ tslib_1.__exportStar(require("./mutators"), exports);
12
13
  tslib_1.__exportStar(require("./number"), exports);
13
14
  tslib_1.__exportStar(require("./object"), exports);
14
15
  tslib_1.__exportStar(require("./store"), exports);
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withGenerateButton = exports.isArrayItem = exports.transformArrOut = exports.transformArrIn = exports.isCorrectConfig = void 0;
3
+ exports.isValueMutatorCorrect = exports.isErrorMutatorCorrect = exports.withGenerateButton = exports.isArrayItem = exports.transformArrOut = exports.transformArrIn = exports.isCorrectConfig = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
6
6
  const constants_1 = require("../../../constants");
@@ -54,3 +54,7 @@ const withGenerateButton = (spec) => (0, helpers_1.isStringSpec)(spec) &&
54
54
  constants_2.SPEC_TYPE_FOR_GENERATE_BUTTON.includes(spec.viewSpec.type) &&
55
55
  spec.viewSpec.generateRandomValueButton;
56
56
  exports.withGenerateButton = withGenerateButton;
57
+ const isErrorMutatorCorrect = (errorMutator) => lodash_1.default.isString(errorMutator) || lodash_1.default.isBoolean(errorMutator) || lodash_1.default.isUndefined(errorMutator);
58
+ exports.isErrorMutatorCorrect = isErrorMutatorCorrect;
59
+ const isValueMutatorCorrect = (valueMutator, spec) => typeof valueMutator === spec.type || (lodash_1.default.isArray(valueMutator) && spec.type === constants_1.SpecTypes.Array);
60
+ exports.isValueMutatorCorrect = isValueMutatorCorrect;
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DynamicView = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
- const lodash_1 = tslib_1.__importDefault(require("lodash"));
7
6
  const react_is_1 = require("react-is");
8
7
  const helpers_1 = require("../../helpers");
9
8
  const ViewController_1 = require("./ViewController");
@@ -12,7 +11,7 @@ const hooks_1 = require("./hooks");
12
11
  const DynamicView = ({ value, spec, config, Link, Monaco }) => {
13
12
  const DynamicFormsCtx = (0, hooks_1.useCreateContext)();
14
13
  const context = react_1.default.useMemo(() => ({ config, value, Link, Monaco: (0, react_is_1.isValidElementType)(Monaco) ? Monaco : undefined }), [config, value, Link, Monaco]);
15
- if (lodash_1.default.isObjectLike(value) && (0, helpers_1.isCorrectSpec)(spec) && (0, helpers_2.isCorrectViewConfig)(config)) {
14
+ if ((0, helpers_1.isCorrectSpec)(spec) && (0, helpers_2.isCorrectViewConfig)(config)) {
16
15
  return (react_1.default.createElement(DynamicFormsCtx.Provider, { value: context },
17
16
  react_1.default.createElement(ViewController_1.ViewController, { spec: spec, name: "" })));
18
17
  }
@@ -3,38 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Text = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
- const icons_1 = require("@gravity-ui/icons");
6
+ const components_1 = require("@gravity-ui/components");
7
7
  const uikit_1 = require("@gravity-ui/uikit");
8
8
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
9
- const utils_1 = require("../../../utils");
10
- const b = (0, utils_1.block)('text');
11
- const Text = ({ name, input, spec }) => {
12
- const { value, onBlur, onChange, onFocus } = input;
13
- const [hideValue, setHideValue] = react_1.default.useState(spec.viewSpec.type === 'password');
14
- const handleChange = react_1.default.useCallback((value) => {
15
- onChange(value);
16
- }, [onChange, spec]);
17
- const type = react_1.default.useMemo(() => {
18
- if (spec.viewSpec.type === 'password') {
19
- return 'password';
20
- }
21
- return 'text';
22
- }, [spec.viewSpec.type]);
23
- const additionalRightContent = react_1.default.useMemo(() => {
24
- if (type === 'password') {
25
- const onClick = () => {
26
- setHideValue((hideValue) => !hideValue);
27
- };
28
- return (react_1.default.createElement("div", { className: b() },
29
- input.value ? (react_1.default.createElement(uikit_1.CopyToClipboard, { text: String(value), timeout: 500 }, (state) => (react_1.default.createElement(uikit_1.Button, { view: "flat-secondary", className: b('button'), size: "s" },
30
- react_1.default.createElement(uikit_1.Icon, { size: 14, data: state === uikit_1.CopyToClipboardStatus.Pending
31
- ? icons_1.Copy
32
- : icons_1.CopyCheck }))))) : null,
33
- react_1.default.createElement(uikit_1.Button, { view: "flat-secondary", onClick: onClick, className: b('button'), size: "s" },
34
- react_1.default.createElement(uikit_1.Icon, { data: hideValue ? icons_1.Eye : icons_1.EyeSlash, size: 14 }))));
35
- }
36
- return undefined;
37
- }, [hideValue, input.value, type, value]);
38
- return (react_1.default.createElement(uikit_1.TextInput, { type: hideValue ? 'password' : 'text', value: lodash_1.default.isNil(value) ? '' : `${value}`, hasClear: true, onBlur: onBlur, onFocus: onFocus, onUpdate: handleChange, disabled: spec.viewSpec.disabled, placeholder: spec.viewSpec.placeholder, autoComplete: type === 'password' ? 'new-password' : undefined, qa: name, rightContent: additionalRightContent }));
9
+ const Text = ({ name, input: { value, onBlur, onChange, onFocus }, spec, }) => {
10
+ const props = {
11
+ value: lodash_1.default.isNil(value) ? '' : `${value}`,
12
+ hasClear: true,
13
+ onBlur: onBlur,
14
+ onFocus: onFocus,
15
+ onUpdate: onChange,
16
+ disabled: spec.viewSpec.disabled,
17
+ placeholder: spec.viewSpec.placeholder,
18
+ qa: name,
19
+ };
20
+ if (spec.viewSpec.type === 'password') {
21
+ return (react_1.default.createElement(components_1.PasswordInput, Object.assign({}, props, { autoComplete: "new-password", showCopyButton: true, showRevealButton: true })));
22
+ }
23
+ return react_1.default.createElement(uikit_1.TextInput, Object.assign({}, props, { type: "text" }));
39
24
  };
40
25
  exports.Text = Text;
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ViewAccordeon = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
6
7
  const utils_1 = require("../../../utils");
7
8
  const SimpleVerticalAccordeon_1 = require("../../SimpleVerticalAccordeon");
8
9
  const ViewAccordeon = ({ name, value, spec, children, }) => {
9
- const [open, setOpen] = react_1.default.useState(true);
10
+ const [open, setOpen] = react_1.default.useState(lodash_1.default.isBoolean(spec.viewSpec.layoutOpen) ? spec.viewSpec.layoutOpen : true);
10
11
  if (!(0, utils_1.isNotEmptyValue)(value, spec)) {
11
12
  return null;
12
13
  }
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ViewCardAccordeon = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
6
7
  const __1 = require("../");
7
8
  const utils_1 = require("../../utils");
8
9
  const ViewCardAccordeon = ({ name, value, spec, children, }) => {
9
- const [open, setOpen] = react_1.default.useState(true);
10
+ const [open, setOpen] = react_1.default.useState(lodash_1.default.isBoolean(spec.viewSpec.layoutOpen) ? spec.viewSpec.layoutOpen : true);
10
11
  const onToggle = react_1.default.useCallback(() => setOpen((f) => !f), [setOpen]);
11
12
  if (!(0, utils_1.isNotEmptyValue)(value, spec)) {
12
13
  return null;
@@ -7,4 +7,4 @@ export interface ControllerProps<Value extends FieldValue, SpecType extends Spec
7
7
  parentOnChange: ((childName: string, childValue: FieldValue, childErrors: Record<string, ValidateError>) => void) | null;
8
8
  parentOnUnmount: ((childName: string) => void) | null;
9
9
  }
10
- export declare const Controller: <Value extends FieldValue, SpecType extends Spec>({ spec, name, value, parentOnChange, parentOnUnmount, }: ControllerProps<Value, SpecType>) => JSX.Element | null;
10
+ export declare const Controller: <Value extends FieldValue, SpecType extends Spec>({ spec: _spec, name, value, parentOnChange, parentOnUnmount, }: ControllerProps<Value, SpecType>) => JSX.Element | null;
@@ -1,7 +1,16 @@
1
+ import React from 'react';
1
2
  import _ from 'lodash';
3
+ import { EMPTY_MUTATOR } from './constants';
2
4
  import { useComponents, useControllerMirror, useDynamicFormsCtx, useField, useRender, useSearch, useValidate, } from './hooks';
3
- export const Controller = ({ spec, name, value, parentOnChange, parentOnUnmount, }) => {
4
- const { tools, __mirror } = useDynamicFormsCtx();
5
+ export const Controller = ({ spec: _spec, name, value, parentOnChange, parentOnUnmount, }) => {
6
+ const { tools, mutators, __mirror } = useDynamicFormsCtx();
7
+ const spec = React.useMemo(() => {
8
+ const specMutator = _.get(mutators.spec, name, EMPTY_MUTATOR);
9
+ if (specMutator !== EMPTY_MUTATOR) {
10
+ return _.merge(_spec, specMutator);
11
+ }
12
+ return _spec;
13
+ }, [_spec, mutators.spec, name]);
5
14
  const { inputEntity, Layout } = useComponents(spec);
6
15
  const render = useRender({ name, spec, inputEntity, Layout });
7
16
  const validate = useValidate(spec);
@@ -14,6 +23,7 @@ export const Controller = ({ spec, name, value, parentOnChange, parentOnUnmount,
14
23
  tools,
15
24
  parentOnChange,
16
25
  parentOnUnmount,
26
+ mutators,
17
27
  });
18
28
  const withSearch = useSearch(spec, renderProps.input.value, name);
19
29
  useControllerMirror(name, {
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import type { MonacoEditorProps } from 'react-monaco-editor/lib/types';
3
3
  import { Spec, StringSpec } from '../../types';
4
- import { DynamicFormConfig, FieldValue, WonderMirror } from './types';
4
+ import { DynamicFormConfig, DynamicFormMutators, FieldValue, WonderMirror } from './types';
5
5
  export interface DynamicFieldProps {
6
6
  name: string;
7
7
  spec: Spec;
@@ -10,6 +10,7 @@ export interface DynamicFieldProps {
10
10
  search?: string | ((spec: Spec, input: FieldValue, name: string) => boolean);
11
11
  generateRandomValue?: (spec: StringSpec) => string;
12
12
  withoutInsertFFDebounce?: boolean;
13
+ mutators?: DynamicFormMutators;
13
14
  __mirror?: WonderMirror;
14
15
  }
15
16
  export declare const DynamicField: React.FC<DynamicFieldProps>;
@@ -3,21 +3,24 @@ 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, useDynamicFieldMirror, useIntegrationFF, useSearchStore, useStore, } from './hooks';
6
+ import { useCreateContext, useCreateSearchContext, useDynamicFieldMirror, useIntegrationFF, useMutators, useSearchStore, useStore, } from './hooks';
7
7
  import { getDefaultSearchFunction, isCorrectConfig } from './utils';
8
- export const DynamicField = ({ name, spec, config, Monaco, generateRandomValue, search, withoutInsertFFDebounce, __mirror, }) => {
8
+ export const DynamicField = ({ name, spec, config, Monaco, generateRandomValue, search, withoutInsertFFDebounce, mutators: externalMutators, __mirror, }) => {
9
9
  const DynamicFormsCtx = useCreateContext();
10
10
  const SearchContext = useCreateSearchContext();
11
11
  const { tools, store } = useStore(name);
12
12
  const watcher = useIntegrationFF(store, withoutInsertFFDebounce);
13
+ const { mutators, mutateDFState } = useMutators(externalMutators);
13
14
  const { store: searchStore, setField, removeField, isHiddenField } = useSearchStore();
14
15
  const context = React.useMemo(() => ({
15
16
  config,
16
17
  Monaco: isValidElementType(Monaco) ? Monaco : undefined,
17
18
  generateRandomValue,
18
- tools,
19
+ tools: Object.assign(Object.assign({}, tools), { mutateDFState }),
20
+ store,
21
+ mutators,
19
22
  __mirror,
20
- }), [tools, config, Monaco, __mirror, generateRandomValue]);
23
+ }), [tools, config, Monaco, __mirror, generateRandomValue, mutators, mutateDFState, store]);
21
24
  const searchContext = React.useMemo(() => ({
22
25
  setField,
23
26
  removeField,
@@ -1,3 +1,4 @@
1
1
  export declare const OBJECT_ARRAY_FLAG = "____arr-obj";
2
2
  export declare const OBJECT_ARRAY_CNT = "____arr-obj-cnt";
3
3
  export declare const SPEC_TYPE_FOR_GENERATE_BUTTON: string[];
4
+ export declare const EMPTY_MUTATOR = "____empty-mutator";
@@ -1,3 +1,4 @@
1
1
  export const OBJECT_ARRAY_FLAG = '____arr-obj';
2
2
  export const OBJECT_ARRAY_CNT = '____arr-obj-cnt';
3
3
  export const SPEC_TYPE_FOR_GENERATE_BUTTON = ['base', 'password', 'textarea'];
4
+ export const EMPTY_MUTATOR = '____empty-mutator';
@@ -6,8 +6,11 @@ export * from './useDynamicFormsCtx';
6
6
  export * from './useField';
7
7
  export * from './useGenerateRandomValue';
8
8
  export * from './useIntegrationFF';
9
+ export * from './useMutateDFState';
10
+ export * from './useMutators';
9
11
  export * from './useRender';
10
12
  export * from './useStore';
13
+ export * from './useStoreValue';
11
14
  export * from './useValidate';
12
15
  export * from './useMonaco';
13
16
  export * from './useSearchStore';
@@ -6,8 +6,11 @@ export * from './useDynamicFormsCtx';
6
6
  export * from './useField';
7
7
  export * from './useGenerateRandomValue';
8
8
  export * from './useIntegrationFF';
9
+ export * from './useMutateDFState';
10
+ export * from './useMutators';
9
11
  export * from './useRender';
10
12
  export * from './useStore';
13
+ export * from './useStoreValue';
11
14
  export * from './useValidate';
12
15
  export * from './useMonaco';
13
16
  export * from './useSearchStore';
@@ -1,5 +1,5 @@
1
1
  import { Spec } from '../../../types';
2
- import { DynamicFormsContext, FieldRenderProps, FieldValue, ValidateError } from '../types';
2
+ import { DynamicFormMutators, DynamicFormsContext, FieldRenderProps, FieldValue, ValidateError } from '../types';
3
3
  export interface UseFieldProps<Value extends FieldValue, SpecType extends Spec> {
4
4
  name: string;
5
5
  spec: SpecType;
@@ -9,5 +9,6 @@ export interface UseFieldProps<Value extends FieldValue, SpecType extends Spec>
9
9
  tools: DynamicFormsContext['tools'];
10
10
  parentOnChange: ((childName: string, childValue: FieldValue, childErrors: Record<string, ValidateError>) => void) | null;
11
11
  parentOnUnmount: ((childName: string) => void) | null;
12
+ mutators: DynamicFormMutators;
12
13
  }
13
- export declare const useField: <Value extends FieldValue, SpecType extends Spec>({ name, spec, initialValue, value: externalValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount: externalParentOnUnmount, }: UseFieldProps<Value, SpecType>) => FieldRenderProps<Value>;
14
+ export declare const useField: <Value extends FieldValue, SpecType extends Spec>({ name, spec, initialValue, value: externalValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount: externalParentOnUnmount, mutators, }: UseFieldProps<Value, SpecType>) => FieldRenderProps<Value>;
@@ -1,13 +1,17 @@
1
1
  import React from 'react';
2
2
  import _ from 'lodash';
3
3
  import { isArraySpec, isNumberSpec, isObjectSpec } from '../../../helpers';
4
- import { OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG } from '../constants';
5
- import { isArrayItem, transformArrIn, transformArrOut } from '../utils';
6
- export const useField = ({ name, spec, initialValue, value: externalValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount: externalParentOnUnmount, }) => {
4
+ import { EMPTY_MUTATOR, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG } from '../constants';
5
+ import { isArrayItem, isErrorMutatorCorrect, isValueMutatorCorrect, transformArrIn, transformArrOut, } from '../utils';
6
+ export const useField = ({ name, spec, initialValue, value: externalValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount: externalParentOnUnmount, mutators, }) => {
7
7
  const firstRenderRef = React.useRef(true);
8
8
  const validate = React.useCallback((value) => propsValidate === null || propsValidate === void 0 ? void 0 : propsValidate(transformArrOut(value)), [propsValidate]);
9
9
  const [state, setState] = React.useState(() => {
10
+ const valueMutator = _.get(mutators.values, name, EMPTY_MUTATOR);
10
11
  let value = _.cloneDeep(externalValue);
12
+ if (isValueMutatorCorrect(valueMutator, spec) && valueMutator !== EMPTY_MUTATOR) {
13
+ value = valueMutator;
14
+ }
11
15
  if (_.isNil(value)) {
12
16
  if (spec.defaultValue) {
13
17
  value = transformArrIn(spec.defaultValue);
@@ -23,7 +27,11 @@ export const useField = ({ name, spec, initialValue, value: externalValue, valid
23
27
  }
24
28
  }
25
29
  }
26
- const error = validate === null || validate === void 0 ? void 0 : validate(value);
30
+ let errorMutator = _.get(mutators.errors, name);
31
+ if (!isErrorMutatorCorrect(errorMutator)) {
32
+ errorMutator = undefined;
33
+ }
34
+ const error = (validate === null || validate === void 0 ? void 0 : validate(value)) || errorMutator;
27
35
  const dirty = !_.isEqual(value, initialValue);
28
36
  return {
29
37
  active: false,
@@ -39,11 +47,11 @@ export const useField = ({ name, spec, initialValue, value: externalValue, valid
39
47
  childErrors: {},
40
48
  };
41
49
  });
42
- const { onChange, onDrop } = React.useMemo(() => {
43
- const onChange = (valOrSetter, childErrors) => {
50
+ const { onChange, onLocalChange, onDrop } = React.useMemo(() => {
51
+ const onLocalChange = (valOrSetter, childErrors, errorMutator) => {
44
52
  setState((state) => {
45
53
  const _value = _.isFunction(valOrSetter) ? valOrSetter(state.value) : valOrSetter;
46
- const error = validate === null || validate === void 0 ? void 0 : validate(_value);
54
+ const error = (validate === null || validate === void 0 ? void 0 : validate(_value)) || errorMutator;
47
55
  let value = transformArrIn(_value);
48
56
  if (isNumberSpec(spec) && !error) {
49
57
  value = (value ? Number(value) : undefined);
@@ -59,6 +67,7 @@ export const useField = ({ name, spec, initialValue, value: externalValue, valid
59
67
  return Object.assign(Object.assign({}, state), { dirty: !_.isEqual(value, initialValue), error, invalid: Boolean(error), modified: true, pristine: value === initialValue, touched: true, valid: !error, value, visited: true, childErrors: newChildErrors });
60
68
  });
61
69
  };
70
+ const onChange = (valOrSetter, childErrors) => onLocalChange(valOrSetter, childErrors);
62
71
  const onDrop = () => {
63
72
  if (isArrayItem(name)) {
64
73
  (externalParentOnUnmount ? externalParentOnUnmount : tools.onUnmount)(name);
@@ -67,7 +76,7 @@ export const useField = ({ name, spec, initialValue, value: externalValue, valid
67
76
  onChange(undefined, { [name]: false });
68
77
  }
69
78
  };
70
- return { onChange, onDrop };
79
+ return { onChange, onLocalChange, onDrop };
71
80
  }, [initialValue, setState, name, validate, spec, externalParentOnUnmount, tools.onUnmount]);
72
81
  const onBlur = React.useCallback(() => {
73
82
  setState((state) => (Object.assign(Object.assign({}, state), { active: false, touched: true })));
@@ -134,6 +143,24 @@ export const useField = ({ name, spec, initialValue, value: externalValue, valid
134
143
  (parentOnChange ? parentOnChange : tools.onChange)(name, state.value, Object.assign(Object.assign({}, state.childErrors), { [name]: state.error }));
135
144
  }
136
145
  }, [state.value]);
146
+ React.useEffect(() => {
147
+ if (!firstRenderRef.current) {
148
+ const valueMutator = _.get(mutators.values, name, EMPTY_MUTATOR);
149
+ let errorMutator = _.get(mutators.errors, name);
150
+ if (!isErrorMutatorCorrect(errorMutator)) {
151
+ errorMutator = undefined;
152
+ }
153
+ if (isValueMutatorCorrect(valueMutator, spec) &&
154
+ valueMutator !== state.value &&
155
+ valueMutator !== EMPTY_MUTATOR) {
156
+ onLocalChange(valueMutator, undefined, errorMutator);
157
+ }
158
+ else if (state.error !== errorMutator && !(state.error && !errorMutator)) {
159
+ setState(Object.assign(Object.assign({}, state), { error: errorMutator }));
160
+ (parentOnChange ? parentOnChange : tools.onChange)(name, state.value, Object.assign(Object.assign({}, state.childErrors), { [name]: errorMutator }));
161
+ }
162
+ }
163
+ }, [mutators]);
137
164
  React.useEffect(() => {
138
165
  firstRenderRef.current = false;
139
166
  return () => {
@@ -0,0 +1 @@
1
+ export declare const useMutateDFState: () => (mutators: import("..").DynamicFormMutators) => void;
@@ -0,0 +1,2 @@
1
+ import { useDynamicFormsCtx } from './useDynamicFormsCtx';
2
+ export const useMutateDFState = () => useDynamicFormsCtx().tools.mutateDFState;
@@ -0,0 +1,5 @@
1
+ import { DynamicFormMutators } from '../types';
2
+ export declare const useMutators: (externalMutators?: DynamicFormMutators) => {
3
+ mutators: DynamicFormMutators;
4
+ mutateDFState: (mutators: DynamicFormMutators) => void;
5
+ };
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import _ from 'lodash';
3
+ export const useMutators = (externalMutators) => {
4
+ const firstRenderRef = React.useRef(true);
5
+ const [store, setStore] = React.useState(externalMutators || {});
6
+ const mutateDFState = React.useCallback((mutators) => {
7
+ setStore((store) => (Object.assign(Object.assign(Object.assign(Object.assign({}, store), (mutators.errors ? { errors: _.merge(store.errors, mutators.errors) } : {})), (mutators.values ? { values: _.merge(store.values, mutators.values) } : {})), (mutators.spec ? { spec: _.merge(store.spec, mutators.spec) } : {}))));
8
+ }, [setStore]);
9
+ React.useEffect(() => {
10
+ if (firstRenderRef.current) {
11
+ firstRenderRef.current = false;
12
+ }
13
+ else if (externalMutators) {
14
+ mutateDFState(externalMutators);
15
+ }
16
+ }, [externalMutators]);
17
+ return { mutators: store, mutateDFState };
18
+ };
@@ -1,16 +1,16 @@
1
1
  import React from 'react';
2
2
  import _ from 'lodash';
3
- import { useForm } from 'react-final-form';
3
+ import { useFormState } from 'react-final-form';
4
4
  import { transformArrIn } from '../utils';
5
5
  export const useStore = (name) => {
6
- const form = useForm();
6
+ const formState = useFormState();
7
7
  const firstRenderRef = React.useRef(true);
8
8
  const [store, setStore] = React.useState(() => {
9
9
  const values = transformArrIn({
10
- [name]: _.get(form.getState().values, name),
10
+ [name]: _.get(formState.values, name),
11
11
  });
12
12
  const initialValue = transformArrIn({
13
- [name]: _.get(form.getState().initialValues, name),
13
+ [name]: _.get(formState.initialValues, name),
14
14
  });
15
15
  return {
16
16
  name,
@@ -19,7 +19,7 @@ export const useStore = (name) => {
19
19
  errors: {},
20
20
  };
21
21
  });
22
- const submitFailed = form.getState().submitFailed;
22
+ const submitFailed = formState.submitFailed;
23
23
  const tools = React.useMemo(() => ({
24
24
  initialValue: store.initialValue,
25
25
  onChange: (name, value, errors) => setStore((store) => (Object.assign(Object.assign({}, store), { values: _.set(Object.assign({}, store.values), name, _.clone(value)), errors: errors || {} }))),
@@ -29,10 +29,10 @@ export const useStore = (name) => {
29
29
  React.useEffect(() => {
30
30
  if (!firstRenderRef.current) {
31
31
  const values = transformArrIn({
32
- [name]: _.get(form.getState().values, name),
32
+ [name]: _.get(formState.values, name),
33
33
  });
34
34
  const initialValue = transformArrIn({
35
- [name]: _.get(form.getState().initialValues, name),
35
+ [name]: _.get(formState.initialValues, name),
36
36
  });
37
37
  setStore({
38
38
  name: name,
@@ -0,0 +1 @@
1
+ export declare const useStoreValue: () => import("..").DynamicFieldStore;
@@ -0,0 +1,2 @@
1
+ import { useDynamicFormsCtx } from './useDynamicFormsCtx';
2
+ export const useStoreValue = () => useDynamicFormsCtx().store;
@@ -1,5 +1,6 @@
1
1
  export * from './constants';
2
2
  export * from './Controller';
3
3
  export * from './DynamicField';
4
+ export { useMutateDFState, useStoreValue } from './hooks';
4
5
  export * from './types';
5
6
  export * from './utils';
@@ -1,5 +1,6 @@
1
1
  export * from './constants';
2
2
  export * from './Controller';
3
3
  export * from './DynamicField';
4
+ export { useMutateDFState, useStoreValue } from './hooks';
4
5
  export * from './types';
5
6
  export * from './utils';
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import type { MonacoEditorProps } from 'react-monaco-editor/lib/types';
3
3
  import { StringSpec } from '../../../types';
4
- import { DynamicFormConfig, FieldValue, ValidateError, WonderMirror } from './';
4
+ import { DynamicFieldStore, DynamicFormConfig, DynamicFormMutators, FieldValue, ValidateError, WonderMirror } from './';
5
5
  export interface DynamicFormsContext {
6
6
  config: DynamicFormConfig;
7
7
  Monaco?: React.ComponentType<MonacoEditorProps>;
@@ -11,6 +11,9 @@ export interface DynamicFormsContext {
11
11
  onChange: (name: string, value: FieldValue, errors?: Record<string, ValidateError>) => void;
12
12
  onUnmount: (name: string) => void;
13
13
  submitFailed: boolean;
14
+ mutateDFState: (mutators: DynamicFormMutators) => void;
14
15
  };
16
+ store: DynamicFieldStore;
17
+ mutators: DynamicFormMutators;
15
18
  __mirror?: WonderMirror;
16
19
  }
@@ -6,6 +6,7 @@ export * from './field';
6
6
  export * from './input';
7
7
  export * from './layout';
8
8
  export * from './mirror';
9
+ export * from './mutators';
9
10
  export * from './number';
10
11
  export * from './object';
11
12
  export * from './store';
@@ -6,6 +6,7 @@ export * from './field';
6
6
  export * from './input';
7
7
  export * from './layout';
8
8
  export * from './mirror';
9
+ export * from './mutators';
9
10
  export * from './number';
10
11
  export * from './object';
11
12
  export * from './store';
@@ -0,0 +1,7 @@
1
+ import { FormValue, Spec } from '../../../types';
2
+ import { BaseValidateError } from './';
3
+ export interface DynamicFormMutators {
4
+ errors?: Record<string, BaseValidateError>;
5
+ values?: Record<string, FormValue>;
6
+ spec?: Record<string, Partial<Spec>>;
7
+ }
@@ -1,6 +1,9 @@
1
1
  import { FormValue, Spec } from '../../../types';
2
+ import { ValidateError } from '../types';
2
3
  export declare const isCorrectConfig: (candidate: any) => boolean;
3
4
  export declare const transformArrIn: <Type extends FormValue, ReturnType_1 extends FormValue = Type>(value: Type) => ReturnType_1;
4
5
  export declare const transformArrOut: <Type extends FormValue, ReturnType_1 extends FormValue = Type>(value: Type) => ReturnType_1;
5
6
  export declare const isArrayItem: (name: string) => boolean;
6
7
  export declare const withGenerateButton: (spec: Spec) => boolean | undefined;
8
+ export declare const isErrorMutatorCorrect: (errorMutator: ValidateError) => boolean;
9
+ export declare const isValueMutatorCorrect: (valueMutator: FormValue, spec: Spec) => boolean;
@@ -45,3 +45,5 @@ export const isArrayItem = (name) => name[name.length - 1] === '>';
45
45
  export const withGenerateButton = (spec) => isStringSpec(spec) &&
46
46
  SPEC_TYPE_FOR_GENERATE_BUTTON.includes(spec.viewSpec.type) &&
47
47
  spec.viewSpec.generateRandomValueButton;
48
+ export const isErrorMutatorCorrect = (errorMutator) => _.isString(errorMutator) || _.isBoolean(errorMutator) || _.isUndefined(errorMutator);
49
+ export const isValueMutatorCorrect = (valueMutator, spec) => typeof valueMutator === spec.type || (_.isArray(valueMutator) && spec.type === SpecTypes.Array);
@@ -1,9 +1,9 @@
1
1
  import React from 'react';
2
2
  import type { MonacoEditorProps } from 'react-monaco-editor/lib/types';
3
- import { AnyObject, FormValue, Spec } from '../../types';
3
+ import { FormValue, Spec } from '../../types';
4
4
  import { DynamicViewConfig } from './types';
5
5
  export interface DynamicViewProps {
6
- value: AnyObject;
6
+ value: FormValue;
7
7
  spec: Spec;
8
8
  config: DynamicViewConfig;
9
9
  Link?: React.ComponentType<{
@@ -1,5 +1,4 @@
1
1
  import React from 'react';
2
- import _ from 'lodash';
3
2
  import { isValidElementType } from 'react-is';
4
3
  import { isCorrectSpec } from '../../helpers';
5
4
  import { ViewController } from './ViewController';
@@ -8,7 +7,7 @@ import { useCreateContext } from './hooks';
8
7
  export const DynamicView = ({ value, spec, config, Link, Monaco }) => {
9
8
  const DynamicFormsCtx = useCreateContext();
10
9
  const context = React.useMemo(() => ({ config, value, Link, Monaco: isValidElementType(Monaco) ? Monaco : undefined }), [config, value, Link, Monaco]);
11
- if (_.isObjectLike(value) && isCorrectSpec(spec) && isCorrectViewConfig(config)) {
10
+ if (isCorrectSpec(spec) && isCorrectViewConfig(config)) {
12
11
  return (React.createElement(DynamicFormsCtx.Provider, { value: context },
13
12
  React.createElement(ViewController, { spec: spec, name: "" })));
14
13
  }
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
2
  import type { MonacoEditorProps } from 'react-monaco-editor/lib/types';
3
- import { AnyObject, FormValue, Spec } from '../../../types';
3
+ import { FormValue, Spec } from '../../../types';
4
4
  import { DynamicViewConfig } from './';
5
5
  export interface DynamicViewContext {
6
6
  config: DynamicViewConfig;
7
- value: AnyObject;
7
+ value: FormValue;
8
8
  Link?: React.ComponentType<{
9
9
  value: FormValue;
10
10
  link: Spec['viewSpec']['link'];
@@ -1,3 +1,2 @@
1
1
  import { NumberInputProps, StringInputProps } from '../../../../core';
2
- import './Text.css';
3
- export declare const Text: <T extends NumberInputProps | StringInputProps>({ name, input, spec }: T) => JSX.Element;
2
+ export declare const Text: <T extends NumberInputProps | StringInputProps>({ name, input: { value, onBlur, onChange, onFocus }, spec, }: T) => JSX.Element;
@@ -1,36 +1,20 @@
1
1
  import React from 'react';
2
- import { Copy, CopyCheck, Eye, EyeSlash } from '@gravity-ui/icons';
3
- import { Button, CopyToClipboard, CopyToClipboardStatus, Icon, TextInput } from '@gravity-ui/uikit';
2
+ import { PasswordInput } from '@gravity-ui/components';
3
+ import { TextInput } from '@gravity-ui/uikit';
4
4
  import _ from 'lodash';
5
- import { block } from '../../../utils';
6
- import './Text.css';
7
- const b = block('text');
8
- export const Text = ({ name, input, spec }) => {
9
- const { value, onBlur, onChange, onFocus } = input;
10
- const [hideValue, setHideValue] = React.useState(spec.viewSpec.type === 'password');
11
- const handleChange = React.useCallback((value) => {
12
- onChange(value);
13
- }, [onChange, spec]);
14
- const type = React.useMemo(() => {
15
- if (spec.viewSpec.type === 'password') {
16
- return 'password';
17
- }
18
- return 'text';
19
- }, [spec.viewSpec.type]);
20
- const additionalRightContent = React.useMemo(() => {
21
- if (type === 'password') {
22
- const onClick = () => {
23
- setHideValue((hideValue) => !hideValue);
24
- };
25
- return (React.createElement("div", { className: b() },
26
- input.value ? (React.createElement(CopyToClipboard, { text: String(value), timeout: 500 }, (state) => (React.createElement(Button, { view: "flat-secondary", className: b('button'), size: "s" },
27
- React.createElement(Icon, { size: 14, data: state === CopyToClipboardStatus.Pending
28
- ? Copy
29
- : CopyCheck }))))) : null,
30
- React.createElement(Button, { view: "flat-secondary", onClick: onClick, className: b('button'), size: "s" },
31
- React.createElement(Icon, { data: hideValue ? Eye : EyeSlash, size: 14 }))));
32
- }
33
- return undefined;
34
- }, [hideValue, input.value, type, value]);
35
- return (React.createElement(TextInput, { type: hideValue ? 'password' : 'text', value: _.isNil(value) ? '' : `${value}`, hasClear: true, onBlur: onBlur, onFocus: onFocus, onUpdate: handleChange, disabled: spec.viewSpec.disabled, placeholder: spec.viewSpec.placeholder, autoComplete: type === 'password' ? 'new-password' : undefined, qa: name, rightContent: additionalRightContent }));
5
+ export const Text = ({ name, input: { value, onBlur, onChange, onFocus }, spec, }) => {
6
+ const props = {
7
+ value: _.isNil(value) ? '' : `${value}`,
8
+ hasClear: true,
9
+ onBlur: onBlur,
10
+ onFocus: onFocus,
11
+ onUpdate: onChange,
12
+ disabled: spec.viewSpec.disabled,
13
+ placeholder: spec.viewSpec.placeholder,
14
+ qa: name,
15
+ };
16
+ if (spec.viewSpec.type === 'password') {
17
+ return (React.createElement(PasswordInput, Object.assign({}, props, { autoComplete: "new-password", showCopyButton: true, showRevealButton: true })));
18
+ }
19
+ return React.createElement(TextInput, Object.assign({}, props, { type: "text" }));
36
20
  };
@@ -1,8 +1,9 @@
1
1
  import React from 'react';
2
+ import _ from 'lodash';
2
3
  import { isNotEmptyValue } from '../../../utils';
3
4
  import { SimpleVerticalAccordeon } from '../../SimpleVerticalAccordeon';
4
5
  export const ViewAccordeon = ({ name, value, spec, children, }) => {
5
- const [open, setOpen] = React.useState(true);
6
+ const [open, setOpen] = React.useState(_.isBoolean(spec.viewSpec.layoutOpen) ? spec.viewSpec.layoutOpen : true);
6
7
  if (!isNotEmptyValue(value, spec)) {
7
8
  return null;
8
9
  }
@@ -1,8 +1,9 @@
1
1
  import React from 'react';
2
+ import _ from 'lodash';
2
3
  import { Card } from '../';
3
4
  import { isNotEmptyValue } from '../../utils';
4
5
  export const ViewCardAccordeon = ({ name, value, spec, children, }) => {
5
- const [open, setOpen] = React.useState(true);
6
+ const [open, setOpen] = React.useState(_.isBoolean(spec.viewSpec.layoutOpen) ? spec.viewSpec.layoutOpen : true);
6
7
  const onToggle = React.useCallback(() => setOpen((f) => !f), [setOpen]);
7
8
  if (!isNotEmptyValue(value, spec)) {
8
9
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dynamic-forms",
3
- "version": "3.0.1",
3
+ "version": "3.2.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "main": "build/cjs/index.js",
@@ -38,9 +38,9 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@bem-react/classname": "^1.6.0",
41
- "@gravity-ui/components": "^2.4.0",
41
+ "@gravity-ui/components": "^2.8.0",
42
42
  "@gravity-ui/i18n": "^1.1.0",
43
- "@gravity-ui/icons": "^2.5.0",
43
+ "@gravity-ui/icons": "^2.8.1",
44
44
  "lodash": "^4.17.20"
45
45
  },
46
46
  "devDependencies": {
@@ -48,11 +48,11 @@
48
48
  "@babel/preset-typescript": "^7.18.6",
49
49
  "@commitlint/cli": "^17.0.0",
50
50
  "@commitlint/config-conventional": "^17.0.0",
51
- "@gravity-ui/eslint-config": "^2.1.1",
52
- "@gravity-ui/prettier-config": "^1.0.1",
51
+ "@gravity-ui/eslint-config": "^2.2.0",
52
+ "@gravity-ui/prettier-config": "^1.1.0",
53
53
  "@gravity-ui/stylelint-config": "^2.0.0",
54
54
  "@gravity-ui/tsconfig": "^1.0.0",
55
- "@gravity-ui/uikit": "^5.8.0",
55
+ "@gravity-ui/uikit": "^5.19.1",
56
56
  "@storybook/addon-essentials": "^7.0.27",
57
57
  "@storybook/preset-scss": "^1.0.3",
58
58
  "@storybook/react": "^7.0.27",
@@ -1,6 +0,0 @@
1
- .df-text {
2
- display: flex;
3
- }
4
- .df-text__button {
5
- --yc-button-background-color-hover: transparent;
6
- }
@@ -1,6 +0,0 @@
1
- .df-text {
2
- display: flex;
3
- }
4
- .df-text__button {
5
- --yc-button-background-color-hover: transparent;
6
- }