@gravity-ui/dynamic-forms 5.25.0 → 5.27.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 (59) hide show
  1. package/build/cjs/lib/unstable/core/SchemaRendererNode/SchemaRendererNode.js +61 -16
  2. package/build/cjs/lib/unstable/core/SchemaRendererNode/utils.d.ts +6 -3
  3. package/build/cjs/lib/unstable/core/SchemaRendererNode/utils.js +63 -14
  4. package/build/cjs/lib/unstable/core/index.d.ts +1 -1
  5. package/build/cjs/lib/unstable/core/index.js +4 -1
  6. package/build/cjs/lib/unstable/core/useSchemaRenderer/types/state.d.ts +1 -0
  7. package/build/cjs/lib/unstable/core/useSchemaRenderer/useSchemaRenderer.d.ts +2 -1
  8. package/build/cjs/lib/unstable/core/useSchemaRenderer/useSchemaRenderer.js +40 -19
  9. package/build/cjs/lib/unstable/core/useSchemaRenderer/utils/get-validate.js +6 -1
  10. package/build/cjs/lib/unstable/core/useSchemaRendererState/useSchemaRendererState.js +14 -0
  11. package/build/cjs/lib/unstable/core/utils/common.d.ts +3 -0
  12. package/build/cjs/lib/unstable/core/utils/common.js +7 -1
  13. package/build/cjs/lib/unstable/core/utils/index.d.ts +1 -0
  14. package/build/cjs/lib/unstable/core/utils/index.js +1 -0
  15. package/build/cjs/lib/unstable/core/utils/strict-mode.d.ts +6 -0
  16. package/build/cjs/lib/unstable/core/utils/strict-mode.js +30 -0
  17. package/build/cjs/lib/unstable/kit/components/EntityError/EntityError.js +1 -1
  18. package/build/cjs/lib/unstable/kit/entities/Alert/Alert.js +3 -3
  19. package/build/cjs/lib/unstable/kit/entities/FewOfNested/FewOfNested.js +6 -1
  20. package/build/cjs/lib/unstable/kit/entities/OneOfNested/OneOfNested.js +12 -2
  21. package/build/cjs/lib/unstable/kit/form-entities/StringNumberWithScaleInput/StringNumberWithScaleInput.d.ts +1 -1
  22. package/build/cjs/lib/unstable/kit/form-entities/StringNumberWithScaleInput/StringNumberWithScaleInput.js +8 -7
  23. package/build/cjs/lib/unstable/kit/overview-entities/StringNumberWithScaleValue/StringNumberWithScaleValue.d.ts +1 -1
  24. package/build/cjs/lib/unstable/kit/overview-entities/StringNumberWithScaleValue/StringNumberWithScaleValue.js +5 -5
  25. package/build/cjs/lib/unstable/kit/utils/common.d.ts +0 -3
  26. package/build/cjs/lib/unstable/kit/utils/common.js +1 -7
  27. package/build/cjs/lib/unstable/kit/utils/index.d.ts +1 -1
  28. package/build/cjs/lib/unstable/kit/utils/index.js +1 -4
  29. package/build/cjs/lib/unstable/kit/utils/transformer.js +10 -2
  30. package/build/esm/lib/unstable/core/SchemaRendererNode/SchemaRendererNode.js +64 -19
  31. package/build/esm/lib/unstable/core/SchemaRendererNode/utils.d.ts +6 -3
  32. package/build/esm/lib/unstable/core/SchemaRendererNode/utils.js +63 -14
  33. package/build/esm/lib/unstable/core/index.d.ts +1 -1
  34. package/build/esm/lib/unstable/core/index.js +1 -1
  35. package/build/esm/lib/unstable/core/useSchemaRenderer/types/state.d.ts +1 -0
  36. package/build/esm/lib/unstable/core/useSchemaRenderer/useSchemaRenderer.d.ts +2 -1
  37. package/build/esm/lib/unstable/core/useSchemaRenderer/useSchemaRenderer.js +41 -20
  38. package/build/esm/lib/unstable/core/useSchemaRenderer/utils/get-validate.js +6 -1
  39. package/build/esm/lib/unstable/core/useSchemaRendererState/useSchemaRendererState.js +15 -1
  40. package/build/esm/lib/unstable/core/utils/common.d.ts +3 -0
  41. package/build/esm/lib/unstable/core/utils/common.js +3 -0
  42. package/build/esm/lib/unstable/core/utils/index.d.ts +1 -0
  43. package/build/esm/lib/unstable/core/utils/index.js +1 -0
  44. package/build/esm/lib/unstable/core/utils/strict-mode.d.ts +6 -0
  45. package/build/esm/lib/unstable/core/utils/strict-mode.js +26 -0
  46. package/build/esm/lib/unstable/kit/components/EntityError/EntityError.js +1 -1
  47. package/build/esm/lib/unstable/kit/entities/Alert/Alert.js +3 -3
  48. package/build/esm/lib/unstable/kit/entities/FewOfNested/FewOfNested.js +6 -1
  49. package/build/esm/lib/unstable/kit/entities/OneOfNested/OneOfNested.js +12 -2
  50. package/build/esm/lib/unstable/kit/form-entities/StringNumberWithScaleInput/StringNumberWithScaleInput.d.ts +1 -1
  51. package/build/esm/lib/unstable/kit/form-entities/StringNumberWithScaleInput/StringNumberWithScaleInput.js +2 -1
  52. package/build/esm/lib/unstable/kit/overview-entities/StringNumberWithScaleValue/StringNumberWithScaleValue.d.ts +1 -1
  53. package/build/esm/lib/unstable/kit/overview-entities/StringNumberWithScaleValue/StringNumberWithScaleValue.js +1 -1
  54. package/build/esm/lib/unstable/kit/utils/common.d.ts +0 -3
  55. package/build/esm/lib/unstable/kit/utils/common.js +0 -3
  56. package/build/esm/lib/unstable/kit/utils/index.d.ts +1 -1
  57. package/build/esm/lib/unstable/kit/utils/index.js +1 -1
  58. package/build/esm/lib/unstable/kit/utils/transformer.js +10 -2
  59. package/package.json +1 -1
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SchemaRendererNode = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
+ const get_1 = tslib_1.__importDefault(require("lodash/get"));
6
7
  const noop_1 = tslib_1.__importDefault(require("lodash/noop"));
