Skip to content

Commit 944952d

Browse files
authored
feat: add new controller (#143)
1 parent 43b9dec commit 944952d

File tree

17 files changed

+928
-1759
lines changed

17 files changed

+928
-1759
lines changed

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

Lines changed: 0 additions & 70 deletions
This file was deleted.
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import React from 'react';
2+
3+
import _ from 'lodash';
4+
5+
import {FormValue, Spec} from '../../../types';
6+
import {useControllerMirror, useDynamicFormsCtx, useSearch} from '../hooks';
7+
import {ControllerMirror, FieldValue, ValidateError} from '../types';
8+
9+
import {ControllerStore} from './types';
10+
import {callUnmout, getFieldMethods, initializeStore, updateStore} from './utils';
11+
12+
export interface ControllerProps<DirtyValue extends FieldValue, SpecType extends Spec> {
13+
spec: SpecType;
14+
name: string;
15+
value: DirtyValue;
16+
parentOnChange:
17+
| ((
18+
childName: string,
19+
childValue: FieldValue,
20+
childErrors: Record<string, ValidateError>,
21+
) => void)
22+
| null;
23+
parentOnUnmount: ((childName: string) => void) | null;
24+
}
25+
26+
export const Controller = <
27+
DirtyValue extends FieldValue,
28+
Value extends FormValue,
29+
SpecType extends Spec,
30+
>({
31+
spec: _spec,
32+
name,
33+
value: valueFromParent,
34+
parentOnChange,
35+
parentOnUnmount,
36+
}: ControllerProps<DirtyValue, SpecType>) => {
37+
const {config, tools, mutators, __mirror} = useDynamicFormsCtx();
38+
39+
const firstRenderRef = React.useRef(true);
40+
const [store, setStore] = React.useState<ControllerStore<DirtyValue, Value, SpecType>>(
41+
initializeStore({
42+
name,
43+
spec: _spec,
44+
mutators,
45+
config,
46+
valueFromParent,
47+
tools,
48+
parentOnChange,
49+
parentOnUnmount,
50+
}),
51+
);
52+
53+
const {methods, fieldMethods} = React.useMemo(() => {
54+
const fieldMethods = getFieldMethods<DirtyValue, Value, SpecType>();
55+
56+
const onChange = (
57+
valOrSetter: DirtyValue | ((currentValue: DirtyValue) => DirtyValue),
58+
childErrors?: Record<string, ValidateError>,
59+
errorMutator?: ValidateError,
60+
) => {
61+
setStore((store) =>
62+
fieldMethods.onChange(store, {valOrSetter, childErrors, errorMutator}),
63+
);
64+
};
65+
66+
const onDrop = () => {
67+
setStore((store) => fieldMethods.onDrop(store, undefined));
68+
};
69+
70+
const onBlur = () => {
71+
setStore((store) => fieldMethods.onBlur(store, undefined));
72+
};
73+
74+
const onFocus = () => {
75+
setStore((store) => fieldMethods.onFocus(store, undefined));
76+
};
77+
78+
const parentOnUnmount = (childName: string) => {
79+
setStore((store) => fieldMethods.parentOnUnmount(store, childName));
80+
};
81+
82+
const onItemAdd = (value: FieldValue) => {
83+
setStore((store) => fieldMethods.onItemAdd(store, value));
84+
};
85+
86+
const onItemRemove = (idx: string | number) => {
87+
setStore((store) => fieldMethods.onItemRemove(store, idx));
88+
};
89+
90+
return {
91+
methods: {
92+
onChange,
93+
onDrop,
94+
onBlur,
95+
onFocus,
96+
parentOnUnmount,
97+
onItemAdd,
98+
onItemRemove,
99+
},
100+
fieldMethods,
101+
};
102+
}, [setStore]);
103+
104+
const renderProps = React.useMemo(
105+
() => ({
106+
input: {
107+
name: store.name,
108+
value: store.state.value,
109+
onChange: methods.onChange,
110+
onBlur: methods.onBlur,
111+
onFocus: methods.onFocus,
112+
onDrop: methods.onDrop,
113+
parentOnUnmount: methods.parentOnUnmount,
114+
},
115+
arrayInput: {
116+
name: store.name,
117+
value: store.state.value,
118+
onItemAdd: methods.onItemAdd,
119+
onItemRemove: methods.onItemRemove,
120+
onDrop: methods.onDrop,
121+
},
122+
meta: {..._.omit(store.state, 'value'), submitFailed: store.tools.submitFailed},
123+
}),
124+
[methods, store.name, store.state, store.tools.submitFailed],
125+
);
126+
127+
const withSearch = useSearch(store.spec, store.state.value, store.name);
128+
129+
useControllerMirror(
130+
store.name,
131+
{
132+
useField: renderProps,
133+
useSearch: withSearch,
134+
} as ControllerMirror,
135+
__mirror,
136+
);
137+
138+
React.useEffect(() => {
139+
store.afterStoreUpdateCB?.();
140+
}, [store.afterStoreUpdateCB]);
141+
142+
React.useEffect(() => {
143+
if (!firstRenderRef.current) {
144+
updateStore({
145+
store,
146+
setStore,
147+
spec: _spec,
148+
name,
149+
parentOnChange,
150+
parentOnUnmount,
151+
mutators,
152+
config,
153+
tools,
154+
methodOnChange: fieldMethods.onChange,
155+
valueFromParent,
156+
});
157+
}
158+
}, [
159+
_spec,
160+
name,
161+
parentOnChange,
162+
parentOnUnmount,
163+
mutators,
164+
config,
165+
tools.onChange,
166+
tools.onUnmount,
167+
]);
168+
169+
React.useEffect(() => {
170+
firstRenderRef.current = false;
171+
172+
return () => {
173+
callUnmout(store);
174+
};
175+
}, []);
176+
177+
return withSearch(store.render(renderProps));
178+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Controller';

0 commit comments

Comments
 (0)