@gravity-ui/dynamic-forms 5.24.0 → 5.25.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 (41) hide show
  1. package/build/cjs/lib/kit/i18n/en.json +34 -0
  2. package/build/cjs/lib/kit/i18n/ru.json +34 -0
  3. package/build/cjs/lib/unstable/core/SchemaRendererNode/SchemaRendererNode.js +25 -19
  4. package/build/cjs/lib/unstable/core/SchemaRendererNode/utils.d.ts +3 -0
  5. package/build/cjs/lib/unstable/core/SchemaRendererNode/utils.js +25 -1
  6. package/build/cjs/lib/unstable/core/types/validation.d.ts +1 -1
  7. package/build/cjs/lib/unstable/core/useSchemaRenderer/useSchemaRenderer.js +1 -1
  8. package/build/cjs/lib/unstable/kit/constants/index.d.ts +1 -0
  9. package/build/cjs/lib/unstable/kit/constants/index.js +3 -1
  10. package/build/cjs/lib/unstable/kit/constants/messages.d.ts +2 -0
  11. package/build/cjs/lib/unstable/kit/constants/messages.js +89 -0
  12. package/build/cjs/lib/unstable/kit/entities/ArrayTable/ArrayTable.js +2 -2
  13. package/build/cjs/lib/unstable/kit/form-entities/SegmentedRadioGroupInput/SegmentedRadioGroupInput.css +4 -0
  14. package/build/cjs/lib/unstable/kit/form-entities/SegmentedRadioGroupInput/SegmentedRadioGroupInput.d.ts +1 -1
  15. package/build/cjs/lib/unstable/kit/form-entities/SegmentedRadioGroupInput/SegmentedRadioGroupInput.js +30 -5
  16. package/build/cjs/lib/unstable/kit/form-entities/SelectInput/SelectInput.d.ts +1 -2
  17. package/build/cjs/lib/unstable/kit/form-layouts/FormRow/FormRow.css +3 -0
  18. package/build/cjs/lib/unstable/kit/layouts/Accordeon/Accordeon.js +29 -27
  19. package/build/cjs/lib/unstable/kit/utils/transformer.d.ts +3 -3
  20. package/build/cjs/lib/unstable/kit/utils/transformer.js +16 -10
  21. package/build/esm/lib/kit/i18n/en.json +34 -0
  22. package/build/esm/lib/kit/i18n/ru.json +34 -0
  23. package/build/esm/lib/unstable/core/SchemaRendererNode/SchemaRendererNode.js +26 -20
  24. package/build/esm/lib/unstable/core/SchemaRendererNode/utils.d.ts +3 -0
  25. package/build/esm/lib/unstable/core/SchemaRendererNode/utils.js +22 -0
  26. package/build/esm/lib/unstable/core/types/validation.d.ts +1 -1
  27. package/build/esm/lib/unstable/core/useSchemaRenderer/useSchemaRenderer.js +1 -1
  28. package/build/esm/lib/unstable/kit/constants/index.d.ts +1 -0
  29. package/build/esm/lib/unstable/kit/constants/index.js +1 -0
  30. package/build/esm/lib/unstable/kit/constants/messages.d.ts +2 -0
  31. package/build/esm/lib/unstable/kit/constants/messages.js +85 -0
  32. package/build/esm/lib/unstable/kit/entities/ArrayTable/ArrayTable.js +2 -2
  33. package/build/esm/lib/unstable/kit/form-entities/SegmentedRadioGroupInput/SegmentedRadioGroupInput.css +4 -0
  34. package/build/esm/lib/unstable/kit/form-entities/SegmentedRadioGroupInput/SegmentedRadioGroupInput.d.ts +1 -1
  35. package/build/esm/lib/unstable/kit/form-entities/SegmentedRadioGroupInput/SegmentedRadioGroupInput.js +30 -5
  36. package/build/esm/lib/unstable/kit/form-entities/SelectInput/SelectInput.d.ts +1 -2
  37. package/build/esm/lib/unstable/kit/form-layouts/FormRow/FormRow.css +3 -0
  38. package/build/esm/lib/unstable/kit/layouts/Accordeon/Accordeon.js +29 -27
  39. package/build/esm/lib/unstable/kit/utils/transformer.d.ts +3 -3
  40. package/build/esm/lib/unstable/kit/utils/transformer.js +16 -10
  41. package/package.json +1 -1
@@ -35,6 +35,40 @@
35
35
  "Value can't be longer than {{count}} items",
36
36
  "Value can't be longer than {{count}} items"
37
37
  ],
