@goodie-forms/react 1.1.6-alpha → 1.2.0-alpha
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/LICENSE +426 -426
- package/dist/components/FieldRenderer.d.ts +9 -9
- package/dist/components/FieldRenderer.d.ts.map +1 -1
- package/dist/hooks/useForm.d.ts +9 -8
- package/dist/hooks/useForm.d.ts.map +1 -1
- package/dist/hooks/useFormErrorObserver.d.ts +2 -2
- package/dist/hooks/useFormErrorObserver.d.ts.map +1 -1
- package/dist/hooks/useFormField.d.ts +2 -2
- package/dist/hooks/useFormField.d.ts.map +1 -1
- package/dist/hooks/useFormValuesObserver.d.ts +3 -3
- package/dist/hooks/useFormValuesObserver.d.ts.map +1 -1
- package/dist/index.js +82 -76
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/FieldRenderer.tsx +166 -120
- package/src/hooks/useForm.tsx +50 -55
- package/src/hooks/useFormErrorObserver.ts +44 -42
- package/src/hooks/useFormField.tsx +63 -55
- package/src/hooks/useFormValuesObserver.ts +49 -45
- package/src/hooks/useRenderControl.tsx +26 -26
- package/src/index.ts +7 -7
- package/src/utils/composeFns.ts +7 -7
- package/src/utils/groupBy.ts +13 -13
- package/tsconfig.json +8 -8
- package/vite.config.ts +23 -23
|
@@ -1,120 +1,166 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
ChangeEvent,
|
|
4
|
-
FocusEvent,
|
|
5
|
-
ReactNode,
|
|
6
|
-
Ref,
|
|
7
|
-
useEffect,
|
|
8
|
-
useRef,
|
|
9
|
-
} from "react";
|
|
10
|
-
import { UseForm } from "../hooks/useForm";
|
|
11
|
-
import { useFormField } from "../hooks/useFormField";
|
|
12
|
-
import { composeFns } from "../utils/composeFns";
|
|
13
|
-
|
|
14
|
-
export interface RenderParams<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
TPath
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
props.form.hookConfigs?.validateMode === "
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
1
|
+
import { FieldPath, FormField, NonnullFormField } from "@goodie-forms/core";
|
|
2
|
+
import {
|
|
3
|
+
ChangeEvent,
|
|
4
|
+
FocusEvent,
|
|
5
|
+
ReactNode,
|
|
6
|
+
Ref,
|
|
7
|
+
useEffect,
|
|
8
|
+
useRef,
|
|
9
|
+
} from "react";
|
|
10
|
+
import { useForm, UseForm } from "../hooks/useForm";
|
|
11
|
+
import { useFormField } from "../hooks/useFormField";
|
|
12
|
+
import { composeFns } from "../utils/composeFns";
|
|
13
|
+
|
|
14
|
+
export interface RenderParams<TOutput extends object, TValue> {
|
|
15
|
+
ref: Ref<any | null>;
|
|
16
|
+
|
|
17
|
+
value: TValue | undefined;
|
|
18
|
+
|
|
19
|
+
handlers: {
|
|
20
|
+
onChange: (event: ChangeEvent<EventTarget>) => void;
|
|
21
|
+
onFocus: (event: FocusEvent) => void;
|
|
22
|
+
onBlur: (event: FocusEvent) => void;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
field: undefined extends TValue
|
|
26
|
+
? FormField<TOutput, TValue>
|
|
27
|
+
: NonnullFormField<TOutput, TValue>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type DefaultValueProps<TValue> = undefined extends TValue
|
|
31
|
+
? { defaultValue?: TValue | (() => TValue) }
|
|
32
|
+
: { defaultValue: TValue | (() => TValue) };
|
|
33
|
+
|
|
34
|
+
export type FieldRendererProps<
|
|
35
|
+
TOutput extends object,
|
|
36
|
+
TPath extends FieldPath.Segments,
|
|
37
|
+
> = {
|
|
38
|
+
form: UseForm<TOutput>;
|
|
39
|
+
path: TPath;
|
|
40
|
+
overrideInitialValue?: boolean;
|
|
41
|
+
unbindOnUnmount?: boolean;
|
|
42
|
+
render: (
|
|
43
|
+
params: RenderParams<TOutput, FieldPath.Resolve<TOutput, NoInfer<TPath>>>,
|
|
44
|
+
) => ReactNode;
|
|
45
|
+
} & DefaultValueProps<FieldPath.Resolve<TOutput, NoInfer<TPath>>>;
|
|
46
|
+
|
|
47
|
+
export function FieldRenderer<
|
|
48
|
+
TOutput extends object,
|
|
49
|
+
const TPath extends FieldPath.Segments,
|
|
50
|
+
>(props: FieldRendererProps<TOutput, TPath>) {
|
|
51
|
+
type TValue = FieldPath.Resolve<TOutput, TPath>;
|
|
52
|
+
|
|
53
|
+
const elementRef = useRef<HTMLElement>(null);
|
|
54
|
+
|
|
55
|
+
const field = useFormField(props.form, props.path, {
|
|
56
|
+
overrideInitialValue: props.overrideInitialValue ?? true,
|
|
57
|
+
defaultValue:
|
|
58
|
+
typeof props.defaultValue === "function"
|
|
59
|
+
? (props.defaultValue as any)()
|
|
60
|
+
: props.defaultValue,
|
|
61
|
+
})!;
|
|
62
|
+
|
|
63
|
+
const handlers: RenderParams<TOutput, TValue>["handlers"] = {
|
|
64
|
+
onChange(event) {
|
|
65
|
+
const { target } = event;
|
|
66
|
+
if (target !== field.boundElement) return;
|
|
67
|
+
if (!("value" in target)) return;
|
|
68
|
+
if (typeof target.value !== "string") return;
|
|
69
|
+
field.setValue(target.value as TValue, {
|
|
70
|
+
shouldTouch: true,
|
|
71
|
+
shouldMarkDirty: true,
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
onFocus() {
|
|
75
|
+
field.touch();
|
|
76
|
+
},
|
|
77
|
+
onBlur() {
|
|
78
|
+
if (
|
|
79
|
+
props.form.hookConfigs?.validateMode === "onBlur" ||
|
|
80
|
+
props.form.hookConfigs?.validateMode === "onChange"
|
|
81
|
+
) {
|
|
82
|
+
props.form.controller.validateField(props.path);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
const { events } = props.form.controller;
|
|
89
|
+
|
|
90
|
+
return composeFns(
|
|
91
|
+
events.on("valueChanged", (_path) => {
|
|
92
|
+
if (
|
|
93
|
+
!FieldPath.equals(_path, props.path) &&
|
|
94
|
+
!FieldPath.isDescendant(_path, props.path)
|
|
95
|
+
) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (props.form.hookConfigs?.validateMode === "onChange") {
|
|
100
|
+
props.form.controller.validateField(props.path);
|
|
101
|
+
}
|
|
102
|
+
}),
|
|
103
|
+
);
|
|
104
|
+
}, []);
|
|
105
|
+
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
field.bindElement(elementRef.current!);
|
|
108
|
+
|
|
109
|
+
return () => {
|
|
110
|
+
if (props.unbindOnUnmount) {
|
|
111
|
+
props.form.controller.unbindField(props.path);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}, []);
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<>
|
|
118
|
+
{props.render({
|
|
119
|
+
ref: elementRef,
|
|
120
|
+
value: field.value,
|
|
121
|
+
handlers: handlers,
|
|
122
|
+
field: field as any,
|
|
123
|
+
})}
|
|
124
|
+
</>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* ---- TESTS ---------------- */
|
|
129
|
+
|
|
130
|
+
// function TestComp() {
|
|
131
|
+
// const form = useForm<{ a?: { b: 99 } }>({});
|
|
132
|
+
|
|
133
|
+
// const jsx = (
|
|
134
|
+
// <>
|
|
135
|
+
// <FieldRenderer
|
|
136
|
+
// form={form}
|
|
137
|
+
// path={form.paths.fromProxy((data) => data.a.b)}
|
|
138
|
+
// defaultValue={() => 99 as const}
|
|
139
|
+
// render={({ ref, value, handlers, field }) => {
|
|
140
|
+
// // ^?
|
|
141
|
+
// return <></>;
|
|
142
|
+
// }}
|
|
143
|
+
// />
|
|
144
|
+
|
|
145
|
+
// {/* defaultField olmayabilir, çünkü "a" nullable */}
|
|
146
|
+
// <FieldRenderer
|
|
147
|
+
// form={form}
|
|
148
|
+
// path={form.paths.fromProxy((data) => data.a)}
|
|
149
|
+
// render={({ ref, value, handlers, field }) => {
|
|
150
|
+
// // ^?
|
|
151
|
+
// return <></>;
|
|
152
|
+
// }}
|
|
153
|
+
// />
|
|
154
|
+
|
|
155
|
+
// <FieldRenderer
|
|
156
|
+
// form={form}
|
|
157
|
+
// path={form.paths.fromStringPath("a.b")}
|
|
158
|
+
// defaultValue={() => 99 as const}
|
|
159
|
+
// render={({ ref, value, handlers, field }) => {
|
|
160
|
+
// // ^?
|
|
161
|
+
// return <></>;
|
|
162
|
+
// }}
|
|
163
|
+
// />
|
|
164
|
+
// </>
|
|
165
|
+
// );
|
|
166
|
+
// }
|
package/src/hooks/useForm.tsx
CHANGED
|
@@ -1,55 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export function useForm<
|
|
7
|
-
formConfigs:
|
|
8
|
-
hookConfigs?: {
|
|
9
|
-
validateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
10
|
-
revalidateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
11
|
-
watchIssues?: boolean;
|
|
12
|
-
watchValues?: boolean;
|
|
13
|
-
}
|
|
14
|
-
) {
|
|
15
|
-
const [controller] = useState(() => new FormController(formConfigs));
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
watchIssues?: boolean;
|
|
52
|
-
watchValues?: boolean;
|
|
53
|
-
};
|
|
54
|
-
controller: FormController<TShape>;
|
|
55
|
-
};
|
|
1
|
+
import { FieldPathBuilder, FormController } from "@goodie-forms/core";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { useRenderControl } from "../hooks/useRenderControl";
|
|
4
|
+
import { composeFns } from "../utils/composeFns";
|
|
5
|
+
|
|
6
|
+
export function useForm<TOutput extends object>(
|
|
7
|
+
formConfigs: FormController.Configs<TOutput>,
|
|
8
|
+
hookConfigs?: {
|
|
9
|
+
validateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
10
|
+
revalidateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
11
|
+
watchIssues?: boolean;
|
|
12
|
+
watchValues?: boolean;
|
|
13
|
+
},
|
|
14
|
+
) {
|
|
15
|
+
const [controller] = useState(() => new FormController(formConfigs));
|
|
16
|
+
const [paths] = useState(() => new FieldPathBuilder<TOutput>());
|
|
17
|
+
|
|
18
|
+
const renderControl = useRenderControl();
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const noop = () => {};
|
|
22
|
+
|
|
23
|
+
return composeFns(
|
|
24
|
+
controller.events.on("submissionStatusChange", () => {
|
|
25
|
+
renderControl.forceRerender();
|
|
26
|
+
}),
|
|
27
|
+
hookConfigs?.watchIssues
|
|
28
|
+
? controller.events.on("fieldIssuesUpdated", () =>
|
|
29
|
+
renderControl.forceRerender(),
|
|
30
|
+
)
|
|
31
|
+
: noop,
|
|
32
|
+
hookConfigs?.watchValues
|
|
33
|
+
? controller.events.on("valueChanged", () =>
|
|
34
|
+
renderControl.forceRerender(),
|
|
35
|
+
)
|
|
36
|
+
: noop,
|
|
37
|
+
);
|
|
38
|
+
}, [controller]);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
formConfigs,
|
|
42
|
+
paths,
|
|
43
|
+
hookConfigs,
|
|
44
|
+
controller,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type UseForm<TOutput extends object> = ReturnType<
|
|
49
|
+
typeof useForm<TOutput>
|
|
50
|
+
>;
|
|
@@ -1,42 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import type { UseForm } from "./useForm";
|
|
6
|
-
import { useRenderControl } from "./useRenderControl";
|
|
7
|
-
|
|
8
|
-
export function useFormErrorObserver<
|
|
9
|
-
|
|
10
|
-
TInclude extends
|
|
11
|
-
>(
|
|
12
|
-
form: UseForm<
|
|
13
|
-
options?: {
|
|
14
|
-
include?: TInclude;
|
|
15
|
-
}
|
|
16
|
-
) {
|
|
17
|
-
const renderControl = useRenderControl();
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
if (options?.include == null) return true;
|
|
21
|
-
const
|
|
22
|
-
return options.include.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
import { FieldPath } from "@goodie-forms/core";
|
|
2
|
+
import { groupBy } from "../utils/groupBy";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { composeFns } from "../utils/composeFns";
|
|
5
|
+
import type { UseForm } from "./useForm";
|
|
6
|
+
import { useRenderControl } from "./useRenderControl";
|
|
7
|
+
|
|
8
|
+
export function useFormErrorObserver<
|
|
9
|
+
TOutput extends object,
|
|
10
|
+
TInclude extends FieldPath.Segments[] | undefined = undefined,
|
|
11
|
+
>(
|
|
12
|
+
form: UseForm<TOutput>,
|
|
13
|
+
options?: {
|
|
14
|
+
include?: TInclude;
|
|
15
|
+
},
|
|
16
|
+
) {
|
|
17
|
+
const renderControl = useRenderControl();
|
|
18
|
+
|
|
19
|
+
const observedIssues = form.controller._issues.filter((issue) => {
|
|
20
|
+
if (options?.include == null) return true;
|
|
21
|
+
const normalizedIssuePath = FieldPath.normalize(issue.path);
|
|
22
|
+
return options.include.some((path) =>
|
|
23
|
+
FieldPath.equals(path, normalizedIssuePath),
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const { events } = form.controller;
|
|
29
|
+
|
|
30
|
+
return composeFns(
|
|
31
|
+
events.on("fieldIssuesUpdated", (path) => {
|
|
32
|
+
if (options?.include?.includes?.(path) ?? true) {
|
|
33
|
+
renderControl.forceRerender();
|
|
34
|
+
}
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
return groupBy(observedIssues, (issue) =>
|
|
40
|
+
issue.path == null
|
|
41
|
+
? "$"
|
|
42
|
+
: FieldPath.toStringPath(FieldPath.normalize(issue.path)),
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -1,55 +1,63 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
import { UseForm } from "../hooks/useForm";
|
|
4
|
-
import { useRenderControl } from "../hooks/useRenderControl";
|
|
5
|
-
import { composeFns } from "../utils/composeFns";
|
|
6
|
-
|
|
7
|
-
export function useFormField<
|
|
8
|
-
|
|
9
|
-
TPath extends
|
|
10
|
-
>(
|
|
11
|
-
form: UseForm<
|
|
12
|
-
path: TPath,
|
|
13
|
-
bindingConfig?: Parameters<typeof form.controller.bindField<TPath>>[1]
|
|
14
|
-
) {
|
|
15
|
-
const renderControl = useRenderControl();
|
|
16
|
-
|
|
17
|
-
const [field, setField] = useState(() => {
|
|
18
|
-
let field = form.controller.getField(path);
|
|
19
|
-
if (field == null && bindingConfig != null) {
|
|
20
|
-
field = form.controller.bindField(path, bindingConfig);
|
|
21
|
-
}
|
|
22
|
-
return field;
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
const { events } = form.controller;
|
|
27
|
-
|
|
28
|
-
setField(form.controller.getField(path));
|
|
29
|
-
|
|
30
|
-
return composeFns(
|
|
31
|
-
events.on("fieldBound", (_path) => {
|
|
32
|
-
if (_path
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
1
|
+
import { FieldPath } from "@goodie-forms/core";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { UseForm } from "../hooks/useForm";
|
|
4
|
+
import { useRenderControl } from "../hooks/useRenderControl";
|
|
5
|
+
import { composeFns } from "../utils/composeFns";
|
|
6
|
+
|
|
7
|
+
export function useFormField<
|
|
8
|
+
TOutput extends object,
|
|
9
|
+
TPath extends FieldPath.Segments,
|
|
10
|
+
>(
|
|
11
|
+
form: UseForm<TOutput>,
|
|
12
|
+
path: TPath,
|
|
13
|
+
bindingConfig?: Parameters<typeof form.controller.bindField<TPath>>[1],
|
|
14
|
+
) {
|
|
15
|
+
const renderControl = useRenderControl();
|
|
16
|
+
|
|
17
|
+
const [field, setField] = useState(() => {
|
|
18
|
+
let field = form.controller.getField(path);
|
|
19
|
+
if (field == null && bindingConfig != null) {
|
|
20
|
+
field = form.controller.bindField(path, bindingConfig);
|
|
21
|
+
}
|
|
22
|
+
return field;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const { events } = form.controller;
|
|
27
|
+
|
|
28
|
+
setField(form.controller.getField(path));
|
|
29
|
+
|
|
30
|
+
return composeFns(
|
|
31
|
+
events.on("fieldBound", (_path) => {
|
|
32
|
+
if (!FieldPath.equals(_path, path)) return;
|
|
33
|
+
setField(form.controller.getField(path));
|
|
34
|
+
}),
|
|
35
|
+
events.on("fieldUnbound", (_path) => {
|
|
36
|
+
if (!FieldPath.equals(_path, path)) return;
|
|
37
|
+
setField(undefined);
|
|
38
|
+
}),
|
|
39
|
+
events.on("valueChanged", (changedPath) => {
|
|
40
|
+
if (
|
|
41
|
+
FieldPath.equals(changedPath, path) ||
|
|
42
|
+
FieldPath.isDescendant(changedPath, path)
|
|
43
|
+
) {
|
|
44
|
+
renderControl.forceRerender();
|
|
45
|
+
}
|
|
46
|
+
}),
|
|
47
|
+
events.on("fieldTouchUpdated", (_path) => {
|
|
48
|
+
if (!FieldPath.equals(_path, path)) return;
|
|
49
|
+
renderControl.forceRerender();
|
|
50
|
+
}),
|
|
51
|
+
events.on("fieldDirtyUpdated", (_path) => {
|
|
52
|
+
if (!FieldPath.equals(_path, path)) return;
|
|
53
|
+
renderControl.forceRerender();
|
|
54
|
+
}),
|
|
55
|
+
events.on("fieldIssuesUpdated", (_path) => {
|
|
56
|
+
if (!FieldPath.equals(_path, path)) return;
|
|
57
|
+
renderControl.forceRerender();
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
return field;
|
|
63
|
+
}
|