@gravity-ui/dynamic-forms 2.1.1 → 2.3.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 (32) hide show
  1. package/build/cjs/lib/kit/components/ErrorWrapper/ErrorWrapper.css +2 -2
  2. package/build/cjs/lib/kit/components/Inputs/ArrayBase/ArrayBase.css +14 -0
  3. package/build/cjs/lib/kit/components/Inputs/ArrayBase/ArrayBase.js +56 -22
  4. package/build/cjs/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +2 -2
  5. package/build/cjs/lib/kit/components/Layouts/Row/Row.js +2 -2
  6. package/build/cjs/lib/kit/components/Layouts/Row2/Row2.js +2 -2
  7. package/build/cjs/lib/kit/components/Layouts/Transparent/Transparent.js +2 -2
  8. package/build/cjs/lib/kit/components/SimpleVerticalAccordeon/SimpleVerticalAccordeon.css +1 -1
  9. package/build/cjs/lib/kit/components/Views/ArrayBaseView/ArrayBaseView.css +4 -0
  10. package/build/cjs/lib/kit/components/Views/{ArrayBaseView.js → ArrayBaseView/ArrayBaseView.js} +9 -3
  11. package/build/cjs/lib/kit/components/Views/ArrayBaseView/index.js +4 -0
  12. package/build/cjs/lib/kit/utils/common.js +6 -3
  13. package/build/cjs/lib/kit/validators/validators.js +2 -1
  14. package/build/esm/lib/core/types/specs.d.ts +2 -0
  15. package/build/esm/lib/kit/components/ErrorWrapper/ErrorWrapper.css +2 -2
  16. package/build/esm/lib/kit/components/Inputs/ArrayBase/ArrayBase.css +14 -0
  17. package/build/esm/lib/kit/components/Inputs/ArrayBase/ArrayBase.d.ts +1 -0
  18. package/build/esm/lib/kit/components/Inputs/ArrayBase/ArrayBase.js +58 -23
  19. package/build/esm/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +3 -3
  20. package/build/esm/lib/kit/components/Layouts/Row/Row.js +3 -3
  21. package/build/esm/lib/kit/components/Layouts/Row2/Row2.js +3 -3
  22. package/build/esm/lib/kit/components/Layouts/Transparent/Transparent.js +3 -3
  23. package/build/esm/lib/kit/components/SimpleVerticalAccordeon/SimpleVerticalAccordeon.css +1 -1
  24. package/build/esm/lib/kit/components/Views/ArrayBaseView/ArrayBaseView.css +4 -0
  25. package/build/esm/lib/kit/components/Views/ArrayBaseView/ArrayBaseView.d.ts +3 -0
  26. package/build/esm/lib/kit/components/Views/{ArrayBaseView.js → ArrayBaseView/ArrayBaseView.js} +10 -3
  27. package/build/esm/lib/kit/components/Views/ArrayBaseView/index.d.ts +1 -0
  28. package/build/esm/lib/kit/components/Views/ArrayBaseView/index.js +1 -0
  29. package/build/esm/lib/kit/utils/common.js +6 -3
  30. package/build/esm/lib/kit/validators/validators.js +2 -1
  31. package/package.json +1 -1
  32. package/build/esm/lib/kit/components/Views/ArrayBaseView.d.ts +0 -2
@@ -19,6 +19,6 @@
19
19
  .df-error-wrapper__error-text {
20
20
  color: var(--yc-color-text-danger);
21
21
  margin-top: 2px;
22
- font-size: var(--yc-text-body-font-size);
23
- line-height: var(--yc-text-body-line-height);
22
+ font-size: var(--yc-text-body-1-font-size);
23
+ line-height: var(--yc-text-body-1-line-height);
24
24
  }
@@ -0,0 +1,14 @@
1
+ .df-array-base_add-button-right {
2
+ display: flex;
3
+ align-items: flex-end;
4
+ }
5
+ .df-array-base__items-wrapper_add-button-down {
6
+ margin-bottom: 15px;
7
+ }
8
+ .df-array-base__item-prefix {
9
+ margin-top: -7px;
10
+ margin-bottom: 8px;
11
+ }
12
+ .df-array-base__add-button_right {
13
+ margin-left: 4px;
14
+ }
@@ -7,25 +7,14 @@ const icons_1 = require("@gravity-ui/icons");
7
7
  const uikit_1 = require("@gravity-ui/uikit");
8
8
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
9
9
  const core_1 = require("../../../../core");
