@gravity-ui/dynamic-forms 5.29.2 → 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 (63) 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/components/EntityContainer/EntityContainer.d.ts +1 -0
  6. package/build/cjs/lib/unstable/kit/constants/config.d.ts +4 -2
  7. package/build/cjs/lib/unstable/kit/constants/config.js +4 -4
  8. package/build/cjs/lib/unstable/kit/entities/FewOfNested/FewOfNested.d.ts +1 -0
  9. package/build/cjs/lib/unstable/kit/entities/FewOfNested/FewOfNested.js +8 -3
  10. package/build/cjs/lib/unstable/kit/entities/ObjectEntity/ObjectEntity.js +8 -5
  11. package/build/cjs/lib/unstable/kit/entities/ObjectInline/ObjectInline.js +1 -1
  12. package/build/cjs/lib/unstable/kit/entities/OneOfNested/OneOfNested.d.ts +1 -0
  13. package/build/cjs/lib/unstable/kit/entities/OneOfNested/OneOfNested.js +9 -4
  14. package/build/cjs/lib/unstable/kit/form-entities/NumberWithScaleInput/NumberWithScaleInput.js +1 -1
  15. package/build/cjs/lib/unstable/kit/form-entities/RangeInput/RangeInput.js +2 -2
  16. package/build/cjs/lib/unstable/kit/form-entities/SegmentedRadioGroupInput/SegmentedRadioGroupInput.css +9 -4
  17. package/build/cjs/lib/unstable/kit/form-entities/SegmentedRadioGroupInput/SegmentedRadioGroupInput.js +14 -15
  18. package/build/cjs/lib/unstable/kit/form-entities/StringNumberWithScaleInput/StringNumberWithScaleInput.js +1 -1
  19. package/build/cjs/lib/unstable/kit/form-entities/TextAreaInput/TextAreaInput.js +1 -1
  20. package/build/cjs/lib/unstable/kit/form-layouts/FormColumn/FormColumn.js +1 -1
  21. package/build/cjs/lib/unstable/kit/form-layouts/FormRow/FormRow.js +1 -1
  22. package/build/cjs/lib/unstable/kit/hooks/index.d.ts +1 -0
  23. package/build/cjs/lib/unstable/kit/hooks/index.js +5 -0
  24. package/build/cjs/lib/unstable/kit/hooks/useExpanded.d.ts +11 -0
  25. package/build/cjs/lib/unstable/kit/hooks/useExpanded.js +25 -0
  26. package/build/cjs/lib/unstable/kit/index.d.ts +1 -0
  27. package/build/cjs/lib/unstable/kit/index.js +1 -0
  28. package/build/cjs/lib/unstable/kit/layouts/Accordeon/Accordeon.js +4 -2
  29. package/build/cjs/lib/unstable/kit/layouts/Card/Card.js +11 -9
  30. package/build/cjs/lib/unstable/kit/layouts/Section/Section.js +1 -1
  31. package/build/cjs/lib/unstable/kit/utils/transformer.js +18 -3
  32. package/build/esm/lib/unstable/core/constants.d.ts +1 -0
  33. package/build/esm/lib/unstable/core/constants.js +1 -0
  34. package/build/esm/lib/unstable/core/useSchemaRenderer/types/state.d.ts +1 -0
  35. package/build/esm/lib/unstable/core/useSchemaRenderer/useSchemaRenderer.js +17 -0
  36. package/build/esm/lib/unstable/kit/components/EntityContainer/EntityContainer.d.ts +1 -0
  37. package/build/esm/lib/unstable/kit/constants/config.d.ts +4 -2
  38. package/build/esm/lib/unstable/kit/constants/config.js +4 -4
  39. package/build/esm/lib/unstable/kit/entities/FewOfNested/FewOfNested.d.ts +1 -0
  40. package/build/esm/lib/unstable/kit/entities/FewOfNested/FewOfNested.js +8 -3
  41. package/build/esm/lib/unstable/kit/entities/ObjectEntity/ObjectEntity.js +10 -7
  42. package/build/esm/lib/unstable/kit/entities/ObjectInline/ObjectInline.js +1 -1
  43. package/build/esm/lib/unstable/kit/entities/OneOfNested/OneOfNested.d.ts +1 -0
  44. package/build/esm/lib/unstable/kit/entities/OneOfNested/OneOfNested.js +9 -4
  45. package/build/esm/lib/unstable/kit/form-entities/NumberWithScaleInput/NumberWithScaleInput.js +1 -1
  46. package/build/esm/lib/unstable/kit/form-entities/RangeInput/RangeInput.js +2 -2
  47. package/build/esm/lib/unstable/kit/form-entities/SegmentedRadioGroupInput/SegmentedRadioGroupInput.css +9 -4
  48. package/build/esm/lib/unstable/kit/form-entities/SegmentedRadioGroupInput/SegmentedRadioGroupInput.js +14 -15
  49. package/build/esm/lib/unstable/kit/form-entities/StringNumberWithScaleInput/StringNumberWithScaleInput.js +1 -1
  50. package/build/esm/lib/unstable/kit/form-entities/TextAreaInput/TextAreaInput.js +1 -1
  51. package/build/esm/lib/unstable/kit/form-layouts/FormColumn/FormColumn.js +1 -1
  52. package/build/esm/lib/unstable/kit/form-layouts/FormRow/FormRow.js +1 -1
  53. package/build/esm/lib/unstable/kit/hooks/index.d.ts +1 -0
  54. package/build/esm/lib/unstable/kit/hooks/index.js +1 -0
  55. package/build/esm/lib/unstable/kit/hooks/useExpanded.d.ts +11 -0
  56. package/build/esm/lib/unstable/kit/hooks/useExpanded.js +20 -0
  57. package/build/esm/lib/unstable/kit/index.d.ts +1 -0
  58. package/build/esm/lib/unstable/kit/index.js +1 -0
  59. package/build/esm/lib/unstable/kit/layouts/Accordeon/Accordeon.js +4 -2
  60. package/build/esm/lib/unstable/kit/layouts/Card/Card.js +11 -9
  61. package/build/esm/lib/unstable/kit/layouts/Section/Section.js +1 -1
  62. package/build/esm/lib/unstable/kit/utils/transformer.js +18 -3
  63. package/package.json +1 -1
