@gravity-ui/dynamic-forms 2.7.2 → 2.8.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 (49) 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.js +2 -2
  7. package/build/cjs/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.css +3 -0
  8. package/build/cjs/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.js +19 -0
  9. package/build/cjs/lib/kit/components/GenerateRandomValueButton/index.js +4 -0
  10. package/build/cjs/lib/kit/components/Inputs/Text/Text.css +6 -0
  11. package/build/cjs/lib/kit/components/Inputs/Text/Text.js +20 -1
  12. package/build/cjs/lib/kit/components/Layouts/Row/Row.css +3 -4
  13. package/build/cjs/lib/kit/components/Layouts/Row/Row.js +4 -2
  14. package/build/cjs/lib/kit/components/Layouts/Row2/Row2.js +2 -0
  15. package/build/cjs/lib/kit/components/Layouts/Transparent/Transparent.js +2 -0
  16. package/build/cjs/lib/kit/components/index.js +1 -0
  17. package/build/cjs/lib/kit/i18n/en.json +2 -1
  18. package/build/cjs/lib/kit/i18n/ru.json +2 -1
  19. package/build/esm/lib/core/components/Form/DynamicField.d.ts +2 -1
  20. package/build/esm/lib/core/components/Form/DynamicField.js +3 -2
  21. package/build/esm/lib/core/components/Form/constants.d.ts +1 -0
  22. package/build/esm/lib/core/components/Form/constants.js +1 -0
  23. package/build/esm/lib/core/components/Form/hooks/index.d.ts +1 -0
  24. package/build/esm/lib/core/components/Form/hooks/index.js +1 -0
  25. package/build/esm/lib/core/components/Form/hooks/useGenerateRandomValue.d.ts +1 -0
  26. package/build/esm/lib/core/components/Form/hooks/useGenerateRandomValue.js +2 -0
  27. package/build/esm/lib/core/components/Form/types/context.d.ts +2 -0
  28. package/build/esm/lib/core/components/Form/utils/common.d.ts +2 -1
  29. package/build/esm/lib/core/components/Form/utils/common.js +5 -1
  30. package/build/esm/lib/core/types/specs.d.ts +1 -0
  31. package/build/esm/lib/kit/components/ErrorWrapper/ErrorWrapper.d.ts +1 -0
  32. package/build/esm/lib/kit/components/ErrorWrapper/ErrorWrapper.js +2 -2
  33. package/build/esm/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.css +3 -0
  34. package/build/esm/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.d.ts +9 -0
  35. package/build/esm/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.js +15 -0
  36. package/build/esm/lib/kit/components/GenerateRandomValueButton/index.d.ts +1 -0
  37. package/build/esm/lib/kit/components/GenerateRandomValueButton/index.js +1 -0
  38. package/build/esm/lib/kit/components/Inputs/Text/Text.css +6 -0
  39. package/build/esm/lib/kit/components/Inputs/Text/Text.d.ts +1 -0
  40. package/build/esm/lib/kit/components/Inputs/Text/Text.js +22 -2
  41. package/build/esm/lib/kit/components/Layouts/Row/Row.css +3 -4
  42. package/build/esm/lib/kit/components/Layouts/Row/Row.js +6 -4
  43. package/build/esm/lib/kit/components/Layouts/Row2/Row2.js +4 -2
  44. package/build/esm/lib/kit/components/Layouts/Transparent/Transparent.js +4 -2
  45. package/build/esm/lib/kit/components/index.d.ts +1 -0
  46. package/build/esm/lib/kit/components/index.js +1 -0
  47. package/build/esm/lib/kit/i18n/en.json +2 -1
  48. package/build/esm/lib/kit/i18n/ru.json +2 -1
  49. 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;
@@ -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;
@@ -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.0",
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",