Skip to content

Commit e43c7e3

Browse files
authored
feat: add dynamic field store mutators, add store value hook (#139)
1 parent bc0a993 commit e43c7e3

File tree

16 files changed

+178
-70
lines changed

16 files changed

+178
-70
lines changed

src/lib/core/components/Form/Controller.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import React from 'react';
2+
13
import _ from 'lodash';
24

35
import {Spec} from '../../types';
46

7+
import {EMPTY_MUTATOR} from './constants';
58
import {
69
useComponents,
710
useControllerMirror,
@@ -28,13 +31,24 @@ export interface ControllerProps<Value extends FieldValue, SpecType extends Spec
2831
}
2932

3033
export const Controller = <Value extends FieldValue, SpecType extends Spec>({
31-
spec,
34+
spec: _spec,
3235
name,
3336
value,
3437
parentOnChange,
3538
parentOnUnmount,
3639
}: ControllerProps<Value, SpecType>) => {
37-
const {tools, externalErrors, __mirror} = useDynamicFormsCtx();
40+
const {tools, mutators, __mirror} = useDynamicFormsCtx();
41+
42+
const spec = React.useMemo(() => {
43+
const specMutator = _.get(mutators.spec, name, EMPTY_MUTATOR);
44+
45+
if (specMutator !== EMPTY_MUTATOR) {
46+
return _.merge(_spec, specMutator);
47+
}
48+
49+
return _spec;
50+
}, [_spec, mutators.spec, name]);
51+
3852
const {inputEntity, Layout} = useComponents(spec);
3953
const render = useRender({name, spec, inputEntity, Layout});
4054
const validate = useValidate(spec);
@@ -47,7 +61,7 @@ export const Controller = <Value extends FieldValue, SpecType extends Spec>({
4761
tools,
4862
parentOnChange,
4963
parentOnUnmount,
50-
externalErrors,
64+
mutators,
5165
});
5266
const withSearch = useSearch(spec, renderProps.input.value, name);
5367

src/lib/core/components/Form/DynamicField.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import {
1313
useCreateSearchContext,
1414
useDynamicFieldMirror,
1515
useIntegrationFF,
16+
useMutators,
1617
useSearchStore,
1718
useStore,
1819
} from './hooks';
19-
import {BaseValidateError, DynamicFormConfig, FieldValue, WonderMirror} from './types';
20+
import {DynamicFormConfig, DynamicFormMutators, FieldValue, WonderMirror} from './types';
2021
import {getDefaultSearchFunction, isCorrectConfig} from './utils';
2122

2223
export interface DynamicFieldProps {
@@ -27,7 +28,7 @@ export interface DynamicFieldProps {
2728
search?: string | ((spec: Spec, input: FieldValue, name: string) => boolean);
2829
generateRandomValue?: (spec: StringSpec) => string;
2930
withoutInsertFFDebounce?: boolean;
30-
errors?: Record<string, BaseValidateError>;
31+
mutators?: DynamicFormMutators;
3132
__mirror?: WonderMirror;
3233
}
3334

@@ -39,25 +40,27 @@ export const DynamicField: React.FC<DynamicFieldProps> = ({
3940
generateRandomValue,
4041
search,
4142
withoutInsertFFDebounce,
42-
errors: externalErrors,
43+
mutators: externalMutators,
4344
__mirror,
4445
}) => {
4546
const DynamicFormsCtx = useCreateContext();
4647
const SearchContext = useCreateSearchContext();
4748
const {tools, store} = useStore(name);
4849
const watcher = useIntegrationFF(store, withoutInsertFFDebounce);
50+
const {mutators, mutateDFState} = useMutators(externalMutators);
4951
const {store: searchStore, setField, removeField, isHiddenField} = useSearchStore();
5052

5153
const context = React.useMemo(
5254
() => ({
5355
config,
5456
Monaco: isValidElementType(Monaco) ? Monaco : undefined,
5557
generateRandomValue,
56-
tools,
57-
externalErrors,
58+
tools: {...tools, mutateDFState},
59+
store,
60+
mutators,
5861
__mirror,
5962
}),
60-
[tools, config, Monaco, __mirror, generateRandomValue, externalErrors],
63+
[tools, config, Monaco, __mirror, generateRandomValue, mutators, mutateDFState, store],
6164
);
6265

6366
const searchContext = React.useMemo(

src/lib/core/components/Form/__tests__/DynamicField.test.tsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,12 @@ test('Form/hooks/DynamicField', () => {
176176
};
177177

178178
const errors = {
179-
name: false,
179+
name: undefined,
180180
'name.name': ErrorMessages.REQUIRED,
181181
'name.description': ErrorMessages.REQUIRED,
182182
'name.settings': ErrorMessages.REQUIRED,
183-
'name.autor': false,
184-
'name.autor.external': false,
183+
'name.autor': undefined,
184+
'name.autor.external': undefined,
185185
'name.autor.external.name': ErrorMessages.REQUIRED,
186186
'name.autor.external.age': ErrorMessages.REQUIRED,
187187
'name.autor.external.license': ErrorMessages.REQUIRED,
@@ -211,17 +211,17 @@ test('Form/hooks/DynamicField', () => {
211211
};
212212

213213
const errors1 = {
214-
name: false,
214+
name: undefined,
215215
'name.name': ErrorMessages.REQUIRED,
216216
'name.description': ErrorMessages.REQUIRED,
217217
'name.settings': ErrorMessages.REQUIRED,
218-
'name.autor': false,
219-
'name.autor.external': false,
218+
'name.autor': undefined,
219+
'name.autor.external': undefined,
220220
'name.autor.external.name': ErrorMessages.REQUIRED,
221221
'name.autor.external.age': ErrorMessages.REQUIRED,
222222
'name.autor.external.license': ErrorMessages.REQUIRED,
223223
'name.labels': ErrorMessages.minLengthArr(1),
224-
'name.additional': false,
224+
'name.additional': undefined,
225225
'name.additional.surname': ErrorMessages.REQUIRED,
226226
'name.additional.username': ErrorMessages.REQUIRED,
227227
};
@@ -247,13 +247,13 @@ test('Form/hooks/DynamicField', () => {
247247
};
248248

249249
const errors2 = {
250-
name: false,
250+
name: undefined,
251251
'name.name': ErrorMessages.REQUIRED,
252252
'name.description': ErrorMessages.REQUIRED,
253253
'name.settings': ErrorMessages.REQUIRED,
254254
'name.autor': ErrorMessages.REQUIRED,
255255
'name.labels': ErrorMessages.minLengthArr(1),
256-
'name.additional': false,
256+
'name.additional': undefined,
257257
'name.additional.surname': ErrorMessages.REQUIRED,
258258
'name.additional.username': ErrorMessages.REQUIRED,
259259
};
@@ -318,13 +318,13 @@ test('Form/hooks/DynamicField', () => {
318318
};
319319

320320
const errors4 = {
321-
name: false,
321+
name: undefined,
322322
'name.id': false,
323323
'name.name': ErrorMessages.REQUIRED,
324324
'name.description': ErrorMessages.REQUIRED,
325325
'name.settings': ErrorMessages.REQUIRED,
326-
'name.autor': false,
327-
'name.autor.external': false,
326+
'name.autor': undefined,
327+
'name.autor.external': undefined,
328328
'name.autor.external.name': ErrorMessages.REQUIRED,
329329
'name.autor.external.age': ErrorMessages.REQUIRED,
330330
'name.autor.external.license': ErrorMessages.REQUIRED,
@@ -368,13 +368,13 @@ test('Form/hooks/DynamicField', () => {
368368
};
369369

370370
const errors5 = {
371-
name: false,
371+
name: undefined,
372372
'name.id': false,
373373
'name.name': ErrorMessages.REQUIRED,
374374
'name.description': ErrorMessages.REQUIRED,
375375
'name.settings': ErrorMessages.REQUIRED,
376-
'name.autor': false,
377-
'name.autor.external': false,
376+
'name.autor': undefined,
377+
'name.autor.external': undefined,
378378
'name.autor.external.name': ErrorMessages.REQUIRED,
379379
'name.autor.external.age': ErrorMessages.REQUIRED,
380380
'name.autor.external.license': ErrorMessages.REQUIRED,

src/lib/core/components/Form/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ export const OBJECT_ARRAY_FLAG = '____arr-obj';
33
export const OBJECT_ARRAY_CNT = '____arr-obj-cnt';
44

55
export const SPEC_TYPE_FOR_GENERATE_BUTTON = ['base', 'password', 'textarea'];
6+
7+
export const EMPTY_MUTATOR = '____empty-mutator';

src/lib/core/components/Form/hooks/__tests__/useField.test.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,12 @@ describe('Form/hooks/useField', () => {
252252
expect(mirror.field.useStore?.store.values[name]).not.toBe(nextValue);
253253
expect(mirror.field.useStore?.store.values[name]).toMatchObject(nextValue);
254254
expect(mirror.field.useStore?.store.errors).toMatchObject({
255-
[name]: false,
255+
[name]: undefined,
256256
[`${name}.key`]: 'too long',
257257
});
258258

259259
expect(mirror.controller[name]?.useField?.meta.dirty).toBe(true);
260-
expect(mirror.controller[name]?.useField?.meta.error).toBe(false);
260+
expect(mirror.controller[name]?.useField?.meta.error).toBe(undefined);
261261
expect(mirror.controller[name]?.useField?.meta.invalid).toBe(false);
262262
expect(mirror.controller[name]?.useField?.meta.modified).toBe(true);
263263
expect(mirror.controller[name]?.useField?.meta.touched).toBe(true);
@@ -285,12 +285,12 @@ describe('Form/hooks/useField', () => {
285285
expect(mirror.field.useStore?.store.values[name]).not.toBe(value[name]);
286286
expect(mirror.field.useStore?.store.values[name]).toMatchObject(value[name]);
287287
expect(mirror.field.useStore?.store.errors).toMatchObject({
288-
[name]: false,
288+
[name]: undefined,
289289
[`${name}.key`]: false,
290290
});
291291

292292
expect(mirror.controller[name]?.useField?.meta.dirty).toBe(false);
293-
expect(mirror.controller[name]?.useField?.meta.error).toBe(false);
293+
expect(mirror.controller[name]?.useField?.meta.error).toBe(undefined);
294294
expect(mirror.controller[name]?.useField?.meta.invalid).toBe(false);
295295
expect(mirror.controller[name]?.useField?.meta.modified).toBe(true);
296296
expect(mirror.controller[name]?.useField?.meta.touched).toBe(true);
@@ -343,10 +343,10 @@ describe('Form/hooks/useField', () => {
343343
expect(mirror.controller[name]?.useField?.input.value).toBe(undefined);
344344
expect(mirror.controller[name]?.useField?.arrayInput.value).toBe(undefined);
345345
expect(mirror.field.useStore?.store.values[name]).toBe(undefined);
346-
expect(mirror.field.useStore?.store.errors).toMatchObject({[name]: false});
346+
expect(mirror.field.useStore?.store.errors).toMatchObject({[name]: undefined});
347347

348348
expect(mirror.controller[name]?.useField?.meta.dirty).toBe(true);
349-
expect(mirror.controller[name]?.useField?.meta.error).toBe(false);
349+
expect(mirror.controller[name]?.useField?.meta.error).toBe(undefined);
350350
expect(mirror.controller[name]?.useField?.meta.invalid).toBe(false);
351351
expect(mirror.controller[name]?.useField?.meta.modified).toBe(true);
352352
expect(mirror.controller[name]?.useField?.meta.touched).toBe(true);
@@ -591,10 +591,10 @@ describe('Form/hooks/useField', () => {
591591
expect(mirror.controller[name]?.useField?.arrayInput.value).toMatchObject(nextValue1);
592592
expect(mirror.field.useStore?.store.values[name]).toMatchObject(nextValue1);
593593

594-
expect(mirror.field.useStore?.store.errors).toMatchObject({[name]: false});
594+
expect(mirror.field.useStore?.store.errors).toMatchObject({[name]: undefined});
595595

596596
expect(mirror.controller[name]?.useField?.meta.dirty).toBe(true);
597-
expect(mirror.controller[name]?.useField?.meta.error).toBe(false);
597+
expect(mirror.controller[name]?.useField?.meta.error).toBe(undefined);
598598
expect(mirror.controller[name]?.useField?.meta.invalid).toBe(false);
599599
expect(mirror.controller[name]?.useField?.meta.modified).toBe(true);
600600
expect(mirror.controller[name]?.useField?.meta.touched).toBe(true);

src/lib/core/components/Form/hooks/__tests__/useIntegrationFF.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ describe('Form/hooks/useIntegrationFF', () => {
108108
mirror.controller[name]?.useField?.input.onChange({});
109109
});
110110

111-
expect(mirror.field.useStore?.store.errors[name]).toBe(false);
111+
expect(mirror.field.useStore?.store.errors[name]).toBe(undefined);
112112
expect(mirror.field.useIntegrationFF?.props.validate()).toBe(undefined);
113113
expect(form?.getState().errors?.[name]).toBe(undefined);
114114
});

src/lib/core/components/Form/hooks/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ export * from './useDynamicFormsCtx';
66
export * from './useField';
77
export * from './useGenerateRandomValue';
88
export * from './useIntegrationFF';
9+
export * from './useMutateDFState';
10+
export * from './useMutators';
911
export * from './useRender';
1012
export * from './useStore';
13+
export * from './useStoreValue';
1114
export * from './useValidate';
1215
export * from './useMonaco';
1316
export * from './useSearchStore';

0 commit comments

Comments
 (0)