@@ -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 () => {
@@ -4,6 +4,7 @@ import './EntityContainer.css';
4
4
  export interface EntityContainerProps extends FlexProps {
5
5
  children: React.ReactNode;
6
6
  fill?: 'populated' | 'empty' | 'by-child';
7
+ ref?: React.ComponentPropsWithRef<'div'>['ref'];
7
8
  stretch: 'max' | 'fit' | 'by-child';
8
9
  }
9
10
  export declare const EntityContainer: React.FC<EntityContainerProps>;
@@ -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 },
@@ -4,5 +4,6 @@ export interface FewOfNestedProps {
4
4
  toggler: JsonSchema;
5
5
  withIndent?: boolean;
6
6
  togglerArrayRemoveButton?: boolean;
7
+ order?: string[];
7
8
  }
8
9
  export declare const FewOfNested: NodeEntity<JsonSchemaObject, FewOfNestedProps>;
@@ -7,7 +7,7 @@ import './FewOfNested.css';
7
7
  const b = block('few-of-nested');
8
8
  export const FewOfNested = ({ Layout, headName, input, layoutProps, meta, mode, props, schema, schemaPath, }) => {
9
9
  const { name, value } = input;
10
- const { togglerArrayRemoveButton = false, toggler: togglerSchema = {}, withIndent = false, } = props;
10
+ const { togglerArrayRemoveButton = false, toggler: togglerSchema = {}, withIndent = false, order, } = props;
11
11
  const overviewFlag = mode === SchemaRendererMode.Overview;
12
12
  const srState = useSchemaRendererState({
13
13
  headName,
@@ -17,8 +17,13 @@ export const FewOfNested = ({ Layout, headName, input, layoutProps, meta, mode,
17
17
  if (value && Object.keys(value).length) {
18
18
  return Object.keys(value);
19
19
  }
20
- if (!overviewFlag && schema.properties && Object.keys(schema.properties).length) {
21
- return [Object.keys(schema.properties)[0]];
20
+ if (!overviewFlag) {
21
+ if ((order === null || order === void 0 ? void 0 : order[0]) !== undefined) {
22
+ return [order[0]];
23
+ }
24
+ if (schema.properties && Object.keys(schema.properties).length) {
25
+ return [Object.keys(schema.properties)[0]];
26
+ }
22
27
  }
23
28
  return [];
24
29
  });
@@ -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
  };
@@ -8,5 +8,6 @@ export interface OneOfNestedProps {
8
8
  };
9
9
  withIndent?: boolean;
10
10
  togglerArrayRemoveButton?: boolean;
11
+ order?: string[];
11
12
  }
12
13
  export declare const OneOfNested: NodeEntity<JsonSchemaObject, OneOfNestedProps>;
@@ -6,7 +6,7 @@ import './OneOfNested.css';
6
6
  const b = block('one-of-nested');
7
7
  export const OneOfNested = ({ Layout, headName, input, layoutProps, meta, mode, props, schema, schemaPath, }) => {
8
8
  const { name, value } = input;
9
- const { booleanToKey, togglerArrayRemoveButton = false, toggler: togglerSchema = {}, withIndent = false, } = props;
9
+ const { booleanToKey, togglerArrayRemoveButton = false, toggler: togglerSchema = {}, withIndent = false, order, } = props;
10
10
  const overviewFlag = mode === SchemaRendererMode.Overview;
11
11
  const srState = useSchemaRendererState({
12
12
  headName,
@@ -16,8 +16,13 @@ export const OneOfNested = ({ Layout, headName, input, layoutProps, meta, mode,
16
16
  if (value && Object.keys(value).length) {
17
17
  return Object.keys(value)[0];
18
18
  }
19
- if (!overviewFlag && schema.properties) {
20
- return Object.keys(schema.properties)[0];
19
+ if (!overviewFlag) {
20
+ if ((order === null || order === void 0 ? void 0 : order[0]) !== undefined) {
21
+ return order[0];
22
+ }
23
+ if (schema.properties) {
24
+ return Object.keys(schema.properties)[0];
25
+ }
21
26
  }
22
27
  return undefined;
23
28
  });
@@ -64,7 +69,7 @@ export const OneOfNested = ({ Layout, headName, input, layoutProps, meta, mode,
64
69
  }, [name, input, togglerArrayRemoveButton]);
65
70
  let content = (React.createElement(EntityContainer, { direction: "column-reverse", stretch: "by-child", fill: "populated" },
66
71
  togglerValue === undefined ? null : (React.createElement(LayoutContainer, { className: b('content', { 'with-indent': withIndent }), hideEmpty: overviewFlag },
67
- 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 }))),
68
73
  toggler));
69
74
  if (overviewFlag && Object.values(value || {}).length === 0) {
70
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
  };
@@ -1,11 +1,16 @@
1
+ .sr-segmented-radio-group-input {
2
+ position: relative;
3
+ }
1
4
  .sr-segmented-radio-group-input_error .g-segmented-radio-group .g-segmented-radio-group__option_checked:hover::after {
2
5
  border: 1px solid var(--g-color-text-danger);
3
6
  }
4
7
  .sr-segmented-radio-group-input_error .g-segmented-radio-group .g-segmented-radio-group__option_checked::after {
5
8
  border: 1px solid var(--g-color-text-danger);
6
9
  }
7
- .sr-segmented-radio-group-input_overflowed {
8
- height: 0;
9
- opacity: 0;
10
- overflow: hidden;
10
+ .sr-segmented-radio-group-input__checker {
11
+ position: absolute;
12
+ left: 0;
13
+ top: 0;
14
+ width: max-content;
15
+ visibility: hidden;
11
16
  }
@@ -12,7 +12,8 @@ export const SegmentedRadioGroupInput = (_a) => {
12
12
  const { name, onBlur, onChange, onFocus, value } = input;
13
13
  const { enumDescriptions, optionsDisabled } = props, restEntityProps = __rest(props, ["enumDescriptions", "optionsDisabled"]);
14
14
  const { disabled } = ((_b = schema.nodeParameters) === null || _b === void 0 ? void 0 : _b.flags) || {};
15
- const ref = React.useRef(null);
15
+ const containerRef = React.useRef(null);
16
+ const controlRef = React.useRef(null);
16
17
  const [overflowed, setOverflowed] = React.useState(false);
17
18
  const options = React.useMemo(() => {
18
19
  var _a;
@@ -28,26 +29,24 @@ export const SegmentedRadioGroupInput = (_a) => {
28
29
  onBlur();
29
30
  }, [onBlur, onChange, onFocus]);
30
31
  React.useLayoutEffect(() => {
31
- const root = ref.current;
32
- if (!root) {
32
+ const container = containerRef.current;
33
+ const control = controlRef.current;
34
+ if (!container || !control) {
33
35
  return;
34
36
  }
35
37
  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
- }));
38
+ const GAP = 48; // little bit more than potential remove button width + spacing
39
+ const containerWidth = container.offsetWidth - GAP;
40
+ const controlWidth = control.offsetWidth;
41
+ setOverflowed(controlWidth > containerWidth);
43
42
  };
44
43
  measure();
45
44
  const observer = new ResizeObserver(measure);
46
- observer.observe(root);
45
+ observer.observe(container);
47
46
  return () => observer.disconnect();
48
47
  }, [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 })))));