38
+ "label-sr_error-additional-items": "Maximum allowed number of items is {{count}}",
39
+ "label-sr_error-additional-properties": "Maximum allowed number of properties is {{count}}",
40
+ "label-sr_error-any-of": "Incorrect value in field",
41
+ "label-sr_error-const": "Value must be {{expected}}",
42
+ "label-sr_error-contains": "At least one item must be added",
43
+ "label-sr_error-contains-min": "At least one item matching the condition must be added",
44
+ "label-sr_error-dependencies": "Field \"{{property}}\" is required",
45
+ "label-sr_error-enum": "Value {{value}} cannot be used",
46
+ "label-sr_error-exclusive-maximum": "Value must be less than {{count}}",
47
+ "label-sr_error-exclusive-minimum": "Value must be greater than {{count}}",
48
+ "label-sr_error-max-items": "Maximum allowed number of items is {{count}}",
49
+ "label-sr_error-max-length": "Maximum allowed number of characters is {{count}}",
50
+ "label-sr_error-max-properties": "Maximum allowed number of properties is {{count}}",
51
+ "label-sr_error-maximum": "Value must be less than or equal to {{count}}",
52
+ "label-sr_error-min-items": "Minimum allowed number of items is {{count}}",
53
+ "label-sr_error-min-length": "Minimum allowed number of characters is {{count}}",
54
+ "label-sr_error-min-properties": "Minimum allowed number of properties is {{count}}",
55
+ "label-sr_error-minimum": "Value must be greater than or equal to {{count}}",
56
+ "label-sr_error-multiple-of": "Value must be a multiple of {{count}}",
57
+ "label-sr_error-not": "Value cannot be used",
58
+ "label-sr_error-one-of": "Incorrect value in field",
59
+ "label-sr_error-pattern": "Value must match the pattern - {{pattern}}",
60
+ "label-sr_error-property-names": "Invalid property name \"{{property}}\"",
61
+ "label-sr_error-required": "Empty field",
62
+ "label-sr_error-type": "Value must be {{expected}}",
63
+ "label-sr_error-type-or": " or {{type}}",
64
+ "label-sr_error-unique-items": "Values must be unique",
65
+ "label-sr_type-array": "an array",
66
+ "label-sr_type-boolean": "a boolean",
67
+ "label-sr_type-integer": "an integer",
68
+ "label-sr_type-null": "null",
69
+ "label-sr_type-number": "a number",
70
+ "label-sr_type-object": "an object",
71
+ "label-sr_type-string": "a string",
38
72
  "label_error-min-number": "Value must be an integer no less than {{count}}",
39
73
  "label_error-max-number": "Value must not be greater than {{count}}",
40
74
  "label_error-min-number-with-scale": "Value must be no less than {{count}} {{scale}}",
@@ -35,6 +35,40 @@
35
35
  "Значение не может быть длиннее {{count}} элементов",
36
36
  "Значение не может быть длиннее {{count}} элементов"
37
37
  ],
38
+ "label-sr_error-additional-items": "Максимальное допустимое количество элементов: {{count}}",
39
+ "label-sr_error-additional-properties": "Максимальное допустимое количество свойств: {{count}}",
40
+ "label-sr_error-any-of": "Поле заполнено неправильно",
41
+ "label-sr_error-const": "Значение должно быть равно {{expected}}",
42
+ "label-sr_error-contains": "Необходимо добавить хотя бы один элемент",
43
+ "label-sr_error-contains-min": "Необходимо добавить хотя бы один элемент, удовлетворяющий условию",
44
+ "label-sr_error-dependencies": "Необходимо заполнить поле \"{{property}}\"",
45
+ "label-sr_error-enum": "Значение {{value}} не допустимо к использованию",
46
+ "label-sr_error-exclusive-maximum": "Значение должно быть меньше {{count}}",
47
+ "label-sr_error-exclusive-minimum": "Значение должно быть больше {{count}}",
48
+ "label-sr_error-max-items": "Максимальное допустимое количество элементов: {{count}}",
49
+ "label-sr_error-max-length": "Максимальное допустимое количество символов: {{count}}",
50
+ "label-sr_error-max-properties": "Максимальное допустимое количество свойств: {{count}}",
51
+ "label-sr_error-maximum": "Значение должно быть меньше или равно {{count}}",
52
+ "label-sr_error-min-items": "Минимальное допустимое количество элементов: {{count}}",
53
+ "label-sr_error-min-length": "Минимальное допустимое количество символов: {{count}}",
54
+ "label-sr_error-min-properties": "Минимальное допустимое количество свойств: {{count}}",
55
+ "label-sr_error-minimum": "Значение должно быть больше или равно {{count}}",
56
+ "label-sr_error-multiple-of": "Значение должно быть кратно {{count}}",
57
+ "label-sr_error-not": "Значение не допустимо к использованию",
58
+ "label-sr_error-one-of": "Поле заполнено неправильно",
59
+ "label-sr_error-pattern": "Значение должно удовлетворять шаблону - {{pattern}}",
60
+ "label-sr_error-property-names": "Недопустимое имя свойства \"{{property}}\"",
61
+ "label-sr_error-required": "Поле не заполнено",
62
+ "label-sr_error-type": "Значение должно быть {{expected}}",
63
+ "label-sr_error-type-or": " или {{type}}",
64
+ "label-sr_error-unique-items": "Значения должны быть уникальными",
65
+ "label-sr_type-array": "массивом",
66
+ "label-sr_type-boolean": "булевым значением",
67
+ "label-sr_type-integer": "целым числом",
68
+ "label-sr_type-null": "null",
69
+ "label-sr_type-number": "числом",
70
+ "label-sr_type-object": "объектом",
71
+ "label-sr_type-string": "строкой",
38
72
  "label_error-min-number": "Значение должно быть числом не меньше {{count}}",
