@gravity-ui/dynamic-forms 5.30.0 → 5.32.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 (45) hide show
  1. package/build/cjs/lib/unstable/core/constants.d.ts +1 -0
  2. package/build/cjs/lib/unstable/core/constants.js +1 -0
  3. package/build/cjs/lib/unstable/core/useSchemaRenderer/types/state.d.ts +1 -0
  4. package/build/cjs/lib/unstable/core/useSchemaRenderer/useSchemaRenderer.js +17 -0
  5. package/build/cjs/lib/unstable/kit/constants/config.d.ts +4 -2
  6. package/build/cjs/lib/unstable/kit/constants/config.js +4 -4
  7. package/build/cjs/lib/unstable/kit/entities/ObjectEntity/ObjectEntity.js +8 -5
  8. package/build/cjs/lib/unstable/kit/entities/ObjectInline/ObjectInline.js +1 -1
  9. package/build/cjs/lib/unstable/kit/entities/OneOfNested/OneOfNested.js +1 -1
  10. package/build/cjs/lib/unstable/kit/form-entities/NumberWithScaleInput/NumberWithScaleInput.js +1 -1
  11. package/build/cjs/lib/unstable/kit/form-entities/RangeInput/RangeInput.js +2 -2
  12. package/build/cjs/lib/unstable/kit/form-entities/StringNumberWithScaleInput/StringNumberWithScaleInput.js +1 -1
  13. package/build/cjs/lib/unstable/kit/form-entities/TextAreaInput/TextAreaInput.js +1 -1
  14. package/build/cjs/lib/unstable/kit/hooks/index.d.ts +1 -0
  15. package/build/cjs/lib/unstable/kit/hooks/index.js +5 -0
  16. package/build/cjs/lib/unstable/kit/hooks/useExpanded.d.ts +11 -0
  17. package/build/cjs/lib/unstable/kit/hooks/useExpanded.js +25 -0
  18. package/build/cjs/lib/unstable/kit/index.d.ts +1 -0
  19. package/build/cjs/lib/unstable/kit/index.js +1 -0
  20. package/build/cjs/lib/unstable/kit/layouts/Accordeon/Accordeon.js +3 -1
  21. package/build/cjs/lib/unstable/kit/layouts/Card/Card.js +10 -8
  22. package/build/cjs/lib/unstable/kit/utils/transformer.js +18 -3
  23. package/build/esm/lib/unstable/core/constants.d.ts +1 -0
  24. package/build/esm/lib/unstable/core/constants.js +1 -0
  25. package/build/esm/lib/unstable/core/useSchemaRenderer/types/state.d.ts +1 -0
  26. package/build/esm/lib/unstable/core/useSchemaRenderer/useSchemaRenderer.js +17 -0
  27. package/build/esm/lib/unstable/kit/constants/config.d.ts +4 -2
  28. package/build/esm/lib/unstable/kit/constants/config.js +4 -4
  29. package/build/esm/lib/unstable/kit/entities/ObjectEntity/ObjectEntity.js +10 -7
  30. package/build/esm/lib/unstable/kit/entities/ObjectInline/ObjectInline.js +1 -1
  31. package/build/esm/lib/unstable/kit/entities/OneOfNested/OneOfNested.js +1 -1
  32. package/build/esm/lib/unstable/kit/form-entities/NumberWithScaleInput/NumberWithScaleInput.js +1 -1
  33. package/build/esm/lib/unstable/kit/form-entities/RangeInput/RangeInput.js +2 -2
  34. package/build/esm/lib/unstable/kit/form-entities/StringNumberWithScaleInput/StringNumberWithScaleInput.js +1 -1
  35. package/build/esm/lib/unstable/kit/form-entities/TextAreaInput/TextAreaInput.js +1 -1
  36. package/build/esm/lib/unstable/kit/hooks/index.d.ts +1 -0
  37. package/build/esm/lib/unstable/kit/hooks/index.js +1 -0
  38. package/build/esm/lib/unstable/kit/hooks/useExpanded.d.ts +11 -0
  39. package/build/esm/lib/unstable/kit/hooks/useExpanded.js +20 -0
  40. package/build/esm/lib/unstable/kit/index.d.ts +1 -0
  41. package/build/esm/lib/unstable/kit/index.js +1 -0
  42. package/build/esm/lib/unstable/kit/layouts/Accordeon/Accordeon.js +3 -1
  43. package/build/esm/lib/unstable/kit/layouts/Card/Card.js +10 -8
  44. package/build/esm/lib/unstable/kit/utils/transformer.js +18 -3
  45. package/package.json +1 -1
@@ -11,6 +11,7 @@ export declare enum SchemaRendererEventType {
11
11
  Patch = "patch",
12
12
  Settings = "settings",
13
13
  Schema = "schema",
14
+ Submit = "submit",
14
15
  UserContext = "userContext"
15
16
  }
16
17
  export declare enum JsonSchemaType {
@@ -16,6 +16,7 @@ var SchemaRendererEventType;
16
16
  SchemaRendererEventType["Patch"] = "patch";
17
17
  SchemaRendererEventType["Settings"] = "settings";
18
18
  SchemaRendererEventType["Schema"] = "schema";
19
+ SchemaRendererEventType["Submit"] = "submit";
19
20
  SchemaRendererEventType["UserContext"] = "userContext";
20
21
  })(SchemaRendererEventType || (exports.SchemaRendererEventType = SchemaRendererEventType = {}));
21
22
  var JsonSchemaType;
@@ -21,6 +21,7 @@ export interface SchemaRendererState<UserContext extends Record<string, unknown>
21
21
  coerceInitialValues: boolean;
22
22
  jsonDefaultValues: boolean;
23
23
  };
24
+ submitCount: number;
24
25
  subscribe: (subscriber: SchemaRendererSubscriber) => string;