48
+ return (React.createElement(EntityContainer, { ref: containerRef, className: b({ error: getBooleanValidationState(meta) }), stretch: "max" },
49
+ overflowed ? (React.createElement(SelectInput, Object.assign({ input: input, meta: meta, props: props, schema: schema }, restProps))) : (React.createElement(SegmentedRadioGroup, Object.assign({ width: "max", disabled: disabled || schema.readOnly, options: options }, restEntityProps, { value: value, onFocus: onFocus, onBlur: onBlur, onUpdate: onUpdate, qa: name }))),
50
+ React.createElement("div", { className: b('checker') },
51
+ React.createElement(SegmentedRadioGroup, Object.assign({ ref: controlRef, width: "max", disabled: disabled || schema.readOnly, options: options }, restEntityProps)))));
53
52
  };
@@ -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
  };
@@ -23,7 +23,7 @@ export const FormColumn = ({ children, headName, input, meta, schema, props, })
23
23
  return (React.createElement(LayoutContainer, { className: b(), gap: 2, hidden: hidden },
24
24
  React.createElement(Flex, { direction: "column", gap: 0.5 },
25
25
  React.createElement("div", { className: b('top') },
26
- React.createElement(Text, { className: b('title', { required }), wordBreak: "break-word" }, schema.title),
26
+ React.createElement(Text, { className: b('title', { required }), variant: "subheader-1", color: "complementary", wordBreak: "break-word" }, schema.title),
27
27
  tooltip,
28
28
  React.createElement(ArrayRemoveButton, { name: input.name, headName: headName })),
29
29
  bottomDescription),
@@ -22,7 +22,7 @@ export const FormRow = ({ children, headName, input, meta, schema, props, }) =>
22
22
  }, [headName, schema.description, props.descriptionType]);