10
+ const utils_1 = require("../../../utils");
11
+ const b = (0, utils_1.block)('array-base');
10
12
  const ArrayBase = ({ spec, name, arrayInput, input }) => {
11
13
  const keys = react_1.default.useMemo(() => Object.keys(arrayInput.value || {})
12
14
  .filter((k) => k !== core_1.OBJECT_ARRAY_FLAG && k !== core_1.OBJECT_ARRAY_CNT)
13
15
  .map((k) => k.split('<').join('').split('>').join(''))
14
16
  .sort((a, b) => Number(a) - Number(b)), [arrayInput.value]);
15
17
  const itemSpecCorrect = react_1.default.useMemo(() => (0, core_1.isCorrectSpec)(spec.items), [spec.items]);
16
- const onItemAdd = react_1.default.useCallback(() => {
17
- var _a;
18
- let item;
19
- if (!((_a = spec.items) === null || _a === void 0 ? void 0 : _a.required)) {
20
- if ((0, core_1.isArraySpec)(spec.items)) {
21
- item = { [core_1.OBJECT_ARRAY_FLAG]: true, [core_1.OBJECT_ARRAY_CNT]: 0 };
22
- }
23
- else if ((0, core_1.isObjectSpec)(spec.items)) {
24
- item = {};
25
- }
26
- }
27
- arrayInput.onItemAdd(item);
28
- }, [arrayInput.onItemAdd, spec.items]);
29
18
  const getItemSpec = react_1.default.useCallback((idx) => {
30
19
  if (!itemSpecCorrect) {
31
20
  return null;
@@ -37,23 +26,68 @@ const ArrayBase = ({ spec, name, arrayInput, input }) => {
37
26
  return itemSpec;
38
27
  }, [spec.items, itemSpecCorrect]);
39
28
  const parentOnChange = react_1.default.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => lodash_1.default.set(Object.assign({}, currentValue), childName.split(`${input.name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
29
+ const AddButton = react_1.default.useCallback(() => {
30
+ let onClick = () => {
31
+ var _a;
32
+ let item;
33
+ if (!((_a = spec.items) === null || _a === void 0 ? void 0 : _a.required)) {
34
+ if ((0, core_1.isArraySpec)(spec.items)) {
35
+ item = { [core_1.OBJECT_ARRAY_FLAG]: true, [core_1.OBJECT_ARRAY_CNT]: 0 };
36
+ }
37
+ else if ((0, core_1.isObjectSpec)(spec.items)) {
38
+ item = {};
39
+ }
40
+ }
41
+ arrayInput.onItemAdd(item);
42
+ };
43
+ let qa = `${name}-add-item`;
44
+ let title = spec.viewSpec.itemLabel;
45
+ if (!arrayInput.value && spec.defaultValue) {
46
+ onClick = () => {
47
+ input.onChange((0, core_1.transformArrIn)(spec.defaultValue));
48
+ };
49
+ qa = `${name}-init-arr`;
50
+ title = spec.viewSpec.layoutTitle;
51
+ }
52
+ return (react_1.default.createElement(uikit_1.Button, { onClick: onClick, disabled: spec.viewSpec.disabled, qa: qa, className: b('add-button', { right: spec.viewSpec.addButtonPosition === 'right' }) },
53
+ react_1.default.createElement(uikit_1.Icon, { data: icons_1.Plus, size: 14 }),
54
+ title || null));
55
+ }, [
56
+ arrayInput,
57
+ input,
58
+ name,
59
+ spec.defaultValue,
60
+ spec.items,
61
+ spec.viewSpec.disabled,
62
+ spec.viewSpec.itemLabel,
63
+ spec.viewSpec.layoutTitle,
64
+ ]);
40
65
  const items = react_1.default.useMemo(() => keys.map((key, idx) => {
41
66
  var _a;
42
67
  const itemSpec = getItemSpec(idx);
43
68
  if (!itemSpec) {
44
69
  return null;
45
70
  }
46
- return (react_1.default.createElement(core_1.Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[`<${key}>`], parentOnChange: parentOnChange, parentOnUnmount: input.parentOnUnmount, spec: itemSpec, name: `${name}.<${key}>`, key: `${name}.<${key}>` }));
47
- }), [keys.join(''), name, getItemSpec, parentOnChange, input.parentOnUnmount, input.value]);
71
+ const showItemPrefix = idx !== 0 && spec.viewSpec.itemPrefix;
72
+ return (react_1.default.createElement(react_1.default.Fragment, { key: `${name}.<${key}>` },
73
+ showItemPrefix ? (react_1.default.createElement(uikit_1.Label, { size: "m", className: b('item-prefix') }, spec.viewSpec.itemPrefix)) : null,
74
+ react_1.default.createElement(core_1.Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[`<${key}>`], parentOnChange: parentOnChange, parentOnUnmount: input.parentOnUnmount, spec: itemSpec, name: `${name}.<${key}>` })));
75
+ }), [
76
+ keys.join(''),
77
+ name,
78
+ getItemSpec,
79
+ parentOnChange,
80
+ input.parentOnUnmount,
81
+ input.value,
82
+ spec.viewSpec.itemPrefix,
83
+ ]);
48
84
  if (!itemSpecCorrect) {
49
85
  return null;
50
86
  }
51
- return (react_1.default.createElement(react_1.default.Fragment, null,
52
- items,
53
- !arrayInput.value && spec.defaultValue ? (react_1.default.createElement(uikit_1.Button, { onClick: () => input.onChange((0, core_1.transformArrIn)(spec.defaultValue)), disabled: spec.viewSpec.disabled, qa: `${name}-init-arr` },
54
- react_1.default.createElement(uikit_1.Icon, { data: icons_1.Plus, size: 14 }),
55
- spec.viewSpec.layoutTitle || null)) : (react_1.default.createElement(uikit_1.Button, { onClick: onItemAdd, disabled: spec.viewSpec.disabled, qa: `${name}-add-item` },
56
- react_1.default.createElement(uikit_1.Icon, { data: icons_1.Plus, size: 14 }),
57
- spec.viewSpec.itemLabel || null))));
87
+ return (react_1.default.createElement("div", { className: b({ 'add-button-right': spec.viewSpec.addButtonPosition === 'right' }) },
88
+ react_1.default.createElement("div", { className: b('items-wrapper', {
89
+ 'add-button-down': spec.viewSpec.addButtonPosition !== 'right' && keys.length > 0,
90
+ }) }, items),
91
+ react_1.default.createElement(AddButton, null)));
58
92
  };
59
93
  exports.ArrayBase = ArrayBase;
@@ -41,8 +41,8 @@ const TableArrayInput = ({ spec, name, arrayInput, input }) => {
41
41
  id: 'remove',
42
42
  name: '',
43
43
  sticky: 'right',
44
- template: ({ key }) => (react_1.default.createElement(uikit_1.Button, { view: "flat", onClick: () => onItemRemove(key), key: `remove-${key}`, qa: `${name}-item-remove-${key}` },
45
- react_1.default.createElement(uikit_1.Icon, { data: icons_1.Xmark, size: 16 }))),
44
+ template: ({ key }) => (react_1.default.createElement(uikit_1.Button, { view: "flat-secondary", onClick: () => onItemRemove(key), key: `remove-${key}`, qa: `${name}-item-remove-${key}` },
45
+ react_1.default.createElement(uikit_1.Icon, { data: icons_1.TrashBin, size: 16 }))),
46
46
  };
47
47
  const columns = table.map(({ property, label }) => ({
48
48
  id: property,
@@ -22,8 +22,8 @@ const RowBase = ({ name, spec, input, meta, verboseDescription, children, }) =>
22
22
  react_1.default.createElement("div", { className: b('right') },
23
23
  react_1.default.createElement("div", { className: b('right-inner') },
24
24
  react_1.default.createElement(components_2.ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: (0, core_1.isArraySpec)(spec) || (0, core_1.isObjectSpec)(spec) }, children),
25
- arrayItem ? (react_1.default.createElement(uikit_1.Button, { view: "flat", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
26
- react_1.default.createElement(uikit_1.Icon, { data: icons_1.Xmark, size: 16 }))) : null),
25
+ arrayItem ? (react_1.default.createElement(uikit_1.Button, { view: "flat-secondary", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
26
+ react_1.default.createElement(uikit_1.Icon, { data: icons_1.TrashBin, size: 16 }))) : null),
27
27
  verboseDescription && spec.viewSpec.layoutDescription ? (react_1.default.createElement("div", { className: b('description'), dangerouslySetInnerHTML: { __html: spec.viewSpec.layoutDescription } })) : null)));
28
28
  };
29
29
  const Row = (props) => (react_1.default.createElement(RowBase, Object.assign({}, props)));
@@ -18,8 +18,8 @@ const Row2 = ({ name, spec, input, meta, children, }) => {
18
18
  react_1.default.createElement("div", { className: b('right') },
19
19
  react_1.default.createElement("div", { className: b('right-inner') },
20
20
  react_1.default.createElement(components_1.ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: (0, core_1.isArraySpec)(spec) || (0, core_1.isObjectSpec)(spec) }, children),
21
- (0, core_1.isArrayItem)(name) ? (react_1.default.createElement(uikit_1.Button, { view: "flat", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
22
- react_1.default.createElement(uikit_1.Icon, { data: icons_1.Xmark, size: 16 }))) : null),
21
+ (0, core_1.isArrayItem)(name) ? (react_1.default.createElement(uikit_1.Button, { view: "flat-secondary", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
22
+ react_1.default.createElement(uikit_1.Icon, { data: icons_1.TrashBin, size: 16 }))) : null),
23
23
  spec.viewSpec.layoutDescription ? (react_1.default.createElement("div", { className: b('description'), dangerouslySetInnerHTML: { __html: spec.viewSpec.layoutDescription } })) : null)));
24
24
  };
25
25
  exports.Row2 = Row2;
@@ -14,8 +14,8 @@ const Transparent = ({ name, spec, input, meta, children, }) => {
14
14
  const arrOrObjFlag = react_1.default.useMemo(() => (0, core_1.isArraySpec)(spec) || (0, core_1.isObjectSpec)(spec), [spec]);
15
15
  const removeButton = react_1.default.useMemo(() => {
16
16
  if (arrayItem) {
17
- return (react_1.default.createElement(uikit_1.Button, { view: "flat", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
18
- react_1.default.createElement(uikit_1.Icon, { data: icons_1.Xmark, size: 16 })));
17
+ return (react_1.default.createElement(uikit_1.Button, { view: "flat-secondary", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
18
+ react_1.default.createElement(uikit_1.Icon, { data: icons_1.TrashBin, size: 16 })));
19
19
  }
20
20
  return null;
21
21
  }, [input.onDrop, arrayItem, name]);
@@ -22,7 +22,7 @@
22
22
  }
23
23
  .df-simple-vertical-accordeon__title_size_s {
24
24
  margin-bottom: 0;
25
- font-size: var(--yc-text-body-font-size);
25
+ font-size: var(--yc-text-body-1-font-size);
26
26
  }
27
27
  .df-simple-vertical-accordeon__title_size_m {
28
28
  margin-bottom: 1px;
@@ -0,0 +1,4 @@
1
+ .df-array-base-view__item-prefix {
2
+ margin-top: -10px;
3
+ margin-bottom: 15px;
4
+ }
@@ -3,8 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ArrayBaseView = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
+ const uikit_1 = require("@gravity-ui/uikit");
6
7
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
7
- const core_1 = require("../../../core");
8
+ const core_1 = require("../../../../core");
9
+ const utils_1 = require("../../../utils");
10
+ const b = (0, utils_1.block)('array-base-view');
8
11
  const ArrayBaseView = ({ spec, name, value = [] }) => {
9
12
  const itemSpecCorrect = react_1.default.useMemo(() => (0, core_1.isCorrectSpec)(spec.items), [spec.items]);
10
13
  const getItemSpec = react_1.default.useCallback((idx) => {
@@ -22,8 +25,11 @@ const ArrayBaseView = ({ spec, name, value = [] }) => {
22
25
  if (!itemSpec) {
23
26
  return null;
24
27
  }
25
- return (react_1.default.createElement(core_1.ViewController, { spec: itemSpec, name: `${name}[${idx}]`, key: `${name}[${idx}]` }));
26
- }), [value.length, name, getItemSpec]);
28
+ const showItemPrefix = idx !== 0 && spec.viewSpec.itemPrefix;
29
+ return (react_1.default.createElement(react_1.default.Fragment, { key: `${name}[${idx}]` },
30
+ showItemPrefix ? (react_1.default.createElement(uikit_1.Label, { size: "m", className: b('item-prefix') }, spec.viewSpec.itemPrefix)) : null,
31
+ react_1.default.createElement(core_1.ViewController, { spec: itemSpec, name: `${name}[${idx}]` })));
32
+ }), [value.length, name, getItemSpec, spec.viewSpec.itemPrefix]);
27
33
  if (!itemSpecCorrect) {
28
34
  return null;
29
35
  }
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./ArrayBaseView"), exports);
@@ -36,7 +36,7 @@ const isNotEmptyValue = (value, spec) => {
36
36
  };
37
37
  exports.isNotEmptyValue = isNotEmptyValue;
38
38
  const prepareSpec = (spec, parseJsonDefaultValue) => {
39
- var _a, _b, _c;
39
+ var _a, _b, _c, _d;
40
40
  if (lodash_1.default.isObjectLike(spec)) {
41
41
  const result = lodash_1.default.cloneDeep(spec);
42
42
  if (lodash_1.default.isString(result.type)) {
@@ -48,7 +48,7 @@ const prepareSpec = (spec, parseJsonDefaultValue) => {
48
48
  try {
49
49
  _defaultValue = JSON.parse(result.defaultValue);
50
50
  }
51
- catch (_d) {
51
+ catch (_e) {
52
52
  _defaultValue = undefined;
53
53
  }
54
54
  }
@@ -66,7 +66,10 @@ const prepareSpec = (spec, parseJsonDefaultValue) => {
66
66
  if (lodash_1.default.isString((_b = result.viewSpec) === null || _b === void 0 ? void 0 : _b.layout)) {
67
67
  result.viewSpec.layout = result.viewSpec.layout.toLowerCase();
68
68
  }
69
- if (lodash_1.default.isString((_c = result.viewSpec) === null || _c === void 0 ? void 0 : _c.themeLabel)) {
69
+ if (lodash_1.default.isString((_c = result.viewSpec) === null || _c === void 0 ? void 0 : _c.addButtonPosition)) {
70
+ result.viewSpec.addButtonPosition = result.viewSpec.addButtonPosition.toLowerCase();
71
+ }
72
+ if (lodash_1.default.isString((_d = result.viewSpec) === null || _d === void 0 ? void 0 : _d.themeLabel)) {
70
73
  result.viewSpec.themeLabel = result.viewSpec.themeLabel.toLowerCase();
71
74
  }
72
75
  if (lodash_1.default.isString(result.validator)) {
@@ -72,7 +72,8 @@ const getNumberValidator = (params = {}) => {
72
72
  }
73
73
  if (!ignoreMinimumCheck &&
74
74
  lodash_1.default.isNumber(spec.minimum) &&
75
- ((stringValue.length && spec.minimum > Number(stringValue)) || !stringValue.length)) {
75
+ stringValue.length &&
76
+ spec.minimum > Number(stringValue)) {
76
77
  return validators_1.ErrorMessages.minNumber(spec.minimum);
77
78
  }
78
79
  if (lodash_1.default.isString(spec.format) && stringValue.length) {
@@ -19,12 +19,14 @@ export interface ArraySpec<LinkType = any> {
19
19
  layoutDescription?: string;
20
20
  layoutOpen?: boolean;
21
21
  itemLabel?: string;
22
+ itemPrefix?: string;
22
23
  table?: {
23
24
  label: string;
24
25
  property: string;
25
26
  }[];
26
27
  link?: LinkType;
27
28
  placeholder?: string;
29
+ addButtonPosition?: 'down' | 'right';
28
30
  };
29
31
  }
30
32
  export interface BooleanSpec<LinkType = any> {
@@ -19,6 +19,6 @@
19
19
  .df-error-wrapper__error-text {
20
20
  color: var(--yc-color-text-danger);
21
21
  margin-top: 2px;
22
- font-size: var(--yc-text-body-font-size);
23
- line-height: var(--yc-text-body-line-height);
22
+ font-size: var(--yc-text-body-1-font-size);
23
+ line-height: var(--yc-text-body-1-line-height);
24
24
  }
@@ -0,0 +1,14 @@
1
+ .df-array-base_add-button-right {
2
+ display: flex;
3
+ align-items: flex-end;
4
+ }
5
+ .df-array-base__items-wrapper_add-button-down {
6
+ margin-bottom: 15px;
7
+ }
8
+ .df-array-base__item-prefix {
9
+ margin-top: -7px;
10
+ margin-bottom: 8px;
11
+ }
12
+ .df-array-base__add-button_right {
13
+ margin-left: 4px;
14
+ }
@@ -1,2 +1,3 @@
1
1
  import { ArrayInput } from '../../../../core';
2
+ import './ArrayBase.css';
2
3
  export declare const ArrayBase: ArrayInput;
@@ -1,27 +1,17 @@
1
1
  import React from 'react';
2
2
  import { Plus } from '@gravity-ui/icons';
3
- import { Button, Icon } from '@gravity-ui/uikit';
3
+ import { Button, Icon, Label } from '@gravity-ui/uikit';
4
4
  import _ from 'lodash';
5
5
  import { Controller, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, isArraySpec, isCorrectSpec, isObjectSpec, transformArrIn, } from '../../../../core';
6
+ import { block } from '../../../utils';
7
+ import './ArrayBase.css';
8
+ const b = block('array-base');
6
9
  export const ArrayBase = ({ spec, name, arrayInput, input }) => {
7
10
  const keys = React.useMemo(() => Object.keys(arrayInput.value || {})
8
11
  .filter((k) => k !== OBJECT_ARRAY_FLAG && k !== OBJECT_ARRAY_CNT)
9
12
  .map((k) => k.split('<').join('').split('>').join(''))
10
13
  .sort((a, b) => Number(a) - Number(b)), [arrayInput.value]);
11
14
  const itemSpecCorrect = React.useMemo(() => isCorrectSpec(spec.items), [spec.items]);
12
- const onItemAdd = React.useCallback(() => {
13
- var _a;
14
- let item;
15
- if (!((_a = spec.items) === null || _a === void 0 ? void 0 : _a.required)) {
16
- if (isArraySpec(spec.items)) {
17
- item = { [OBJECT_ARRAY_FLAG]: true, [OBJECT_ARRAY_CNT]: 0 };
18
- }
19
- else if (isObjectSpec(spec.items)) {
20
- item = {};
21
- }
22
- }
23
- arrayInput.onItemAdd(item);
24
- }, [arrayInput.onItemAdd, spec.items]);
25
15
  const getItemSpec = React.useCallback((idx) => {
26
16
  if (!itemSpecCorrect) {
27
17
  return null;
@@ -33,22 +23,67 @@ export const ArrayBase = ({ spec, name, arrayInput, input }) => {
33
23
  return itemSpec;
34
24
  }, [spec.items, itemSpecCorrect]);
35
25
  const parentOnChange = React.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${input.name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
26
+ const AddButton = React.useCallback(() => {
27
+ let onClick = () => {
28
+ var _a;
29
+ let item;
30
+ if (!((_a = spec.items) === null || _a === void 0 ? void 0 : _a.required)) {
31
+ if (isArraySpec(spec.items)) {
32
+ item = { [OBJECT_ARRAY_FLAG]: true, [OBJECT_ARRAY_CNT]: 0 };
33
+ }
34
+ else if (isObjectSpec(spec.items)) {
35
+ item = {};
36
+ }
37
+ }
38
+ arrayInput.onItemAdd(item);
39
+ };
40
+ let qa = `${name}-add-item`;
41
+ let title = spec.viewSpec.itemLabel;
42
+ if (!arrayInput.value && spec.defaultValue) {
43
+ onClick = () => {
44
+ input.onChange(transformArrIn(spec.defaultValue));
45
+ };
46
+ qa = `${name}-init-arr`;
47
+ title = spec.viewSpec.layoutTitle;
48
+ }
49
+ return (React.createElement(Button, { onClick: onClick, disabled: spec.viewSpec.disabled, qa: qa, className: b('add-button', { right: spec.viewSpec.addButtonPosition === 'right' }) },
50
+ React.createElement(Icon, { data: Plus, size: 14 }),
51
+ title || null));
52
+ }, [
53
+ arrayInput,
54
+ input,
55
+ name,
56
+ spec.defaultValue,
57
+ spec.items,
58
+ spec.viewSpec.disabled,
59
+ spec.viewSpec.itemLabel,
60
+ spec.viewSpec.layoutTitle,
61
+ ]);
36
62
  const items = React.useMemo(() => keys.map((key, idx) => {
37
63
  var _a;
38
64
  const itemSpec = getItemSpec(idx);
39
65
  if (!itemSpec) {
40
66
  return null;
41
67
  }
42
- return (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[`<${key}>`], parentOnChange: parentOnChange, parentOnUnmount: input.parentOnUnmount, spec: itemSpec, name: `${name}.<${key}>`, key: `${name}.<${key}>` }));
43
- }), [keys.join(''), name, getItemSpec, parentOnChange, input.parentOnUnmount, input.value]);
68
+ const showItemPrefix = idx !== 0 && spec.viewSpec.itemPrefix;
69
+ return (React.createElement(React.Fragment, { key: `${name}.<${key}>` },
70
+ showItemPrefix ? (React.createElement(Label, { size: "m", className: b('item-prefix') }, spec.viewSpec.itemPrefix)) : null,
71
+ React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[`<${key}>`], parentOnChange: parentOnChange, parentOnUnmount: input.parentOnUnmount, spec: itemSpec, name: `${name}.<${key}>` })));
72
+ }), [
73
+ keys.join(''),
74
+ name,
75
+ getItemSpec,
76
+ parentOnChange,
77
+ input.parentOnUnmount,
78
+ input.value,
79
+ spec.viewSpec.itemPrefix,
80
+ ]);
44
81
  if (!itemSpecCorrect) {
45
82
  return null;
46
83
  }
47
- return (React.createElement(React.Fragment, null,
48
- items,
49
- !arrayInput.value && spec.defaultValue ? (React.createElement(Button, { onClick: () => input.onChange(transformArrIn(spec.defaultValue)), disabled: spec.viewSpec.disabled, qa: `${name}-init-arr` },
50
- React.createElement(Icon, { data: Plus, size: 14 }),
51
- spec.viewSpec.layoutTitle || null)) : (React.createElement(Button, { onClick: onItemAdd, disabled: spec.viewSpec.disabled, qa: `${name}-add-item` },
52
- React.createElement(Icon, { data: Plus, size: 14 }),
53
- spec.viewSpec.itemLabel || null))));
84
+ return (React.createElement("div", { className: b({ 'add-button-right': spec.viewSpec.addButtonPosition === 'right' }) },
85
+ React.createElement("div", { className: b('items-wrapper', {
86
+ 'add-button-down': spec.viewSpec.addButtonPosition !== 'right' && keys.length > 0,
87
+ }) }, items),
88
+ React.createElement(AddButton, null)));
54
89
  };
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Plus, Xmark } from '@gravity-ui/icons';
2
+ import { Plus, TrashBin } from '@gravity-ui/icons';
3
3
  import { Button, Icon, Table } from '@gravity-ui/uikit';
4
4
  import _ from 'lodash';
5
5
  import { Controller, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, isArraySpec, isBooleanSpec, isObjectSpec, transformArrIn, } from '../../../../core';
@@ -38,8 +38,8 @@ export const TableArrayInput = ({ spec, name, arrayInput, input }) => {
38
38
  id: 'remove',
39
39
  name: '',
40
40
  sticky: 'right',
41
- template: ({ key }) => (React.createElement(Button, { view: "flat", onClick: () => onItemRemove(key), key: `remove-${key}`, qa: `${name}-item-remove-${key}` },
42
- React.createElement(Icon, { data: Xmark, size: 16 }))),
41
+ template: ({ key }) => (React.createElement(Button, { view: "flat-secondary", onClick: () => onItemRemove(key), key: `remove-${key}`, qa: `${name}-item-remove-${key}` },
42
+ React.createElement(Icon, { data: TrashBin, size: 16 }))),
43
43
  };
44
44
  const columns = table.map(({ property, label }) => ({
45
45
  id: property,
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { HelpPopover } from '@gravity-ui/components';
3
- import { Xmark } from '@gravity-ui/icons';
3
+ import { TrashBin } from '@gravity-ui/icons';
4
4
  import { Button, Icon } from '@gravity-ui/uikit';
5
5
  import { isArrayItem, isArraySpec, isObjectSpec, } from '../../../../core';
6
6
  import { ErrorWrapper } from '../../../components';
@@ -19,8 +19,8 @@ const RowBase = ({ name, spec, input, meta, verboseDescription, children, }) =>
19
19
  React.createElement("div", { className: b('right') },
20
20
  React.createElement("div", { className: b('right-inner') },
21
21
  React.createElement(ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: isArraySpec(spec) || isObjectSpec(spec) }, children),
22
- arrayItem ? (React.createElement(Button, { view: "flat", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
23
- React.createElement(Icon, { data: Xmark, size: 16 }))) : null),
22
+ arrayItem ? (React.createElement(Button, { view: "flat-secondary", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
23
+ React.createElement(Icon, { data: TrashBin, size: 16 }))) : null),
24
24
  verboseDescription && spec.viewSpec.layoutDescription ? (React.createElement("div", { className: b('description'), dangerouslySetInnerHTML: { __html: spec.viewSpec.layoutDescription } })) : null)));
25
25
  };
26
26
  export const Row = (props) => (React.createElement(RowBase, Object.assign({}, props)));
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Xmark } from '@gravity-ui/icons';
2
+ import { TrashBin } from '@gravity-ui/icons';
3
3
  import { Button, Icon } from '@gravity-ui/uikit';
4
4
  import { isArrayItem, isArraySpec, isObjectSpec, } from '../../../../core';
5
5
  import { ErrorWrapper } from '../../../components';
@@ -15,7 +15,7 @@ export const Row2 = ({ name, spec, input, meta, children, }) => {
15
15
  React.createElement("div", { className: b('right') },
16
16
  React.createElement("div", { className: b('right-inner') },
17
17
  React.createElement(ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: isArraySpec(spec) || isObjectSpec(spec) }, children),
18
- isArrayItem(name) ? (React.createElement(Button, { view: "flat", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
19
- React.createElement(Icon, { data: Xmark, size: 16 }))) : null),
18
+ isArrayItem(name) ? (React.createElement(Button, { view: "flat-secondary", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
19
+ React.createElement(Icon, { data: TrashBin, size: 16 }))) : null),
20
20
  spec.viewSpec.layoutDescription ? (React.createElement("div", { className: b('description'), dangerouslySetInnerHTML: { __html: spec.viewSpec.layoutDescription } })) : null)));
21
21
  };
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Xmark } from '@gravity-ui/icons';
2
+ import { TrashBin } from '@gravity-ui/icons';
3
3
  import { Button, Icon } from '@gravity-ui/uikit';
4
4
  import { isArrayItem, isArraySpec, isObjectSpec, } from '../../../../core';
5
5
  import { ErrorWrapper } from '../../../components';
@@ -11,8 +11,8 @@ export const Transparent = ({ name, spec, input, meta, children, }) => {
11
11
  const arrOrObjFlag = React.useMemo(() => isArraySpec(spec) || isObjectSpec(spec), [spec]);
12
12
  const removeButton = React.useMemo(() => {
13
13
  if (arrayItem) {
14
- return (React.createElement(Button, { view: "flat", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
15
- React.createElement(Icon, { data: Xmark, size: 16 })));
14
+ return (React.createElement(Button, { view: "flat-secondary", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
15
+ React.createElement(Icon, { data: TrashBin, size: 16 })));
16
16
  }
17
17
  return null;
18
18
  }, [input.onDrop, arrayItem, name]);
@@ -22,7 +22,7 @@
22
22
  }
23
23
  .df-simple-vertical-accordeon__title_size_s {
24
24
  margin-bottom: 0;
25
- font-size: var(--yc-text-body-font-size);
25
+ font-size: var(--yc-text-body-1-font-size);
26
26
  }
27
27
  .df-simple-vertical-accordeon__title_size_m {
28
28
  margin-bottom: 1px;
@@ -0,0 +1,4 @@
1
+ .df-array-base-view__item-prefix {
2
+ margin-top: -10px;
3
+ margin-bottom: 15px;
4
+ }
@@ -0,0 +1,3 @@
1
+ import { ArrayView } from '../../../../core';
2
+ import './ArrayBaseView.css';
3
+ export declare const ArrayBaseView: ArrayView;
@@ -1,6 +1,10 @@
1
1
  import React from 'react';
2
+ import { Label } from '@gravity-ui/uikit';
2
3
  import _ from 'lodash';
3
- import { ViewController, isCorrectSpec } from '../../../core';
4
+ import { ViewController, isCorrectSpec } from '../../../../core';
5
+ import { block } from '../../../utils';
6
+ import './ArrayBaseView.css';
7
+ const b = block('array-base-view');
4
8
  export const ArrayBaseView = ({ spec, name, value = [] }) => {
5
9
  const itemSpecCorrect = React.useMemo(() => isCorrectSpec(spec.items), [spec.items]);
6
10
  const getItemSpec = React.useCallback((idx) => {
@@ -18,8 +22,11 @@ export const ArrayBaseView = ({ spec, name, value = [] }) => {
18
22
  if (!itemSpec) {
19
23
  return null;
20
24
  }
21
- return (React.createElement(ViewController, { spec: itemSpec, name: `${name}[${idx}]`, key: `${name}[${idx}]` }));
22
- }), [value.length, name, getItemSpec]);
25
+ const showItemPrefix = idx !== 0 && spec.viewSpec.itemPrefix;
26
+ return (React.createElement(React.Fragment, { key: `${name}[${idx}]` },
27
+ showItemPrefix ? (React.createElement(Label, { size: "m", className: b('item-prefix') }, spec.viewSpec.itemPrefix)) : null,
28
+ React.createElement(ViewController, { spec: itemSpec, name: `${name}[${idx}]` })));
29
+ }), [value.length, name, getItemSpec, spec.viewSpec.itemPrefix]);
23
30
  if (!itemSpecCorrect) {
24
31
  return null;
25
32
  }
@@ -0,0 +1 @@
1
+ export * from './ArrayBaseView';
@@ -0,0 +1 @@
1
+ export * from './ArrayBaseView';
@@ -31,7 +31,7 @@ export const isNotEmptyValue = (value, spec) => {
31
31
  return true;
32
32
  };
33
33
  export const prepareSpec = (spec, parseJsonDefaultValue) => {
34
- var _a, _b, _c;
34
+ var _a, _b, _c, _d;
35
35
  if (_.isObjectLike(spec)) {
36
36
  const result = _.cloneDeep(spec);
37
37
  if (_.isString(result.type)) {
@@ -43,7 +43,7 @@ export const prepareSpec = (spec, parseJsonDefaultValue) => {
43
43
  try {
44
44
  _defaultValue = JSON.parse(result.defaultValue);
45
45
  }
46
- catch (_d) {
46
+ catch (_e) {
47
47
  _defaultValue = undefined;
48
48
  }
49
49
  }
@@ -61,7 +61,10 @@ export const prepareSpec = (spec, parseJsonDefaultValue) => {
61
61
  if (_.isString((_b = result.viewSpec) === null || _b === void 0 ? void 0 : _b.layout)) {
62
62
  result.viewSpec.layout = result.viewSpec.layout.toLowerCase();
63
63
  }
64
- if (_.isString((_c = result.viewSpec) === null || _c === void 0 ? void 0 : _c.themeLabel)) {
64
+ if (_.isString((_c = result.viewSpec) === null || _c === void 0 ? void 0 : _c.addButtonPosition)) {
65
+ result.viewSpec.addButtonPosition = result.viewSpec.addButtonPosition.toLowerCase();
66
+ }
67
+ if (_.isString((_d = result.viewSpec) === null || _d === void 0 ? void 0 : _d.themeLabel)) {
65
68
  result.viewSpec.themeLabel = result.viewSpec.themeLabel.toLowerCase();
66
69
  }
67
70
  if (_.isString(result.validator)) {
@@ -66,7 +66,8 @@ export const getNumberValidator = (params = {}) => {
66
66
  }
67
67
  if (!ignoreMinimumCheck &&
68
68
  _.isNumber(spec.minimum) &&
69
- ((stringValue.length && spec.minimum > Number(stringValue)) || !stringValue.length)) {
69
+ stringValue.length &&
70
+ spec.minimum > Number(stringValue)) {
70
71
  return ErrorMessages.minNumber(spec.minimum);
71
72
  }
72
73
  if (_.isString(spec.format) && stringValue.length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dynamic-forms",
3
- "version": "2.1.1",
3
+ "version": "2.3.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "main": "build/cjs/index.js",
@@ -1,2 +0,0 @@
1
- import { ArrayView } from '../../../core';
2
- export declare const ArrayBaseView: ArrayView;