@gravity-ui/dynamic-forms 2.7.2 → 2.8.1

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 (51) hide show
  1. package/build/cjs/lib/core/components/Form/DynamicField.js +3 -2
  2. package/build/cjs/lib/core/components/Form/constants.js +2 -1
  3. package/build/cjs/lib/core/components/Form/hooks/index.js +1 -0
  4. package/build/cjs/lib/core/components/Form/hooks/useGenerateRandomValue.js +6 -0
  5. package/build/cjs/lib/core/components/Form/utils/common.js +6 -1
  6. package/build/cjs/lib/kit/components/ErrorWrapper/ErrorWrapper.css +2 -0
  7. package/build/cjs/lib/kit/components/ErrorWrapper/ErrorWrapper.js +2 -2
  8. package/build/cjs/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.css +3 -0
  9. package/build/cjs/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.js +19 -0
  10. package/build/cjs/lib/kit/components/GenerateRandomValueButton/index.js +4 -0
  11. package/build/cjs/lib/kit/components/Inputs/Text/Text.css +6 -0
  12. package/build/cjs/lib/kit/components/Inputs/Text/Text.js +20 -1
  13. package/build/cjs/lib/kit/components/Layouts/Row/Row.css +3 -4
  14. package/build/cjs/lib/kit/components/Layouts/Row/Row.js +4 -2
  15. package/build/cjs/lib/kit/components/Layouts/Row2/Row2.js +2 -0
  16. package/build/cjs/lib/kit/components/Layouts/Transparent/Transparent.js +2 -0
  17. package/build/cjs/lib/kit/components/index.js +1 -0
  18. package/build/cjs/lib/kit/i18n/en.json +2 -1
  19. package/build/cjs/lib/kit/i18n/ru.json +2 -1
  20. package/build/esm/lib/core/components/Form/DynamicField.d.ts +2 -1
  21. package/build/esm/lib/core/components/Form/DynamicField.js +3 -2
  22. package/build/esm/lib/core/components/Form/constants.d.ts +1 -0
  23. package/build/esm/lib/core/components/Form/constants.js +1 -0
  24. package/build/esm/lib/core/components/Form/hooks/index.d.ts +1 -0
  25. package/build/esm/lib/core/components/Form/hooks/index.js +1 -0
  26. package/build/esm/lib/core/components/Form/hooks/useGenerateRandomValue.d.ts +1 -0
  27. package/build/esm/lib/core/components/Form/hooks/useGenerateRandomValue.js +2 -0
  28. package/build/esm/lib/core/components/Form/types/context.d.ts +2 -0
  29. package/build/esm/lib/core/components/Form/utils/common.d.ts +2 -1
  30. package/build/esm/lib/core/components/Form/utils/common.js +5 -1
  31. package/build/esm/lib/core/types/specs.d.ts +1 -0
  32. package/build/esm/lib/kit/components/ErrorWrapper/ErrorWrapper.css +2 -0
  33. package/build/esm/lib/kit/components/ErrorWrapper/ErrorWrapper.d.ts +1 -0
  34. package/build/esm/lib/kit/components/ErrorWrapper/ErrorWrapper.js +2 -2
  35. package/build/esm/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.css +3 -0
  36. package/build/esm/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.d.ts +9 -0
  37. package/build/esm/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.js +15 -0
  38. package/build/esm/lib/kit/components/GenerateRandomValueButton/index.d.ts +1 -0
  39. package/build/esm/lib/kit/components/GenerateRandomValueButton/index.js +1 -0
  40. package/build/esm/lib/kit/components/Inputs/Text/Text.css +6 -0
  41. package/build/esm/lib/kit/components/Inputs/Text/Text.d.ts +1 -0
  42. package/build/esm/lib/kit/components/Inputs/Text/Text.js +22 -2
  43. package/build/esm/lib/kit/components/Layouts/Row/Row.css +3 -4
  44. package/build/esm/lib/kit/components/Layouts/Row/Row.js +6 -4
  45. package/build/esm/lib/kit/components/Layouts/Row2/Row2.js +4 -2
  46. package/build/esm/lib/kit/components/Layouts/Transparent/Transparent.js +4 -2
  47. package/build/esm/lib/kit/components/index.d.ts +1 -0
  48. package/build/esm/lib/kit/components/index.js +1 -0
  49. package/build/esm/lib/kit/i18n/en.json +2 -1
  50. package/build/esm/lib/kit/i18n/ru.json +2 -1
  51. package/package.json +5 -2
@@ -9,7 +9,7 @@ const helpers_1 = require("../../helpers");
9
9
  const Controller_1 = require("./Controller");
10
10
  const hooks_1 = require("./hooks");
11
11
  const utils_1 = require("./utils");