7
8
  const react_final_form_1 = require("react-final-form");
8
9
  const constants_1 = require("../constants");
@@ -11,9 +12,9 @@ const useSchemaRendererState_1 = require("../useSchemaRendererState");
11
12
  const utils_1 = require("../utils");
12
13
  const utils_2 = require("./utils");
13
14
  const SchemaRendererNodeComponent = ({ headName, modeOverride, name, schemaOverride, schemaPath, }) => {
14
- var _a;
15
+ var _a, _b, _c, _d, _e, _f;
15
16
  const form = (0, react_final_form_1.useForm)();
16
- const compareValuesRef = react_1.default.useRef((0, utils_2.getCompareValues)());
17
+ const strictCheckerRef = react_1.default.useRef((0, utils_1.getStrictModeChecker)());
17
18
  const fieldRef = react_1.default.useRef(null);
18
19
  const unsubscribeRef = react_1.default.useRef(null);
19
20
  const [ticks, setTicks] = react_1.default.useState({ input: 0, meta: 0 });
@@ -34,13 +35,15 @@ const SchemaRendererNodeComponent = ({ headName, modeOverride, name, schemaOverr
34
35
  const schema = react_1.default.useMemo(() => (0, utils_2.getAccumulatedSchema)(schemaPath, srState === null || srState === void 0 ? void 0 : srState.schema, schemaOverride), [schemaOverride, schemaPath, srState === null || srState === void 0 ? void 0 : srState.schema]);
35
36
  const error = srState === null || srState === void 0 ? void 0 : srState.errors[name];
36
37
  const mode = modeOverride || (srState === null || srState === void 0 ? void 0 : srState.mode);
37
- const jsonDefaultValues = ((_a = srState === null || srState === void 0 ? void 0 : srState.settings) === null || _a === void 0 ? void 0 : _a.jsonDefaultValues) || false;
38
+ // todo: check parent
39
+ const required = (_b = (_a = schema === null || schema === void 0 ? void 0 : schema.nodeParameters) === null || _a === void 0 ? void 0 : _a.flags) === null || _b === void 0 ? void 0 : _b.required;
40
+ const coerceInitialValues = (_d = (_c = srState === null || srState === void 0 ? void 0 : srState.settings) === null || _c === void 0 ? void 0 : _c.coerceInitialValues) !== null && _d !== void 0 ? _d : true;
41
+ const jsonDefaultValues = (_f = (_e = srState === null || srState === void 0 ? void 0 : srState.settings) === null || _e === void 0 ? void 0 : _e.jsonDefaultValues) !== null && _f !== void 0 ? _f : false;
38
42
  const kit = react_1.default.useMemo(() => (0, utils_2.getRenderKit)({ config: srState === null || srState === void 0 ? void 0 : srState.config, schema }), [schema, srState === null || srState === void 0 ? void 0 : srState.config]);
39
43
  react_1.default.useMemo(() => {
40
44
  var _a;
41
- if (compareValuesRef.current({
45
+ if (!strictCheckerRef.current.checkDiff({
42
46
  form,
43
- jsonDefaultValues,
44
47
  headName,
45
48
  name,
46
49
  default: schema === null || schema === void 0 ? void 0 : schema.default,
@@ -51,13 +54,35 @@ const SchemaRendererNodeComponent = ({ headName, modeOverride, name, schemaOverr
51
54
  }
52
55
  (_a = unsubscribeRef.current) === null || _a === void 0 ? void 0 : _a.call(unsubscribeRef);
53
56
  const initialState = { schemaPath };
54
- let defaultValue = schema === null || schema === void 0 ? void 0 : schema.default;
55
- if (jsonDefaultValues && typeof defaultValue === 'string') {
56
- try {
57
- defaultValue = JSON.parse(defaultValue);
57
+ const defaultValue = (() => {
58
+ let result = schema === null || schema === void 0 ? void 0 : schema.default;
59
+ if (jsonDefaultValues) {
60
+ try {
61
+ result = JSON.parse(result);
62
+ }
63
+ catch (_a) {
64
+ result = undefined;
65
+ }
58
66
  }
59
- catch (_b) { }
60
- }
67
+ if (result === undefined && required) {
68
+ if ((Array.isArray(schema.type) &&
69
+ schema.type.length &&
70
+ !schema.type.filter((t) => t !== constants_1.JsonSchemaType.Array).length) ||
71
+ schema.type === constants_1.JsonSchemaType.Array) {
72
+ result = [];
73
+ }
74
+ else if ((Array.isArray(schema.type) &&
75
+ schema.type.length &&
76
+ !schema.type.filter((t) => t !== constants_1.JsonSchemaType.Object).length) ||
77
+ schema.type === constants_1.JsonSchemaType.Object) {
78
+ result = {};
79
+ }
80
+ }
81
+ if (coerceInitialValues) {
82
+ result = (0, utils_2.coerceToJsonSchemaType)(result, schema === null || schema === void 0 ? void 0 : schema.type);
83
+ }
84
+ return result;
85
+ })();
61
86
  const unsubscribe = form.registerField(name, (f) => {
62
87
  const prevF = fieldRef.current;
63
88
  if (prevF) {
@@ -85,14 +110,30 @@ const SchemaRendererNodeComponent = ({ headName, modeOverride, name, schemaOverr
85
110
  silent: true,
86
111
  validateFields: [(0, utils_1.getServiceFieldName)(useSchemaRenderer_1.SCHEMA_RENDERER_SERVICE_FIELD, headName)],
87
112
  });
88
- if (defaultValue !== undefined) {
89
- (0, utils_2.scheduleFlush)(form);
90
- }
113
+ const castParams = (() => {
114
+ if (!coerceInitialValues) {
115
+ return undefined;
116
+ }
117
+ const formValues = form.getState().values;
118
+ const currentValue = name ? (0, get_1.default)(formValues, name) : formValues;
119
+ if (currentValue === undefined) {
120
+ return undefined;
121
+ }
122
+ const coercedCurrentValue = (0, utils_2.coerceToJsonSchemaType)(currentValue, schema === null || schema === void 0 ? void 0 : schema.type);
123
+ if (coercedCurrentValue !== undefined && coercedCurrentValue !== currentValue) {
124
+ return { name, value: coercedCurrentValue };
125
+ }
126
+ if (defaultValue !== undefined && defaultValue !== currentValue) {
127
+ return { name, value: defaultValue };
128
+ }
129
+ return undefined;
130
+ })();
131
+ (0, utils_2.scheduleFlush)(form, headName, castParams);
91
132
  unsubscribeRef.current = () => {
92
133
  unsubscribe();
93
- (0, utils_2.scheduleFlush)(form);
134
+ (0, utils_2.scheduleFlush)(form, headName);
94
135
  };
95
- }, [form, jsonDefaultValues, headName, name, schema === null || schema === void 0 ? void 0 : schema.default, schema === null || schema === void 0 ? void 0 : schema.type, schemaPath]);
136
+ }, [form, headName, name, schema === null || schema === void 0 ? void 0 : schema.default, schema === null || schema === void 0 ? void 0 : schema.type, schemaPath]);
96
137
  const input = react_1.default.useMemo(() => {
97
138
  var _a;
98
139
  const fieldState = form.getFieldState(name);
@@ -116,8 +157,12 @@ const SchemaRendererNodeComponent = ({ headName, modeOverride, name, schemaOverr
116
157
  };
117
158
  }, [error, form, name, ticks.meta]);
118
159
  react_1.default.useEffect(() => {
160
+ const strictChecker = strictCheckerRef.current;
119
161
  return () => {
120
162
  var _a;
163
+ if (strictChecker.isStrict()) {
164
+ return;
165
+ }
121
166
  (_a = unsubscribeRef.current) === null || _a === void 0 ? void 0 : _a.call(unsubscribeRef);
122
167
  };
123
168
  }, []);
@@ -1,6 +1,6 @@
1
1
  import type { FormApi } from 'final-form';
2
2
  import { SchemaRendererMode } from '../constants';
3
- import type { JsonSchema, NodeEntity, NodeLayout, NodesConfig } from '../types';
3
+ import type { FieldValue, JsonSchema, NodeEntity, NodeLayout, NodesConfig } from '../types';
4
4
  type GetRenderKitParams<Schema extends JsonSchema> = {
5
5
  config?: NodesConfig;
6
6
  schema?: Schema;
@@ -23,6 +23,9 @@ type GetRenderKitReturn<Schema extends JsonSchema> = {
23
23
  };
24
24
  export declare const getRenderKit: <Schema extends JsonSchema>({ config, schema, }: GetRenderKitParams<Schema>) => GetRenderKitReturn<Schema>;
25
25
  export declare const getAccumulatedSchema: (schemaPath: string, rootSchema?: JsonSchema, override?: JsonSchema, collectedPaths?: Set<string>) => JsonSchema;
26
- export declare const scheduleFlush: (form: FormApi) => void;
27
- export declare const getCompareValues: () => (currentValues: Record<string, unknown>) => boolean;
26
+ export declare const scheduleFlush: (form: FormApi, headName: string, change?: {
27
+ name: string;
28
+ value: FieldValue;
29
+ }) => void;
30
+ export declare const coerceToJsonSchemaType: (value: FieldValue, type?: JsonSchema["type"]) => FieldValue;
28
31
  export {};
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getCompareValues = exports.scheduleFlush = exports.getAccumulatedSchema = exports.getRenderKit = void 0;
3
+ exports.coerceToJsonSchemaType = exports.scheduleFlush = exports.getAccumulatedSchema = exports.getRenderKit = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const get_1 = tslib_1.__importDefault(require("lodash/get"));
6
+ const isObjectLike_1 = tslib_1.__importDefault(require("lodash/isObjectLike"));
6
7
  const isString_1 = tslib_1.__importDefault(require("lodash/isString"));
7
8
  const set_1 = tslib_1.__importDefault(require("lodash/set"));
8
9
  const constants_1 = require("../constants");
10
+ const useSchemaRenderer_1 = require("../useSchemaRenderer");
9
11
  const utils_1 = require("../utils");
10
12
  const fixType = (value) => value;
11
13
  const mergeValues = (first, second) => {
@@ -161,26 +163,73 @@ const getAccumulatedSchema = (schemaPath, rootSchema, override, collectedPaths =
161
163
  };
162
164
  exports.getAccumulatedSchema = getAccumulatedSchema;
163
165
  const flushes = new WeakMap();
164
- const scheduleFlush = (form) => {
165
- if (flushes.get(form)) {
166
+ const scheduleFlush = (form, headName, change) => {
167
+ const scheduled = flushes.get(form);
168
+ if (scheduled) {
169
+ scheduled.headNames.add(headName);
170
+ if (change) {
171
+ scheduled.changes.set(change.name, change.value);
172
+ }
166
173
  return;
167
174
  }
168
- flushes.set(form, true);
175
+ const changes = new Map();
176
+ const headNames = new Set([headName]);
177
+ if (change) {
178
+ changes.set(change.name, change.value);
179
+ }
180
+ flushes.set(form, { changes, headNames });
169
181
  queueMicrotask(() => {
170
182
  flushes.delete(form);
171
- form.batch(() => { });
183
+ form.batch(() => {
184
+ changes.forEach((value, name) => {
185
+ form.change(name, value);
186
+ });
187
+ });
188
+ headNames.forEach((name) => {
189
+ var _a;
190
+ const srName = (0, utils_1.getServiceFieldName)(useSchemaRenderer_1.SCHEMA_RENDERER_SERVICE_FIELD, name);
191
+ const srField = form.getFieldState(srName);
192
+ const srState = (_a = srField === null || srField === void 0 ? void 0 : srField.data) === null || _a === void 0 ? void 0 : _a.state;
193
+ srState === null || srState === void 0 ? void 0 : srState.runValidate();
194
+ });
172
195
  });
173
196
  };
174
197
  exports.scheduleFlush = scheduleFlush;
175
- const getCompareValues = () => {
176
- let cachedValues;
177
- return (currentValues) => {
178
- if (!cachedValues ||
179
- [...Object.keys(cachedValues), ...Object.keys(currentValues)].some((key) => cachedValues[key] !== currentValues[key])) {
180
- cachedValues = Object.assign({}, currentValues);
198
+ // eslint-disable-next-line complexity
199
+ const coerceToJsonSchemaType = (value, type) => {
200
+ if (value === undefined || value === null || !type) {
201
+ return value;
202
+ }
203
+ const typeArray = Array.isArray(type) ? type : [type];
204
+ if (typeArray.length &&
205
+ typeArray.some((t) => t === constants_1.JsonSchemaType.Number || t === constants_1.JsonSchemaType.Integer) &&
206
+ !typeArray.filter((t) => t !== constants_1.JsonSchemaType.Number &&
207
+ t !== constants_1.JsonSchemaType.Integer &&
208
+ t !== constants_1.JsonSchemaType.Null).length) {
209
+ if ((0, utils_1.isStringNumber)(value)) {
210
+ return Number(value);
211
+ }
212
+ return value;
213
+ }
214
+ if (typeArray.length &&
215
+ typeArray.some((t) => t === constants_1.JsonSchemaType.Boolean) &&
216
+ !typeArray.filter((t) => t !== constants_1.JsonSchemaType.Boolean && t !== constants_1.JsonSchemaType.Null).length) {
217
+ if (value === 'true' || value === 1) {
218
+ return true;
219
+ }
220
+ if (value === 'false' || value === 0) {
181
221
  return false;
182
222
  }
183
- return true;
184
- };
223
+ return value;
224
+ }
225
+ if (typeArray.length &&
226
+ typeArray.some((t) => t === constants_1.JsonSchemaType.String) &&
227
+ !typeArray.filter((t) => t !== constants_1.JsonSchemaType.String && t !== constants_1.JsonSchemaType.Null).length) {
228
+ if (!(typeof value === 'string' || (0, isObjectLike_1.default)(value))) {
229
+ return String(value);
230
+ }
231
+ return value;
232
+ }
233
+ return value;
185
234
  };
186
- exports.getCompareValues = getCompareValues;
235
+ exports.coerceToJsonSchemaType = coerceToJsonSchemaType;
@@ -5,4 +5,4 @@ export type * from './types';
5
5
  export { SCHEMA_RENDERER_SERVICE_FIELD, type SchemaRendererState, type SchemaPatch, type SchemaPatchRemover, type UseSchemaRendererParams, useSchemaRenderer, } from './useSchemaRenderer';
6
6
  export { type UseSchemaRendererStateParams, useSchemaRendererState } from './useSchemaRendererState';
7
7
  export { useSchemaRendererTools } from './useSchemaRendererTools';
8
- export { createNodeParametersDefiner, defineNodeEntityConfig, defineNodeLayoutConfig, getServiceFieldName, getSchemaByPointer, } from './utils';
8
+ export { createNodeParametersDefiner, defineNodeEntityConfig, defineNodeLayoutConfig, getServiceFieldName, getSchemaByPointer, isStringFloat, isStringInt, isStringNumber, } from './utils';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSchemaByPointer = exports.getServiceFieldName = exports.defineNodeLayoutConfig = exports.defineNodeEntityConfig = exports.createNodeParametersDefiner = exports.useSchemaRendererTools = exports.useSchemaRendererState = exports.useSchemaRenderer = exports.SCHEMA_RENDERER_SERVICE_FIELD = exports.SchemaRendererMode = exports.SchemaRendererEventType = exports.JsonSchemaType = exports.NodeType = exports.SchemaRenderer = exports.getRenderKit = exports.getAccumulatedSchema = exports.SchemaRendererNode = void 0;
3
+ exports.isStringNumber = exports.isStringInt = exports.isStringFloat = exports.getSchemaByPointer = exports.getServiceFieldName = exports.defineNodeLayoutConfig = exports.defineNodeEntityConfig = exports.createNodeParametersDefiner = exports.useSchemaRendererTools = exports.useSchemaRendererState = exports.useSchemaRenderer = exports.SCHEMA_RENDERER_SERVICE_FIELD = exports.SchemaRendererMode = exports.SchemaRendererEventType = exports.JsonSchemaType = exports.NodeType = exports.SchemaRenderer = exports.getRenderKit = exports.getAccumulatedSchema = exports.SchemaRendererNode = void 0;
4
4
  var SchemaRendererNode_1 = require("./SchemaRendererNode");
5
5
  Object.defineProperty(exports, "SchemaRendererNode", { enumerable: true, get: function () { return SchemaRendererNode_1.SchemaRendererNode; } });
6
6
  Object.defineProperty(exports, "getAccumulatedSchema", { enumerable: true, get: function () { return SchemaRendererNode_1.getAccumulatedSchema; } });
@@ -25,3 +25,6 @@ Object.defineProperty(exports, "defineNodeEntityConfig", { enumerable: true, get
25
25
  Object.defineProperty(exports, "defineNodeLayoutConfig", { enumerable: true, get: function () { return utils_1.defineNodeLayoutConfig; } });
26
26
  Object.defineProperty(exports, "getServiceFieldName", { enumerable: true, get: function () { return utils_1.getServiceFieldName; } });
27
27
  Object.defineProperty(exports, "getSchemaByPointer", { enumerable: true, get: function () { return utils_1.getSchemaByPointer; } });
28
+ Object.defineProperty(exports, "isStringFloat", { enumerable: true, get: function () { return utils_1.isStringFloat; } });
29
+ Object.defineProperty(exports, "isStringInt", { enumerable: true, get: function () { return utils_1.isStringInt; } });
30
+ Object.defineProperty(exports, "isStringNumber", { enumerable: true, get: function () { return utils_1.isStringNumber; } });
@@ -18,6 +18,7 @@ export interface SchemaRendererState<UserContext extends Record<string, unknown>
18
18
  runValidate: () => void;
19
19
  schema: JsonSchema;
20
20
  settings: {
21
+ coerceInitialValues: boolean;
21
22
  jsonDefaultValues: boolean;
22
23
  };
23
24
  subscribe: (subscriber: SchemaRendererSubscriber) => string;
@@ -3,6 +3,7 @@ import { type SchemaRendererMode } from '../constants';
3
3
  import type { ErrorMessages, FieldValue, JsonSchema, NodesConfig } from '../types';
4
4
  import type { SchemaRendererState } from './types';
5
5
  export interface UseSchemaRendererParams {
6
+ coerceInitialValues?: boolean;
6
7
  config?: NodesConfig;
7
8
  connectValidate?: boolean;
8
9
  errorMessages?: ErrorMessages;
@@ -13,4 +14,4 @@ export interface UseSchemaRendererParams {
13
14
  validateOnBlur: boolean;
14
15
  userContext?: SchemaRendererState['userContext'];
15
16
  }
16
- export declare const useSchemaRenderer: ({ config, connectValidate, errorMessages, jsonDefaultValues, mode, name: headName, schema: originalSchema, validateOnBlur, userContext, }: UseSchemaRendererParams) => FieldValidator<FieldValue>;
17
+ export declare const useSchemaRenderer: ({ coerceInitialValues, config, connectValidate, errorMessages, jsonDefaultValues, mode, name: headName, schema: originalSchema, validateOnBlur, userContext, }: UseSchemaRendererParams) => FieldValidator<FieldValue>;
@@ -10,8 +10,9 @@ const constants_1 = require("../constants");
10
10
  const utils_1 = require("../utils");
11
11
  const constants_2 = require("./constants");
12
12
  const utils_2 = require("./utils");
13
- const useSchemaRenderer = ({ config, connectValidate = true, errorMessages, jsonDefaultValues = false, mode, name: headName, schema: originalSchema, validateOnBlur, userContext, }) => {
13
+ const useSchemaRenderer = ({ coerceInitialValues = true, config, connectValidate = true, errorMessages, jsonDefaultValues = false, mode, name: headName, schema: originalSchema, validateOnBlur, userContext, }) => {
14
14
  const form = (0, react_final_form_1.useForm)();
15
+ const strictCheckerRef = react_1.default.useRef((0, utils_1.getStrictModeChecker)());
15
16
  const stateRef = react_1.default.useRef(null);
16
17
  const prevParamsRef = react_1.default.useRef(null);
17
18
  const unsubscribeRef = react_1.default.useRef(null);
@@ -19,9 +20,7 @@ const useSchemaRenderer = ({ config, connectValidate = true, errorMessages, json
19
20
  const dispatchEvent = react_1.default.useMemo(() => (0, utils_2.getDispatch)(form, headName), [form, headName]);
20
21
  const runValidate = react_1.default.useMemo(() => (0, utils_2.getRunValidate)(form, headName, validateOnBlur), [form, headName, validateOnBlur]);
21
22
  const validate = react_1.default.useMemo(() => (0, utils_2.getValidate)(form, headName), [form, headName]);
22
- react_1.default.useMemo(() => {
23
- var _a;
24
- (_a = unsubscribeRef.current) === null || _a === void 0 ? void 0 : _a.call(unsubscribeRef);
23
+ const { initialEvents, initialState } = react_1.default.useMemo(() => {
25
24
  const prevParams = prevParamsRef.current;
26
25
  const prevState = stateRef.current;
27
26
  const configUpdated = config !== (prevParams === null || prevParams === void 0 ? void 0 : prevParams.config);
@@ -30,7 +29,8 @@ const useSchemaRenderer = ({ config, connectValidate = true, errorMessages, json
30
29
  const modeUpdated = mode !== (prevParams === null || prevParams === void 0 ? void 0 : prevParams.mode);
31
30
  const schemaUpdated = originalSchema !== (prevParams === null || prevParams === void 0 ? void 0 : prevParams.schema);
32
31
  const userContextUpdated = userContext !== (prevParams === null || prevParams === void 0 ? void 0 : prevParams.userContext);
33
- const settingsUpdated = jsonDefaultValues !== (prevParams === null || prevParams === void 0 ? void 0 : prevParams.jsonDefaultValues);
32
+ const settingsUpdated = coerceInitialValues !== (prevParams === null || prevParams === void 0 ? void 0 : prevParams.coerceInitialValues) ||
33
+ jsonDefaultValues !== (prevParams === null || prevParams === void 0 ? void 0 : prevParams.jsonDefaultValues);
34
34
  const initialState = {
35
35
  cache: nameUpdated || schemaUpdated || !(prevState === null || prevState === void 0 ? void 0 : prevState.cache) ? {} : prevState.cache,
36
36
  config: config || {},
@@ -47,7 +47,7 @@ const useSchemaRenderer = ({ config, connectValidate = true, errorMessages, json
47
47
  ? {}
48
48
  : prevState.regularErrors,
49
49
  runValidate,
50
- settings: { jsonDefaultValues },
50
+ settings: { coerceInitialValues, jsonDefaultValues },
51
51
  schema: nameUpdated || schemaUpdated ? (0, cloneDeep_1.default)(originalSchema) : (prevState === null || prevState === void 0 ? void 0 : prevState.schema) || {},
52
52
  subscribe,
53
53
  subscribers: (prevState === null || prevState === void 0 ? void 0 : prevState.subscribers) || { byId: {}, byName: new Map(), byPath: new Map() },
@@ -55,8 +55,7 @@ const useSchemaRenderer = ({ config, connectValidate = true, errorMessages, json
55
55
  userContext: userContextUpdated ? userContext || {} : (prevState === null || prevState === void 0 ? void 0 : prevState.userContext) || {},
56
56
  waiters: nameUpdated || schemaUpdated || !(prevState === null || prevState === void 0 ? void 0 : prevState.waiters) ? {} : prevState.waiters,
57
57
  };
58
- const getValidator = connectValidate ? () => validate : undefined;
59
- let initialEvents = [
58
+ const initialEvents = [
60
59
  ...(configUpdated ? [constants_1.SchemaRendererEventType.Config] : []),
61
60
  ...(errorMessagesUpdated ? [constants_1.SchemaRendererEventType.ErrorMessages] : []),
62
61
  ...(nameUpdated ? [constants_1.SchemaRendererEventType.Name] : []),
@@ -65,15 +64,8 @@ const useSchemaRenderer = ({ config, connectValidate = true, errorMessages, json
65
64
  ...(userContextUpdated ? [constants_1.SchemaRendererEventType.UserContext] : []),
66
65
  ...(settingsUpdated ? [constants_1.SchemaRendererEventType.Settings] : []),
67
66
  ].map((type) => ({ type, all: true }));
68
- unsubscribeRef.current = form.registerField((0, utils_1.getServiceFieldName)(constants_2.SCHEMA_RENDERER_SERVICE_FIELD, headName), (f) => {
69
- var _a;
70
- const state = (_a = f.data) === null || _a === void 0 ? void 0 : _a.state;
71
- if (state && initialEvents.length) {
72
- state.dispatchEvent(initialEvents);
73
- initialEvents = [];
74
- }
75
- }, { data: true }, { data: { state: initialState }, getValidator, silent: true, validateFields: [headName] });
76
67
  prevParamsRef.current = {
68
+ coerceInitialValues,
77
69
  config,
78
70
  errorMessages,
79
71
  jsonDefaultValues,
@@ -84,12 +76,12 @@ const useSchemaRenderer = ({ config, connectValidate = true, errorMessages, json
84
76
  validateOnBlur,
85
77
  };
86
78
  stateRef.current = initialState;
79
+ return { initialEvents, initialState };
87
80
  }, [
81
+ coerceInitialValues,
88
82
  config,
89
- connectValidate,
90
83
  dispatchEvent,
91
84
  errorMessages,
92
- form,
93
85
  jsonDefaultValues,
94
86
  headName,
95
87
  mode,
@@ -97,13 +89,42 @@ const useSchemaRenderer = ({ config, connectValidate = true, errorMessages, json
97
89
  runValidate,
98
90
  subscribe,
99
91
  unsubscribe,
100
- validate,
101
92
  validateOnBlur,
102
93
  userContext,
103
94
  ]);
95
+ react_1.default.useMemo(() => {
96
+ var _a;
97
+ if (!strictCheckerRef.current.checkDiff({
98
+ connectValidate,
99
+ form,
100
+ headName,
101
+ validate,
102
+ })) {
103
+ return;
104
+ }
105
+ const getValidator = connectValidate ? () => validate : undefined;
106
+ (_a = unsubscribeRef.current) === null || _a === void 0 ? void 0 : _a.call(unsubscribeRef);
107
+ unsubscribeRef.current = form.registerField((0, utils_1.getServiceFieldName)(constants_2.SCHEMA_RENDERER_SERVICE_FIELD, headName), () => { }, { data: true }, {
108
+ data: { state: stateRef.current },
109
+ getValidator,
110
+ silent: true,
111
+ validateFields: [headName],
112
+ });
113
+ }, [connectValidate, form, headName, validate]);
114
+ react_1.default.useEffect(() => {
115
+ const srField = form.getFieldState((0, utils_1.getServiceFieldName)(constants_2.SCHEMA_RENDERER_SERVICE_FIELD, headName));
116
+ if (srField === null || srField === void 0 ? void 0 : srField.data) {
117
+ srField.data.state = initialState;
118
+ initialState.dispatchEvent(initialEvents);
119
+ }
120
+ }, [initialEvents, initialState]);
104
121
  react_1.default.useEffect(() => {
122
+ const strictChecker = strictCheckerRef.current;
105
123
  return () => {
106
124
  var _a;
125
+ if (strictChecker.isStrict()) {
126
+ return;
127
+ }
107
128
  (_a = unsubscribeRef.current) === null || _a === void 0 ? void 0 : _a.call(unsubscribeRef);
108
129
  };
109
130
  }, []);
@@ -70,9 +70,14 @@ const getValidate = (form, headName) => {
70
70
  Object.keys(Object.assign(Object.assign({}, srState.errors), allErrors)).forEach((key) => {
71
71
  if (srState.errors[key] !== allErrors[key]) {
72
72
  newErrors[key] = allErrors[key];
73
+ if (allErrors[key] === undefined) {
74
+ delete srState.errors[key];
75
+ }
76
+ else {
77
+ srState.errors[key] = allErrors[key];
78
+ }
73
79
  }
74
80
  });
75
- srState.errors = allErrors;
76
81
  srState.waiters = Object.assign(Object.assign({}, srState.waiters), waiters);
77
82
  if (Object.values(newErrors).length) {
78
83
  srState.dispatchEvent([
@@ -9,11 +9,21 @@ const useSchemaRenderer_1 = require("../useSchemaRenderer");
9
9
  const utils_1 = require("../utils");
10
10
  const useSchemaRendererState = ({ headName, name, schemaPath, subscriptions = Object.values(constants_1.SchemaRendererEventType), }) => {
11
11
  const form = (0, react_final_form_1.useForm)();
12
+ const strictCheckerRef = react_1.default.useRef((0, utils_1.getStrictModeChecker)());
12
13
  const uuidRef = react_1.default.useRef(null);
13
14
  const [tick, setTick] = react_1.default.useState(0);
14
15
  const srName = react_1.default.useMemo(() => (0, utils_1.getServiceFieldName)(useSchemaRenderer_1.SCHEMA_RENDERER_SERVICE_FIELD, headName), [headName]);
15
16
  react_1.default.useMemo(() => {
16
17
  var _a;
18
+ if (!strictCheckerRef.current.checkDiff({
19
+ form,
20
+ headName,
21
+ name,
22
+ schemaPath,
23
+ subscriptions: subscriptions.join(','),
24
+ })) {
25
+ return;
26
+ }
17
27
  const srField = form.getFieldState(srName);
18
28
  const srState = (_a = srField === null || srField === void 0 ? void 0 : srField.data) === null || _a === void 0 ? void 0 : _a.state;
19
29
  if (srState) {
@@ -48,8 +58,12 @@ const useSchemaRendererState = ({ headName, name, schemaPath, subscriptions = Ob
48
58
  return undefined;
49
59
  }, [form, srName, tick]);
50
60
  react_1.default.useEffect(() => {
61
+ const strictChecker = strictCheckerRef.current;
51
62
  return () => {
52
63
  var _a;
64
+ if (strictChecker.isStrict()) {
65
+ return;
66
+ }
53
67
  const srField = form.getFieldState(srName);
54
68
  const srState = (_a = srField === null || srField === void 0 ? void 0 : srField.data) === null || _a === void 0 ? void 0 : _a.state;
55
69
  if (srState && uuidRef.current) {
@@ -58,3 +58,6 @@ export declare const arrayPathToDotBracket: (arrayPath: string[]) => string;
58
58
  export declare const getSchemaByPointer: (schema: JsonSchema, pointer: string | string[]) => JsonSchema | undefined;
59
59
  export declare const getValuePaths: (value: unknown, path?: string[]) => string[][];
60
60
  export declare const getServiceFieldName: (serviceFieldName: string, headName: string) => string;
61
+ export declare const isStringInt: (v: unknown) => v is string;
62
+ export declare const isStringFloat: (v: unknown) => v is string;
63
+ export declare const isStringNumber: (v: unknown) => v is string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getServiceFieldName = exports.getValuePaths = exports.getSchemaByPointer = exports.arrayPathToDotBracket = exports.dotBracketToArrayPath = exports.pointerToArrayPath = void 0;
3
+ exports.isStringNumber = exports.isStringFloat = exports.isStringInt = exports.getServiceFieldName = exports.getValuePaths = exports.getSchemaByPointer = exports.arrayPathToDotBracket = exports.dotBracketToArrayPath = exports.pointerToArrayPath = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const get_1 = tslib_1.__importDefault(require("lodash/get"));
6
6
  /**
@@ -116,3 +116,9 @@ const getValuePaths = (value, path = []) => {
116
116
  exports.getValuePaths = getValuePaths;
117
117
  const getServiceFieldName = (serviceFieldName, headName) => headName ? `${serviceFieldName}.${headName}` : serviceFieldName;
118
118
  exports.getServiceFieldName = getServiceFieldName;
119
+ const isStringInt = (v) => /^-?(0|[1-9][0-9]*)$/.test(`${v}`);
120
+ exports.isStringInt = isStringInt;
121
+ const isStringFloat = (v) => /^-?(0|[1-9][0-9]*)(\.[0-9]+)?$/.test(`${v}`);
122
+ exports.isStringFloat = isStringFloat;
123
+ const isStringNumber = (v) => (0, exports.isStringInt)(v) || (0, exports.isStringFloat)(v);
124
+ exports.isStringNumber = isStringNumber;
@@ -1,2 +1,3 @@
1
1
  export * from './common';
2
2
  export * from './definers';
3
+ export * from './strict-mode';
@@ -3,3 +3,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./common"), exports);
5
5
  tslib_1.__exportStar(require("./definers"), exports);
6
+ tslib_1.__exportStar(require("./strict-mode"), exports);
@@ -0,0 +1,6 @@
1
+ export declare const getStrictModeChecker: () => {
2
+ cachedValues: Record<string, unknown> | undefined;
3
+ hasDiff: boolean | undefined;
4
+ checkDiff: (currentValues: Record<string, unknown>) => boolean;
5
+ isStrict: () => boolean | undefined;
6
+ };
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getStrictModeChecker = void 0;
4
+ const getStrictModeChecker = () => {
5
+ const checker = {
6
+ cachedValues: undefined,
7
+ hasDiff: undefined,
8
+ checkDiff: (currentValues) => {
9
+ const cachedValues = checker.cachedValues;
10
+ if (!cachedValues ||
11
+ [...Object.keys(cachedValues), ...Object.keys(currentValues)].some((key) => cachedValues[key] !== currentValues[key])) {
12
+ checker.cachedValues = Object.assign({}, currentValues);
13
+ checker.hasDiff = true;
14
+ return true;
15
+ }
16
+ checker.hasDiff = false;
17
+ return false;
18
+ },
19
+ isStrict: () => {
20
+ if (checker.hasDiff === undefined) {
21
+ return undefined;
22
+ }
23
+ const hasDiff = checker.hasDiff;
24
+ checker.hasDiff = undefined;
25
+ return !hasDiff;
26
+ },
27
+ };
28
+ return checker;
29
+ };
30
+ exports.getStrictModeChecker = getStrictModeChecker;
@@ -8,7 +8,7 @@ const utils_1 = require("../../utils");
8
8
  const b = (0, utils_1.block)('entity-error');
9
9
  const EntityError = ({ errorMessage, validationState }) => {
10
10
  if (validationState === 'invalid' && errorMessage) {
11
- return (react_1.default.createElement(uikit_1.Text, { className: b(), color: "danger" }, errorMessage));
11
+ return (react_1.default.createElement(uikit_1.Text, { className: b(), color: "danger", wordBreak: "break-word", "data-sr-error": "true" }, errorMessage));
12
12
  }
13
13
  return null;
14
14
  };
@@ -29,17 +29,17 @@ const Alert = ({ headName, props, schema }) => {
29
29
  const msg = react_1.default.useMemo(() => {
30
30
  if (message) {
31
31
  if (typeof message === 'string') {
32
- return (react_1.default.createElement("div", { className: b('message', { expanded }) },
32
+ return (react_1.default.createElement("div", { className: b('message', { expanded: expanded || !title }) },
33
33
  react_1.default.createElement(components_1.HTMLContent, { content: message, headName: headName })));
34
34
  }
35
35
  return message;
36
36
  }
37
37
  if (schema.description) {
38
- return (react_1.default.createElement("div", { className: b('message', { expanded }) },
38
+ return (react_1.default.createElement("div", { className: b('message', { expanded: expanded || !title }) },
39
39
  react_1.default.createElement(components_1.HTMLContent, { content: schema.description, headName: headName })));
40
40
  }
41
41
  return undefined;
42
- }, [expanded, headName, message, schema.description]);
42
+ }, [expanded, headName, message, schema.description, title]);
43
43
  return (react_1.default.createElement(components_1.EntityContainer, { className: b({ expanded }), stretch: "fit", fill: "populated" },
44
44
  react_1.default.createElement(uikit_1.Alert, Object.assign({ icon: icon, message: msg, title: title }, entityRestProps))));
45
45
  };
@@ -31,7 +31,12 @@ const FewOfNested = ({ Layout, headName, input, layoutProps, meta, mode, props,
31
31
  const { Entity, Layout, entityProps, independent, layoutProps } = renderKit[mode];
32
32
  const togglerInput = Object.assign(Object.assign({}, input), { name: togglerArrayRemoveButton ? name : `${name}._____toggler`, value: togglerValues, onChange: (value) => {
33
33
  if (Array.isArray(value)) {
34
- setTogglerValues(value.filter(isString_1.default));
34
+ const nextTogglerValues = value.filter(isString_1.default);
35
+ setTogglerValues(nextTogglerValues);
36
+ input.onChange(nextTogglerValues.reduce((acc, togglerValue) => {
37
+ var _a;
38
+ return (Object.assign(Object.assign({}, acc), { [togglerValue]: (_a = input.value) === null || _a === void 0 ? void 0 : _a[togglerValue] }));
39
+ }, {}));
35
40
  }
36
41
  } });
37
42
  const togglerMeta = Object.assign(Object.assign({}, meta), { error: undefined });
@@ -15,7 +15,15 @@ const OneOfNested = ({ Layout, headName, input, layoutProps, meta, mode, props,
15
15
  headName,
16
16
  subscriptions: [core_1.SchemaRendererEventType.Config],
17
17
  });
18
- const [togglerValue, setTogglerValue] = react_1.default.useState(Object.keys(value || (overviewFlag ? undefined : schema.properties) || {})[0]);
18
+ const [togglerValue, setTogglerValue] = react_1.default.useState(() => {
19
+ if (value && Object.keys(value).length) {
20
+ return Object.keys(value)[0];
21
+ }
22
+ if (!overviewFlag && schema.properties) {
23
+ return Object.keys(schema.properties)[0];
24
+ }
25
+ return undefined;
26
+ });
19
27
  const toggler = react_1.default.useMemo(() => {
20
28
  var _a;
21
29
  let result = null;
@@ -27,7 +35,9 @@ const OneOfNested = ({ Layout, headName, input, layoutProps, meta, mode, props,
27
35
  ? booleanToKey.true === togglerValue
28
36
  : togglerValue, onChange: (value) => {
29
37
  const nextValue = `${value}`;
30
- setTogglerValue((booleanToKey === null || booleanToKey === void 0 ? void 0 : booleanToKey[nextValue]) || nextValue);
38
+ const nextTogglerValue = (booleanToKey === null || booleanToKey === void 0 ? void 0 : booleanToKey[nextValue]) || nextValue;
39
+ setTogglerValue(nextTogglerValue);
40
+ input.onChange({ [nextTogglerValue]: undefined });
31
41
  } });
32
42
  const togglerMeta = Object.assign(Object.assign({}, meta), { error: undefined });
33
43
  if (Entity) {
@@ -1,5 +1,5 @@
1
1
  import { type TextInputProps } from '@gravity-ui/uikit';
2
- import type { JsonSchemaString, NodeEntity } from '../../../core';
2
+ import { type JsonSchemaString, type NodeEntity } from '../../../core';
3
3
  export interface StringNumberWithScaleInputProps extends Omit<TextInputProps, 'defaultValue' | 'value' | 'onFocus' | 'onBlur' | 'onChange' | 'onUpdate' | 'errorMessage' | 'validationState' | 'qa'> {
4
4
  defaultType?: string;
5
5
  viewType?: string;