39
73
  "label_error-max-number": "Значение должно быть числом не больше {{count}}",
40
74
  "label_error-min-number-with-scale": "Значение должно быть не меньше {{count}} {{scale}}",
@@ -5,12 +5,11 @@ import { SchemaRendererEventType, SchemaRendererMode } from '../constants';
5
5
  import { SCHEMA_RENDERER_SERVICE_FIELD } from '../useSchemaRenderer';
6
6
  import { useSchemaRendererState } from '../useSchemaRendererState';
7
7
  import { getServiceFieldName } from '../utils';
8
- import { getAccumulatedSchema, getRenderKit } from './utils';
8
+ import { getAccumulatedSchema, getCompareValues, getRenderKit, scheduleFlush } from './utils';
9
9
  const SchemaRendererNodeComponent = ({ headName, modeOverride, name, schemaOverride, schemaPath, }) => {
10
10
  var _a;
11
11
  const form = useForm();
12
- const firstRenderRef = React.useRef(true);
13
- const pendingTicksRef = React.useRef({ input: 0, meta: 0 });
12
+ const compareValuesRef = React.useRef(getCompareValues());
14
13
  const fieldRef = React.useRef(null);
15
14
  const unsubscribeRef = React.useRef(null);
16
15
  const [ticks, setTicks] = React.useState({ input: 0, meta: 0 });
@@ -35,6 +34,17 @@ const SchemaRendererNodeComponent = ({ headName, modeOverride, name, schemaOverr
35
34
  const kit = React.useMemo(() => getRenderKit({ config: srState === null || srState === void 0 ? void 0 : srState.config, schema }), [schema, srState === null || srState === void 0 ? void 0 : srState.config]);
36
35
  React.useMemo(() => {
37
36
  var _a;
37
+ if (compareValuesRef.current({
38
+ form,
39
+ jsonDefaultValues,
40
+ headName,
41
+ name,
42
+ default: schema === null || schema === void 0 ? void 0 : schema.default,
43
+ type: schema === null || schema === void 0 ? void 0 : schema.type,
44
+ schemaPath,
45
+ })) {
46
+ return;
47
+ }
38
48
  (_a = unsubscribeRef.current) === null || _a === void 0 ? void 0 : _a.call(unsubscribeRef);
39
49
  const initialState = { schemaPath };
40
50
  let defaultValue = schema === null || schema === void 0 ? void 0 : schema.default;
@@ -44,7 +54,7 @@ const SchemaRendererNodeComponent = ({ headName, modeOverride, name, schemaOverr
44
54
  }
45
55
  catch (_b) { }
46
56
  }
47
- unsubscribeRef.current = form.registerField(name, (f) => {
57
+ const unsubscribe = form.registerField(name, (f) => {
48
58
  const prevF = fieldRef.current;
49
59
  if (prevF) {
50
60
  let inputTick = 0;
@@ -58,23 +68,26 @@ const SchemaRendererNodeComponent = ({ headName, modeOverride, name, schemaOverr
58
68
  metaTick = 1;
59
69
  }
60
70
  if (inputTick + metaTick) {
61
- if (firstRenderRef.current) {
62
- pendingTicksRef.current = { input: inputTick, meta: metaTick };
63
- }
64
- else {
65
- setTicks((t) => ({
66
- input: t.input + inputTick,
67
- meta: t.meta + metaTick,
68
- }));
69
- }
71
+ setTicks((t) => ({
72
+ input: t.input + inputTick,
73
+ meta: t.meta + metaTick,
74
+ }));
70
75
  }
71
76
  }
72
77
  fieldRef.current = f;
73
78
  }, { submitFailed: true, touched: true, validating: true, value: true }, {
74
79
  data: { state: initialState },
75
80
  defaultValue,
81
+ silent: true,
76
82
  validateFields: [getServiceFieldName(SCHEMA_RENDERER_SERVICE_FIELD, headName)],
77
83
  });
84
+ if (defaultValue !== undefined) {
85
+ scheduleFlush(form);
86
+ }
87
+ unsubscribeRef.current = () => {
88
+ unsubscribe();
89
+ scheduleFlush(form);
90
+ };
78
91
  }, [form, jsonDefaultValues, headName, name, schema === null || schema === void 0 ? void 0 : schema.default, schema === null || schema === void 0 ? void 0 : schema.type, schemaPath]);
79
92
  const input = React.useMemo(() => {
80
93
  var _a;
@@ -99,13 +112,6 @@ const SchemaRendererNodeComponent = ({ headName, modeOverride, name, schemaOverr
99
112
  };
100
113
  }, [error, form, name, ticks.meta]);
101
114
  React.useEffect(() => {
102
- firstRenderRef.current = false;
103
- if (pendingTicksRef.current.input || pendingTicksRef.current.meta) {
104
- setTicks((t) => ({
105
- input: t.input + pendingTicksRef.current.input,
106
- meta: t.meta + pendingTicksRef.current.meta,
107
- }));
108
- }
109
115
  return () => {
110
116
  var _a;
111
117
  (_a = unsubscribeRef.current) === null || _a === void 0 ? void 0 : _a.call(unsubscribeRef);
@@ -1,3 +1,4 @@
1
+ import type { FormApi } from 'final-form';
1
2
  import { SchemaRendererMode } from '../constants';
2
3
  import type { JsonSchema, NodeEntity, NodeLayout, NodesConfig } from '../types';
3
4
  type GetRenderKitParams<Schema extends JsonSchema> = {
@@ -22,4 +23,6 @@ type GetRenderKitReturn<Schema extends JsonSchema> = {
22
23
  };
23
24
  export declare const getRenderKit: <Schema extends JsonSchema>({ config, schema, }: GetRenderKitParams<Schema>) => GetRenderKitReturn<Schema>;
24
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;
25
28
  export {};
@@ -154,3 +154,25 @@ export const getAccumulatedSchema = (schemaPath, rootSchema, override, collected
154
154
  }
155
155
  return accumulatedSchema;
156
156
  };
157
+ const flushes = new WeakMap();
158
+ export const scheduleFlush = (form) => {
159
+ if (flushes.get(form)) {
160
+ return;
161
+ }
162
+ flushes.set(form, true);
163
+ queueMicrotask(() => {
164
+ flushes.delete(form);
165
+ form.batch(() => { });
166
+ });
167
+ };
168
+ export const getCompareValues = () => {
169
+ let cachedValues;
170
+ return (currentValues) => {
171
+ if (!cachedValues ||
172
+ [...Object.keys(cachedValues), ...Object.keys(currentValues)].some((key) => cachedValues[key] !== currentValues[key])) {
173
+ cachedValues = Object.assign({}, currentValues);
174
+ return false;
175
+ }
176
+ return true;
177
+ };
178
+ };
@@ -12,7 +12,7 @@ export interface ErrorMessages {
12
12
  additionalProperties?: ((e: JSLErrors.AdditionalProperties) => string) | string;
13
13
  anyOf?: ((e: JSLErrors.AnyOf) => string) | string;
14
14
  const?: ((e: JSLErrors.Const) => string) | string;
15
- contains?: ((e: JSLErrors.ContainsAny) => string) | string;
15
+ contains?: ((e: JSLErrors.ContainsAny | JSLErrors.ContainsMin) => string) | string;
16
16
  dependencies?: ((e: JSLErrors.Dependencies) => string) | string;
17
17
  enum?: ((e: JSLErrors.Enum) => string) | string;
18
18
  exclusiveMaximum?: ((e: JSLErrors.ExclusiveMaximum) => string) | string;
@@ -68,7 +68,7 @@ export const useSchemaRenderer = ({ config, connectValidate = true, errorMessage
68
68
  state.dispatchEvent(initialEvents);
69
69
  initialEvents = [];
70
70
  }
71
- }, { data: true }, { data: { state: initialState }, getValidator, validateFields: [headName] });
71
+ }, { data: true }, { data: { state: initialState }, getValidator, silent: true, validateFields: [headName] });
72
72
  prevParamsRef.current = {
73
73
  config,
74
74
  errorMessages,
@@ -1,2 +1,3 @@
1
1
  export { DASH, DEFAULT_DATE_FORMAT } from './common';
2
2
  export { config, untypedConfig } from './config';
3
+ export { errorMessages } from './messages';
@@ -1,2 +1,3 @@
1
1
  export { DASH, DEFAULT_DATE_FORMAT } from './common';
2
2
  export { config, untypedConfig } from './config';
3
+ export { errorMessages } from './messages';
@@ -0,0 +1,2 @@
1
+ import type { ErrorMessages } from '../../core';
2
+ export declare let errorMessages: Required<ErrorMessages>;
@@ -0,0 +1,85 @@
1
+ import get from 'lodash/get';
2
+ import i18n from '../../../kit/i18n';
3
+ import { subscribeConfigure } from '../../../kit/i18n/configure';
4
+ const TYPE_I18N_KEYS = {
5
+ array: 'label-sr_type-array',
6
+ boolean: 'label-sr_type-boolean',
7
+ integer: 'label-sr_type-integer',
8
+ null: 'label-sr_type-null',
9
+ number: 'label-sr_type-number',
10
+ object: 'label-sr_type-object',
11
+ string: 'label-sr_type-string',
12
+ };
13
+ const getErrorMessages = () => ({
14
+ additionalItems: (e) => {
15
+ const schema = e.data.schema;
16
+ if (Array.isArray(schema.items)) {
17
+ return i18n('label-sr_error-additional-items', { count: schema.items.length });
18
+ }
19
+ return e.message;
20
+ },
21
+ additionalProperties: (e) => {
22
+ const schema = e.data.schema;
23
+ if (schema.properties) {
24
+ return i18n('label-sr_error-additional-properties', {
25
+ count: Object.keys(schema.properties).length,
26
+ });
27
+ }
28
+ return e.message;
29
+ },
30
+ anyOf: i18n('label-sr_error-any-of'),
31
+ const: (e) => i18n('label-sr_error-const', { expected: JSON.stringify(e.data.expected) }),
32
+ contains: (e) => e.code === 'contains-min-error'
33
+ ? i18n('label-sr_error-contains-min')
34
+ : i18n('label-sr_error-contains'),
35
+ dependencies: (e) => {
36
+ let property = e.data.missingProperty;
37
+ const title = get(e, `data.schema.properties.${property}.title`);
38
+ if (typeof title === 'string') {
39
+ property = title;
40
+ }
41
+ return i18n('label-sr_error-dependencies', { property });
42
+ },
43
+ enum: (e) => i18n('label-sr_error-enum', { value: JSON.stringify(e.data.value) }),
44
+ exclusiveMaximum: (e) => i18n('label-sr_error-exclusive-maximum', { count: e.data.maximum }),
45
+ exclusiveMinimum: (e) => i18n('label-sr_error-exclusive-minimum', { count: e.data.minimum }),
46
+ maxItems: (e) => i18n('label-sr_error-max-items', { count: e.data.maximum }),
47
+ maxLength: (e) => i18n('label-sr_error-max-length', { count: e.data.maxLength }),
48
+ maxProperties: (e) => i18n('label-sr_error-max-properties', { count: e.data.maxProperties }),
49
+ maximum: (e) => i18n('label-sr_error-maximum', { count: e.data.maximum }),
50
+ minItems: (e) => i18n('label-sr_error-min-items', { count: e.data.minItems }),
51
+ minLength: (e) => i18n('label-sr_error-min-length', { count: e.data.minLength }),
52
+ minProperties: (e) => i18n('label-sr_error-min-properties', { count: e.data.minProperties }),
53
+ minimum: (e) => i18n('label-sr_error-minimum', { count: e.data.minimum }),
54
+ multipleOf: (e) => i18n('label-sr_error-multiple-of', { count: e.data.multipleOf }),
55
+ not: i18n('label-sr_error-not'),
56
+ oneOf: i18n('label-sr_error-one-of'),
57
+ pattern: (e) => i18n('label-sr_error-pattern', { pattern: e.data.pattern }),
58
+ propertyNames: (e) => i18n('label-sr_error-property-names', { property: e.data.property }),
59
+ required: i18n('label-sr_error-required'),
60
+ type: (e) => {
61
+ const types = e.data.expected.split(',');
62
+ let expected = '';
63
+ types.forEach((t, i, arr) => {
64
+ let type = t.trim();
65
+ if (TYPE_I18N_KEYS[type]) {
66
+ type = i18n(TYPE_I18N_KEYS[type]);
67
+ }
68
+ if (i === 0) {
69
+ expected += type;
70
+ }
71
+ else if (i === arr.length - 1) {
72
+ expected += i18n('label-sr_error-type-or', { type });
73
+ }
74
+ else {
75
+ expected += `, ${type}`;
76
+ }
77
+ });
78
+ return i18n('label-sr_error-type', { expected });
79
+ },
80
+ uniqueItems: i18n('label-sr_error-unique-items'),
81
+ });
82
+ export let errorMessages = getErrorMessages();
83
+ subscribeConfigure(() => {
84
+ errorMessages = getErrorMessages();
85
+ });
@@ -57,7 +57,7 @@ export const ArrayTable = ({ headName, input, mode, props, schema, schemaPath, }
57
57
  }, [props.order, schema.items]);
58
58
  const { head, rows } = React.useMemo(() => {
59
59
  let tupleItems = false;
60
- let rowsCount = value === null || value === void 0 ? void 0 : value.length;
60
+ let rowsCount = (value === null || value === void 0 ? void 0 : value.length) || 0;
61
61
  let withRemoveButton = true;
62
62
  const getItemName = (index, property) => `${name}[${index}]${property === undefined ? '' : `.${property}`}`;
63
63
  const getItemSchemaPath = (index, property) => `${schemaPath}/items${tupleItems ? `/${index}` : ''}${property === undefined ? '' : `/properties/${property}`}`;
@@ -94,7 +94,7 @@ export const ArrayTable = ({ headName, input, mode, props, schema, schemaPath, }
94
94
  }
95
95
  return (React.createElement(EntityContainer, { stretch: "by-child", gap: 2, fill: "by-child" },
96
96
  React.createElement("div", null,
97
- head,
97
+ rows.length ? head : null,
98
98
  rows),
99
99
  addButton));
100
100
  };
@@ -3,4 +3,8 @@
3
3
  }
4
4
  .sr-segmented-radio-group-input_error .g-segmented-radio-group .g-segmented-radio-group__option_checked::after {
5
5
  border: 1px solid var(--g-color-text-danger);
6
+ }
7
+ .sr-segmented-radio-group-input_overflowed {
8
+ height: 0;
9
+ opacity: 0;
6
10
  }
@@ -1,7 +1,7 @@
1
1
  import { type SegmentedRadioGroupProps } from '@gravity-ui/uikit';
2
2
  import type { JsonSchemaString, NodeEntity } from '../../../core';
3
3
  import './SegmentedRadioGroupInput.css';
4
- export interface SegmentedRadioGroupInputProps extends Omit<SegmentedRadioGroupProps, 'value' | 'onFocus' | 'onBlur' | 'onChange' | 'onUpdate' | 'qa'> {
4
+ export interface SegmentedRadioGroupInputProps extends Omit<SegmentedRadioGroupProps, 'children' | 'defaultValue' | 'value' | 'onFocus' | 'onBlur' | 'onChange' | 'onUpdate' | 'qa'> {
5
5
  enumDescriptions?: Record<string, string>;
6
6
  optionsDisabled?: Record<string, boolean>;
7
7
  }
@@ -3,13 +3,17 @@ import React from 'react';
3
3
  import { SegmentedRadioGroup } from '@gravity-ui/uikit';
4
4
  import { EntityContainer } from '../../components';
5
5
  import { block, getBooleanValidationState } from '../../utils';
6
+ import { SelectInput } from '../SelectInput';
6
7
  import './SegmentedRadioGroupInput.css';
7
8
  const b = block('segmented-radio-group-input');
8
- export const SegmentedRadioGroupInput = ({ input, meta, props, schema }) => {
9
- var _a;
9
+ export const SegmentedRadioGroupInput = (_a) => {
10
+ var _b;
11
+ var { input, meta, props, schema } = _a, restProps = __rest(_a, ["input", "meta", "props", "schema"]);
10
12
  const { name, onBlur, onChange, onFocus, value } = input;
11
13
  const { enumDescriptions, optionsDisabled } = props, restEntityProps = __rest(props, ["enumDescriptions", "optionsDisabled"]);
12
- const { disabled } = ((_a = schema.nodeParameters) === null || _a === void 0 ? void 0 : _a.flags) || {};
14
+ const { disabled } = ((_b = schema.nodeParameters) === null || _b === void 0 ? void 0 : _b.flags) || {};
15
+ const ref = React.useRef(null);
16
+ const [overflowed, setOverflowed] = React.useState(false);
13
17
  const options = React.useMemo(() => {
14
18
  var _a;
15
19
  return (_a = schema.enum) === null || _a === void 0 ? void 0 : _a.map((value) => ({
@@ -23,6 +27,27 @@ export const SegmentedRadioGroupInput = ({ input, meta, props, schema }) => {
23
27
  onChange(value);
24
28
  onBlur();
25
29
  }, [onBlur, onChange, onFocus]);
26
- return (React.createElement(EntityContainer, { stretch: "max", className: b({ error: getBooleanValidationState(meta) }) },
27
- React.createElement(SegmentedRadioGroup, Object.assign({ width: "max", disabled: disabled || schema.readOnly, options: options }, restEntityProps, { value: value, onFocus: onFocus, onBlur: onBlur, onUpdate: onUpdate, qa: name }))));
30
+ React.useLayoutEffect(() => {
31
+ const root = ref.current;
32
+ if (!root) {
33
+ return;
34
+ }
35
+ const measure = () => {
36
+ const texts = root.querySelectorAll('.g-segmented-radio-group__option-text');
37
+ setOverflowed(Array.from(texts).some((node) => {
38
+ if (node.offsetWidth === 0 && node.scrollWidth === 0) {
39
+ return false;
40
+ }
41
+ return node.scrollWidth > node.clientWidth;
42
+ }));
43
+ };
44
+ measure();
45
+ const observer = new ResizeObserver(measure);
46
+ observer.observe(root);
47
+ return () => observer.disconnect();
48
+ }, [options]);
49
+ return (React.createElement(EntityContainer, { stretch: "max" },
50
+ overflowed ? (React.createElement(SelectInput, Object.assign({ input: input, meta: meta, props: props, schema: schema }, restProps))) : null,
51
+ React.createElement(EntityContainer, { stretch: "max", className: b({ error: getBooleanValidationState(meta), overflowed }) },
52
+ React.createElement(SegmentedRadioGroup, Object.assign({ ref: ref, width: "max", disabled: disabled || schema.readOnly, options: options }, restEntityProps, { value: value, onFocus: onFocus, onBlur: onBlur, onUpdate: onUpdate, qa: name })))));
28
53
  };
@@ -1,8 +1,7 @@
1
1
  import { type SelectProps } from '@gravity-ui/uikit';
2
2
  import type { JsonSchemaString, NodeEntity } from '../../../core';
3
- export interface SelectInputProps extends Omit<SelectProps, 'value' | 'onFocus' | 'onBlur' | 'onChange' | 'onUpdate' | 'multiple' | 'errorMessage' | 'validationState' | 'qa'> {
3
+ export interface SelectInputProps extends Omit<SelectProps, 'defaultValue' | 'value' | 'onFocus' | 'onBlur' | 'onChange' | 'onUpdate' | 'multiple' | 'errorMessage' | 'validationState' | 'qa'> {
4
4
  enumDescriptions?: Record<string, string>;
5
5
  optionsMeta?: Record<string, string>;
6
- options?: SelectProps['options'];
7
6
  }
8
7
  export declare const SelectInput: NodeEntity<JsonSchemaString, SelectInputProps>;
@@ -22,4 +22,7 @@
22
22
  }
23
23
  .sr-form-row__help-mark {
24
24
  margin-top: 1.5px;
25
+ }
26
+ .sr-form-row__right {
27
+ max-width: calc(100% - 180px - var(--g-spacing-base) * 2);
25
28
  }
@@ -12,34 +12,36 @@ export const Accordeon = ({ children, headName, input, meta, mode, schema, props
12
12
  const { titleProps, togglerProps, withIndent = false, withDefaultSummary = false } = props, restLayoutProps = __rest(props, ["titleProps", "togglerProps", "withIndent", "withDefaultSummary"]);
13
13
  const { copy, required, hidden, open } = ((_a = schema.nodeParameters) === null || _a === void 0 ? void 0 : _a.flags) || {};
14
14
  const overviewFlag = mode === SchemaRendererMode.Overview;
15
- const summary = React.useMemo(() => {
16
- const stopPropagation = (event) => {
17
- event.stopPropagation();
18
- };
19
- return (React.createElement(Flex, { alignItems: "center", gap: 2 },
20
- withDefaultSummary ? (React.createElement(Text, Object.assign({}, titleProps, { className: b('title', { required: required && !overviewFlag }, titleProps === null || titleProps === void 0 ? void 0 : titleProps.className) }), schema.title)) : (React.createElement(Disclosure.Summary, null, (props) => (React.createElement(Button, Object.assign({}, togglerProps, { className: b('toggler', togglerProps === null || togglerProps === void 0 ? void 0 : togglerProps.className) }),
21
- React.createElement(Flex, { alignItems: "center", gap: 2, height: "100%" },
22
- React.createElement(Icon, { data: props.expanded ? ChevronUp : ChevronDown }),
23
- React.createElement(Text, Object.assign({}, titleProps, { className: b('title', { required: required && !overviewFlag }, titleProps === null || titleProps === void 0 ? void 0 : titleProps.className) }), schema.title)))))),
24
- schema.description ? (React.createElement(HelpMark, { onClick: stopPropagation },
25
- React.createElement(HTMLContent, { content: schema.description, headName: headName }))) : null,
26
- overviewFlag ? (React.createElement(CopyButton, { className: b('copy-button'), copy: copy, value: input.value })) : null,
27
- overviewFlag ? null : (React.createElement(ArrayRemoveButton, { name: input.name, headName: headName, onClick: stopPropagation }))));
28
- }, [
29
- copy,
30
- headName,
31
- input.name,
32
- input.value,
33
- overviewFlag,
34
- required,
35
- schema.title,
36
- schema.description,
37
- titleProps,
38
- togglerProps,
39
- withDefaultSummary,
40
- ]);
15
+ const summary = React.useMemo(() => (React.createElement(Text, Object.assign({}, titleProps, { className: b('title', { required: required && !overviewFlag }, titleProps === null || titleProps === void 0 ? void 0 : titleProps.className) }), schema.title)), [overviewFlag, required, schema.title, titleProps]);
16
+ const helpMark = React.useMemo(() => {
17
+ if (schema.description) {
18
+ return (React.createElement(HelpMark, null,
19
+ React.createElement(HTMLContent, { content: schema.description, headName: headName })));
20
+ }
21
+ return null;
22
+ }, [schema.description, headName]);
23
+ const copyButton = React.useMemo(() => {
24
+ if (overviewFlag) {
25
+ return React.createElement(CopyButton, { className: b('copy-button'), copy: copy, value: input.value });
26
+ }
27
+ return null;
28
+ }, [overviewFlag, copy, input.value]);
29
+ const removeButton = React.useMemo(() => {
30
+ if (overviewFlag) {
31
+ return null;
32
+ }
33
+ return React.createElement(ArrayRemoveButton, { name: input.name, headName: headName });
34
+ }, [overviewFlag, input.name, headName]);
41
35
  return (React.createElement(LayoutContainer, { className: b({ 'without-default-summary': !withDefaultSummary }), hideEmpty: overviewFlag, hidden: hidden },
42
- React.createElement(Disclosure, Object.assign({ summary: summary, defaultExpanded: open }, restLayoutProps),
36
+ React.createElement(Disclosure, Object.assign({ defaultExpanded: open, summary: summary }, restLayoutProps),
37
+ React.createElement(Disclosure.Summary, null, ({ expanded, onClick }, defaultSummary) => (React.createElement(Flex, { minHeight: "28px", alignItems: "center", gap: 2 },
38
+ withDefaultSummary ? (defaultSummary) : (React.createElement(Button, Object.assign({}, togglerProps, { onClick: onClick, className: b('toggler', togglerProps === null || togglerProps === void 0 ? void 0 : togglerProps.className) }),
39
+ React.createElement(Flex, { alignItems: "center", gap: 2, height: "100%" },
40
+ React.createElement(Icon, { data: expanded ? ChevronUp : ChevronDown }),
41
+ summary))),
42
+ helpMark,
43
+ copyButton,
44
+ removeButton))),
43
45
  React.createElement(Flex, { direction: "column", gap: 0.5, grow: 1 },
44
46
  React.createElement("div", { className: b('content', { 'with-indent': withIndent }) }, children),
45
47
  overviewFlag ? null : (React.createElement(EntityError, { errorMessage: meta.error, validationState: getValidationState(meta) }))))));
@@ -1,11 +1,11 @@
1
1
  import { type Spec } from '../../../core';
2
- import { type JsonSchema } from '../../core';
2
+ import { type ErrorMessages, type JsonSchema } from '../../core';
3
3
  type Rules = Record<string, (spec: Spec, mutableSchema: JsonSchema, rules: {
4
4
  specRules: Rules;
5
5
  viewSpecRules: Rules;
6
- }) => void>;
6
+ }, errorMessages: ErrorMessages) => void>;
7
7
  export declare function specToJsonSchema(spec: Spec, mutableSchema?: JsonSchema, rules?: {
8
8
  specRules: Rules;
9
9
  viewSpecRules: Rules;
10
- }): JsonSchema;
10
+ }, errorMessages?: ErrorMessages): JsonSchema;
11
11
  export {};
@@ -3,6 +3,7 @@ import isObject from 'lodash/isObject';
3
3
  import set from 'lodash/set';
4
4
  import { SpecTypes } from '../../../core';
5
5
  import { JsonSchemaType, NodeType } from '../../core';
6
+ import { errorMessages as defaultErrorMessages } from '../constants';
6
7
  const viewSpecRules = {
7
8
  disabled: (spec, mutableSchema) => {
8
9
  if (spec.viewSpec.disabled) {
@@ -549,11 +550,16 @@ const specRules = {
549
550
  set(mutableSchema, 'nodeParameters.type', specTypeToNodeType[spec.type]);
550
551
  }
551
552
  },
552
- required: (spec, mutableSchema) => {
553
+ required: (spec, mutableSchema, _rules, errorMessages) => {
553
554
  if (spec.required) {
554
555
  set(mutableSchema, 'allOf', [
555
556
  ...(mutableSchema.allOf || []),
556
- { not: { enum: [null, undefined, '', false] } },
557
+ {
558
+ not: {
559
+ enum: [null, undefined, '', false],
560
+ nodeParameters: { errorMessages: { not: errorMessages.required } },
561
+ },
562
+ },
557
563
  ]);
558
564
  set(mutableSchema, 'nodeParameters.flags.required', true);
559
565
  }
@@ -586,12 +592,12 @@ const specRules = {
586
592
  }
587
593
  }
588
594
  },
589
- items: (spec, mutableSchema, rules) => {
595
+ items: (spec, mutableSchema, rules, errorMessages) => {
590
596
  if (spec.type === SpecTypes.Array && spec.items) {
591
597
  const childSchema = specToJsonSchema(spec.items, 'items' in mutableSchema &&
592
598
  mutableSchema.items &&
593
599
  !Array.isArray(mutableSchema.items)
594
- ? Object.assign({}, mutableSchema.items) : {}, rules);
600
+ ? Object.assign({}, mutableSchema.items) : {}, rules, errorMessages);
595
601
  set(mutableSchema, 'items', childSchema);
596
602
  }
597
603
  },
@@ -649,10 +655,10 @@ const specRules = {
649
655
  set(mutableSchema, 'type', JsonSchemaType.Integer);
650
656
  }
651
657
  },
652
- properties: (spec, mutableSchema, rules) => {
658
+ properties: (spec, mutableSchema, rules, errorMessages) => {
653
659
  if (spec.type === SpecTypes.Object && spec.properties) {
654
660
  Object.entries(spec.properties).forEach(([key, childSpec]) => {
655
- const childSchema = specToJsonSchema(childSpec, Object.assign({}, (get(mutableSchema, ['properties', key]) || {})), rules);
661
+ const childSchema = specToJsonSchema(childSpec, Object.assign({}, (get(mutableSchema, ['properties', key]) || {})), rules, errorMessages);
656
662
  set(mutableSchema, ['properties', key], childSchema);
657
663
  });
658
664
  }
@@ -667,13 +673,13 @@ const specRules = {
667
673
  set(mutableSchema, 'nodeParameters.errorMessages.pattern', spec.patternError);
668
674
  }
669
675
  },
670
- viewSpec: (spec, mutableSchema, rules) => {
671
- Object.values(rules.viewSpecRules).forEach((rule) => rule(spec, mutableSchema, rules));
676
+ viewSpec: (spec, mutableSchema, rules, errorMessages) => {
677
+ Object.values(rules.viewSpecRules).forEach((rule) => rule(spec, mutableSchema, rules, errorMessages));
672
678
  },
673
679
  };
674
- export function specToJsonSchema(spec, mutableSchema = {}, rules) {
680
+ export function specToJsonSchema(spec, mutableSchema = {}, rules, errorMessages = defaultErrorMessages) {
675
681
  const mergedSpecRules = Object.assign(Object.assign({}, specRules), rules === null || rules === void 0 ? void 0 : rules.specRules);
676
682
  const mergedViewSpecRules = Object.assign(Object.assign({}, viewSpecRules), rules === null || rules === void 0 ? void 0 : rules.viewSpecRules);
677
- Object.values(mergedSpecRules).forEach((rule) => rule(spec, mutableSchema, { specRules: mergedSpecRules, viewSpecRules: mergedViewSpecRules }));
683
+ Object.values(mergedSpecRules).forEach((rule) => rule(spec, mutableSchema, { specRules: mergedSpecRules, viewSpecRules: mergedViewSpecRules }, errorMessages));
678
684
  return mutableSchema;
679
685
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dynamic-forms",
3
- "version": "5.24.0",
3
+ "version": "5.25.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "main": "build/cjs/index.js",