23
23
  return (React.createElement(LayoutContainer, { className: b(), direction: "row", alignItems: "flex-start", gap: 2, hidden: hidden },
24
24
  React.createElement("div", { className: b('left') },
25
- React.createElement(Text, { className: b('title', { required }), wordBreak: "break-word" }, schema.title),
25
+ React.createElement(Text, { className: b('title', { required }), variant: "subheader-1", color: "complementary", wordBreak: "break-word" }, schema.title),
26
26
  tooltip),
27
27
  React.createElement(Flex, { className: b('right'), direction: "column", gap: 0.5, grow: 1 },
28
28
  React.createElement(Flex, { grow: 1, gap: 2 },
@@ -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,8 +12,9 @@ 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
- 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]);
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(() => {
17
19
  if (schema.description) {
18
20
  return (React.createElement(HelpMark, null,
@@ -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,19 +33,19 @@ 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 },
38
- React.createElement(Text, { variant: "subheader-1", className: b('title', { required: required && !overviewFlag }) }, schema.title),
40
+ React.createElement(Text, { variant: "subheader-1", color: "complementary", className: b('title', { required: required && !overviewFlag }) }, schema.title),
39
41
  tooltip),
40
42
  React.createElement(Flex, { className: b('header-actions'), alignItems: "center", gap: 2 },
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
  };
@@ -28,7 +28,7 @@ export const Section = ({ children, headName, input, meta, mode, schema, props,
28
28
  React.createElement(Flex, { direction: "column", gap: 4 },
29
29
  React.createElement(Flex, { direction: "column" },
30
30
  React.createElement(Flex, { className: b('header'), gap: 2, alignItems: "center" },
31
- React.createElement(Text, Object.assign({ variant: "subheader-1" }, restLayoutProps, { className: b('title', { required: required && !overviewFlag }, restLayoutProps === null || restLayoutProps === void 0 ? void 0 : restLayoutProps.className) }), schema.title),
31
+ React.createElement(Text, Object.assign({ variant: "subheader-1", color: "complementary" }, restLayoutProps, { className: b('title', { required: required && !overviewFlag }, restLayoutProps === null || restLayoutProps === void 0 ? void 0 : restLayoutProps.className) }), schema.title),
32
32
  tooltip,
33
33
  overviewFlag ? (React.createElement(CopyButton, { className: b('copy-button'), copy: copy, value: input.value })) : null,
34
34
  overviewFlag ? null : (React.createElement(ArrayRemoveButton, { name: input.name, headName: headName }))),