@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.
- package/build/cjs/lib/core/components/Form/DynamicField.js +3 -2
- package/build/cjs/lib/core/components/Form/constants.js +2 -1
- package/build/cjs/lib/core/components/Form/hooks/index.js +1 -0
- package/build/cjs/lib/core/components/Form/hooks/useGenerateRandomValue.js +6 -0
- package/build/cjs/lib/core/components/Form/utils/common.js +6 -1
- package/build/cjs/lib/kit/components/ErrorWrapper/ErrorWrapper.js +2 -2
- package/build/cjs/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.css +3 -0
- package/build/cjs/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.js +19 -0
- package/build/cjs/lib/kit/components/GenerateRandomValueButton/index.js +4 -0
- package/build/cjs/lib/kit/components/Inputs/Text/Text.css +6 -0
- package/build/cjs/lib/kit/components/Inputs/Text/Text.js +20 -1
- package/build/cjs/lib/kit/components/Layouts/Row/Row.css +3 -4
- package/build/cjs/lib/kit/components/Layouts/Row/Row.js +4 -2
- package/build/cjs/lib/kit/components/Layouts/Row2/Row2.js +2 -0
- package/build/cjs/lib/kit/components/Layouts/Transparent/Transparent.js +2 -0
- package/build/cjs/lib/kit/components/index.js +1 -0
- package/build/cjs/lib/kit/i18n/en.json +2 -1
- package/build/cjs/lib/kit/i18n/ru.json +2 -1
- package/build/esm/lib/core/components/Form/DynamicField.d.ts +2 -1
- package/build/esm/lib/core/components/Form/DynamicField.js +3 -2
- package/build/esm/lib/core/components/Form/constants.d.ts +1 -0
- package/build/esm/lib/core/components/Form/constants.js +1 -0
- package/build/esm/lib/core/components/Form/hooks/index.d.ts +1 -0
- package/build/esm/lib/core/components/Form/hooks/index.js +1 -0
- package/build/esm/lib/core/components/Form/hooks/useGenerateRandomValue.d.ts +1 -0
- package/build/esm/lib/core/components/Form/hooks/useGenerateRandomValue.js +2 -0
- package/build/esm/lib/core/components/Form/types/context.d.ts +2 -0
- package/build/esm/lib/core/components/Form/utils/common.d.ts +2 -1
- package/build/esm/lib/core/components/Form/utils/common.js +5 -1
- package/build/esm/lib/core/types/specs.d.ts +1 -0
- package/build/esm/lib/kit/components/ErrorWrapper/ErrorWrapper.d.ts +1 -0
- package/build/esm/lib/kit/components/ErrorWrapper/ErrorWrapper.js +2 -2
- package/build/esm/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.css +3 -0
- package/build/esm/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.d.ts +9 -0
- package/build/esm/lib/kit/components/GenerateRandomValueButton/GenerateRandomValueButton.js +15 -0
- package/build/esm/lib/kit/components/GenerateRandomValueButton/index.d.ts +1 -0
- package/build/esm/lib/kit/components/GenerateRandomValueButton/index.js +1 -0
- package/build/esm/lib/kit/components/Inputs/Text/Text.css +6 -0
- package/build/esm/lib/kit/components/Inputs/Text/Text.d.ts +1 -0
- package/build/esm/lib/kit/components/Inputs/Text/Text.js +22 -2
- package/build/esm/lib/kit/components/Layouts/Row/Row.css +3 -4
- package/build/esm/lib/kit/components/Layouts/Row/Row.js +6 -4
- package/build/esm/lib/kit/components/Layouts/Row2/Row2.js +4 -2
- package/build/esm/lib/kit/components/Layouts/Transparent/Transparent.js +4 -2
- package/build/esm/lib/kit/components/index.d.ts +1 -0
- package/build/esm/lib/kit/components/index.js +1 -0
- package/build/esm/lib/kit/i18n/en.json +2 -1
- package/build/esm/lib/kit/i18n/ru.json +2 -1
- 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,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;
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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);
|
|
@@ -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,
|
|
@@ -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;
|
|
@@ -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 {
|
|
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;
|
|
@@ -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,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';
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/dynamic-forms",
|
|
3
|
-
"version": "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",
|