@gravity-ui/dynamic-forms 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/lib/core/components/Form/Controller/Controller.js +120 -0
- package/build/cjs/lib/core/components/Form/Controller/index.js +4 -0
- package/build/cjs/lib/core/components/Form/Controller/types.js +2 -0
- package/build/cjs/lib/core/components/Form/Controller/utils.js +305 -0
- package/build/cjs/lib/core/components/Form/hooks/index.js +0 -4
- package/build/cjs/lib/core/components/Form/hooks/useMutators.js +21 -1
- package/build/cjs/lib/core/components/Form/utils/common.js +1 -5
- package/build/esm/lib/core/components/Form/Controller/Controller.d.ts +10 -0
- package/build/esm/lib/core/components/Form/Controller/Controller.js +115 -0
- package/build/esm/lib/core/components/Form/Controller/index.d.ts +1 -0
- package/build/esm/lib/core/components/Form/Controller/index.js +1 -0
- package/build/esm/lib/core/components/Form/Controller/types.d.ts +98 -0
- package/build/esm/lib/core/components/Form/Controller/types.js +1 -0
- package/build/esm/lib/core/components/Form/Controller/utils.d.ts +26 -0
- package/build/esm/lib/core/components/Form/Controller/utils.js +291 -0
- package/build/esm/lib/core/components/Form/hooks/index.d.ts +0 -4
- package/build/esm/lib/core/components/Form/hooks/index.js +0 -4
- package/build/esm/lib/core/components/Form/hooks/useMutators.js +21 -1
- package/build/esm/lib/core/components/Form/types/mirror.d.ts +3 -5
- package/build/esm/lib/core/components/Form/types/mutators.d.ts +13 -2
- package/build/esm/lib/core/components/Form/utils/common.d.ts +0 -3
- package/build/esm/lib/core/components/Form/utils/common.js +0 -2
- package/package.json +1 -1
- package/build/cjs/lib/core/components/Form/Controller.js +0 -42
- package/build/cjs/lib/core/components/Form/hooks/useComponents.js +0 -40
- package/build/cjs/lib/core/components/Form/hooks/useField.js +0 -176
- package/build/cjs/lib/core/components/Form/hooks/useRender.js +0 -28
- package/build/cjs/lib/core/components/Form/hooks/useValidate.js +0 -32
- package/build/esm/lib/core/components/Form/Controller.d.ts +0 -10
- package/build/esm/lib/core/components/Form/Controller.js +0 -37
- package/build/esm/lib/core/components/Form/hooks/useComponents.d.ts +0 -6
- package/build/esm/lib/core/components/Form/hooks/useComponents.js +0 -35
- package/build/esm/lib/core/components/Form/hooks/useField.d.ts +0 -14
- package/build/esm/lib/core/components/Form/hooks/useField.js +0 -171
- package/build/esm/lib/core/components/Form/hooks/useRender.d.ts +0 -9
- package/build/esm/lib/core/components/Form/hooks/useRender.js +0 -23
- package/build/esm/lib/core/components/Form/hooks/useValidate.d.ts +0 -3
- package/build/esm/lib/core/components/Form/hooks/useValidate.js +0 -27
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { FormValue, Spec } from '../../../types';
|
|
3
|
+
import { DynamicFormConfig, DynamicFormMutators, DynamicFormsContext, FieldRenderProps, FieldValue, IndependentInputEntity, InputEntity, LayoutType, ValidateError } from '../types';
|
|
4
|
+
export interface GetSpecParams<SpecType extends Spec> {
|
|
5
|
+
name: string;
|
|
6
|
+
spec: SpecType;
|
|
7
|
+
mutators: DynamicFormMutators;
|
|
8
|
+
}
|
|
9
|
+
export interface GetComponentsParams<SpecType extends Spec> {
|
|
10
|
+
spec: SpecType;
|
|
11
|
+
config: DynamicFormConfig;
|
|
12
|
+
}
|
|
13
|
+
export interface GetComponentsReturn<DirtyValue extends FieldValue, SpecType extends Spec> {
|
|
14
|
+
inputEntity?: InputEntity<DirtyValue, SpecType> | IndependentInputEntity<DirtyValue, SpecType>;
|
|
15
|
+
Layout?: LayoutType<DirtyValue, SpecType>;
|
|
16
|
+
}
|
|
17
|
+
export interface GetRenderParams<DirtyValue extends FieldValue, SpecType extends Spec> {
|
|
18
|
+
name: string;
|
|
19
|
+
spec: SpecType;
|
|
20
|
+
inputEntity?: InputEntity<DirtyValue, SpecType> | IndependentInputEntity<DirtyValue, SpecType>;
|
|
21
|
+
Layout?: LayoutType<DirtyValue, SpecType>;
|
|
22
|
+
}
|
|
23
|
+
export interface GetValidateParams<SpecType extends Spec> {
|
|
24
|
+
spec: SpecType;
|
|
25
|
+
config: DynamicFormConfig;
|
|
26
|
+
}
|
|
27
|
+
export interface GetFieldInitialsParams<DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec> {
|
|
28
|
+
name: string;
|
|
29
|
+
spec: SpecType;
|
|
30
|
+
valueFromParent: DirtyValue;
|
|
31
|
+
initialValue: DirtyValue;
|
|
32
|
+
validate: (value?: Value) => ValidateError;
|
|
33
|
+
mutators: DynamicFormMutators;
|
|
34
|
+
}
|
|
35
|
+
export type FieldMethod<DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec, Params extends any = undefined> = (store: ControllerStore<DirtyValue, Value, SpecType>, params: Params) => ControllerStore<DirtyValue, Value, SpecType>;
|
|
36
|
+
export interface GetFieldMethodsReturn<DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec> {
|
|
37
|
+
onChange: FieldMethod<DirtyValue, Value, SpecType, {
|
|
38
|
+
valOrSetter: DirtyValue | ((currentValue: DirtyValue) => DirtyValue);
|
|
39
|
+
childErrors?: Record<string, ValidateError>;
|
|
40
|
+
errorMutator?: ValidateError;
|
|
41
|
+
}>;
|
|
42
|
+
onDrop: FieldMethod<DirtyValue, Value, SpecType>;
|
|
43
|
+
onBlur: FieldMethod<DirtyValue, Value, SpecType>;
|
|
44
|
+
onFocus: FieldMethod<DirtyValue, Value, SpecType>;
|
|
45
|
+
parentOnUnmount: FieldMethod<DirtyValue, Value, SpecType, string>;
|
|
46
|
+
onItemAdd: FieldMethod<DirtyValue, Value, SpecType, FieldValue>;
|
|
47
|
+
onItemRemove: FieldMethod<DirtyValue, Value, SpecType, number | string>;
|
|
48
|
+
}
|
|
49
|
+
export interface InitializeStoreParams<DirtyValue extends FieldValue, SpecType extends Spec> {
|
|
50
|
+
name: string;
|
|
51
|
+
spec: SpecType;
|
|
52
|
+
mutators: DynamicFormMutators;
|
|
53
|
+
config: DynamicFormConfig;
|
|
54
|
+
valueFromParent: DirtyValue;
|
|
55
|
+
tools: DynamicFormsContext['tools'];
|
|
56
|
+
parentOnChange: ((childName: string, childValue: FieldValue, childErrors: Record<string, ValidateError>) => void) | null;
|
|
57
|
+
parentOnUnmount: ((childName: string) => void) | null;
|
|
58
|
+
}
|
|
59
|
+
export interface ControllerStore<DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec> {
|
|
60
|
+
name: string;
|
|
61
|
+
spec: SpecType;
|
|
62
|
+
initialSpec: SpecType;
|
|
63
|
+
config: DynamicFormConfig;
|
|
64
|
+
tools: DynamicFormsContext['tools'];
|
|
65
|
+
mutators: DynamicFormMutators;
|
|
66
|
+
render: (props: FieldRenderProps<DirtyValue>) => JSX.Element | null;
|
|
67
|
+
validate: (value?: Value) => ValidateError;
|
|
68
|
+
parentOnChange: ((childName: string, childValue: FieldValue, childErrors: Record<string, ValidateError>) => void) | null;
|
|
69
|
+
parentOnUnmount: ((childName: string) => void) | null;
|
|
70
|
+
state: {
|
|
71
|
+
initialValue: DirtyValue;
|
|
72
|
+
active: boolean;
|
|
73
|
+
dirty: boolean;
|
|
74
|
+
error: ValidateError;
|
|
75
|
+
invalid: boolean;
|
|
76
|
+
modified: boolean;
|
|
77
|
+
pristine: boolean;
|
|
78
|
+
touched: boolean;
|
|
79
|
+
valid: boolean;
|
|
80
|
+
value: DirtyValue;
|
|
81
|
+
visited: boolean;
|
|
82
|
+
childErrors: Record<string, ValidateError>;
|
|
83
|
+
};
|
|
84
|
+
afterStoreUpdateCB?: () => void;
|
|
85
|
+
}
|
|
86
|
+
export interface UpdateStoreParams<DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec> {
|
|
87
|
+
store: ControllerStore<DirtyValue, Value, SpecType>;
|
|
88
|
+
setStore: (store: ControllerStore<DirtyValue, Value, SpecType>) => void;
|
|
89
|
+
spec: SpecType;
|
|
90
|
+
name: string;
|
|
91
|
+
parentOnChange: ((childName: string, childValue: FieldValue, childErrors: Record<string, ValidateError>) => void) | null;
|
|
92
|
+
parentOnUnmount: ((childName: string) => void) | null;
|
|
93
|
+
mutators: DynamicFormMutators;
|
|
94
|
+
valueFromParent: DirtyValue;
|
|
95
|
+
config: DynamicFormConfig;
|
|
96
|
+
tools: DynamicFormsContext['tools'];
|
|
97
|
+
methodOnChange: GetFieldMethodsReturn<DirtyValue, Value, SpecType>['onChange'];
|
|
98
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { FormValue, Spec } from '../../../types';
|
|
2
|
+
import { FieldRenderProps, FieldValue, ValidateError } from '../types';
|
|
3
|
+
import { ControllerStore, GetComponentsParams, GetComponentsReturn, GetFieldInitialsParams, GetFieldMethodsReturn, GetRenderParams, GetSpecParams, GetValidateParams, InitializeStoreParams, UpdateStoreParams } from './types';
|
|
4
|
+
export declare const updateParentStore: <DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec>(store: ControllerStore<DirtyValue, Value, SpecType>) => void;
|
|
5
|
+
export declare const callUnmout: <DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec>(store: ControllerStore<DirtyValue, Value, SpecType>) => void;
|
|
6
|
+
export declare const getSpec: <SpecType extends Spec>({ name, spec, mutators, }: GetSpecParams<SpecType>) => SpecType;
|
|
7
|
+
export declare const getComponents: <DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec>({ spec, config, }: GetComponentsParams<SpecType>) => GetComponentsReturn<DirtyValue, SpecType>;
|
|
8
|
+
export declare const getRender: <DirtyValue extends FieldValue, SpecType extends Spec>({ name, spec, inputEntity, Layout, }: GetRenderParams<DirtyValue, SpecType>) => (props: FieldRenderProps<DirtyValue>) => JSX.Element | null;
|
|
9
|
+
export declare const getValidate: <DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec>({ spec, config, }: GetValidateParams<SpecType>) => (value?: Value | undefined) => ValidateError;
|
|
10
|
+
export declare const getFieldInitials: <DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec>({ name, spec, valueFromParent, initialValue, validate, mutators, }: GetFieldInitialsParams<DirtyValue, Value, SpecType>) => {
|
|
11
|
+
initialValue: DirtyValue;
|
|
12
|
+
active: boolean;
|
|
13
|
+
dirty: boolean;
|
|
14
|
+
error: string | boolean | import("../types").AsyncValidateError | undefined;
|
|
15
|
+
invalid: boolean;
|
|
16
|
+
modified: boolean;
|
|
17
|
+
pristine: boolean;
|
|
18
|
+
touched: boolean;
|
|
19
|
+
valid: boolean;
|
|
20
|
+
value: DirtyValue;
|
|
21
|
+
visited: boolean;
|
|
22
|
+
childErrors: {};
|
|
23
|
+
};
|
|
24
|
+
export declare const getFieldMethods: <DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec>() => GetFieldMethodsReturn<DirtyValue, Value, SpecType>;
|
|
25
|
+
export declare const initializeStore: <DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec>({ name, spec: _spec, mutators, config, valueFromParent, tools, parentOnChange, parentOnUnmount, }: InitializeStoreParams<DirtyValue, SpecType>) => ControllerStore<DirtyValue, Value, SpecType>;
|
|
26
|
+
export declare const updateStore: <DirtyValue extends FieldValue, Value extends FormValue, SpecType extends Spec>({ store, setStore, spec: _spec, name, parentOnChange, parentOnUnmount, mutators, valueFromParent, config, tools, methodOnChange, }: UpdateStoreParams<DirtyValue, Value, SpecType>) => void;
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
import { isValidElementType } from 'react-is';
|
|
4
|
+
import { SpecTypes } from '../../../constants';
|
|
5
|
+
import { isArraySpec, isCorrectSpec, isNumberSpec, isObjectSpec } from '../../../helpers';
|
|
6
|
+
import { EMPTY_MUTATOR, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG } from '../constants';
|
|
7
|
+
import { isArrayItem, isCorrectConfig, transformArrIn, transformArrOut } from '../utils';
|
|
8
|
+
const isErrorMutatorCorrect = (errorMutator) => errorMutator !== EMPTY_MUTATOR && (_.isString(errorMutator) || _.isBoolean(errorMutator));
|
|
9
|
+
const isValueMutatorCorrect = (valueMutator, spec) => valueMutator !== EMPTY_MUTATOR &&
|
|
10
|
+
(typeof valueMutator === spec.type ||
|
|
11
|
+
(_.isArray(valueMutator) && spec.type === SpecTypes.Array));
|
|
12
|
+
export const updateParentStore = (store) => {
|
|
13
|
+
(store.parentOnChange ? store.parentOnChange : store.tools.onChange)(store.name, store.state.value, Object.assign(Object.assign({}, store.state.childErrors), { [store.name]: store.state.error }));
|
|
14
|
+
};
|
|
15
|
+
export const callUnmout = (store) => {
|
|
16
|
+
(store.parentOnUnmount ? store.parentOnUnmount : store.tools.onUnmount)(store.name);
|
|
17
|
+
};
|
|
18
|
+
export const getSpec = ({ name, spec, mutators, }) => {
|
|
19
|
+
const mutator = _.get(mutators.spec, name, EMPTY_MUTATOR);
|
|
20
|
+
if (mutator !== EMPTY_MUTATOR) {
|
|
21
|
+
const mutatedSpec = _.merge(_.cloneDeep(spec), mutator);
|
|
22
|
+
if (isCorrectSpec(mutatedSpec)) {
|
|
23
|
+
return mutatedSpec;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return spec;
|
|
27
|
+
};
|
|
28
|
+
export const getComponents = ({ spec, config, }) => {
|
|
29
|
+
const result = {};
|
|
30
|
+
if (isCorrectConfig(config) && isCorrectSpec(spec)) {
|
|
31
|
+
const { inputs, layouts } = config[spec.type];
|
|
32
|
+
if (inputs) {
|
|
33
|
+
const entity = inputs[spec.viewSpec.type];
|
|
34
|
+
if (isValidElementType(entity === null || entity === void 0 ? void 0 : entity.Component)) {
|
|
35
|
+
result.inputEntity = entity;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (layouts && _.isString(spec.viewSpec.layout)) {
|
|
39
|
+
const Component = layouts[spec.viewSpec.layout];
|
|
40
|
+
if (isValidElementType(Component)) {
|
|
41
|
+
result.Layout = Component;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
export const getRender = ({ name, spec, inputEntity, Layout, }) => {
|
|
48
|
+
const render = (props) => {
|
|
49
|
+
if (inputEntity && isCorrectSpec(spec) && _.isString(name)) {
|
|
50
|
+
if (!spec.viewSpec.hidden) {
|
|
51
|
+
if (inputEntity.independent) {
|
|
52
|
+
const InputComponent = inputEntity.Component;
|
|
53
|
+
return React.createElement(InputComponent, Object.assign({ spec: spec, name: name, Layout: Layout }, props));
|
|
54
|
+
}
|
|
55
|
+
const InputComponent = inputEntity.Component;
|
|
56
|
+
const input = React.createElement(InputComponent, Object.assign({ spec: spec, name: name }, props));
|
|
57
|
+
if (Layout) {
|
|
58
|
+
return (React.createElement(Layout, Object.assign({ spec: spec, name: name }, props), input));
|
|
59
|
+
}
|
|
60
|
+
return input;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
};
|
|
65
|
+
return render;
|
|
66
|
+
};
|
|
67
|
+
export const getValidate = ({ spec, config, }) => {
|
|
68
|
+
let validate = () => undefined;
|
|
69
|
+
if (isCorrectConfig(config) && isCorrectSpec(spec)) {
|
|
70
|
+
const { validators } = config[spec.type];
|
|
71
|
+
if (validators) {
|
|
72
|
+
if ((!_.isString(spec.validator) || !spec.validator.length) &&
|
|
73
|
+
_.isFunction(validators.base)) {
|
|
74
|
+
validate = (value) => validators.base(spec, value);
|
|
75
|
+
}
|
|
76
|
+
if (_.isString(spec.validator) && _.isFunction(validators[spec.validator])) {
|
|
77
|
+
validate = (value) => validators[spec.validator](spec, value);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return validate;
|
|
82
|
+
};
|
|
83
|
+
export const getFieldInitials = ({ name, spec, valueFromParent, initialValue, validate, mutators, }) => {
|
|
84
|
+
const valueMutator = transformArrIn(_.get(mutators.values, name, EMPTY_MUTATOR));
|
|
85
|
+
let value = _.cloneDeep(valueFromParent);
|
|
86
|
+
if (isValueMutatorCorrect(valueMutator, spec)) {
|
|
87
|
+
value = valueMutator;
|
|
88
|
+
}
|
|
89
|
+
if (_.isNil(value)) {
|
|
90
|
+
if (spec.defaultValue) {
|
|
91
|
+
value = transformArrIn(spec.defaultValue);
|
|
92
|
+
}
|
|
93
|
+
// if the spec with type array or object, and this spec has "required === true",
|
|
94
|
+
// we immediately exclude empty value
|
|
95
|
+
else if (spec.required) {
|
|
96
|
+
if (isArraySpec(spec)) {
|
|
97
|
+
value = { [OBJECT_ARRAY_FLAG]: true, [OBJECT_ARRAY_CNT]: 0 };
|
|
98
|
+
}
|
|
99
|
+
else if (isObjectSpec(spec)) {
|
|
100
|
+
value = {};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
let errorMutator = _.get(mutators.errors, name, EMPTY_MUTATOR);
|
|
105
|
+
if (!isErrorMutatorCorrect(errorMutator)) {
|
|
106
|
+
errorMutator = undefined;
|
|
107
|
+
}
|
|
108
|
+
const error = (validate === null || validate === void 0 ? void 0 : validate(transformArrOut(value))) || errorMutator;
|
|
109
|
+
const dirty = !_.isEqual(value, initialValue);
|
|
110
|
+
return {
|
|
111
|
+
initialValue,
|
|
112
|
+
active: false,
|
|
113
|
+
dirty,
|
|
114
|
+
error,
|
|
115
|
+
invalid: Boolean(error),
|
|
116
|
+
modified: dirty,
|
|
117
|
+
pristine: true,
|
|
118
|
+
touched: false,
|
|
119
|
+
valid: !error,
|
|
120
|
+
value,
|
|
121
|
+
visited: false,
|
|
122
|
+
childErrors: {},
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
export const getFieldMethods = () => {
|
|
126
|
+
const onChange = (store, { valOrSetter, childErrors, errorMutator }) => {
|
|
127
|
+
const { state, validate, spec } = store;
|
|
128
|
+
const _value = _.isFunction(valOrSetter) ? valOrSetter(state.value) : valOrSetter;
|
|
129
|
+
const error = (validate === null || validate === void 0 ? void 0 : validate(transformArrOut(_value))) || errorMutator;
|
|
130
|
+
let value = transformArrIn(_value);
|
|
131
|
+
if (isNumberSpec(spec) && !error) {
|
|
132
|
+
value = (value ? Number(value) : undefined);
|
|
133
|
+
}
|
|
134
|
+
let newChildErrors = Object.assign({}, state.childErrors);
|
|
135
|
+
if (childErrors) {
|
|
136
|
+
const nearestChildName = _.keys(childErrors).sort((a, b) => a.length - b.length)[0];
|
|
137
|
+
if (nearestChildName) {
|
|
138
|
+
const existingСhildNames = _.keys(newChildErrors).filter((childName) => childName.startsWith(nearestChildName));
|
|
139
|
+
newChildErrors = Object.assign(Object.assign({}, _.omit(newChildErrors, existingСhildNames)), childErrors);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const nextStore = Object.assign(Object.assign({}, store), { state: Object.assign(Object.assign({}, store.state), { dirty: !_.isEqual(value, state.initialValue), error, invalid: Boolean(error), modified: true, pristine: value === state.initialValue, touched: true, valid: !error, value, visited: true, childErrors: newChildErrors }) });
|
|
143
|
+
nextStore.afterStoreUpdateCB = () => updateParentStore(nextStore);
|
|
144
|
+
return nextStore;
|
|
145
|
+
};
|
|
146
|
+
const onDrop = (store) => {
|
|
147
|
+
const { name } = store;
|
|
148
|
+
if (isArrayItem(name)) {
|
|
149
|
+
const afterStoreUpdateCB = () => callUnmout(store);
|
|
150
|
+
return Object.assign(Object.assign({}, store), { afterStoreUpdateCB });
|
|
151
|
+
}
|
|
152
|
+
return onChange(store, {
|
|
153
|
+
valOrSetter: undefined,
|
|
154
|
+
childErrors: { [name]: false },
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
const onBlur = (store) => {
|
|
158
|
+
return Object.assign(Object.assign({}, store), { state: Object.assign(Object.assign({}, store.state), { active: false, touched: true }) });
|
|
159
|
+
};
|
|
160
|
+
const onFocus = (store) => {
|
|
161
|
+
return Object.assign(Object.assign({}, store), { state: Object.assign(Object.assign({}, store.state), { active: true, visited: true }) });
|
|
162
|
+
};
|
|
163
|
+
const parentOnUnmount = (store, childName) => {
|
|
164
|
+
const { name, spec } = store;
|
|
165
|
+
if (isArraySpec(spec) || isObjectSpec(spec)) {
|
|
166
|
+
return onChange(store, {
|
|
167
|
+
valOrSetter: (currentValue) => currentValue
|
|
168
|
+
? _.omit(currentValue, childName.split(`${name}.`)[1])
|
|
169
|
+
: currentValue,
|
|
170
|
+
childErrors: { [childName]: false },
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return store;
|
|
174
|
+
};
|
|
175
|
+
const onItemAdd = (store, _value) => {
|
|
176
|
+
const { validate, state } = store;
|
|
177
|
+
const stateValue = (state.value || {
|
|
178
|
+
[OBJECT_ARRAY_FLAG]: true,
|
|
179
|
+
[OBJECT_ARRAY_CNT]: 0,
|
|
180
|
+
});
|
|
181
|
+
const value = Object.assign(Object.assign({}, stateValue), { [`<${stateValue[OBJECT_ARRAY_CNT]}>`]: transformArrIn(_value), [OBJECT_ARRAY_CNT]: stateValue[OBJECT_ARRAY_CNT] + 1 });
|
|
182
|
+
const error = validate === null || validate === void 0 ? void 0 : validate(transformArrOut(value));
|
|
183
|
+
const nextStore = Object.assign(Object.assign({}, store), { state: Object.assign(Object.assign({}, store.state), { dirty: !_.isEqual(value, store.state.initialValue), error, invalid: Boolean(error), modified: true, pristine: value === store.state.initialValue, touched: true, valid: !error, value, visited: true }) });
|
|
184
|
+
nextStore.afterStoreUpdateCB = () => updateParentStore(nextStore);
|
|
185
|
+
return nextStore;
|
|
186
|
+
};
|
|
187
|
+
const onItemRemove = (store, idx) => {
|
|
188
|
+
return parentOnUnmount(store, `${store.name}.<${idx}>`);
|
|
189
|
+
};
|
|
190
|
+
return {
|
|
191
|
+
onChange,
|
|
192
|
+
onDrop,
|
|
193
|
+
onBlur,
|
|
194
|
+
onFocus,
|
|
195
|
+
parentOnUnmount,
|
|
196
|
+
onItemAdd,
|
|
197
|
+
onItemRemove,
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
export const initializeStore = ({ name, spec: _spec, mutators, config, valueFromParent, tools, parentOnChange, parentOnUnmount, }) => {
|
|
201
|
+
const spec = getSpec({ name, spec: _spec, mutators });
|
|
202
|
+
const components = getComponents({ spec, config });
|
|
203
|
+
const render = getRender(Object.assign({ name, spec }, components));
|
|
204
|
+
const validate = getValidate({ spec, config });
|
|
205
|
+
const state = getFieldInitials({
|
|
206
|
+
name,
|
|
207
|
+
spec,
|
|
208
|
+
valueFromParent,
|
|
209
|
+
validate,
|
|
210
|
+
mutators,
|
|
211
|
+
initialValue: _.get(tools.initialValue, name),
|
|
212
|
+
});
|
|
213
|
+
const initialsStore = {
|
|
214
|
+
name,
|
|
215
|
+
spec,
|
|
216
|
+
initialSpec: _spec,
|
|
217
|
+
config,
|
|
218
|
+
tools,
|
|
219
|
+
mutators,
|
|
220
|
+
render,
|
|
221
|
+
validate,
|
|
222
|
+
parentOnChange,
|
|
223
|
+
parentOnUnmount,
|
|
224
|
+
state,
|
|
225
|
+
};
|
|
226
|
+
if (!_.isEqual(valueFromParent, state.value) || state.error) {
|
|
227
|
+
initialsStore.afterStoreUpdateCB = () => updateParentStore(initialsStore);
|
|
228
|
+
}
|
|
229
|
+
return initialsStore;
|
|
230
|
+
};
|
|
231
|
+
export const updateStore = ({ store, setStore, spec: _spec, name, parentOnChange, parentOnUnmount, mutators, valueFromParent, config, tools, methodOnChange, }) => {
|
|
232
|
+
const storeSpecMutator = _.get(store.mutators.spec, store.name, EMPTY_MUTATOR);
|
|
233
|
+
const storeValueMutator = _.get(store.mutators.values, store.name, EMPTY_MUTATOR);
|
|
234
|
+
const storeErrorMutator = _.get(store.mutators.errors, store.name, EMPTY_MUTATOR);
|
|
235
|
+
const specMutator = _.get(mutators.errors, name, EMPTY_MUTATOR);
|
|
236
|
+
const valueMutator = _.get(mutators.values, name, EMPTY_MUTATOR);
|
|
237
|
+
const errorMutator = _.get(mutators.errors, name, EMPTY_MUTATOR);
|
|
238
|
+
const valueMutatorUpdated = isValueMutatorCorrect(valueMutator, getSpec({ name, spec: _spec, mutators })) &&
|
|
239
|
+
valueMutator !== storeValueMutator;
|
|
240
|
+
const errorMutatorUpdated = isErrorMutatorCorrect(errorMutator) && errorMutator !== storeErrorMutator;
|
|
241
|
+
const updateState = valueMutatorUpdated || errorMutatorUpdated;
|
|
242
|
+
const updateNonCritical = parentOnChange !== store.parentOnChange ||
|
|
243
|
+
parentOnUnmount !== store.parentOnUnmount ||
|
|
244
|
+
tools.onChange !== store.tools.onChange ||
|
|
245
|
+
tools.onUnmount !== store.tools.onUnmount;
|
|
246
|
+
const updateAllStore = !_.isEqual(_spec, store.initialSpec) ||
|
|
247
|
+
config !== store.config ||
|
|
248
|
+
(specMutator !== EMPTY_MUTATOR && specMutator !== storeSpecMutator);
|
|
249
|
+
const updateAllStoreAndClearParentValues = name !== store.name;
|
|
250
|
+
if (updateAllStoreAndClearParentValues) {
|
|
251
|
+
callUnmout(store);
|
|
252
|
+
setStore(initializeStore({
|
|
253
|
+
name,
|
|
254
|
+
spec: _spec,
|
|
255
|
+
mutators,
|
|
256
|
+
config,
|
|
257
|
+
valueFromParent,
|
|
258
|
+
tools,
|
|
259
|
+
parentOnChange,
|
|
260
|
+
parentOnUnmount,
|
|
261
|
+
}));
|
|
262
|
+
}
|
|
263
|
+
else if (updateAllStore) {
|
|
264
|
+
let nextStore = Object.assign(Object.assign({}, initializeStore({
|
|
265
|
+
name,
|
|
266
|
+
spec: _spec,
|
|
267
|
+
mutators,
|
|
268
|
+
config,
|
|
269
|
+
valueFromParent,
|
|
270
|
+
tools,
|
|
271
|
+
parentOnChange,
|
|
272
|
+
parentOnUnmount,
|
|
273
|
+
})), { state: store.state });
|
|
274
|
+
if (updateState) {
|
|
275
|
+
nextStore = methodOnChange(nextStore, Object.assign({ valOrSetter: (value) => valueMutatorUpdated ? valueMutator : value }, (errorMutatorUpdated ? { errorMutator } : {})));
|
|
276
|
+
}
|
|
277
|
+
setStore(nextStore);
|
|
278
|
+
}
|
|
279
|
+
else if (updateNonCritical) {
|
|
280
|
+
let nextStore = Object.assign(Object.assign({}, store), { parentOnChange,
|
|
281
|
+
parentOnUnmount,
|
|
282
|
+
tools });
|
|
283
|
+
if (updateState) {
|
|
284
|
+
nextStore = methodOnChange(nextStore, Object.assign({ valOrSetter: (value) => valueMutatorUpdated ? valueMutator : value }, (errorMutatorUpdated ? { errorMutator } : {})));
|
|
285
|
+
}
|
|
286
|
+
setStore(nextStore);
|
|
287
|
+
}
|
|
288
|
+
else if (updateState) {
|
|
289
|
+
setStore(methodOnChange(store, Object.assign({ valOrSetter: (value) => valueMutatorUpdated ? valueMutator : value }, (errorMutatorUpdated ? { errorMutator } : {}))));
|
|
290
|
+
}
|
|
291
|
+
};
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
export * from './useComponents';
|
|
2
1
|
export * from './useControllerMirror';
|
|
3
2
|
export * from './useCreateContext';
|
|
4
3
|
export * from './useDynamicFieldMirror';
|
|
5
4
|
export * from './useDynamicFormsCtx';
|
|
6
|
-
export * from './useField';
|
|
7
5
|
export * from './useGenerateRandomValue';
|
|
8
6
|
export * from './useIntegrationFF';
|
|
9
7
|
export * from './useMutateDFState';
|
|
10
8
|
export * from './useMutators';
|
|
11
|
-
export * from './useRender';
|
|
12
9
|
export * from './useStore';
|
|
13
10
|
export * from './useStoreValue';
|
|
14
|
-
export * from './useValidate';
|
|
15
11
|
export * from './useMonaco';
|
|
16
12
|
export * from './useSearchStore';
|
|
17
13
|
export * from './useSearchContext';
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
export * from './useComponents';
|
|
2
1
|
export * from './useControllerMirror';
|
|
3
2
|
export * from './useCreateContext';
|
|
4
3
|
export * from './useDynamicFieldMirror';
|
|
5
4
|
export * from './useDynamicFormsCtx';
|
|
6
|
-
export * from './useField';
|
|
7
5
|
export * from './useGenerateRandomValue';
|
|
8
6
|
export * from './useIntegrationFF';
|
|
9
7
|
export * from './useMutateDFState';
|
|
10
8
|
export * from './useMutators';
|
|
11
|
-
export * from './useRender';
|
|
12
9
|
export * from './useStore';
|
|
13
10
|
export * from './useStoreValue';
|
|
14
|
-
export * from './useValidate';
|
|
15
11
|
export * from './useMonaco';
|
|
16
12
|
export * from './useSearchStore';
|
|
17
13
|
export * from './useSearchContext';
|
|
@@ -4,7 +4,27 @@ export const useMutators = (externalMutators) => {
|
|
|
4
4
|
const firstRenderRef = React.useRef(true);
|
|
5
5
|
const [store, setStore] = React.useState(externalMutators || {});
|
|
6
6
|
const mutateDFState = React.useCallback((mutators) => {
|
|
7
|
-
|
|
7
|
+
const mergeSpec = (a, b) => {
|
|
8
|
+
const result = _.cloneDeep(a);
|
|
9
|
+
const getKeys = (parent) => {
|
|
10
|
+
if (_.isObjectLike(parent)) {
|
|
11
|
+
return _.keys(parent).reduce((acc, parentKey) => {
|
|
12
|
+
const childKeys = getKeys(parent[parentKey]);
|
|
13
|
+
return [
|
|
14
|
+
...acc,
|
|
15
|
+
...(childKeys.length ? [] : [[parentKey]]),
|
|
16
|
+
...childKeys.map((childKey) => [parentKey, ...childKey]),
|
|
17
|
+
];
|
|
18
|
+
}, []);
|
|
19
|
+
}
|
|
20
|
+
return [];
|
|
21
|
+
};
|
|
22
|
+
getKeys(b).forEach((key) => {
|
|
23
|
+
_.set(result, key, _.get(b, key));
|
|
24
|
+
});
|
|
25
|
+
return result;
|
|
26
|
+
};
|
|
27
|
+
setStore((store) => (Object.assign(Object.assign(Object.assign(Object.assign({}, store), (mutators.errors ? { errors: _.merge(store.errors, mutators.errors) } : {})), (mutators.values ? { values: _.merge(store.values, mutators.values) } : {})), (mutators.spec ? { spec: mergeSpec(store.spec || {}, mutators.spec) } : {}))));
|
|
8
28
|
}, [setStore]);
|
|
9
29
|
React.useEffect(() => {
|
|
10
30
|
if (firstRenderRef.current) {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useIntegrationFF, useSearch, useSearchStore, useStore } from '../hooks';
|
|
2
|
+
import { FieldRenderProps } from './field';
|
|
2
3
|
export interface ControllerMirror {
|
|
3
|
-
|
|
4
|
-
useRender?: ReturnType<typeof useRender>;
|
|
5
|
-
useValidate?: ReturnType<typeof useValidate>;
|
|
6
|
-
useField?: ReturnType<typeof useField>;
|
|
4
|
+
useField?: FieldRenderProps<any>;
|
|
7
5
|
useSearch?: ReturnType<typeof useSearch>;
|
|
8
6
|
}
|
|
9
7
|
export interface DynamicFieldMirror {
|
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
import { FormValue,
|
|
1
|
+
import { ArraySpec, BooleanSpec, FormValue, NumberSpec, ObjectSpec, StringSpec } from '../../../types';
|
|
2
2
|
import { BaseValidateError } from './';
|
|
3
|
+
export type SpecMutator = Partial<(Omit<ArraySpec, 'viewSpec'> & {
|
|
4
|
+
viewSpec: Partial<ArraySpec['viewSpec']>;
|
|
5
|
+
}) | (Omit<BooleanSpec, 'viewSpec'> & {
|
|
6
|
+
viewSpec: Partial<BooleanSpec['viewSpec']>;
|
|
7
|
+
}) | (Omit<NumberSpec, 'viewSpec'> & {
|
|
8
|
+
viewSpec: Partial<NumberSpec['viewSpec']>;
|
|
9
|
+
}) | (Omit<ObjectSpec, 'viewSpec'> & {
|
|
10
|
+
viewSpec: Partial<ObjectSpec['viewSpec']>;
|
|
11
|
+
}) | (Omit<StringSpec, 'viewSpec'> & {
|
|
12
|
+
viewSpec: Partial<StringSpec['viewSpec']>;
|
|
13
|
+
})>;
|
|
3
14
|
export interface DynamicFormMutators {
|
|
4
15
|
errors?: Record<string, BaseValidateError>;
|
|
5
16
|
values?: Record<string, FormValue>;
|
|
6
|
-
spec?: Record<string,
|
|
17
|
+
spec?: Record<string, SpecMutator>;
|
|
7
18
|
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { FormValue, Spec } from '../../../types';
|
|
2
|
-
import { ValidateError } from '../types';
|
|
3
2
|
export declare const isCorrectConfig: (candidate: any) => boolean;
|
|
4
3
|
export declare const transformArrIn: <Type extends FormValue, ReturnType_1 extends FormValue = Type>(value: Type) => ReturnType_1;
|
|
5
4
|
export declare const transformArrOut: <Type extends FormValue, ReturnType_1 extends FormValue = Type>(value: Type) => ReturnType_1;
|
|
6
5
|
export declare const isArrayItem: (name: string) => boolean;
|
|
7
6
|
export declare const withGenerateButton: (spec: Spec) => boolean | undefined;
|
|
8
|
-
export declare const isErrorMutatorCorrect: (errorMutator: ValidateError) => boolean;
|
|
9
|
-
export declare const isValueMutatorCorrect: (valueMutator: FormValue, spec: Spec) => boolean;
|
|
@@ -45,5 +45,3 @@ export const isArrayItem = (name) => name[name.length - 1] === '>';
|
|
|
45
45
|
export const withGenerateButton = (spec) => isStringSpec(spec) &&
|
|
46
46
|
SPEC_TYPE_FOR_GENERATE_BUTTON.includes(spec.viewSpec.type) &&
|
|
47
47
|
spec.viewSpec.generateRandomValueButton;
|
|
48
|
-
export const isErrorMutatorCorrect = (errorMutator) => _.isString(errorMutator) || _.isBoolean(errorMutator) || _.isUndefined(errorMutator);
|
|
49
|
-
export const isValueMutatorCorrect = (valueMutator, spec) => typeof valueMutator === spec.type || (_.isArray(valueMutator) && spec.type === SpecTypes.Array);
|
package/package.json
CHANGED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Controller = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const react_1 = tslib_1.__importDefault(require("react"));
|
|
6
|
-
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
7
|
-
const constants_1 = require("./constants");
|
|
8
|
-
const hooks_1 = require("./hooks");
|
|
9
|
-
const Controller = ({ spec: _spec, name, value, parentOnChange, parentOnUnmount, }) => {
|
|
10
|
-
const { tools, mutators, __mirror } = (0, hooks_1.useDynamicFormsCtx)();
|
|
11
|
-
const spec = react_1.default.useMemo(() => {
|
|
12
|
-
const specMutator = lodash_1.default.get(mutators.spec, name, constants_1.EMPTY_MUTATOR);
|
|
13
|
-
if (specMutator !== constants_1.EMPTY_MUTATOR) {
|
|
14
|
-
return lodash_1.default.merge(_spec, specMutator);
|
|
15
|
-
}
|
|
16
|
-
return _spec;
|
|
17
|
-
}, [_spec, mutators.spec, name]);
|
|
18
|
-
const { inputEntity, Layout } = (0, hooks_1.useComponents)(spec);
|
|
19
|
-
const render = (0, hooks_1.useRender)({ name, spec, inputEntity, Layout });
|
|
20
|
-
const validate = (0, hooks_1.useValidate)(spec);
|
|
21
|
-
const renderProps = (0, hooks_1.useField)({
|
|
22
|
-
name,
|
|
23
|
-
initialValue: lodash_1.default.get(tools.initialValue, name),
|
|
24
|
-
value,
|
|
25
|
-
spec,
|
|
26
|
-
validate,
|
|
27
|
-
tools,
|
|
28
|
-
parentOnChange,
|
|
29
|
-
parentOnUnmount,
|
|
30
|
-
mutators,
|
|
31
|
-
});
|
|
32
|
-
const withSearch = (0, hooks_1.useSearch)(spec, renderProps.input.value, name);
|
|
33
|
-
(0, hooks_1.useControllerMirror)(name, {
|
|
34
|
-
useComponents: { inputEntity, Layout },
|
|
35
|
-
useRender: render,
|
|
36
|
-
useValidate: validate,
|
|
37
|
-
useField: renderProps,
|
|
38
|
-
useSearch: withSearch,
|
|
39
|
-
}, __mirror);
|
|
40
|
-
return withSearch(render(renderProps));
|
|
41
|
-
};
|
|
42
|
-
exports.Controller = Controller;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useComponents = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const react_1 = tslib_1.__importDefault(require("react"));
|
|
6
|
-
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
7
|
-
const react_is_1 = require("react-is");
|
|
8
|
-
const helpers_1 = require("../../../helpers");
|
|
9
|
-
const utils_1 = require("../utils");
|
|
10
|
-
const _1 = require("./");
|
|
11
|
-
const useComponents = (spec) => {
|
|
12
|
-
var _a, _b;
|
|
13
|
-
const { config } = (0, _1.useDynamicFormsCtx)();
|
|
14
|
-
const { inputs, layouts } = react_1.default.useMemo(() => {
|
|
15
|
-
if ((0, utils_1.isCorrectConfig)(config) && (0, helpers_1.isCorrectSpec)(spec)) {
|
|
16
|
-
return config[spec.type];
|
|
17
|
-
}
|
|
18
|
-
return {};
|
|
19
|
-
}, [config, spec]);
|
|
20
|
-
const inputEntity = react_1.default.useMemo(() => {
|
|
21
|
-
if (inputs) {
|
|
22
|
-
const entity = inputs[spec.viewSpec.type];
|
|
23
|
-
if ((0, react_is_1.isValidElementType)(entity === null || entity === void 0 ? void 0 : entity.Component)) {
|
|
24
|
-
return entity;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return;
|
|
28
|
-
}, [inputs, (_a = spec === null || spec === void 0 ? void 0 : spec.viewSpec) === null || _a === void 0 ? void 0 : _a.type]);
|
|
29
|
-
const Layout = react_1.default.useMemo(() => {
|
|
30
|
-
if (layouts && lodash_1.default.isString(spec.viewSpec.layout)) {
|
|
31
|
-
const Component = layouts[spec.viewSpec.layout];
|
|
32
|
-
if ((0, react_is_1.isValidElementType)(Component)) {
|
|
33
|
-
return Component;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return;
|
|
37
|
-
}, [layouts, (_b = spec === null || spec === void 0 ? void 0 : spec.viewSpec) === null || _b === void 0 ? void 0 : _b.layout]);
|
|
38
|
-
return { inputEntity, Layout };
|
|
39
|
-
};
|
|
40
|
-
exports.useComponents = useComponents;
|