@gravity-ui/dynamic-forms 1.8.0 → 1.9.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/CHANGELOG.md +16 -0
- package/build/cjs/lib/core/components/Form/DynamicField.js +2 -2
- package/build/cjs/lib/core/components/Form/constants.js +1 -2
- package/build/cjs/lib/core/components/Form/hooks/useField.js +17 -13
- package/build/cjs/lib/core/components/Form/hooks/useIntegrationFF.js +19 -4
- package/build/cjs/lib/core/components/Form/utils/common.js +1 -3
- package/build/cjs/lib/kit/components/CopyButton/CopyButton.css +4 -0
- package/build/cjs/lib/kit/components/CopyButton/CopyButton.js +20 -0
- package/build/cjs/lib/kit/components/CopyButton/index.js +4 -0
- package/build/cjs/lib/kit/components/Inputs/ArrayBase/ArrayBase.js +3 -6
- package/build/cjs/lib/kit/components/Inputs/CardOneOf/CardOneOf.js +1 -2
- package/build/cjs/lib/kit/components/Inputs/ObjectBase/ObjectBase.js +2 -3
- package/build/cjs/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.js +1 -2
- package/build/cjs/lib/kit/components/Inputs/OneOf/OneOf.js +1 -2
- package/build/cjs/lib/kit/components/Inputs/OneOfCard/OneOfCard.js +1 -2
- package/build/cjs/lib/kit/components/Inputs/Secret/Secret.js +1 -2
- package/build/cjs/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +3 -6
- package/build/cjs/lib/kit/components/Inputs/TextLink/TextLink.js +1 -2
- package/build/cjs/lib/kit/components/ViewLayouts/ViewRow/ViewRow.css +3 -0
- package/build/cjs/lib/kit/components/ViewLayouts/ViewRow/ViewRow.js +3 -1
- package/build/cjs/lib/kit/components/ViewLayouts/ViewTableCell/ViewTableCell.css +9 -3
- package/build/cjs/lib/kit/components/ViewLayouts/ViewTableCell/ViewTableCell.js +7 -1
- package/build/cjs/lib/kit/components/ViewLayouts/ViewTransparent/ViewTransparent.css +4 -0
- package/build/cjs/lib/kit/components/ViewLayouts/ViewTransparent/ViewTransparent.js +4 -1
- package/build/cjs/lib/kit/components/Views/ArrayBaseView.js +2 -1
- package/build/cjs/lib/kit/components/index.js +1 -0
- package/build/cjs/lib/kit/constants/config.js +5 -0
- package/build/cjs/lib/kit/styles/mixins.css +0 -0
- package/build/esm/lib/core/components/Form/DynamicField.d.ts +1 -0
- package/build/esm/lib/core/components/Form/DynamicField.js +2 -2
- package/build/esm/lib/core/components/Form/constants.d.ts +0 -1
- package/build/esm/lib/core/components/Form/constants.js +0 -1
- package/build/esm/lib/core/components/Form/hooks/useField.d.ts +1 -1
- package/build/esm/lib/core/components/Form/hooks/useField.js +18 -14
- package/build/esm/lib/core/components/Form/hooks/useIntegrationFF.d.ts +1 -1
- package/build/esm/lib/core/components/Form/hooks/useIntegrationFF.js +19 -4
- package/build/esm/lib/core/components/Form/types/field.d.ts +1 -0
- package/build/esm/lib/core/components/Form/utils/common.js +2 -4
- package/build/esm/lib/core/types/specs.d.ts +2 -0
- package/build/esm/lib/kit/components/CopyButton/CopyButton.css +4 -0
- package/build/esm/lib/kit/components/CopyButton/CopyButton.d.ts +12 -0
- package/build/esm/lib/kit/components/CopyButton/CopyButton.js +16 -0
- package/build/esm/lib/kit/components/CopyButton/index.d.ts +1 -0
- package/build/esm/lib/kit/components/CopyButton/index.js +1 -0
- package/build/esm/lib/kit/components/Inputs/ArrayBase/ArrayBase.js +4 -7
- package/build/esm/lib/kit/components/Inputs/CardOneOf/CardOneOf.js +1 -2
- package/build/esm/lib/kit/components/Inputs/ObjectBase/ObjectBase.js +2 -3
- package/build/esm/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.js +1 -2
- package/build/esm/lib/kit/components/Inputs/OneOf/OneOf.js +1 -2
- package/build/esm/lib/kit/components/Inputs/OneOfCard/OneOfCard.js +1 -2
- package/build/esm/lib/kit/components/Inputs/Secret/Secret.js +1 -2
- package/build/esm/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +4 -7
- package/build/esm/lib/kit/components/Inputs/TextLink/TextLink.js +1 -2
- package/build/esm/lib/kit/components/ViewLayouts/ViewRow/ViewRow.css +3 -0
- package/build/esm/lib/kit/components/ViewLayouts/ViewRow/ViewRow.js +3 -1
- package/build/esm/lib/kit/components/ViewLayouts/ViewTableCell/ViewTableCell.css +9 -3
- package/build/esm/lib/kit/components/ViewLayouts/ViewTableCell/ViewTableCell.js +7 -1
- package/build/esm/lib/kit/components/ViewLayouts/ViewTransparent/ViewTransparent.css +4 -0
- package/build/esm/lib/kit/components/ViewLayouts/ViewTransparent/ViewTransparent.js +4 -1
- package/build/esm/lib/kit/components/Views/ArrayBaseView.js +2 -1
- 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/constants/config.js +5 -0
- package/build/esm/lib/kit/styles/mixins.css +0 -0
- package/package.json +2 -1
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import _ from 'lodash';
|
|
3
3
|
import { isArraySpec, isNumberSpec, isObjectSpec } from '../../../helpers';
|
|
4
|
-
import { OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG
|
|
4
|
+
import { OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG } from '../constants';
|
|
5
5
|
import { isArrayItem, transformArrIn, transformArrOut } from '../utils';
|
|
6
|
-
export const useField = ({ name, spec, initialValue, value: externalValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount, }) => {
|
|
6
|
+
export const useField = ({ name, spec, initialValue, value: externalValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount: externalParentOnUnmount, }) => {
|
|
7
7
|
const firstRenderRef = React.useRef(true);
|
|
8
|
-
const validate = React.useCallback((value) =>
|
|
9
|
-
if (value === REMOVED_ITEM) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
return propsValidate === null || propsValidate === void 0 ? void 0 : propsValidate(transformArrOut(value));
|
|
13
|
-
}, [propsValidate]);
|
|
8
|
+
const validate = React.useCallback((value) => propsValidate === null || propsValidate === void 0 ? void 0 : propsValidate(transformArrOut(value)), [propsValidate]);
|
|
14
9
|
const [state, setState] = React.useState(() => {
|
|
15
10
|
let value = _.cloneDeep(externalValue);
|
|
16
11
|
if (_.isNil(value)) {
|
|
@@ -67,20 +62,29 @@ export const useField = ({ name, spec, initialValue, value: externalValue, valid
|
|
|
67
62
|
};
|
|
68
63
|
const onDrop = () => {
|
|
69
64
|
if (isArrayItem(name)) {
|
|
70
|
-
|
|
65
|
+
(externalParentOnUnmount ? externalParentOnUnmount : tools.onUnmount)(name);
|
|
71
66
|
}
|
|
72
67
|
else {
|
|
73
68
|
onChange(undefined);
|
|
74
69
|
}
|
|
75
70
|
};
|
|
76
71
|
return { onChange, onDrop };
|
|
77
|
-
}, [initialValue, setState, name, validate, spec]);
|
|
72
|
+
}, [initialValue, setState, name, validate, spec, externalParentOnUnmount, tools.onUnmount]);
|
|
78
73
|
const onBlur = React.useCallback(() => {
|
|
79
74
|
setState((state) => (Object.assign(Object.assign({}, state), { active: false, touched: true })));
|
|
80
75
|
}, [setState]);
|
|
81
76
|
const onFocus = React.useCallback(() => {
|
|
82
77
|
setState((state) => (Object.assign(Object.assign({}, state), { active: true, visited: true })));
|
|
83
78
|
}, [setState]);
|
|
79
|
+
const parentOnUnmount = React.useCallback((childName) => {
|
|
80
|
+
if (isArraySpec(spec) || isObjectSpec(spec)) {
|
|
81
|
+
onChange((currentValue) => currentValue
|
|
82
|
+
? _.omit(currentValue, childName.split(`${name}.`)[1])
|
|
83
|
+
: currentValue, {
|
|
84
|
+
[childName]: false,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}, [onChange, name, spec]);
|
|
84
88
|
const renderProps = React.useMemo(() => {
|
|
85
89
|
const onItemAdd = (_value) => {
|
|
86
90
|
const stateValue = (state.value || {
|
|
@@ -92,9 +96,7 @@ export const useField = ({ name, spec, initialValue, value: externalValue, valid
|
|
|
92
96
|
setState((state) => (Object.assign(Object.assign({}, state), { dirty: !_.isEqual(value, initialValue), error, invalid: Boolean(error), modified: true, pristine: value === initialValue, touched: true, valid: !error, value, visited: true })));
|
|
93
97
|
};
|
|
94
98
|
const onItemRemove = (idx) => {
|
|
95
|
-
|
|
96
|
-
const error = validate === null || validate === void 0 ? void 0 : validate(value);
|
|
97
|
-
setState((state) => (Object.assign(Object.assign({}, state), { dirty: !_.isEqual(value, initialValue), error, invalid: Boolean(error), modified: true, pristine: value === initialValue, touched: true, valid: !error, value, visited: true })));
|
|
99
|
+
parentOnUnmount(`${name}.<${idx}>`);
|
|
98
100
|
};
|
|
99
101
|
return {
|
|
100
102
|
input: {
|
|
@@ -104,6 +106,7 @@ export const useField = ({ name, spec, initialValue, value: externalValue, valid
|
|
|
104
106
|
onBlur,
|
|
105
107
|
onFocus,
|
|
106
108
|
onDrop,
|
|
109
|
+
parentOnUnmount,
|
|
107
110
|
},
|
|
108
111
|
arrayInput: {
|
|
109
112
|
name,
|
|
@@ -125,6 +128,7 @@ export const useField = ({ name, spec, initialValue, value: externalValue, valid
|
|
|
125
128
|
onBlur,
|
|
126
129
|
onFocus,
|
|
127
130
|
onDrop,
|
|
131
|
+
parentOnUnmount,
|
|
128
132
|
]);
|
|
129
133
|
React.useEffect(() => {
|
|
130
134
|
if (!firstRenderRef.current || !_.isEqual(externalValue, state.value) || state.error) {
|
|
@@ -134,7 +138,7 @@ export const useField = ({ name, spec, initialValue, value: externalValue, valid
|
|
|
134
138
|
React.useEffect(() => {
|
|
135
139
|
firstRenderRef.current = false;
|
|
136
140
|
return () => {
|
|
137
|
-
(
|
|
141
|
+
(externalParentOnUnmount ? externalParentOnUnmount : tools.onUnmount)(name);
|
|
138
142
|
};
|
|
139
143
|
}, []);
|
|
140
144
|
return renderProps;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { DynamicFieldStore } from '../types';
|
|
2
|
-
export declare const useIntegrationFF: (store: DynamicFieldStore) => JSX.Element;
|
|
2
|
+
export declare const useIntegrationFF: (store: DynamicFieldStore, withoutDebounce?: boolean) => JSX.Element;
|
|
@@ -3,7 +3,7 @@ import _ from 'lodash';
|
|
|
3
3
|
import debounce from 'lodash/debounce';
|
|
4
4
|
import { Field as FinalFormField, useForm } from 'react-final-form';
|
|
5
5
|
import { transformArrOut } from '../utils';
|
|
6
|
-
export const useIntegrationFF = (store) => {
|
|
6
|
+
export const useIntegrationFF = (store, withoutDebounce) => {
|
|
7
7
|
const form = useForm();
|
|
8
8
|
const watcher = React.useMemo(() => {
|
|
9
9
|
const props = {
|
|
@@ -31,11 +31,26 @@ export const useIntegrationFF = (store) => {
|
|
|
31
31
|
};
|
|
32
32
|
return React.createElement(FinalFormField, Object.assign({}, props));
|
|
33
33
|
}, [store.name, store.errors]);
|
|
34
|
-
const change = React.
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
const change = React.useMemo(() => {
|
|
35
|
+
const cb = (value) => {
|
|
36
|
+
if (store.name) {
|
|
37
|
+
form.change(store.name, _.get(transformArrOut(value), store.name));
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
if (withoutDebounce) {
|
|
41
|
+
return cb;
|
|
42
|
+
}
|
|
43
|
+
return debounce(cb, 100);
|
|
44
|
+
}, [form.change, store.name, withoutDebounce]);
|
|
37
45
|
React.useEffect(() => {
|
|
38
46
|
change(store.values);
|
|
39
47
|
}, [store.values]);
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
return () => {
|
|
50
|
+
if (store.name) {
|
|
51
|
+
form.change(store.name, undefined);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}, []);
|
|
40
55
|
return watcher;
|
|
41
56
|
};
|
|
@@ -8,6 +8,7 @@ export interface FieldRenderProps<Value extends FieldValue> {
|
|
|
8
8
|
onChange: (value: Value | ((currentValue: Value) => Value), childErrors?: Record<string, ValidateError>) => void;
|
|
9
9
|
onFocus: (event?: React.FocusEvent<HTMLElement>) => void;
|
|
10
10
|
onDrop: () => void;
|
|
11
|
+
parentOnUnmount: (childName: string) => void;
|
|
11
12
|
};
|
|
12
13
|
arrayInput: {
|
|
13
14
|
name: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import { SpecTypes } from '../../../constants';
|
|
3
|
-
import { OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG
|
|
3
|
+
import { OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG } from '../constants';
|
|
4
4
|
export const isCorrectConfig = (candidate) => Object.values(SpecTypes).every((type) => _.isObjectLike(candidate) &&
|
|
5
5
|
_.isObjectLike(candidate[type]) &&
|
|
6
6
|
_.isObjectLike(candidate[type].inputs) &&
|
|
@@ -26,9 +26,7 @@ export const transformArrOut = (value) => {
|
|
|
26
26
|
if (_.isObject(value) && !_.isArray(value)) {
|
|
27
27
|
if (value[OBJECT_ARRAY_FLAG]) {
|
|
28
28
|
const _value = Object.keys(value)
|
|
29
|
-
.filter((key) => key !== OBJECT_ARRAY_FLAG &&
|
|
30
|
-
key !== OBJECT_ARRAY_CNT &&
|
|
31
|
-
value[key] !== REMOVED_ITEM)
|
|
29
|
+
.filter((key) => key !== OBJECT_ARRAY_FLAG && key !== OBJECT_ARRAY_CNT)
|
|
32
30
|
.map((key) => key.split('<').join('').split('>').join(''))
|
|
33
31
|
.sort((a, b) => Number(a) - Number(b))
|
|
34
32
|
.map((key) => transformArrOut(value[`<${key}>`]));
|
|
@@ -59,6 +59,7 @@ export interface NumberSpec<LinkType = any> {
|
|
|
59
59
|
layoutOpen?: boolean;
|
|
60
60
|
link?: LinkType;
|
|
61
61
|
placeholder?: string;
|
|
62
|
+
copy?: boolean;
|
|
62
63
|
};
|
|
63
64
|
}
|
|
64
65
|
export interface ObjectSpec<LinkType = any> {
|
|
@@ -121,6 +122,7 @@ export interface StringSpec<LinkType = any> {
|
|
|
121
122
|
readAsMethod?: ReadAsMethod;
|
|
122
123
|
ignoreText?: boolean;
|
|
123
124
|
};
|
|
125
|
+
copy?: boolean;
|
|
124
126
|
};
|
|
125
127
|
}
|
|
126
128
|
export type Spec = ArraySpec | BooleanSpec | NumberSpec | ObjectSpec | StringSpec;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FormValue, Spec } from '../../../core';
|
|
3
|
+
import './CopyButton.css';
|
|
4
|
+
export interface CopyButtonProps {
|
|
5
|
+
spec: Spec;
|
|
6
|
+
value: FormValue;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* Use the with-copy-button scss mixin for visible on hover
|
|
11
|
+
*/
|
|
12
|
+
export declare const CopyButton: React.FC<CopyButtonProps>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ClipboardButton } from '@gravity-ui/uikit';
|
|
3
|
+
import { isNumberSpec, isStringSpec } from '../../../core';
|
|
4
|
+
import { block } from '../../utils';
|
|
5
|
+
import './CopyButton.css';
|
|
6
|
+
const b = block('copy-button');
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* Use the with-copy-button scss mixin for visible on hover
|
|
10
|
+
*/
|
|
11
|
+
export const CopyButton = ({ spec, value }) => {
|
|
12
|
+
if ((isStringSpec(spec) || isNumberSpec(spec)) && spec.viewSpec.copy) {
|
|
13
|
+
return React.createElement(ClipboardButton, { className: b(), text: `${value}`, size: 14 });
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CopyButton';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CopyButton';
|
|
@@ -2,12 +2,10 @@ import React from 'react';
|
|
|
2
2
|
import { Plus } from '@gravity-ui/icons';
|
|
3
3
|
import { Button, Icon } from '@gravity-ui/uikit';
|
|
4
4
|
import _ from 'lodash';
|
|
5
|
-
import { Controller, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG,
|
|
5
|
+
import { Controller, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, isArraySpec, isCorrectSpec, isObjectSpec, transformArrIn, } from '../../../../core';
|
|
6
6
|
export const ArrayBase = ({ spec, name, arrayInput, input }) => {
|
|
7
7
|
const keys = React.useMemo(() => Object.keys(arrayInput.value || {})
|
|
8
|
-
.filter((k) => k !== OBJECT_ARRAY_FLAG &&
|
|
9
|
-
k !== OBJECT_ARRAY_CNT &&
|
|
10
|
-
arrayInput.value[k] !== REMOVED_ITEM)
|
|
8
|
+
.filter((k) => k !== OBJECT_ARRAY_FLAG && k !== OBJECT_ARRAY_CNT)
|
|
11
9
|
.map((k) => k.split('<').join('').split('>').join(''))
|
|
12
10
|
.sort((a, b) => Number(a) - Number(b)), [arrayInput.value]);
|
|
13
11
|
const itemSpecCorrect = React.useMemo(() => isCorrectSpec(spec.items), [spec.items]);
|
|
@@ -35,15 +33,14 @@ export const ArrayBase = ({ spec, name, arrayInput, input }) => {
|
|
|
35
33
|
return itemSpec;
|
|
36
34
|
}, [spec.items, itemSpecCorrect]);
|
|
37
35
|
const parentOnChange = React.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${input.name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
|
|
38
|
-
const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
|
|
39
36
|
const items = React.useMemo(() => keys.map((key, idx) => {
|
|
40
37
|
var _a;
|
|
41
38
|
const itemSpec = getItemSpec(idx);
|
|
42
39
|
if (!itemSpec) {
|
|
43
40
|
return null;
|
|
44
41
|
}
|
|
45
|
-
return (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[`<${key}>`], parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, spec: itemSpec, name: `${name}.<${key}>`, key: `${name}.<${key}>` }));
|
|
46
|
-
}), [keys.join(''), name, getItemSpec, parentOnChange, parentOnUnmount, input.value]);
|
|
42
|
+
return (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[`<${key}>`], parentOnChange: parentOnChange, parentOnUnmount: input.parentOnUnmount, spec: itemSpec, name: `${name}.<${key}>`, key: `${name}.<${key}>` }));
|
|
43
|
+
}), [keys.join(''), name, getItemSpec, parentOnChange, input.parentOnUnmount, input.value]);
|
|
47
44
|
if (!itemSpecCorrect) {
|
|
48
45
|
return null;
|
|
49
46
|
}
|
|
@@ -26,7 +26,6 @@ export const CardOneOf = (props) => {
|
|
|
26
26
|
const value = _.set({}, childName.split(`${input.name}.`).join(''), childValue);
|
|
27
27
|
input.onChange(value, childErrors);
|
|
28
28
|
}, [input.onChange, input.name]);
|
|
29
|
-
const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
|
|
30
29
|
useErrorChecker({ name, meta, open, setOpen });
|
|
31
|
-
return (React.createElement(Card, { name: name, title: toggler, description: spec.viewSpec.layoutDescription, actions: actions, open: open, onToggle: onToggle, disableHeaderToggle: true }, specProperties[oneOfValue] ? (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${name}.${oneOfValue}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, key: `${name}.${oneOfValue}` })) : null));
|
|
30
|
+
return (React.createElement(Card, { name: name, title: toggler, description: spec.viewSpec.layoutDescription, actions: actions, open: open, onToggle: onToggle, disableHeaderToggle: true }, specProperties[oneOfValue] ? (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${name}.${oneOfValue}`, parentOnChange: parentOnChange, parentOnUnmount: input.parentOnUnmount, key: `${name}.${oneOfValue}` })) : null));
|
|
32
31
|
};
|
|
@@ -13,7 +13,6 @@ export const ObjectBase = (_a) => {
|
|
|
13
13
|
spec.viewSpec.layoutTitle || null));
|
|
14
14
|
}, [spec.defaultValue, spec.viewSpec.layoutTitle, restProps.input.onChange]);
|
|
15
15
|
const parentOnChange = React.useCallback((childName, childValue, childErrors) => restProps.input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${restProps.input.name}.`).join(''), childValue), childErrors), [restProps.input.onChange, restProps.input.name]);
|
|
16
|
-
const parentOnUnmount = React.useCallback((childName) => restProps.input.onChange((currentValue) => currentValue, { [childName]: false }), [restProps.input.onChange]);
|
|
17
16
|
const content = React.useMemo(() => {
|
|
18
17
|
if (!_.isObjectLike(spec.properties) || !Object.keys(spec.properties || {}).length) {
|
|
19
18
|
return null;
|
|
@@ -24,7 +23,7 @@ export const ObjectBase = (_a) => {
|
|
|
24
23
|
const specProperties = Object.assign({}, spec.properties);
|
|
25
24
|
return (React.createElement(React.Fragment, null, (spec.viewSpec.order || Object.keys(specProperties)).map((property) => {
|
|
26
25
|
var _a;
|
|
27
|
-
return specProperties[property] ? (React.createElement(Controller, { value: (_a = restProps.input.value) === null || _a === void 0 ? void 0 : _a[property], spec: specProperties[property], name: `${name ? name + '.' : ''}${property}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, key: `${name ? name + '.' : ''}${property}` })) : null;
|
|
26
|
+
return specProperties[property] ? (React.createElement(Controller, { value: (_a = restProps.input.value) === null || _a === void 0 ? void 0 : _a[property], spec: specProperties[property], name: `${name ? name + '.' : ''}${property}`, parentOnChange: parentOnChange, parentOnUnmount: restProps.input.parentOnUnmount, key: `${name ? name + '.' : ''}${property}` })) : null;
|
|
28
27
|
})));
|
|
29
28
|
}, [
|
|
30
29
|
spec.properties,
|
|
@@ -33,7 +32,7 @@ export const ObjectBase = (_a) => {
|
|
|
33
32
|
restProps.input.value,
|
|
34
33
|
addBtn,
|
|
35
34
|
parentOnChange,
|
|
36
|
-
parentOnUnmount,
|
|
35
|
+
restProps.input.parentOnUnmount,
|
|
37
36
|
]);
|
|
38
37
|
if (!Layout || !content) {
|
|
39
38
|
return content;
|
|
@@ -6,7 +6,6 @@ export const ObjectValueInput = (props) => {
|
|
|
6
6
|
var _a;
|
|
7
7
|
const { spec, input, name, Layout } = props;
|
|
8
8
|
const parentOnChange = React.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
|
|
9
|
-
const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
|
|
10
9
|
const childSpec = React.useMemo(() => {
|
|
11
10
|
var _a;
|
|
12
11
|
if ((_a = spec.properties) === null || _a === void 0 ? void 0 : _a[OBJECT_VALUE_PROPERTY_NAME]) {
|
|
@@ -19,7 +18,7 @@ export const ObjectValueInput = (props) => {
|
|
|
19
18
|
if (!childSpec) {
|
|
20
19
|
return null;
|
|
21
20
|
}
|
|
22
|
-
const content = (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[OBJECT_VALUE_PROPERTY_NAME], spec: childSpec, name: `${name}.${OBJECT_VALUE_PROPERTY_NAME}`, key: `${name}.${OBJECT_VALUE_PROPERTY_NAME}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount }));
|
|
21
|
+
const content = (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[OBJECT_VALUE_PROPERTY_NAME], spec: childSpec, name: `${name}.${OBJECT_VALUE_PROPERTY_NAME}`, key: `${name}.${OBJECT_VALUE_PROPERTY_NAME}`, parentOnChange: parentOnChange, parentOnUnmount: input.parentOnUnmount }));
|
|
23
22
|
if (Layout) {
|
|
24
23
|
return React.createElement(Layout, Object.assign({}, props), content);
|
|
25
24
|
}
|
|
@@ -13,14 +13,13 @@ const OneOfComponent = (props) => {
|
|
|
13
13
|
const value = _.set({}, childName.split(`${props.input.name}.`).join(''), childValue);
|
|
14
14
|
props.input.onChange(value, childErrors);
|
|
15
15
|
}, [props.input.onChange, props.input.name]);
|
|
16
|
-
const parentOnUnmount = React.useCallback((childName) => props.input.onChange((currentValue) => currentValue, { [childName]: false }), [props.input.onChange]);
|
|
17
16
|
return (React.createElement("div", { className: b({
|
|
18
17
|
base: !props.withoutIndent,
|
|
19
18
|
flat: props.withoutIndent,
|
|
20
19
|
}) },
|
|
21
20
|
React.createElement("div", null, toggler),
|
|
22
21
|
specProperties[oneOfValue] ? (React.createElement(GroupIndent, null,
|
|
23
|
-
React.createElement(Controller, { value: (_a = props.input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${props.name}.${oneOfValue}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, key: `${props.name}.${oneOfValue}` }))) : null));
|
|
22
|
+
React.createElement(Controller, { value: (_a = props.input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${props.name}.${oneOfValue}`, parentOnChange: parentOnChange, parentOnUnmount: props.input.parentOnUnmount, key: `${props.name}.${oneOfValue}` }))) : null));
|
|
24
23
|
};
|
|
25
24
|
export const OneOf = OneOfComponent;
|
|
26
25
|
export const OneOfFlat = (props) => (React.createElement(OneOfComponent, Object.assign({}, props, { withoutIndent: true })));
|
|
@@ -34,7 +34,6 @@ export const OneOfCard = (props) => {
|
|
|
34
34
|
const value = _.set({}, childName.split(`${input.name}.`).join(''), childValue);
|
|
35
35
|
input.onChange(value, childErrors);
|
|
36
36
|
}, [input.onChange, input.name]);
|
|
37
|
-
const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
|
|
38
37
|
useErrorChecker({ name, meta, open, setOpen });
|
|
39
|
-
return (React.createElement(AccordeonCard, { className: b(), name: name, header: toggler, description: spec.viewSpec.layoutDescription || '', open: open, onToggle: onToggle, ignoreHeaderToggle: true, headerActionsTemplate: headerActionsTemplate }, specProperties[oneOfValue] ? (React.createElement(Controller, { value: (_a = props.input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${name}.${oneOfValue}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, key: `${name}.${oneOfValue}` })) : null));
|
|
38
|
+
return (React.createElement(AccordeonCard, { className: b(), name: name, header: toggler, description: spec.viewSpec.layoutDescription || '', open: open, onToggle: onToggle, ignoreHeaderToggle: true, headerActionsTemplate: headerActionsTemplate }, specProperties[oneOfValue] ? (React.createElement(Controller, { value: (_a = props.input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${name}.${oneOfValue}`, parentOnChange: parentOnChange, parentOnUnmount: input.parentOnUnmount, key: `${name}.${oneOfValue}` })) : null));
|
|
40
39
|
};
|
|
@@ -15,11 +15,10 @@ export const Secret = (props) => {
|
|
|
15
15
|
return undefined;
|
|
16
16
|
}, [spec.properties]);
|
|
17
17
|
const parentOnChange = React.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${input.name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
|
|
18
|
-
const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
|
|
19
18
|
if (!childSpec) {
|
|
20
19
|
return null;
|
|
21
20
|
}
|
|
22
|
-
const content = (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[SECRET_PROPERTY_NAME], spec: childSpec, name: `${name}.${SECRET_PROPERTY_NAME}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, key: `${name}.${SECRET_PROPERTY_NAME}` }));
|
|
21
|
+
const content = (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[SECRET_PROPERTY_NAME], spec: childSpec, name: `${name}.${SECRET_PROPERTY_NAME}`, parentOnChange: parentOnChange, parentOnUnmount: input.parentOnUnmount, key: `${name}.${SECRET_PROPERTY_NAME}` }));
|
|
23
22
|
if (Layout) {
|
|
24
23
|
return React.createElement(Layout, Object.assign({}, props), content);
|
|
25
24
|
}
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { Plus, Xmark } from '@gravity-ui/icons';
|
|
3
3
|
import { Button, Icon, Table } from '@gravity-ui/uikit';
|
|
4
4
|
import _ from 'lodash';
|
|
5
|
-
import { Controller, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG,
|
|
5
|
+
import { Controller, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, isArraySpec, isBooleanSpec, isObjectSpec, transformArrIn, } from '../../../../core';
|
|
6
6
|
import { useSearchContext } from '../../../../core/components/Form/hooks';
|
|
7
7
|
import { block } from '../../../utils';
|
|
8
8
|
import './TableArrayInput.css';
|
|
@@ -10,9 +10,7 @@ const b = block('table-array');
|
|
|
10
10
|
export const TableArrayInput = ({ spec, name, arrayInput, input }) => {
|
|
11
11
|
const { isHiddenField } = useSearchContext();
|
|
12
12
|
const keys = React.useMemo(() => Object.keys(arrayInput.value || {})
|
|
13
|
-
.filter((k) => k !== OBJECT_ARRAY_FLAG &&
|
|
14
|
-
k !== OBJECT_ARRAY_CNT &&
|
|
15
|
-
arrayInput.value[k] !== REMOVED_ITEM)
|
|
13
|
+
.filter((k) => k !== OBJECT_ARRAY_FLAG && k !== OBJECT_ARRAY_CNT)
|
|
16
14
|
.map((k) => k.split('<').join('').split('>').join(''))
|
|
17
15
|
.sort((a, b) => Number(a) - Number(b))
|
|
18
16
|
.map((key) => ({
|
|
@@ -25,7 +23,6 @@ export const TableArrayInput = ({ spec, name, arrayInput, input }) => {
|
|
|
25
23
|
arrayInput.onItemRemove(key);
|
|
26
24
|
}, [arrayInput.onItemRemove]);
|
|
27
25
|
const parentOnChange = React.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${input.name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
|
|
28
|
-
const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
|
|
29
26
|
const columns = React.useMemo(() => {
|
|
30
27
|
const { items, viewSpec: { table }, } = spec;
|
|
31
28
|
if (!(table === null || table === void 0 ? void 0 : table.length) || !isObjectSpec(items)) {
|
|
@@ -59,11 +56,11 @@ export const TableArrayInput = ({ spec, name, arrayInput, input }) => {
|
|
|
59
56
|
arr: isArraySpec(preparedEntitySpec),
|
|
60
57
|
obj: isObjectSpec(preparedEntitySpec),
|
|
61
58
|
}), key: `${name}.<${key}>.${property}` },
|
|
62
|
-
React.createElement(Controller, { value: (_c = (_b = input.value) === null || _b === void 0 ? void 0 : _b[`<${key}>`]) === null || _c === void 0 ? void 0 : _c[property], spec: preparedEntitySpec, name: `${name}.<${key}>.${property}`, parentOnChange: parentOnChange, parentOnUnmount:
|
|
59
|
+
React.createElement(Controller, { value: (_c = (_b = input.value) === null || _b === void 0 ? void 0 : _b[`<${key}>`]) === null || _c === void 0 ? void 0 : _c[property], spec: preparedEntitySpec, name: `${name}.<${key}>.${property}`, parentOnChange: parentOnChange, parentOnUnmount: _.noop })));
|
|
63
60
|
},
|
|
64
61
|
}));
|
|
65
62
|
return [idxColumn, ...columns, removeColumn];
|
|
66
|
-
}, [name, spec, onItemRemove, parentOnChange, parentOnUnmount, input.value]);
|
|
63
|
+
}, [name, spec, onItemRemove, parentOnChange, input.parentOnUnmount, input.value]);
|
|
67
64
|
const getRowClassNames = React.useCallback(({ key }) => {
|
|
68
65
|
var _a;
|
|
69
66
|
const searchResult = (_a = spec.viewSpec.table) === null || _a === void 0 ? void 0 : _a.every(({ property }) => isHiddenField(`${name}.<${key}>.${property}`));
|
|
@@ -6,7 +6,6 @@ export const TextLink = (props) => {
|
|
|
6
6
|
var _a;
|
|
7
7
|
const { spec, input, name, Layout } = props;
|
|
8
8
|
const parentOnChange = React.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
|
|
9
|
-
const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
|
|
10
9
|
const childSpec = React.useMemo(() => {
|
|
11
10
|
var _a;
|
|
12
11
|
if (((_a = spec.properties) === null || _a === void 0 ? void 0 : _a[TEXT_LINK_PROPERTY_NAME]) &&
|
|
@@ -20,7 +19,7 @@ export const TextLink = (props) => {
|
|
|
20
19
|
if (!childSpec) {
|
|
21
20
|
return null;
|
|
22
21
|
}
|
|
23
|
-
const content = (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[TEXT_LINK_PROPERTY_NAME], spec: childSpec, name: `${name}.${TEXT_LINK_PROPERTY_NAME}`, key: `${name}.${TEXT_LINK_PROPERTY_NAME}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount }));
|
|
22
|
+
const content = (React.createElement(Controller, { value: (_a = input.value) === null || _a === void 0 ? void 0 : _a[TEXT_LINK_PROPERTY_NAME], spec: childSpec, name: `${name}.${TEXT_LINK_PROPERTY_NAME}`, key: `${name}.${TEXT_LINK_PROPERTY_NAME}`, parentOnChange: parentOnChange, parentOnUnmount: input.parentOnUnmount }));
|
|
24
23
|
if (Layout) {
|
|
25
24
|
return React.createElement(Layout, Object.assign({}, props), content);
|
|
26
25
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { CopyButton } from '../../../../kit';
|
|
2
3
|
import { block, isNotEmptyValue } from '../../../utils';
|
|
3
4
|
import './ViewRow.css';
|
|
4
5
|
const b = block('view-row');
|
|
@@ -10,5 +11,6 @@ export const ViewRow = ({ value, spec, children, }) => {
|
|
|
10
11
|
React.createElement("div", { className: b('left') },
|
|
11
12
|
React.createElement("div", { className: b('title'), title: spec.viewSpec.layoutTitle }, spec.viewSpec.layoutTitle),
|
|
12
13
|
React.createElement("div", { className: b('dots') })),
|
|
13
|
-
React.createElement("div", { className: b('right') }, children)
|
|
14
|
+
React.createElement("div", { className: b('right') }, children),
|
|
15
|
+
React.createElement(CopyButton, { spec: spec, value: value })));
|
|
14
16
|
};
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
.df-view-table-cell {
|
|
2
2
|
display: flex;
|
|
3
|
+
}
|
|
4
|
+
.df-view-table-cell__inner {
|
|
5
|
+
display: flex;
|
|
3
6
|
flex-direction: column;
|
|
4
7
|
justify-content: center;
|
|
5
8
|
}
|
|
6
|
-
.df-view-table-
|
|
9
|
+
.df-view-table-cell__inner > .df-view-row:last-child {
|
|
7
10
|
margin-bottom: 0;
|
|
8
11
|
}
|
|
9
|
-
.df-view-table-
|
|
12
|
+
.df-view-table-cell__inner > .df-view-transparent {
|
|
10
13
|
margin-bottom: 6px;
|
|
11
14
|
}
|
|
12
|
-
.df-view-table-
|
|
15
|
+
.df-view-table-cell__inner > .df-view-transparent:last-child {
|
|
13
16
|
margin-bottom: 0;
|
|
17
|
+
}
|
|
18
|
+
.df-view-table-cell:hover > .df-copy-button {
|
|
19
|
+
display: block;
|
|
14
20
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { CopyButton } from '../../../../kit';
|
|
2
3
|
import { block, isNotEmptyValue } from '../../../utils';
|
|
3
4
|
import './ViewTableCell.css';
|
|
4
5
|
const b = block('view-table-cell');
|
|
5
|
-
export const ViewTableCell = ({ value, spec, children, }) =>
|
|
6
|
+
export const ViewTableCell = ({ value, spec, children, }) => {
|
|
7
|
+
const empty = isNotEmptyValue(value, spec);
|
|
8
|
+
return (React.createElement("div", { className: b() }, empty ? (React.createElement(React.Fragment, null,
|
|
9
|
+
React.createElement("div", { className: b('inner') }, children),
|
|
10
|
+
React.createElement(CopyButton, { spec: spec, value: value }))) : ('—')));
|
|
11
|
+
};
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { CopyButton } from '../../../../kit';
|
|
2
3
|
import { block, isNotEmptyValue } from '../../../utils';
|
|
3
4
|
import './ViewTransparent.css';
|
|
4
5
|
const b = block('view-transparent');
|
|
5
|
-
export const ViewTransparent = ({ value, spec, children, }) => isNotEmptyValue(value, spec) ? React.createElement("div", { className: b() },
|
|
6
|
+
export const ViewTransparent = ({ value, spec, children, }) => isNotEmptyValue(value, spec) ? (React.createElement("div", { className: b() },
|
|
7
|
+
React.createElement("div", null, children),
|
|
8
|
+
React.createElement(CopyButton, { spec: spec, value: value }))) : null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import _ from 'lodash';
|
|
2
3
|
import { ViewController, isCorrectSpec } from '../../../core';
|
|
3
4
|
export const ArrayBaseView = ({ spec, name, value = [] }) => {
|
|
4
5
|
const itemSpecCorrect = React.useMemo(() => isCorrectSpec(spec.items), [spec.items]);
|
|
@@ -12,7 +13,7 @@ export const ArrayBaseView = ({ spec, name, value = [] }) => {
|
|
|
12
13
|
: `${idx + 1}` });
|
|
13
14
|
return itemSpec;
|
|
14
15
|
}, [spec.items, itemSpecCorrect]);
|
|
15
|
-
const items = React.useMemo(() =>
|
|
16
|
+
const items = React.useMemo(() => _.map(value, (__, idx) => {
|
|
16
17
|
const itemSpec = getItemSpec(idx);
|
|
17
18
|
if (!itemSpec) {
|
|
18
19
|
return null;
|
|
@@ -209,6 +209,7 @@ export const dynamicViewConfig = {
|
|
|
209
209
|
},
|
|
210
210
|
layouts: {
|
|
211
211
|
row: ViewRow,
|
|
212
|
+
row_verbose: ViewRow,
|
|
212
213
|
accordeon: ViewAccordeon,
|
|
213
214
|
section: ViewSection,
|
|
214
215
|
section2: ViewSection2,
|
|
@@ -227,6 +228,7 @@ export const dynamicViewConfig = {
|
|
|
227
228
|
},
|
|
228
229
|
layouts: {
|
|
229
230
|
row: ViewRow,
|
|
231
|
+
row_verbose: ViewRow,
|
|
230
232
|
table_item: ViewTableCell,
|
|
231
233
|
},
|
|
232
234
|
},
|
|
@@ -236,6 +238,7 @@ export const dynamicViewConfig = {
|
|
|
236
238
|
},
|
|
237
239
|
layouts: {
|
|
238
240
|
row: ViewRow,
|
|
241
|
+
row_verbose: ViewRow,
|
|
239
242
|
table_item: ViewTableCell,
|
|
240
243
|
transparent: ViewTransparent,
|
|
241
244
|
},
|
|
@@ -252,6 +255,7 @@ export const dynamicViewConfig = {
|
|
|
252
255
|
},
|
|
253
256
|
layouts: {
|
|
254
257
|
row: ViewRow,
|
|
258
|
+
row_verbose: ViewRow,
|
|
255
259
|
accordeon: ViewAccordeon,
|
|
256
260
|
section: ViewSection,
|
|
257
261
|
section2: ViewSection2,
|
|
@@ -275,6 +279,7 @@ export const dynamicViewConfig = {
|
|
|
275
279
|
},
|
|
276
280
|
layouts: {
|
|
277
281
|
row: ViewRow,
|
|
282
|
+
row_verbose: ViewRow,
|
|
278
283
|
table_item: ViewTableCell,
|
|
279
284
|
transparent: ViewTransparent,
|
|
280
285
|
section: ViewSection,
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/dynamic-forms",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "build/cjs/index.js",
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"@storybook/react": "^6.5.16",
|
|
58
58
|
"@testing-library/jest-dom": "^5.16.5",
|
|
59
59
|
"@testing-library/react": "^14.0.0",
|
|
60
|
+
"@testing-library/user-event": "^14.4.3",
|
|
60
61
|
"@types/jest": "^29.5.0",
|
|
61
62
|
"@types/lodash": "^4.14.180",
|
|
62
63
|
"@types/react": "^18.0.28",
|