25
26
  subscribers: {
26
27
  byId: Record<string, SchemaRendererSubscriber>;
@@ -49,6 +49,7 @@ const useSchemaRenderer = ({ coerceInitialValues = true, config, connectValidate
49
49
  runValidate,
50
50
  settings: { coerceInitialValues, jsonDefaultValues },
51
51
  schema: nameUpdated || schemaUpdated ? (0, cloneDeep_1.default)(originalSchema) : (prevState === null || prevState === void 0 ? void 0 : prevState.schema) || {},
52
+ submitCount: nameUpdated || schemaUpdated || !prevState ? 0 : prevState.submitCount,
52
53
  subscribe,
53
54
  subscribers: (prevState === null || prevState === void 0 ? void 0 : prevState.subscribers) || { byId: {}, byName: new Map(), byPath: new Map() },
54
55
  unsubscribe,
@@ -118,6 +119,22 @@ const useSchemaRenderer = ({ coerceInitialValues = true, config, connectValidate
118
119
  initialState.dispatchEvent(initialEvents);
119
120
  }
120
121
  }, [initialEvents, initialState]);
122
+ react_1.default.useEffect(() => {
123
+ const originalSubmit = form.submit;
124
+ form.submit = () => {
125
+ var _a;
126
+ const srField = form.getFieldState((0, utils_1.getServiceFieldName)(constants_2.SCHEMA_RENDERER_SERVICE_FIELD, headName));
127
+ const srState = (_a = srField === null || srField === void 0 ? void 0 : srField.data) === null || _a === void 0 ? void 0 : _a.state;
128
+ if (srState) {
129
+ srState.submitCount += 1;
130
+ srState.dispatchEvent([{ type: constants_1.SchemaRendererEventType.Submit, all: true }]);
131
+ }
132
+ return originalSubmit.call(form);
133
+ };
134
+ return () => {
135
+ form.submit = originalSubmit;
136
+ };
137
+ }, [form]);
121
138
  react_1.default.useEffect(() => {
122
139
  const strictChecker = strictCheckerRef.current;
123
140
  return () => {
@@ -288,6 +288,7 @@ export declare const untypedConfig: {
288
288
  readonly formEntities: {
289
289
  readonly base: {
290
290
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaObject, import("../entities").ObjectEntityProps>;
291
+ readonly independent: true;
291
292
  };
292
293
  readonly dot_value: {
293
294
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaObject, import("../entities").DotValueProps>;
@@ -336,6 +337,7 @@ export declare const untypedConfig: {
336
337
  readonly overviewEntities: {
337
338
  readonly base: {
338
339
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaObject, import("../entities").ObjectEntityProps>;
340
+ readonly independent: true;
339
341
  };
340
342
  readonly dot_value: {
341
343
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaObject, import("../entities").DotValueProps>;
@@ -397,7 +399,7 @@ export declare const untypedConfig: {
397
399
  readonly color_picker: {
398
400
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaString, import("../form-entities").ColorPickerInputProps>;
399
401
  };
400
- readonly file: {
402
+ readonly file_input: {
401
403
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaString, import("../form-entities").FileInputProps>;
402
404
  };
403
405
  readonly label: {
@@ -461,7 +463,7 @@ export declare const untypedConfig: {
461
463
  readonly color_picker: {
462
464
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaString, import("../overview-entities").ColorPickerValueProps>;
463
465
  };
464
- readonly file: {
466
+ readonly file_input: {
465
467
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaString, import("../overview-entities").StringValueProps>;
466
468
  };
467
469
  readonly label: {
@@ -131,7 +131,7 @@ exports.untypedConfig = {
131
131
  },
132
132
  [core_1.NodeType.Object]: {
133
133
  formEntities: {
134
- base: { Component: entities_1.ObjectEntity },
134
+ base: { Component: entities_1.ObjectEntity, independent: true },
135
135
  dot_value: { Component: entities_1.DotValue },
136
136
  few_of_nested: { Component: entities_1.FewOfNested, independent: true },
137
137
  inline: { Component: entities_1.ObjectInline },
@@ -149,7 +149,7 @@ exports.untypedConfig = {
149
149
  transparent: { Component: layouts_1.Transparent },
150
150
  },
151
151
  overviewEntities: {
152
- base: { Component: entities_1.ObjectEntity },
152
+ base: { Component: entities_1.ObjectEntity, independent: true },
153
153
  dot_value: { Component: entities_1.DotValue },
154
154
  few_of_nested: { Component: entities_1.FewOfNested, independent: true },
155
155
  inline: { Component: entities_1.ObjectInline },
@@ -173,7 +173,7 @@ exports.untypedConfig = {
173
173
  alert: { Component: entities_1.Alert },
174
174
  base: { Component: form_entities_1.StringInput },
175
175
  color_picker: { Component: form_entities_1.ColorPickerInput },
176
- file: { Component: form_entities_1.FileInput },
176
+ file_input: { Component: form_entities_1.FileInput },
177
177
  label: { Component: entities_1.Label },
178
178
  monaco_input: { Component: entities_1.Monaco },
179
179
  password: { Component: form_entities_1.PasswordInput },
@@ -197,7 +197,7 @@ exports.untypedConfig = {
197
197
  alert: { Component: entities_1.Alert },
198
198
  base: { Component: overview_entities_1.StringValue },
199
199
  color_picker: { Component: overview_entities_1.ColorPickerValue },
200
- file: { Component: overview_entities_1.StringValue },
200
+ file_input: { Component: overview_entities_1.StringValue },
201
201
  label: { Component: entities_1.Label },
202
202
  monaco_input: { Component: entities_1.Monaco },
203
203
  password: { Component: overview_entities_1.StringValue },
@@ -5,12 +5,15 @@ const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const core_1 = require("../../../core");
7
7
  const components_1 = require("../../components");
8
- const ObjectEntity = ({ headName, mode, input, props, schema, schemaPath, }) => {
8
+ const ObjectEntity = ({ Layout, headName, input, layoutProps, meta, mode, props, schema, schemaPath, }) => {
9
9
  const { name } = input;
10
- const overviewFlag = mode === core_1.SchemaRendererMode.Overview;
11
- if (overviewFlag && !Object.keys(schema.properties || {}).length) {
12
- return react_1.default.createElement(components_1.EmptyEntityValue, null);
10
+ if (!Object.keys(schema.properties || {}).length) {
11
+ return null;
13
12
  }
14
- return (react_1.default.createElement(components_1.EntityContainer, { stretch: "by-child", fill: "by-child" }, (props.order || Object.keys(schema.properties || {})).map((property) => (react_1.default.createElement(core_1.SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${property}`, schemaPath: `${schemaPath}/properties/${property}`, key: property })))));
13
+ let content = (react_1.default.createElement(components_1.EntityContainer, { stretch: "by-child", fill: "by-child" }, (props.order || Object.keys(schema.properties || {})).map((property) => (react_1.default.createElement(core_1.SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${property}`, schemaPath: `${schemaPath}/properties/${property}`, key: property })))));
14
+ if (Layout) {
15
+ content = (react_1.default.createElement(Layout, { headName: headName, input: input, meta: meta, mode: mode, schema: schema, schemaPath: schemaPath, props: layoutProps || {} }, content));
16
+ }
17
+ return content;
15
18
  };
16
19
  exports.ObjectEntity = ObjectEntity;
@@ -19,7 +19,7 @@ const ObjectInline = ({ headName, input, mode, props, schema, schemaPath, }) =>
19
19
  }
20
20
  return (react_1.default.createElement(components_1.EntityContainer, { stretch: overviewFlag ? 'by-child' : 'max', className: b(), fill: "by-child" },
21
21
  react_1.default.createElement(uikit_1.Flex, { className: b('items', { overview: overviewFlag }), direction: "row", alignItems: "flex-start", gap: overviewFlag ? 1 : 2 }, (order || Object.keys(schema.properties || {})).map((property, index, array) => (react_1.default.createElement(react_1.default.Fragment, { key: property },
22
- react_1.default.createElement(core_1.SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${property}`, schemaPath: `${schemaPath}/properties/${property}` }),
22
+ react_1.default.createElement(core_1.SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${property}`, schemaPath: `${schemaPath}/properties/${property}`, key: property }),
23
23
  (0, isString_1.default)(delimiter) && index + 1 !== array.length ? (react_1.default.createElement(uikit_1.Text, { className: b('delimiter') }, delimiter)) : null,
24
24
  (0, isObject_1.default)(delimiter) && delimiter[property] ? (react_1.default.createElement(uikit_1.Text, { className: b('delimiter') }, delimiter[property])) : null))))));
25
25
  };
@@ -72,7 +72,7 @@ const OneOfNested = ({ Layout, headName, input, layoutProps, meta, mode, props,
72
72
  }, [name, input, togglerArrayRemoveButton]);
73
73
  let content = (react_1.default.createElement(components_1.EntityContainer, { direction: "column-reverse", stretch: "by-child", fill: "populated" },
74
74
  togglerValue === undefined ? null : (react_1.default.createElement(components_1.LayoutContainer, { className: b('content', { 'with-indent': withIndent }), hideEmpty: overviewFlag },
75
- react_1.default.createElement(core_1.SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${togglerValue}`, schemaPath: `${schemaPath}/properties/${togglerValue}` }))),
75
+ react_1.default.createElement(core_1.SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${togglerValue}`, schemaPath: `${schemaPath}/properties/${togglerValue}`, key: togglerValue }))),
76
76
  toggler));
77
77
  if (overviewFlag && Object.values(value || {}).length === 0) {
78
78
  content = react_1.default.createElement(react_1.default.Fragment, null, toggler);
@@ -30,7 +30,7 @@ const NumberWithScaleInput = ({ input, meta, props, schema, }) => {
30
30
  scale: preparedScale,
31
31
  defaultType,
32
32
  viewType: viewType && preparedScale[viewType] ? [viewType] : [defaultType],
33
- minScaleLength: `${minScaleLength + 42}px`,
33
+ minScaleLength: `${minScaleLength + 60}px`,
34
34
  };
35
35
  }
36
36
  }
@@ -64,8 +64,8 @@ const RangeInput = ({ headName, input, props, schemaPath, }) => {
64
64
  }, [inputValue === null || inputValue === void 0 ? void 0 : inputValue[fromKey], inputValue === null || inputValue === void 0 ? void 0 : inputValue[toKey]]);
65
65
  return (react_1.default.createElement(components_1.EntityContainer, { stretch: "max", className: b() },
66
66
  react_1.default.createElement(uikit_1.Flex, { className: b('items'), direction: "row", alignItems: "flex-start", gap: 2 },
67
- react_1.default.createElement(core_1.SchemaRendererNode, { headName: headName, name: fromName, schemaPath: `${schemaPath}/properties/${fromKey}` }),
67
+ react_1.default.createElement(core_1.SchemaRendererNode, { headName: headName, name: fromName, schemaPath: `${schemaPath}/properties/${fromKey}`, key: fromKey }),
68
68
  react_1.default.createElement(uikit_1.Text, { className: b('delimiter') }, separator),
69
- react_1.default.createElement(core_1.SchemaRendererNode, { headName: headName, name: toName, schemaPath: `${schemaPath}/properties/${toKey}` }))));
69
+ react_1.default.createElement(core_1.SchemaRendererNode, { headName: headName, name: toName, schemaPath: `${schemaPath}/properties/${toKey}`, key: toKey }))));
70
70
  };
71
71
  exports.RangeInput = RangeInput;
@@ -31,7 +31,7 @@ const StringNumberWithScaleInput = ({ input, meta, props, schema }) => {
31
31
  scale: preparedScale,
32
32
  defaultType,
33
33
  viewType: viewType && preparedScale[viewType] ? [viewType] : [defaultType],
34
- minScaleLength: `${minScaleLength + 42}px`,
34
+ minScaleLength: `${minScaleLength + 60}px`,
35
35
  };
36
36
  }
37
37
  }
@@ -11,6 +11,6 @@ const TextAreaInput = ({ input, meta, props, schema, }) => {
11
11
  var _a, _b, _c;
12
12
  const { disabled } = ((_a = schema.nodeParameters) === null || _a === void 0 ? void 0 : _a.flags) || {};
13
13
  return (react_1.default.createElement(components_1.EntityContainer, { stretch: "max", className: b({ error: (0, utils_1.getBooleanValidationState)(meta) }) },
14
- react_1.default.createElement(uikit_1.TextArea, Object.assign({ maxRows: 20, minRows: 0, placeholder: (_b = schema.examples) === null || _b === void 0 ? void 0 : _b[0], disabled: disabled || schema.readOnly, hasClear: true }, props, { value: (_c = input.value) !== null && _c !== void 0 ? _c : '', onFocus: input.onFocus, onBlur: input.onBlur, onUpdate: input.onChange, errorMessage: undefined, validationState: (0, utils_1.getValidationState)(meta), qa: input.name }))));
14
+ react_1.default.createElement(uikit_1.TextArea, Object.assign({ maxRows: 20, minRows: 8, placeholder: (_b = schema.examples) === null || _b === void 0 ? void 0 : _b[0], disabled: disabled || schema.readOnly, hasClear: true }, props, { value: (_c = input.value) !== null && _c !== void 0 ? _c : '', onFocus: input.onFocus, onBlur: input.onBlur, onUpdate: input.onChange, errorMessage: undefined, validationState: (0, utils_1.getValidationState)(meta), qa: input.name }))));
15
15
  };
16
16
  exports.TextAreaInput = TextAreaInput;
@@ -0,0 +1 @@
1
+ export { type UseExpandedParams, useExpanded } from './useExpanded';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useExpanded = void 0;
4
+ var useExpanded_1 = require("./useExpanded");
5
+ Object.defineProperty(exports, "useExpanded", { enumerable: true, get: function () { return useExpanded_1.useExpanded; } });
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ export interface UseExpandedParams {
3
+ headName: string;
4
+ name: string;
5
+ open?: boolean;
6
+ }
7
+ export declare const useExpanded: ({ headName, name, open }: UseExpandedParams) => {
8
+ expanded: boolean;
9
+ setExpanded: React.Dispatch<React.SetStateAction<boolean>>;
10
+ toggleExpanded: () => void;
11
+ };
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useExpanded = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const core_1 = require("../../core");
7
+ const useExpanded = ({ headName, name, open = true }) => {
8
+ const srState = (0, core_1.useSchemaRendererState)({
9
+ headName,
10
+ subscriptions: [core_1.SchemaRendererEventType.Submit],
11
+ });
12
+ const [expanded, setExpanded] = react_1.default.useState(open);
13
+ const toggleExpanded = react_1.default.useCallback(() => {
14
+ setExpanded((f) => !f);
15
+ }, []);
16
+ react_1.default.useEffect(() => {
17
+ if (srState &&
18
+ srState.submitCount > 0 &&
19
+ Object.keys(srState.errors).some((key) => key.startsWith(name))) {
20
+ setExpanded(true);
21
+ }
22
+ }, [srState]);
23
+ return { expanded, setExpanded, toggleExpanded };
24
+ };
25
+ exports.useExpanded = useExpanded;
@@ -1,6 +1,7 @@
1
1
  export * from './components';
2
2
  export * from './constants';
3
3
  export * from './entities';
4
+ export * from './hooks';
4
5
  export * from './form-entities';
5
6
  export * from './form-layouts';
6
7
  export * from './layouts';
@@ -4,6 +4,7 @@ const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./components"), exports);
5
5
  tslib_1.__exportStar(require("./constants"), exports);
6
6
  tslib_1.__exportStar(require("./entities"), exports);
7
+ tslib_1.__exportStar(require("./hooks"), exports);
7
8
  tslib_1.__exportStar(require("./form-entities"), exports);
8
9
  tslib_1.__exportStar(require("./form-layouts"), exports);
9
10
  tslib_1.__exportStar(require("./layouts"), exports);
@@ -7,12 +7,14 @@ const icons_1 = require("@gravity-ui/icons");
7
7
  const uikit_1 = require("@gravity-ui/uikit");
8
8
  const core_1 = require("../../../core");
9
9
  const components_1 = require("../../components");
10
+ const hooks_1 = require("../../hooks");
10
11
  const utils_1 = require("../../utils");
11
12
  const b = (0, utils_1.block)('accordeon');
12
13
  const Accordeon = ({ children, headName, input, meta, mode, schema, props, }) => {
13
14
  var _a;
14
15
  const { titleProps, togglerProps, withIndent = false, withDefaultSummary = false } = props, restLayoutProps = tslib_1.__rest(props, ["titleProps", "togglerProps", "withIndent", "withDefaultSummary"]);
15
16
  const { copy, required, hidden, open } = ((_a = schema.nodeParameters) === null || _a === void 0 ? void 0 : _a.flags) || {};
17
+ const { expanded, setExpanded } = (0, hooks_1.useExpanded)({ headName, name: input.name, open });
16
18
  const overviewFlag = mode === core_1.SchemaRendererMode.Overview;
17
19
  const summary = react_1.default.useMemo(() => (react_1.default.createElement(uikit_1.Text, Object.assign({ variant: "subheader-1", color: "complementary" }, titleProps, { className: b('title', { required: required && !overviewFlag }, titleProps === null || titleProps === void 0 ? void 0 : titleProps.className) }), schema.title)), [overviewFlag, required, schema.title, titleProps]);
18
20
  const helpMark = react_1.default.useMemo(() => {
@@ -35,7 +37,7 @@ const Accordeon = ({ children, headName, input, meta, mode, schema, props, }) =>
35
37
  return react_1.default.createElement(components_1.ArrayRemoveButton, { name: input.name, headName: headName });
36
38
  }, [overviewFlag, input.name, headName]);
37
39
  return (react_1.default.createElement(components_1.LayoutContainer, { className: b({ 'without-default-summary': !withDefaultSummary }), hideEmpty: overviewFlag, hidden: hidden },
38
- react_1.default.createElement(uikit_1.Disclosure, Object.assign({ defaultExpanded: open, summary: summary }, restLayoutProps),
40
+ react_1.default.createElement(uikit_1.Disclosure, Object.assign({ summary: summary, expanded: expanded, onUpdate: setExpanded }, restLayoutProps),
39
41
  react_1.default.createElement(uikit_1.Disclosure.Summary, null, ({ expanded, onClick }, defaultSummary) => (react_1.default.createElement(uikit_1.Flex, { minHeight: "28px", alignItems: "center", gap: 2 },
40
42
  withDefaultSummary ? (defaultSummary) : (react_1.default.createElement(uikit_1.Button, Object.assign({}, togglerProps, { onClick: onClick, className: b('toggler', togglerProps === null || togglerProps === void 0 ? void 0 : togglerProps.className) }),
41
43
  react_1.default.createElement(uikit_1.Flex, { alignItems: "center", gap: 2, height: "100%" },
@@ -7,6 +7,7 @@ const icons_1 = require("@gravity-ui/icons");
7
7
  const uikit_1 = require("@gravity-ui/uikit");
8
8
  const core_1 = require("../../../core");
9
9
  const components_1 = require("../../components");
10
+ const hooks_1 = require("../../hooks");
10
11
  const utils_1 = require("../../utils");
11
12
  const b = (0, utils_1.block)('card');
12
13
  const Card = ({ children, headName, input, meta, mode, schema, props, }) => {
@@ -14,10 +15,11 @@ const Card = ({ children, headName, input, meta, mode, schema, props, }) => {
14
15
  const { descriptionType = 'tooltip', likeAccordeon = true } = props, restLayoutProps = tslib_1.__rest(props, ["descriptionType", "likeAccordeon"]);
15
16
  const { copy, required, hidden, open = true } = ((_a = schema.nodeParameters) === null || _a === void 0 ? void 0 : _a.flags) || {};
16
17
  const overviewFlag = mode === core_1.SchemaRendererMode.Overview;
17
- const [visible, setVisible] = react_1.default.useState(likeAccordeon ? open : true);
18
- const toggleVisible = react_1.default.useCallback(() => {
19
- setVisible((f) => !f);
20
- }, []);
18
+ const { expanded, toggleExpanded } = (0, hooks_1.useExpanded)({
19
+ headName,
20
+ name: input.name,
21
+ open: likeAccordeon ? open : true,
22
+ });
21
23
  const tooltip = react_1.default.useMemo(() => {
22
24
  if (!schema.description || descriptionType === 'bottom') {
23
25
  return null;
@@ -33,7 +35,7 @@ const Card = ({ children, headName, input, meta, mode, schema, props, }) => {
33
35
  }, [headName, schema.description, descriptionType, overviewFlag]);
34
36
  return (react_1.default.createElement(components_1.LayoutContainer, { className: b(), hideEmpty: overviewFlag, hidden: hidden },
35
37
  react_1.default.createElement(uikit_1.Card, Object.assign({}, restLayoutProps, { className: b('card') }),
36
- react_1.default.createElement("div", { className: b('inner', { hidden: !visible }) },
38
+ react_1.default.createElement("div", { className: b('inner', { hidden: !expanded }) },
37
39
  react_1.default.createElement(uikit_1.Flex, { className: b('header'), direction: "column", justifyContent: "center" },
38
40
  react_1.default.createElement(uikit_1.Flex, { justifyContent: "space-between", alignItems: "center" },
39
41
  react_1.default.createElement(uikit_1.Flex, { alignItems: "center", gap: 2 },
@@ -43,10 +45,10 @@ const Card = ({ children, headName, input, meta, mode, schema, props, }) => {
43
45
  overviewFlag ? (react_1.default.createElement(components_1.CopyButton, { className: b('copy-button'), copy: copy, value: input.value })) : null,
44
46
  overviewFlag ? null : (react_1.default.createElement(components_1.ArrayRemoveButton, { name: input.name, headName: headName })),
45
47
  likeAccordeon ? (react_1.default.createElement(uikit_1.Flex, { width: "28px", justifyContent: "center" },
46
- react_1.default.createElement(uikit_1.Button, { onClick: toggleVisible, size: "s", view: "flat-secondary" },
47
- react_1.default.createElement(uikit_1.Icon, { data: visible ? icons_1.ChevronUp : icons_1.ChevronDown, size: 16 })))) : null)),
48
+ react_1.default.createElement(uikit_1.Button, { onClick: toggleExpanded, size: "s", view: "flat-secondary" },
49
+ react_1.default.createElement(uikit_1.Icon, { data: expanded ? icons_1.ChevronUp : icons_1.ChevronDown, size: 16 })))) : null)),
48
50
  bottomDescription),
49
- react_1.default.createElement("div", { className: b('content', { hidden: !visible }) }, children)),
51
+ react_1.default.createElement("div", { className: b('content', { hidden: !expanded }) }, children)),
50
52
  overviewFlag ? null : (react_1.default.createElement(components_1.EntityError, { errorMessage: meta.error, validationState: (0, utils_1.getValidationState)(meta) })))));
51
53
  };
52
54
  exports.Card = Card;
@@ -16,9 +16,9 @@ const viewSpecRules = {
16
16
  },
17
17
  layout: (spec, mutableSchema) => {
18
18
  var _a;
19
- const layout = (_a = spec === null || spec === void 0 ? void 0 : spec.viewSpec) === null || _a === void 0 ? void 0 : _a.layout;
19
+ let layout = (_a = spec === null || spec === void 0 ? void 0 : spec.viewSpec) === null || _a === void 0 ? void 0 : _a.layout;
20
20
  if (!layout) {
21
- return;
21
+ layout = 'transparent';
22
22
  }
23
23
  if (layout === 'row_verbose') {
24
24
  (0, set_1.default)(mutableSchema, 'nodeParameters.layout', 'row');
@@ -335,6 +335,9 @@ const viewSpecRules = {
335
335
  if (spec.viewSpec.placeholder) {
336
336
  (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.placeholder', spec.viewSpec.placeholder);
337
337
  }
338
+ if (spec.required) {
339
+ (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.flags.required', true);
340
+ }
338
341
  if (spec.description && Object.keys(spec.description).length) {
339
342
  (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.enumDescriptions', spec.description);
340
343
  }
@@ -380,6 +383,9 @@ const viewSpecRules = {
380
383
  if (spec.viewSpec.placeholder) {
381
384
  (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.placeholder', spec.viewSpec.placeholder);
382
385
  }
386
+ if (spec.required) {
387
+ (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.flags.required', true);
388
+ }
383
389
  if (spec.description && Object.keys(spec.description).length) {
384
390
  (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.enumDescriptions', spec.description);
385
391
  }
@@ -425,6 +431,9 @@ const viewSpecRules = {
425
431
  if (spec.viewSpec.placeholder) {
426
432
  (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.placeholder', spec.viewSpec.placeholder);
427
433
  }
434
+ if (spec.required) {
435
+ (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.flags.required', true);
436
+ }
428
437
  if (spec.description && Object.keys(spec.description).length) {
429
438
  (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.enumDescriptions', spec.description);
430
439
  }
@@ -471,6 +480,9 @@ const viewSpecRules = {
471
480
  if (spec.viewSpec.placeholder) {
472
481
  (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.placeholder', spec.viewSpec.placeholder);
473
482
  }
483
+ if (spec.required) {
484
+ (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.flags.required', true);
485
+ }
474
486
  if (spec.description && Object.keys(spec.description).length) {
475
487
  (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.enumDescriptions', spec.description);
476
488
  }
@@ -506,6 +518,9 @@ const viewSpecRules = {
506
518
  if (spec.viewSpec.placeholder) {
507
519
  (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.placeholder', spec.viewSpec.placeholder);
508
520
  }
521
+ if (spec.required) {
522
+ (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.flags.required', true);
523
+ }
509
524
  if (spec.description && Object.keys(spec.description).length) {
510
525
  (0, set_1.default)(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.enumDescriptions', spec.description);
511
526
  }
@@ -542,7 +557,7 @@ const viewSpecRules = {
542
557
  (0, set_1.default)(mutableSchema, 'nodeParameters.type', core_2.NodeType.Any);
543
558
  }
544
559
  else if (((_j = spec === null || spec === void 0 ? void 0 : spec.viewSpec) === null || _j === void 0 ? void 0 : _j.type) === 'file_input') {
545
- (0, set_1.default)(mutableSchema, 'nodeParameters.entity', 'file');
560
+ (0, set_1.default)(mutableSchema, 'nodeParameters.entity', 'file_input');
546
561
  }
547
562
  else if (((_k = spec === null || spec === void 0 ? void 0 : spec.viewSpec) === null || _k === void 0 ? void 0 : _k.type) === 'monaco_input') {
548
563
  (0, set_1.default)(mutableSchema, 'nodeParameters.entity', 'monaco_input');
@@ -11,6 +11,7 @@ export declare enum SchemaRendererEventType {
11
11
  Patch = "patch",
12
12
  Settings = "settings",
13
13
  Schema = "schema",
14
+ Submit = "submit",
14
15
  UserContext = "userContext"
15
16
  }
16
17
  export declare enum JsonSchemaType {
@@ -13,6 +13,7 @@ export var SchemaRendererEventType;
13
13
  SchemaRendererEventType["Patch"] = "patch";
14
14
  SchemaRendererEventType["Settings"] = "settings";
15
15
  SchemaRendererEventType["Schema"] = "schema";
16
+ SchemaRendererEventType["Submit"] = "submit";
16
17
  SchemaRendererEventType["UserContext"] = "userContext";
17
18
  })(SchemaRendererEventType || (SchemaRendererEventType = {}));
18
19
  export var JsonSchemaType;
@@ -21,6 +21,7 @@ export interface SchemaRendererState<UserContext extends Record<string, unknown>
21
21
  coerceInitialValues: boolean;
22
22
  jsonDefaultValues: boolean;
23
23
  };
24
+ submitCount: number;
24
25
  subscribe: (subscriber: SchemaRendererSubscriber) => string;
25
26
  subscribers: {
26
27
  byId: Record<string, SchemaRendererSubscriber>;
@@ -45,6 +45,7 @@ export const useSchemaRenderer = ({ coerceInitialValues = true, config, connectV
45
45
  runValidate,
46
46
  settings: { coerceInitialValues, jsonDefaultValues },
47
47
  schema: nameUpdated || schemaUpdated ? cloneDeep(originalSchema) : (prevState === null || prevState === void 0 ? void 0 : prevState.schema) || {},
48
+ submitCount: nameUpdated || schemaUpdated || !prevState ? 0 : prevState.submitCount,
48
49
  subscribe,
49
50
  subscribers: (prevState === null || prevState === void 0 ? void 0 : prevState.subscribers) || { byId: {}, byName: new Map(), byPath: new Map() },
50
51
  unsubscribe,
@@ -114,6 +115,22 @@ export const useSchemaRenderer = ({ coerceInitialValues = true, config, connectV
114
115
  initialState.dispatchEvent(initialEvents);
115
116
  }
116
117
  }, [initialEvents, initialState]);
118
+ React.useEffect(() => {
119
+ const originalSubmit = form.submit;
120
+ form.submit = () => {
121
+ var _a;
122
+ const srField = form.getFieldState(getServiceFieldName(SCHEMA_RENDERER_SERVICE_FIELD, headName));
123
+ const srState = (_a = srField === null || srField === void 0 ? void 0 : srField.data) === null || _a === void 0 ? void 0 : _a.state;
124
+ if (srState) {
125
+ srState.submitCount += 1;
126
+ srState.dispatchEvent([{ type: SchemaRendererEventType.Submit, all: true }]);
127
+ }
128
+ return originalSubmit.call(form);
129
+ };
130
+ return () => {
131
+ form.submit = originalSubmit;
132
+ };
133
+ }, [form]);
117
134
  React.useEffect(() => {
118
135
  const strictChecker = strictCheckerRef.current;
119
136
  return () => {
@@ -288,6 +288,7 @@ export declare const untypedConfig: {
288
288
  readonly formEntities: {
289
289
  readonly base: {
290
290
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaObject, import("../entities").ObjectEntityProps>;
291
+ readonly independent: true;
291
292
  };
292
293
  readonly dot_value: {
293
294
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaObject, import("../entities").DotValueProps>;
@@ -336,6 +337,7 @@ export declare const untypedConfig: {
336
337
  readonly overviewEntities: {
337
338
  readonly base: {
338
339
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaObject, import("../entities").ObjectEntityProps>;
340
+ readonly independent: true;
339
341
  };
340
342
  readonly dot_value: {
341
343
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaObject, import("../entities").DotValueProps>;
@@ -397,7 +399,7 @@ export declare const untypedConfig: {
397
399
  readonly color_picker: {
398
400
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaString, import("../form-entities").ColorPickerInputProps>;
399
401
  };
400
- readonly file: {
402
+ readonly file_input: {
401
403
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaString, import("../form-entities").FileInputProps>;
402
404
  };
403
405
  readonly label: {
@@ -461,7 +463,7 @@ export declare const untypedConfig: {
461
463
  readonly color_picker: {
462
464
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaString, import("../overview-entities").ColorPickerValueProps>;
463
465
  };
464
- readonly file: {
466
+ readonly file_input: {
465
467
  readonly Component: import("../../core").NodeEntity<import("../../core").JsonSchemaString, import("../overview-entities").StringValueProps>;
466
468
  };
467
469
  readonly label: {
@@ -128,7 +128,7 @@ export const untypedConfig = {
128
128
  },
129
129
  [NodeType.Object]: {
130
130
  formEntities: {
131
- base: { Component: ObjectEntity },
131
+ base: { Component: ObjectEntity, independent: true },
132
132
  dot_value: { Component: DotValue },
133
133
  few_of_nested: { Component: FewOfNested, independent: true },
134
134
  inline: { Component: ObjectInline },
@@ -146,7 +146,7 @@ export const untypedConfig = {
146
146
  transparent: { Component: Transparent },
147
147
  },
148
148
  overviewEntities: {
149
- base: { Component: ObjectEntity },
149
+ base: { Component: ObjectEntity, independent: true },
150
150
  dot_value: { Component: DotValue },
151
151
  few_of_nested: { Component: FewOfNested, independent: true },
152
152
  inline: { Component: ObjectInline },
@@ -170,7 +170,7 @@ export const untypedConfig = {
170
170
  alert: { Component: Alert },
171
171
  base: { Component: StringInput },
172
172
  color_picker: { Component: ColorPickerInput },
173
- file: { Component: FileInput },
173
+ file_input: { Component: FileInput },
174
174
  label: { Component: Label },
175
175
  monaco_input: { Component: Monaco },
176
176
  password: { Component: PasswordInput },
@@ -194,7 +194,7 @@ export const untypedConfig = {
194
194
  alert: { Component: Alert },
195
195
  base: { Component: StringValue },
196
196
  color_picker: { Component: ColorPickerValue },
197
- file: { Component: StringValue },
197
+ file_input: { Component: StringValue },
198
198
  label: { Component: Label },
199
199
  monaco_input: { Component: Monaco },
200
200
  password: { Component: StringValue },
@@ -1,11 +1,14 @@
1
1
  import React from 'react';
2
- import { SchemaRendererMode, SchemaRendererNode, } from '../../../core';
3
- import { EmptyEntityValue, EntityContainer } from '../../components';
4
- export const ObjectEntity = ({ headName, mode, input, props, schema, schemaPath, }) => {
2
+ import { SchemaRendererNode } from '../../../core';
3
+ import { EntityContainer } from '../../components';
4
+ export const ObjectEntity = ({ Layout, headName, input, layoutProps, meta, mode, props, schema, schemaPath, }) => {
5
5
  const { name } = input;
6
- const overviewFlag = mode === SchemaRendererMode.Overview;
7
- if (overviewFlag && !Object.keys(schema.properties || {}).length) {
8
- return React.createElement(EmptyEntityValue, null);
6
+ if (!Object.keys(schema.properties || {}).length) {
7
+ return null;
9
8
  }
10
- return (React.createElement(EntityContainer, { stretch: "by-child", fill: "by-child" }, (props.order || Object.keys(schema.properties || {})).map((property) => (React.createElement(SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${property}`, schemaPath: `${schemaPath}/properties/${property}`, key: property })))));
9
+ let content = (React.createElement(EntityContainer, { stretch: "by-child", fill: "by-child" }, (props.order || Object.keys(schema.properties || {})).map((property) => (React.createElement(SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${property}`, schemaPath: `${schemaPath}/properties/${property}`, key: property })))));
10
+ if (Layout) {
11
+ content = (React.createElement(Layout, { headName: headName, input: input, meta: meta, mode: mode, schema: schema, schemaPath: schemaPath, props: layoutProps || {} }, content));
12
+ }
13
+ return content;
11
14
  };
@@ -16,7 +16,7 @@ export const ObjectInline = ({ headName, input, mode, props, schema, schemaPath,
16
16
  }
17
17
  return (React.createElement(EntityContainer, { stretch: overviewFlag ? 'by-child' : 'max', className: b(), fill: "by-child" },
18
18
  React.createElement(Flex, { className: b('items', { overview: overviewFlag }), direction: "row", alignItems: "flex-start", gap: overviewFlag ? 1 : 2 }, (order || Object.keys(schema.properties || {})).map((property, index, array) => (React.createElement(React.Fragment, { key: property },
19
- React.createElement(SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${property}`, schemaPath: `${schemaPath}/properties/${property}` }),
19
+ React.createElement(SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${property}`, schemaPath: `${schemaPath}/properties/${property}`, key: property }),
20
20
  isString(delimiter) && index + 1 !== array.length ? (React.createElement(Text, { className: b('delimiter') }, delimiter)) : null,
21
21
  isObject(delimiter) && delimiter[property] ? (React.createElement(Text, { className: b('delimiter') }, delimiter[property])) : null))))));
22
22
  };
@@ -69,7 +69,7 @@ export const OneOfNested = ({ Layout, headName, input, layoutProps, meta, mode,
69
69
  }, [name, input, togglerArrayRemoveButton]);
70
70
  let content = (React.createElement(EntityContainer, { direction: "column-reverse", stretch: "by-child", fill: "populated" },
71
71
  togglerValue === undefined ? null : (React.createElement(LayoutContainer, { className: b('content', { 'with-indent': withIndent }), hideEmpty: overviewFlag },
72
- React.createElement(SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${togglerValue}`, schemaPath: `${schemaPath}/properties/${togglerValue}` }))),
72
+ React.createElement(SchemaRendererNode, { headName: headName, name: `${name ? name + '.' : ''}${togglerValue}`, schemaPath: `${schemaPath}/properties/${togglerValue}`, key: togglerValue }))),
73
73
  toggler));
74
74
  if (overviewFlag && Object.values(value || {}).length === 0) {
75
75
  content = React.createElement(React.Fragment, null, toggler);
@@ -28,7 +28,7 @@ export const NumberWithScaleInput = ({ input, meta, props, schema, }) => {
28
28
  scale: preparedScale,
29
29
  defaultType,
30
30
  viewType: viewType && preparedScale[viewType] ? [viewType] : [defaultType],
31
- minScaleLength: `${minScaleLength + 42}px`,
31
+ minScaleLength: `${minScaleLength + 60}px`,
32
32
  };
33
33
  }
34
34
  }
@@ -61,7 +61,7 @@ export const RangeInput = ({ headName, input, props, schemaPath, }) => {
61
61
  }, [inputValue === null || inputValue === void 0 ? void 0 : inputValue[fromKey], inputValue === null || inputValue === void 0 ? void 0 : inputValue[toKey]]);
62
62
  return (React.createElement(EntityContainer, { stretch: "max", className: b() },
63
63
  React.createElement(Flex, { className: b('items'), direction: "row", alignItems: "flex-start", gap: 2 },
64
- React.createElement(SchemaRendererNode, { headName: headName, name: fromName, schemaPath: `${schemaPath}/properties/${fromKey}` }),
64
+ React.createElement(SchemaRendererNode, { headName: headName, name: fromName, schemaPath: `${schemaPath}/properties/${fromKey}`, key: fromKey }),
65
65
  React.createElement(Text, { className: b('delimiter') }, separator),
66
- React.createElement(SchemaRendererNode, { headName: headName, name: toName, schemaPath: `${schemaPath}/properties/${toKey}` }))));
66
+ React.createElement(SchemaRendererNode, { headName: headName, name: toName, schemaPath: `${schemaPath}/properties/${toKey}`, key: toKey }))));
67
67
  };
@@ -29,7 +29,7 @@ export const StringNumberWithScaleInput = ({ input, meta, props, schema }) => {
29
29
  scale: preparedScale,
30
30
  defaultType,
31
31
  viewType: viewType && preparedScale[viewType] ? [viewType] : [defaultType],
32
- minScaleLength: `${minScaleLength + 42}px`,
32
+ minScaleLength: `${minScaleLength + 60}px`,
33
33
  };
34
34
  }
35
35
  }
@@ -8,5 +8,5 @@ export const TextAreaInput = ({ input, meta, props, schema, }) => {
8
8
  var _a, _b, _c;
9
9
  const { disabled } = ((_a = schema.nodeParameters) === null || _a === void 0 ? void 0 : _a.flags) || {};
10
10
  return (React.createElement(EntityContainer, { stretch: "max", className: b({ error: getBooleanValidationState(meta) }) },
11
- React.createElement(TextArea, Object.assign({ maxRows: 20, minRows: 0, placeholder: (_b = schema.examples) === null || _b === void 0 ? void 0 : _b[0], disabled: disabled || schema.readOnly, hasClear: true }, props, { value: (_c = input.value) !== null && _c !== void 0 ? _c : '', onFocus: input.onFocus, onBlur: input.onBlur, onUpdate: input.onChange, errorMessage: undefined, validationState: getValidationState(meta), qa: input.name }))));
11
+ React.createElement(TextArea, Object.assign({ maxRows: 20, minRows: 8, placeholder: (_b = schema.examples) === null || _b === void 0 ? void 0 : _b[0], disabled: disabled || schema.readOnly, hasClear: true }, props, { value: (_c = input.value) !== null && _c !== void 0 ? _c : '', onFocus: input.onFocus, onBlur: input.onBlur, onUpdate: input.onChange, errorMessage: undefined, validationState: getValidationState(meta), qa: input.name }))));
12
12
  };
@@ -0,0 +1 @@
1
+ export { type UseExpandedParams, useExpanded } from './useExpanded';
@@ -0,0 +1 @@
1
+ export { useExpanded } from './useExpanded';
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ export interface UseExpandedParams {
3
+ headName: string;
4
+ name: string;
5
+ open?: boolean;
6
+ }
7
+ export declare const useExpanded: ({ headName, name, open }: UseExpandedParams) => {
8
+ expanded: boolean;
9
+ setExpanded: React.Dispatch<React.SetStateAction<boolean>>;
10
+ toggleExpanded: () => void;
11
+ };
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { SchemaRendererEventType, useSchemaRendererState } from '../../core';
3
+ export const useExpanded = ({ headName, name, open = true }) => {
4
+ const srState = useSchemaRendererState({
5
+ headName,
6
+ subscriptions: [SchemaRendererEventType.Submit],
7
+ });
8
+ const [expanded, setExpanded] = React.useState(open);
9
+ const toggleExpanded = React.useCallback(() => {
10
+ setExpanded((f) => !f);
11
+ }, []);
12
+ React.useEffect(() => {
13
+ if (srState &&
14
+ srState.submitCount > 0 &&
15
+ Object.keys(srState.errors).some((key) => key.startsWith(name))) {
16
+ setExpanded(true);
17
+ }
18
+ }, [srState]);
19
+ return { expanded, setExpanded, toggleExpanded };
20
+ };
@@ -1,6 +1,7 @@
1
1
  export * from './components';
2
2
  export * from './constants';
3
3
  export * from './entities';
4
+ export * from './hooks';
4
5
  export * from './form-entities';
5
6
  export * from './form-layouts';
6
7
  export * from './layouts';
@@ -1,6 +1,7 @@
1
1
  export * from './components';
2
2
  export * from './constants';
3
3
  export * from './entities';
4
+ export * from './hooks';
4
5
  export * from './form-entities';
5
6
  export * from './form-layouts';
6
7
  export * from './layouts';
@@ -4,6 +4,7 @@ import { ChevronDown, ChevronUp } from '@gravity-ui/icons';
4
4
  import { Button, Disclosure, Flex, HelpMark, Icon, Text, } from '@gravity-ui/uikit';
5
5
  import { SchemaRendererMode } from '../../../core';
6
6
  import { ArrayRemoveButton, CopyButton, EntityError, HTMLContent, LayoutContainer, } from '../../components';
7
+ import { useExpanded } from '../../hooks';
7
8
  import { block, getValidationState } from '../../utils';
8
9
  import './Accordeon.css';
9
10
  const b = block('accordeon');
@@ -11,6 +12,7 @@ export const Accordeon = ({ children, headName, input, meta, mode, schema, props
11
12
  var _a;
12
13
  const { titleProps, togglerProps, withIndent = false, withDefaultSummary = false } = props, restLayoutProps = __rest(props, ["titleProps", "togglerProps", "withIndent", "withDefaultSummary"]);
13
14
  const { copy, required, hidden, open } = ((_a = schema.nodeParameters) === null || _a === void 0 ? void 0 : _a.flags) || {};
15
+ const { expanded, setExpanded } = useExpanded({ headName, name: input.name, open });
14
16
  const overviewFlag = mode === SchemaRendererMode.Overview;
15
17
  const summary = React.useMemo(() => (React.createElement(Text, Object.assign({ variant: "subheader-1", color: "complementary" }, titleProps, { className: b('title', { required: required && !overviewFlag }, titleProps === null || titleProps === void 0 ? void 0 : titleProps.className) }), schema.title)), [overviewFlag, required, schema.title, titleProps]);
16
18
  const helpMark = React.useMemo(() => {
@@ -33,7 +35,7 @@ export const Accordeon = ({ children, headName, input, meta, mode, schema, props
33
35
  return React.createElement(ArrayRemoveButton, { name: input.name, headName: headName });
34
36
  }, [overviewFlag, input.name, headName]);
35
37
  return (React.createElement(LayoutContainer, { className: b({ 'without-default-summary': !withDefaultSummary }), hideEmpty: overviewFlag, hidden: hidden },
36
- React.createElement(Disclosure, Object.assign({ defaultExpanded: open, summary: summary }, restLayoutProps),
38
+ React.createElement(Disclosure, Object.assign({ summary: summary, expanded: expanded, onUpdate: setExpanded }, restLayoutProps),
37
39
  React.createElement(Disclosure.Summary, null, ({ expanded, onClick }, defaultSummary) => (React.createElement(Flex, { minHeight: "28px", alignItems: "center", gap: 2 },
38
40
  withDefaultSummary ? (defaultSummary) : (React.createElement(Button, Object.assign({}, togglerProps, { onClick: onClick, className: b('toggler', togglerProps === null || togglerProps === void 0 ? void 0 : togglerProps.className) }),
39
41
  React.createElement(Flex, { alignItems: "center", gap: 2, height: "100%" },
@@ -4,6 +4,7 @@ import { ChevronDown, ChevronUp } from '@gravity-ui/icons';
4
4
  import { Button, Flex, HelpMark, Icon, Text, Card as UIKitCard, } from '@gravity-ui/uikit';
5
5
  import { SchemaRendererMode } from '../../../core';
6
6
  import { ArrayRemoveButton, CopyButton, EntityError, HTMLContent, LayoutContainer, } from '../../components';
7
+ import { useExpanded } from '../../hooks';
7
8
  import { block, getValidationState } from '../../utils';
8
9
  import './Card.css';
9
10
  const b = block('card');
@@ -12,10 +13,11 @@ export const Card = ({ children, headName, input, meta, mode, schema, props, })
12
13
  const { descriptionType = 'tooltip', likeAccordeon = true } = props, restLayoutProps = __rest(props, ["descriptionType", "likeAccordeon"]);
13
14
  const { copy, required, hidden, open = true } = ((_a = schema.nodeParameters) === null || _a === void 0 ? void 0 : _a.flags) || {};
14
15
  const overviewFlag = mode === SchemaRendererMode.Overview;
15
- const [visible, setVisible] = React.useState(likeAccordeon ? open : true);
16
- const toggleVisible = React.useCallback(() => {
17
- setVisible((f) => !f);
18
- }, []);
16
+ const { expanded, toggleExpanded } = useExpanded({
17
+ headName,
18
+ name: input.name,
19
+ open: likeAccordeon ? open : true,
20
+ });
19
21
  const tooltip = React.useMemo(() => {
20
22
  if (!schema.description || descriptionType === 'bottom') {
21
23
  return null;
@@ -31,7 +33,7 @@ export const Card = ({ children, headName, input, meta, mode, schema, props, })
31
33
  }, [headName, schema.description, descriptionType, overviewFlag]);
32
34
  return (React.createElement(LayoutContainer, { className: b(), hideEmpty: overviewFlag, hidden: hidden },
33
35
  React.createElement(UIKitCard, Object.assign({}, restLayoutProps, { className: b('card') }),
34
- React.createElement("div", { className: b('inner', { hidden: !visible }) },
36
+ React.createElement("div", { className: b('inner', { hidden: !expanded }) },
35
37
  React.createElement(Flex, { className: b('header'), direction: "column", justifyContent: "center" },
36
38
  React.createElement(Flex, { justifyContent: "space-between", alignItems: "center" },
37
39
  React.createElement(Flex, { alignItems: "center", gap: 2 },
@@ -41,9 +43,9 @@ export const Card = ({ children, headName, input, meta, mode, schema, props, })
41
43
  overviewFlag ? (React.createElement(CopyButton, { className: b('copy-button'), copy: copy, value: input.value })) : null,
42
44
  overviewFlag ? null : (React.createElement(ArrayRemoveButton, { name: input.name, headName: headName })),
43
45
  likeAccordeon ? (React.createElement(Flex, { width: "28px", justifyContent: "center" },
44
- React.createElement(Button, { onClick: toggleVisible, size: "s", view: "flat-secondary" },
45
- React.createElement(Icon, { data: visible ? ChevronUp : ChevronDown, size: 16 })))) : null)),
46
+ React.createElement(Button, { onClick: toggleExpanded, size: "s", view: "flat-secondary" },
47
+ React.createElement(Icon, { data: expanded ? ChevronUp : ChevronDown, size: 16 })))) : null)),
46
48
  bottomDescription),
47
- React.createElement("div", { className: b('content', { hidden: !visible }) }, children)),
49
+ React.createElement("div", { className: b('content', { hidden: !expanded }) }, children)),
48
50
  overviewFlag ? null : (React.createElement(EntityError, { errorMessage: meta.error, validationState: getValidationState(meta) })))));
49
51
  };
@@ -12,9 +12,9 @@ const viewSpecRules = {
12
12
  },
13
13
  layout: (spec, mutableSchema) => {
14
14
  var _a;
15
- const layout = (_a = spec === null || spec === void 0 ? void 0 : spec.viewSpec) === null || _a === void 0 ? void 0 : _a.layout;
15
+ let layout = (_a = spec === null || spec === void 0 ? void 0 : spec.viewSpec) === null || _a === void 0 ? void 0 : _a.layout;
16
16
  if (!layout) {
17
- return;
17
+ layout = 'transparent';
18
18
  }
19
19
  if (layout === 'row_verbose') {
20
20
  set(mutableSchema, 'nodeParameters.layout', 'row');
@@ -331,6 +331,9 @@ const viewSpecRules = {
331
331
  if (spec.viewSpec.placeholder) {
332
332
  set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.placeholder', spec.viewSpec.placeholder);
333
333
  }
334
+ if (spec.required) {
335
+ set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.flags.required', true);
336
+ }
334
337
  if (spec.description && Object.keys(spec.description).length) {
335
338
  set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.enumDescriptions', spec.description);
336
339
  }
@@ -376,6 +379,9 @@ const viewSpecRules = {
376
379
  if (spec.viewSpec.placeholder) {
377
380
  set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.placeholder', spec.viewSpec.placeholder);
378
381
  }
382
+ if (spec.required) {
383
+ set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.flags.required', true);
384
+ }
379
385
  if (spec.description && Object.keys(spec.description).length) {
380
386
  set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.enumDescriptions', spec.description);
381
387
  }
@@ -421,6 +427,9 @@ const viewSpecRules = {
421
427
  if (spec.viewSpec.placeholder) {
422
428
  set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.placeholder', spec.viewSpec.placeholder);
423
429
  }
430
+ if (spec.required) {
431
+ set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.flags.required', true);
432
+ }
424
433
  if (spec.description && Object.keys(spec.description).length) {
425
434
  set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.enumDescriptions', spec.description);
426
435
  }
@@ -467,6 +476,9 @@ const viewSpecRules = {
467
476
  if (spec.viewSpec.placeholder) {
468
477
  set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.placeholder', spec.viewSpec.placeholder);
469
478
  }
479
+ if (spec.required) {
480
+ set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.flags.required', true);
481
+ }
470
482
  if (spec.description && Object.keys(spec.description).length) {
471
483
  set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.enumDescriptions', spec.description);
472
484
  }
@@ -502,6 +514,9 @@ const viewSpecRules = {
502
514
  if (spec.viewSpec.placeholder) {
503
515
  set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.placeholder', spec.viewSpec.placeholder);
504
516
  }
517
+ if (spec.required) {
518
+ set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.flags.required', true);
519
+ }
505
520
  if (spec.description && Object.keys(spec.description).length) {
506
521
  set(mutableSchema, 'nodeParameters.entityProps.toggler.nodeParameters.entityProps.enumDescriptions', spec.description);
507
522
  }
@@ -538,7 +553,7 @@ const viewSpecRules = {
538
553
  set(mutableSchema, 'nodeParameters.type', NodeType.Any);
539
554
  }
540
555
  else if (((_j = spec === null || spec === void 0 ? void 0 : spec.viewSpec) === null || _j === void 0 ? void 0 : _j.type) === 'file_input') {
541
- set(mutableSchema, 'nodeParameters.entity', 'file');
556
+ set(mutableSchema, 'nodeParameters.entity', 'file_input');
542
557
  }
543
558
  else if (((_k = spec === null || spec === void 0 ? void 0 : spec.viewSpec) === null || _k === void 0 ? void 0 : _k.type) === 'monaco_input') {
544
559
  set(mutableSchema, 'nodeParameters.entity', 'monaco_input');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dynamic-forms",
3
- "version": "5.30.0",
3
+ "version": "5.32.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "main": "build/cjs/index.js",