12
- const DynamicField = ({ name, spec, config, Monaco, search, withoutInsertFFDebounce, __mirror, }) => {
12
+ const DynamicField = ({ name, spec, config, Monaco, generateRandomValue, search, withoutInsertFFDebounce, __mirror, }) => {
13
13
  const DynamicFormsCtx = (0, hooks_1.useCreateContext)();
14
14
  const SearchContext = (0, hooks_1.useCreateSearchContext)();
15
15
  const { tools, store } = (0, hooks_1.useStore)(name);
@@ -18,9 +18,10 @@ const DynamicField = ({ name, spec, config, Monaco, search, withoutInsertFFDebou
18
18
  const context = react_1.default.useMemo(() => ({
19
19
  config,
20
20
  Monaco: (0, react_is_1.isValidElementType)(Monaco) ? Monaco : undefined,
21
+ generateRandomValue,
21
22
  tools,
22
23
  __mirror,
23
- }), [tools, config, Monaco, __mirror]);
24
+ }), [tools, config, Monaco, __mirror, generateRandomValue]);
24
25
  const searchContext = react_1.default.useMemo(() => ({
25
26
  setField,
26
27
  removeField,
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OBJECT_ARRAY_CNT = exports.OBJECT_ARRAY_FLAG = void 0;
3
+ exports.SPEC_TYPE_FOR_GENERATE_BUTTON = exports.OBJECT_ARRAY_CNT = exports.OBJECT_ARRAY_FLAG = void 0;
4
4
  exports.OBJECT_ARRAY_FLAG = '____arr-obj';
5
5
  exports.OBJECT_ARRAY_CNT = '____arr-obj-cnt';
6
+ exports.SPEC_TYPE_FOR_GENERATE_BUTTON = ['base', 'password', 'textarea'];
@@ -7,6 +7,7 @@ tslib_1.__exportStar(require("./useCreateContext"), exports);
7
7
  tslib_1.__exportStar(require("./useDynamicFieldMirror"), exports);
8
8
  tslib_1.__exportStar(require("./useDynamicFormsCtx"), exports);
9
9
  tslib_1.__exportStar(require("./useField"), exports);
10
+ tslib_1.__exportStar(require("./useGenerateRandomValue"), exports);
10
11
  tslib_1.__exportStar(require("./useIntegrationFF"), exports);
11
12
  tslib_1.__exportStar(require("./useRender"), exports);
12
13
  tslib_1.__exportStar(require("./useStore"), exports);
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useGenerateRandomValue = void 0;
4
+ const useDynamicFormsCtx_1 = require("./useDynamicFormsCtx");
5
+ const useGenerateRandomValue = () => (0, useDynamicFormsCtx_1.useDynamicFormsCtx)().generateRandomValue;
6
+ exports.useGenerateRandomValue = useGenerateRandomValue;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isArrayItem = exports.transformArrOut = exports.transformArrIn = exports.isCorrectConfig = void 0;
3
+ exports.withGenerateButton = exports.isArrayItem = exports.transformArrOut = exports.transformArrIn = exports.isCorrectConfig = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
6
6
  const constants_1 = require("../../../constants");
7
+ const helpers_1 = require("../../../helpers");
7
8
  const constants_2 = require("../constants");
8
9
  const isCorrectConfig = (candidate) => Object.values(constants_1.SpecTypes).every((type) => lodash_1.default.isObjectLike(candidate) &&
9
10
  lodash_1.default.isObjectLike(candidate[type]) &&
@@ -49,3 +50,7 @@ const transformArrOut = (value) => {
49
50
  exports.transformArrOut = transformArrOut;
50
51
  const isArrayItem = (name) => name[name.length - 1] === '>';
51
52
  exports.isArrayItem = isArrayItem;
53
+ const withGenerateButton = (spec) => (0, helpers_1.isStringSpec)(spec) &&
54
+ constants_2.SPEC_TYPE_FOR_GENERATE_BUTTON.includes(spec.viewSpec.type) &&
55
+ spec.viewSpec.generateRandomValueButton;
56
+ exports.withGenerateButton = withGenerateButton;
@@ -11,6 +11,8 @@
11
11
  .df-error-wrapper_error .g-select:focus:not(.df-error-wrapper-ignore),
12
12
  .df-error-wrapper_error .g-select:not(.df-error-wrapper-ignore) .g-select-control::before,
13
13
  .df-error-wrapper_error .g-select:hover:not(.df-error-wrapper-ignore) .g-select-control_open::before,
14
+ .df-error-wrapper_error .g-text-area__content:not(.df-error-wrapper-ignore),
15
+ .df-error-wrapper_error .g-text-area__content:hover:not(.df-error-wrapper-ignore),
14
16
  .df-error-wrapper_error .yc-text-input_view_normal:not(.df-error-wrapper-ignore) .yc-text-input__control,
15
17
  .df-error-wrapper_error .yc-text-input_view_normal:not(.df-error-wrapper-ignore) .yc-text-input__content,
16
18
  .df-error-wrapper_error .yc-checkbox__indicator:not(.df-error-wrapper-ignore)::before {
@@ -5,7 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const utils_1 = require("../../utils");
7
7
  const b = (0, utils_1.block)('error-wrapper');
8
- const ErrorWrapper = ({ name, meta, withoutChildErrorStyles, children, }) => {
8
+ const ErrorWrapper = ({ name, meta, withoutChildErrorStyles, children, className, }) => {
9
9
  const error = react_1.default.useMemo(() => {
10
10
  if ((meta.touched || meta.submitFailed) && meta.error) {
11
11
  return meta.error;
@@ -13,7 +13,7 @@ const ErrorWrapper = ({ name, meta, withoutChildErrorStyles, children, }) => {
13
13
  return;
14
14
  }, [meta.touched, meta.submitFailed, meta.error]);
15
15
  const props = react_1.default.useMemo(() => (meta.error ? { 'data-form-error': true, 'data-form-error-name': name } : {}), [meta.error, name]);
16
- return (react_1.default.createElement("span", Object.assign({ className: b({ error: !withoutChildErrorStyles && Boolean(error) }) }, props),
16
+ return (react_1.default.createElement("span", Object.assign({ className: b({ error: !withoutChildErrorStyles && Boolean(error) }, className) }, props),
17
17
  children,
18
18
  error && typeof error === 'string' ? (react_1.default.createElement("div", { className: b('error-text') }, error)) : null));
19
19
  };
@@ -0,0 +1,3 @@
1
+ .df-generate-random-value-button {
2
+ margin-left: 8px;
3
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GenerateRandomValueButton = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const uikit_1 = require("@gravity-ui/uikit");
7
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
8
+ const hooks_1 = require("../../../core/components/Form/hooks");
9
+ const i18n_1 = tslib_1.__importDefault(require("../../i18n"));
10
+ const utils_1 = require("../../utils");
11
+ const b = (0, utils_1.block)('generate-random-value-button');
12
+ const GenerateRandomValueButton = ({ spec, onChange, }) => {
13
+ const generateRandomValue = (0, hooks_1.useGenerateRandomValue)();
14
+ if (lodash_1.default.isFunction(generateRandomValue) && spec.viewSpec.generateRandomValueButton) {
15
+ return (react_1.default.createElement(uikit_1.Button, { onClick: () => onChange(generateRandomValue(spec)), className: b() }, (0, i18n_1.default)('button-generate')));
16
+ }
17
+ return null;
18
+ };
19
+ exports.GenerateRandomValueButton = GenerateRandomValueButton;
@@ -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("./GenerateRandomValueButton"), exports);
@@ -0,0 +1,6 @@
1
+ .df-text {
2
+ display: flex;
3
+ }
4
+ .df-text__button {
5
+ --yc-button-background-color-hover: transparent;
6
+ }
@@ -3,10 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Text = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
+ const icons_1 = require("@gravity-ui/icons");
6
7
  const uikit_1 = require("@gravity-ui/uikit");
7
8
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
9
+ const utils_1 = require("../../../utils");
10
+ const b = (0, utils_1.block)('text');
8
11
  const Text = ({ name, input, spec }) => {
9
12
  const { value, onBlur, onChange, onFocus } = input;
13
+ const [hideValue, setHideValue] = react_1.default.useState(spec.viewSpec.type === 'password');
10
14
  const handleChange = react_1.default.useCallback((value) => {
11
15
  onChange(value);
12
16
  }, [onChange, spec]);
@@ -16,6 +20,21 @@ const Text = ({ name, input, spec }) => {
16
20
  }
17
21
  return 'text';
18
22
  }, [spec.viewSpec.type]);
19
- return (react_1.default.createElement(uikit_1.TextInput, { type: type, value: lodash_1.default.isNil(value) ? '' : `${value}`, hasClear: true, onBlur: onBlur, onFocus: onFocus, onUpdate: handleChange, disabled: spec.viewSpec.disabled, placeholder: spec.viewSpec.placeholder, autoComplete: type === 'password' ? 'new-password' : undefined, qa: name }));
23
+ const additionalRightContent = react_1.default.useMemo(() => {
24
+ if (type === 'password') {
25
+ const onClick = () => {
26
+ setHideValue((hideValue) => !hideValue);
27
+ };
28
+ return (react_1.default.createElement("div", { className: b() },
29
+ input.value ? (react_1.default.createElement(uikit_1.CopyToClipboard, { text: String(value), timeout: 500 }, (state) => (react_1.default.createElement(uikit_1.Button, { view: "flat-secondary", className: b('button'), size: "s" },
30
+ react_1.default.createElement(uikit_1.Icon, { size: 14, data: state === uikit_1.CopyToClipboardStatus.Pending
31
+ ? icons_1.Copy
32
+ : icons_1.CopyCheck }))))) : null,
33
+ react_1.default.createElement(uikit_1.Button, { view: "flat-secondary", onClick: onClick, className: b('button'), size: "s" },
34
+ react_1.default.createElement(uikit_1.Icon, { data: hideValue ? icons_1.Eye : icons_1.EyeSlash, size: 14 }))));
35
+ }
36
+ return undefined;
37
+ }, [hideValue, input.value, type, value]);
38
+ return (react_1.default.createElement(uikit_1.TextInput, { type: hideValue ? 'password' : 'text', value: lodash_1.default.isNil(value) ? '' : `${value}`, hasClear: true, onBlur: onBlur, onFocus: onFocus, onUpdate: handleChange, disabled: spec.viewSpec.disabled, placeholder: spec.viewSpec.placeholder, autoComplete: type === 'password' ? 'new-password' : undefined, qa: name, rightContent: additionalRightContent }));
20
39
  };
21
40
  exports.Text = Text;
@@ -7,10 +7,6 @@
7
7
  .df-row:last-child {
8
8
  margin-bottom: 0;
9
9
  }
10
- .df-row_extra-width {
11
- width: 533px;
12
- max-width: 533px;
13
- }
14
10
  .df-row__left {
15
11
  width: 180px;
16
12
  min-height: 28px;
@@ -70,4 +66,7 @@
70
66
  }
71
67
  .df-row__required-mark {
72
68
  color: var(--yc-color-text-danger);
69
+ }
70
+ .df-row__error-wrapper {
71
+ min-width: 100%;
73
72
  }
@@ -12,7 +12,8 @@ const utils_1 = require("../../../utils");
12
12
  const b = (0, utils_1.block)('row');
13
13
  const RowBase = ({ name, spec, input, meta, verboseDescription, children, }) => {
14
14
  const arrayItem = react_1.default.useMemo(() => (0, core_1.isArrayItem)(name), [name]);
15
- return (react_1.default.createElement("div", { className: b({ 'extra-width': (0, core_1.isArraySpec)(spec) || arrayItem }) },
15
+ const generateButton = react_1.default.useMemo(() => (0, core_1.withGenerateButton)(spec), [spec]);
16
+ return (react_1.default.createElement("div", { className: b() },
16
17
  react_1.default.createElement("div", { className: b('left') },
17
18
  react_1.default.createElement("div", { className: b('left-inner') },
18
19
  react_1.default.createElement("span", { className: b('title', { required: spec.required }) }, spec.viewSpec.layoutTitle),
@@ -21,7 +22,8 @@ const RowBase = ({ name, spec, input, meta, verboseDescription, children, }) =>
21
22
  react_1.default.createElement(components_1.HelpPopover, { htmlContent: spec.viewSpec.layoutDescription, placement: ['bottom', 'top'] })))) : null)),
22
23
  react_1.default.createElement("div", { className: b('right') },
23
24
  react_1.default.createElement("div", { className: b('right-inner') },
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
+ react_1.default.createElement(components_2.ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: (0, core_1.isArraySpec)(spec) || (0, core_1.isObjectSpec)(spec), className: b('error-wrapper') }, children),
26
+ generateButton ? (react_1.default.createElement(components_2.GenerateRandomValueButton, { spec: spec, onChange: input.onChange })) : null,
25
27
  arrayItem ? (react_1.default.createElement(uikit_1.Button, { view: "flat-secondary", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
26
28
  react_1.default.createElement(uikit_1.Icon, { data: icons_1.TrashBin, size: 16 }))) : null),
27
29
  verboseDescription && spec.viewSpec.layoutDescription ? (react_1.default.createElement("div", { className: b('description'), dangerouslySetInnerHTML: { __html: spec.viewSpec.layoutDescription } })) : null)));
@@ -10,6 +10,7 @@ const components_1 = require("../../../components");
10
10
  const utils_1 = require("../../../utils");
11
11
  const b = (0, utils_1.block)('row2');
12
12
  const Row2 = ({ name, spec, input, meta, children, }) => {
13
+ const generateButton = react_1.default.useMemo(() => (0, core_1.withGenerateButton)(spec), [spec]);
13
14
  return (react_1.default.createElement("div", { className: b() },
14
15
  react_1.default.createElement("div", { className: b('left') },
15
16
  react_1.default.createElement("div", { className: b('title') },
@@ -18,6 +19,7 @@ const Row2 = ({ name, spec, input, meta, children, }) => {
18
19
  react_1.default.createElement("div", { className: b('right') },
19
20
  react_1.default.createElement("div", { className: b('right-inner') },
20
21
  react_1.default.createElement(components_1.ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: (0, core_1.isArraySpec)(spec) || (0, core_1.isObjectSpec)(spec) }, children),
22
+ generateButton ? (react_1.default.createElement(components_1.GenerateRandomValueButton, { spec: spec, onChange: input.onChange })) : null,
21
23
  (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
24
  react_1.default.createElement(uikit_1.Icon, { data: icons_1.TrashBin, size: 16 }))) : null),
23
25
  spec.viewSpec.layoutDescription ? (react_1.default.createElement("div", { className: b('description'), dangerouslySetInnerHTML: { __html: spec.viewSpec.layoutDescription } })) : null)));
@@ -11,6 +11,7 @@ const utils_1 = require("../../../utils");
11
11
  const b = (0, utils_1.block)('transparent');
12
12
  const Transparent = ({ name, spec, input, meta, children, }) => {
13
13
  const arrayItem = react_1.default.useMemo(() => (0, core_1.isArrayItem)(name), [name]);
14
+ const generateButton = react_1.default.useMemo(() => (0, core_1.withGenerateButton)(spec), [spec]);
14
15
  const arrOrObjFlag = react_1.default.useMemo(() => (0, core_1.isArraySpec)(spec) || (0, core_1.isObjectSpec)(spec), [spec]);
15
16
  const removeButton = react_1.default.useMemo(() => {
16
17
  if (arrayItem) {
@@ -24,6 +25,7 @@ const Transparent = ({ name, spec, input, meta, children, }) => {
24
25
  'without-max-width': arrOrObjFlag,
25
26
  }) },
26
27
  react_1.default.createElement(components_1.ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: arrOrObjFlag }, children),
28
+ generateButton ? (react_1.default.createElement(components_1.GenerateRandomValueButton, { spec: spec, onChange: input.onChange })) : null,
27
29
  removeButton));
28
30
  };
29
31
  exports.Transparent = Transparent;
@@ -5,6 +5,7 @@ tslib_1.__exportStar(require("./AccordeonCard"), exports);
5
5
  tslib_1.__exportStar(require("./Card"), exports);
6
6
  tslib_1.__exportStar(require("./CopyButton"), exports);
7
7
  tslib_1.__exportStar(require("./ErrorWrapper"), exports);
8
+ tslib_1.__exportStar(require("./GenerateRandomValueButton"), exports);
8
9
  tslib_1.__exportStar(require("./GroupIndent"), exports);
9
10
  tslib_1.__exportStar(require("./Inputs"), exports);
10
11
  tslib_1.__exportStar(require("./Layouts"), exports);
@@ -44,5 +44,6 @@
44
44
  "label_delete": "Delete",
45
45
  "button_cancel": "Close",
46
46
  "button-upload_file": "Upload file",
47
- "label-data_loaded": "Data uploaded"
47
+ "label-data_loaded": "Data uploaded",
48
+ "button-generate": "Generate"
48
49
  }
@@ -44,5 +44,6 @@
44
44
  "label_delete": "Удалить",
45
45
  "button_cancel": "Закрыть",
46
46
  "button-upload_file": "Загрузить файл",
47
- "label-data_loaded": "Данные загружены"
47
+ "label-data_loaded": "Данные загружены",
48
+ "button-generate": "Сгенерировать"
48
49
  }
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { MonacoEditorProps } from 'react-monaco-editor/lib/types';
3
- import { Spec } from '../../types';
3
+ import { Spec, StringSpec } from '../../types';
4
4
  import { DynamicFormConfig, FieldValue, WonderMirror } from './types';
5
5
  export interface DynamicFieldProps {
6
6
  name: string;
@@ -8,6 +8,7 @@ export interface DynamicFieldProps {
8
8
  config: DynamicFormConfig;
9
9
  Monaco?: React.ComponentType<MonacoEditorProps>;
10
10
  search?: string | ((spec: Spec, input: FieldValue, name: string) => boolean);
11
+ generateRandomValue?: (spec: StringSpec) => string;
11
12
  withoutInsertFFDebounce?: boolean;
12
13
  __mirror?: WonderMirror;
13
14
  }
@@ -5,7 +5,7 @@ import { isCorrectSpec } from '../../helpers';
5
5
  import { Controller } from './Controller';
6
6
  import { useCreateContext, useCreateSearchContext, useDynamicFieldMirror, useIntegrationFF, useSearchStore, useStore, } from './hooks';
7
7
  import { getDefaultSearchFunction, isCorrectConfig } from './utils';
8
- export const DynamicField = ({ name, spec, config, Monaco, search, withoutInsertFFDebounce, __mirror, }) => {
8
+ export const DynamicField = ({ name, spec, config, Monaco, generateRandomValue, search, withoutInsertFFDebounce, __mirror, }) => {
9
9
  const DynamicFormsCtx = useCreateContext();
10
10
  const SearchContext = useCreateSearchContext();
11
11
  const { tools, store } = useStore(name);
@@ -14,9 +14,10 @@ export const DynamicField = ({ name, spec, config, Monaco, search, withoutInsert
14
14
  const context = React.useMemo(() => ({
15
15
  config,
16
16
  Monaco: isValidElementType(Monaco) ? Monaco : undefined,
17
+ generateRandomValue,
17
18
  tools,
18
19
  __mirror,
19
- }), [tools, config, Monaco, __mirror]);
20
+ }), [tools, config, Monaco, __mirror, generateRandomValue]);
20
21
  const searchContext = React.useMemo(() => ({
21
22
  setField,
22
23
  removeField,
@@ -1,2 +1,3 @@
1
1
  export declare const OBJECT_ARRAY_FLAG = "____arr-obj";
2
2
  export declare const OBJECT_ARRAY_CNT = "____arr-obj-cnt";
3
+ export declare const SPEC_TYPE_FOR_GENERATE_BUTTON: string[];
@@ -1,2 +1,3 @@
1
1
  export const OBJECT_ARRAY_FLAG = '____arr-obj';
2
2
  export const OBJECT_ARRAY_CNT = '____arr-obj-cnt';
3
+ export const SPEC_TYPE_FOR_GENERATE_BUTTON = ['base', 'password', 'textarea'];
@@ -4,6 +4,7 @@ export * from './useCreateContext';
4
4
  export * from './useDynamicFieldMirror';
5
5
  export * from './useDynamicFormsCtx';
6
6
  export * from './useField';
7
+ export * from './useGenerateRandomValue';
7
8
  export * from './useIntegrationFF';
8
9
  export * from './useRender';
9
10
  export * from './useStore';
@@ -4,6 +4,7 @@ export * from './useCreateContext';
4
4
  export * from './useDynamicFieldMirror';
5
5
  export * from './useDynamicFormsCtx';
6
6
  export * from './useField';
7
+ export * from './useGenerateRandomValue';
7
8
  export * from './useIntegrationFF';
8
9
  export * from './useRender';
9
10
  export * from './useStore';
@@ -0,0 +1 @@
1
+ export declare const useGenerateRandomValue: () => ((spec: import("../../..").StringSpec<any>) => string) | undefined;
@@ -0,0 +1,2 @@
1
+ import { useDynamicFormsCtx } from './useDynamicFormsCtx';
2
+ export const useGenerateRandomValue = () => useDynamicFormsCtx().generateRandomValue;
@@ -1,9 +1,11 @@
1
1
  import React from 'react';
2
2
  import type { MonacoEditorProps } from 'react-monaco-editor/lib/types';
3
+ import { StringSpec } from '../../../types';
3
4
  import { DynamicFormConfig, FieldValue, ValidateError, WonderMirror } from './';
4
5
  export interface DynamicFormsContext {
5
6
  config: DynamicFormConfig;
6
7
  Monaco?: React.ComponentType<MonacoEditorProps>;
8
+ generateRandomValue?: (spec: StringSpec) => string;
7
9
  tools: {
8
10
  initialValue: FieldValue;
9
11
  onChange: (name: string, value: FieldValue, errors?: Record<string, ValidateError>) => void;
@@ -1,5 +1,6 @@
1
- import { FormValue } from '../../../types';
1
+ import { FormValue, Spec } from '../../../types';
2
2
  export declare const isCorrectConfig: (candidate: any) => boolean;
3
3
  export declare const transformArrIn: <Type extends FormValue, ReturnType_1 extends FormValue = Type>(value: Type) => ReturnType_1;
4
4
  export declare const transformArrOut: <Type extends FormValue, ReturnType_1 extends FormValue = Type>(value: Type) => ReturnType_1;
5
5
  export declare const isArrayItem: (name: string) => boolean;
6
+ export declare const withGenerateButton: (spec: Spec) => boolean | undefined;
@@ -1,6 +1,7 @@
1
1
  import _ from 'lodash';
2
2
  import { SpecTypes } from '../../../constants';
3
- import { OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG } from '../constants';
3
+ import { isStringSpec } from '../../../helpers';
4
+ import { OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, SPEC_TYPE_FOR_GENERATE_BUTTON } from '../constants';
4
5
  export const isCorrectConfig = (candidate) => Object.values(SpecTypes).every((type) => _.isObjectLike(candidate) &&
5
6
  _.isObjectLike(candidate[type]) &&
6
7
  _.isObjectLike(candidate[type].inputs) &&
@@ -41,3 +42,6 @@ export const transformArrOut = (value) => {
41
42
  return value;
42
43
  };
43
44
  export const isArrayItem = (name) => name[name.length - 1] === '>';
45
+ export const withGenerateButton = (spec) => isStringSpec(spec) &&
46
+ SPEC_TYPE_FOR_GENERATE_BUTTON.includes(spec.viewSpec.type) &&
47
+ spec.viewSpec.generateRandomValueButton;
@@ -145,6 +145,7 @@ export interface StringSpec<LinkType = any> {
145
145
  filterPlaceholder?: string;
146
146
  meta?: Record<string, string>;
147
147
  };
148
+ generateRandomValueButton?: boolean;
148
149
  };
149
150
  }
150
151
  export type Spec = ArraySpec | BooleanSpec | NumberSpec | ObjectSpec | StringSpec;
@@ -11,6 +11,8 @@
11
11
  .df-error-wrapper_error .g-select:focus:not(.df-error-wrapper-ignore),
12
12
  .df-error-wrapper_error .g-select:not(.df-error-wrapper-ignore) .g-select-control::before,
13
13
  .df-error-wrapper_error .g-select:hover:not(.df-error-wrapper-ignore) .g-select-control_open::before,
14
+ .df-error-wrapper_error .g-text-area__content:not(.df-error-wrapper-ignore),
15
+ .df-error-wrapper_error .g-text-area__content:hover:not(.df-error-wrapper-ignore),
14
16
  .df-error-wrapper_error .yc-text-input_view_normal:not(.df-error-wrapper-ignore) .yc-text-input__control,
15
17
  .df-error-wrapper_error .yc-text-input_view_normal:not(.df-error-wrapper-ignore) .yc-text-input__content,
16
18
  .df-error-wrapper_error .yc-checkbox__indicator:not(.df-error-wrapper-ignore)::before {
@@ -6,5 +6,6 @@ export interface ErrorWrapperProps {
6
6
  name: string;
7
7
  meta: FieldRenderProps<FieldValue>['meta'];
8
8
  withoutChildErrorStyles?: boolean;
9
+ className?: string;
9
10
  }
10
11
  export declare const ErrorWrapper: React.FC<ErrorWrapperProps>;
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { block } from '../../utils';
3
3
  import './ErrorWrapper.css';
4
4
  const b = block('error-wrapper');
5
- export const ErrorWrapper = ({ name, meta, withoutChildErrorStyles, children, }) => {
5
+ export const ErrorWrapper = ({ name, meta, withoutChildErrorStyles, children, className, }) => {
6
6
  const error = React.useMemo(() => {
7
7
  if ((meta.touched || meta.submitFailed) && meta.error) {
8
8
  return meta.error;
@@ -10,7 +10,7 @@ export const ErrorWrapper = ({ name, meta, withoutChildErrorStyles, children, })
10
10
  return;
11
11
  }, [meta.touched, meta.submitFailed, meta.error]);
12
12
  const props = React.useMemo(() => (meta.error ? { 'data-form-error': true, 'data-form-error-name': name } : {}), [meta.error, name]);
13
- return (React.createElement("span", Object.assign({ className: b({ error: !withoutChildErrorStyles && Boolean(error) }) }, props),
13
+ return (React.createElement("span", Object.assign({ className: b({ error: !withoutChildErrorStyles && Boolean(error) }, className) }, props),
14
14
  children,
15
15
  error && typeof error === 'string' ? (React.createElement("div", { className: b('error-text') }, error)) : null));
16
16
  };
@@ -0,0 +1,3 @@
1
+ .df-generate-random-value-button {
2
+ margin-left: 8px;
3
+ }
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { StringSpec } from '../../../core/types';
3
+ import './GenerateRandomValueButton.css';
4
+ interface GenerateRandomValueButtonProps {
5
+ spec: StringSpec;
6
+ onChange: (value: string) => void;
7
+ }
8
+ export declare const GenerateRandomValueButton: React.FC<GenerateRandomValueButtonProps>;
9
+ export {};
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { Button } from '@gravity-ui/uikit';
3
+ import _ from 'lodash';
4
+ import { useGenerateRandomValue } from '../../../core/components/Form/hooks';
5
+ import i18n from '../../i18n';
6
+ import { block } from '../../utils';
7
+ import './GenerateRandomValueButton.css';
8
+ const b = block('generate-random-value-button');
9
+ export const GenerateRandomValueButton = ({ spec, onChange, }) => {
10
+ const generateRandomValue = useGenerateRandomValue();
11
+ if (_.isFunction(generateRandomValue) && spec.viewSpec.generateRandomValueButton) {
12
+ return (React.createElement(Button, { onClick: () => onChange(generateRandomValue(spec)), className: b() }, i18n('button-generate')));
13
+ }
14
+ return null;
15
+ };
@@ -0,0 +1 @@
1
+ export * from './GenerateRandomValueButton';
@@ -0,0 +1 @@
1
+ export * from './GenerateRandomValueButton';
@@ -0,0 +1,6 @@
1
+ .df-text {
2
+ display: flex;
3
+ }
4
+ .df-text__button {
5
+ --yc-button-background-color-hover: transparent;
6
+ }
@@ -1,2 +1,3 @@
1
1
  import { NumberInputProps, StringInputProps } from '../../../../core';
2
+ import './Text.css';
2
3
  export declare const Text: <T extends NumberInputProps | StringInputProps>({ name, input, spec }: T) => JSX.Element;
@@ -1,8 +1,13 @@
1
1
  import React from 'react';
2
- import { TextInput } from '@gravity-ui/uikit';
2
+ import { Copy, CopyCheck, Eye, EyeSlash } from '@gravity-ui/icons';
3
+ import { Button, CopyToClipboard, CopyToClipboardStatus, Icon, TextInput } from '@gravity-ui/uikit';
3
4
  import _ from 'lodash';
5
+ import { block } from '../../../utils';
6
+ import './Text.css';
7
+ const b = block('text');
4
8
  export const Text = ({ name, input, spec }) => {
5
9
  const { value, onBlur, onChange, onFocus } = input;
10
+ const [hideValue, setHideValue] = React.useState(spec.viewSpec.type === 'password');
6
11
  const handleChange = React.useCallback((value) => {
7
12
  onChange(value);
8
13
  }, [onChange, spec]);
@@ -12,5 +17,20 @@ export const Text = ({ name, input, spec }) => {
12
17
  }
13
18
  return 'text';
14
19
  }, [spec.viewSpec.type]);
15
- return (React.createElement(TextInput, { type: type, value: _.isNil(value) ? '' : `${value}`, hasClear: true, onBlur: onBlur, onFocus: onFocus, onUpdate: handleChange, disabled: spec.viewSpec.disabled, placeholder: spec.viewSpec.placeholder, autoComplete: type === 'password' ? 'new-password' : undefined, qa: name }));
20
+ const additionalRightContent = React.useMemo(() => {
21
+ if (type === 'password') {
22
+ const onClick = () => {
23
+ setHideValue((hideValue) => !hideValue);
24
+ };
25
+ return (React.createElement("div", { className: b() },
26
+ input.value ? (React.createElement(CopyToClipboard, { text: String(value), timeout: 500 }, (state) => (React.createElement(Button, { view: "flat-secondary", className: b('button'), size: "s" },
27
+ React.createElement(Icon, { size: 14, data: state === CopyToClipboardStatus.Pending
28
+ ? Copy
29
+ : CopyCheck }))))) : null,
30
+ React.createElement(Button, { view: "flat-secondary", onClick: onClick, className: b('button'), size: "s" },
31
+ React.createElement(Icon, { data: hideValue ? Eye : EyeSlash, size: 14 }))));
32
+ }
33
+ return undefined;
34
+ }, [hideValue, input.value, type, value]);
35
+ return (React.createElement(TextInput, { type: hideValue ? 'password' : 'text', value: _.isNil(value) ? '' : `${value}`, hasClear: true, onBlur: onBlur, onFocus: onFocus, onUpdate: handleChange, disabled: spec.viewSpec.disabled, placeholder: spec.viewSpec.placeholder, autoComplete: type === 'password' ? 'new-password' : undefined, qa: name, rightContent: additionalRightContent }));
16
36
  };
@@ -7,10 +7,6 @@
7
7
  .df-row:last-child {
8
8
  margin-bottom: 0;
9
9
  }
10
- .df-row_extra-width {
11
- width: 533px;
12
- max-width: 533px;
13
- }
14
10
  .df-row__left {
15
11
  width: 180px;
16
12
  min-height: 28px;
@@ -70,4 +66,7 @@
70
66
  }
71
67
  .df-row__required-mark {
72
68
  color: var(--yc-color-text-danger);
69
+ }
70
+ .df-row__error-wrapper {
71
+ min-width: 100%;
73
72
  }
@@ -2,14 +2,15 @@ import React from 'react';
2
2
  import { HelpPopover } from '@gravity-ui/components';
3
3
  import { TrashBin } from '@gravity-ui/icons';
4
4
  import { Button, Icon } from '@gravity-ui/uikit';
5
- import { isArrayItem, isArraySpec, isObjectSpec, } from '../../../../core';
6
- import { ErrorWrapper } from '../../../components';
5
+ import { isArrayItem, isArraySpec, isObjectSpec, withGenerateButton, } from '../../../../core';
6
+ import { ErrorWrapper, GenerateRandomValueButton } from '../../../components';
7
7
  import { block } from '../../../utils';
8
8
  import './Row.css';
9
9
  const b = block('row');
10
10
  const RowBase = ({ name, spec, input, meta, verboseDescription, children, }) => {
11
11
  const arrayItem = React.useMemo(() => isArrayItem(name), [name]);
12
- return (React.createElement("div", { className: b({ 'extra-width': isArraySpec(spec) || arrayItem }) },
12
+ const generateButton = React.useMemo(() => withGenerateButton(spec), [spec]);
13
+ return (React.createElement("div", { className: b() },
13
14
  React.createElement("div", { className: b('left') },
14
15
  React.createElement("div", { className: b('left-inner') },
15
16
  React.createElement("span", { className: b('title', { required: spec.required }) }, spec.viewSpec.layoutTitle),
@@ -18,7 +19,8 @@ const RowBase = ({ name, spec, input, meta, verboseDescription, children, }) =>
18
19
  React.createElement(HelpPopover, { htmlContent: spec.viewSpec.layoutDescription, placement: ['bottom', 'top'] })))) : null)),
19
20
  React.createElement("div", { className: b('right') },
20
21
  React.createElement("div", { className: b('right-inner') },
21
- React.createElement(ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: isArraySpec(spec) || isObjectSpec(spec) }, children),
22
+ React.createElement(ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: isArraySpec(spec) || isObjectSpec(spec), className: b('error-wrapper') }, children),
23
+ generateButton ? (React.createElement(GenerateRandomValueButton, { spec: spec, onChange: input.onChange })) : null,
22
24
  arrayItem ? (React.createElement(Button, { view: "flat-secondary", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
23
25
  React.createElement(Icon, { data: TrashBin, size: 16 }))) : null),
24
26
  verboseDescription && spec.viewSpec.layoutDescription ? (React.createElement("div", { className: b('description'), dangerouslySetInnerHTML: { __html: spec.viewSpec.layoutDescription } })) : null)));
@@ -1,12 +1,13 @@
1
1
  import React from 'react';
2
2
  import { TrashBin } from '@gravity-ui/icons';
3
3
  import { Button, Icon } from '@gravity-ui/uikit';
4
- import { isArrayItem, isArraySpec, isObjectSpec, } from '../../../../core';
5
- import { ErrorWrapper } from '../../../components';
4
+ import { isArrayItem, isArraySpec, isObjectSpec, withGenerateButton, } from '../../../../core';
5
+ import { ErrorWrapper, GenerateRandomValueButton } from '../../../components';
6
6
  import { block } from '../../../utils';
7
7
  import './Row2.css';
8
8
  const b = block('row2');
9
9
  export const Row2 = ({ name, spec, input, meta, children, }) => {
10
+ const generateButton = React.useMemo(() => withGenerateButton(spec), [spec]);
10
11
  return (React.createElement("div", { className: b() },
11
12
  React.createElement("div", { className: b('left') },
12
13
  React.createElement("div", { className: b('title') },
@@ -15,6 +16,7 @@ export const Row2 = ({ name, spec, input, meta, children, }) => {
15
16
  React.createElement("div", { className: b('right') },
16
17
  React.createElement("div", { className: b('right-inner') },
17
18
  React.createElement(ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: isArraySpec(spec) || isObjectSpec(spec) }, children),
19
+ generateButton ? (React.createElement(GenerateRandomValueButton, { spec: spec, onChange: input.onChange })) : null,
18
20
  isArrayItem(name) ? (React.createElement(Button, { view: "flat-secondary", className: b('remove-button'), onClick: input.onDrop, qa: `${name}-remove-item` },
19
21
  React.createElement(Icon, { data: TrashBin, size: 16 }))) : null),
20
22
  spec.viewSpec.layoutDescription ? (React.createElement("div", { className: b('description'), dangerouslySetInnerHTML: { __html: spec.viewSpec.layoutDescription } })) : null)));
@@ -1,13 +1,14 @@
1
1
  import React from 'react';
2
2
  import { TrashBin } from '@gravity-ui/icons';
3
3
  import { Button, Icon } from '@gravity-ui/uikit';
4
- import { isArrayItem, isArraySpec, isObjectSpec, } from '../../../../core';
5
- import { ErrorWrapper } from '../../../components';
4
+ import { isArrayItem, isArraySpec, isObjectSpec, withGenerateButton, } from '../../../../core';
5
+ import { ErrorWrapper, GenerateRandomValueButton } from '../../../components';
6
6
  import { block } from '../../../utils';
7
7
  import './Transparent.css';
8
8
  const b = block('transparent');
9
9
  export const Transparent = ({ name, spec, input, meta, children, }) => {
10
10
  const arrayItem = React.useMemo(() => isArrayItem(name), [name]);
11
+ const generateButton = React.useMemo(() => withGenerateButton(spec), [spec]);
11
12
  const arrOrObjFlag = React.useMemo(() => isArraySpec(spec) || isObjectSpec(spec), [spec]);
12
13
  const removeButton = React.useMemo(() => {
13
14
  if (arrayItem) {
@@ -21,5 +22,6 @@ export const Transparent = ({ name, spec, input, meta, children, }) => {
21
22
  'without-max-width': arrOrObjFlag,
22
23
  }) },
23
24
  React.createElement(ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: arrOrObjFlag }, children),
25
+ generateButton ? (React.createElement(GenerateRandomValueButton, { spec: spec, onChange: input.onChange })) : null,
24
26
  removeButton));
25
27
  };
@@ -2,6 +2,7 @@ export * from './AccordeonCard';
2
2
  export * from './Card';
3
3
  export * from './CopyButton';
4
4
  export * from './ErrorWrapper';
5
+ export * from './GenerateRandomValueButton';
5
6
  export * from './GroupIndent';
6
7
  export * from './Inputs';
7
8
  export * from './Layouts';
@@ -2,6 +2,7 @@ export * from './AccordeonCard';
2
2
  export * from './Card';
3
3
  export * from './CopyButton';
4
4
  export * from './ErrorWrapper';
5
+ export * from './GenerateRandomValueButton';
5
6
  export * from './GroupIndent';
6
7
  export * from './Inputs';
7
8
  export * from './Layouts';
@@ -44,5 +44,6 @@
44
44
  "label_delete": "Delete",
45
45
  "button_cancel": "Close",
46
46
  "button-upload_file": "Upload file",
47
- "label-data_loaded": "Data uploaded"
47
+ "label-data_loaded": "Data uploaded",
48
+ "button-generate": "Generate"
48
49
  }
@@ -44,5 +44,6 @@
44
44
  "label_delete": "Удалить",
45
45
  "button_cancel": "Закрыть",
46
46
  "button-upload_file": "Загрузить файл",
47
- "label-data_loaded": "Данные загружены"
47
+ "label-data_loaded": "Данные загружены",
48
+ "button-generate": "Сгенерировать"
48
49
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dynamic-forms",
3
- "version": "2.7.2",
3
+ "version": "2.8.1",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "main": "build/cjs/index.js",
@@ -65,6 +65,7 @@
65
65
  "@types/react": "^18.0.28",
66
66
  "@types/react-dom": "^18.0.11",
67
67
  "@types/react-is": "^17.0.3",
68
+ "@types/uuid": "^9.0.4",
68
69
  "css-loader": "^5.2.6",
69
70
  "eslint": "^8.27.0",
70
71
  "final-form": "^4.20.2",
@@ -82,6 +83,7 @@
82
83
  "npm-run-all": "^4.1.5",
83
84
  "postcss": "^8.4.19",
84
85
  "prettier": "^2.7.1",
86
+ "randexp": "^0.5.3",
85
87
  "react": "^18.2.0",
86
88
  "react-dom": "^18.2.0",
87
89
  "react-final-form": "^6.5.3",
@@ -95,7 +97,8 @@
95
97
  "stylelint": "^14.15.0",
96
98
  "stylelint-scss": "^4.2.0",
97
99
  "ts-jest": "^29.0.5",
98
- "typescript": "^4.9.5"
100
+ "typescript": "^4.9.5",
101
+ "uuid": "^9.0.1"
99
102
  },
100
103
  "peerDependencies": {
101
104
  "@gravity-ui/uikit": "^5.0.0",