@goodie-forms/react 1.2.4-alpha → 1.2.6-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/dist/components/FieldRenderer.d.ts +9 -8
- package/dist/components/FieldRenderer.d.ts.map +1 -1
- package/dist/hooks/useFieldIssues.d.ts +4 -0
- package/dist/hooks/useFieldIssues.d.ts.map +1 -0
- package/dist/hooks/useFieldValue.d.ts +1 -1
- package/dist/hooks/useFieldValue.d.ts.map +1 -1
- package/dist/hooks/useForm.d.ts +18 -2
- package/dist/hooks/useForm.d.ts.map +1 -1
- package/dist/hooks/useFormField.d.ts +3 -2
- package/dist/hooks/useFormField.d.ts.map +1 -1
- package/dist/hooks/useSyncMutableStore.d.ts +2 -0
- package/dist/hooks/useSyncMutableStore.d.ts.map +1 -0
- package/dist/index.d.ts +1 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +167 -172
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
- package/dist/hooks/useFieldErrors.d.ts +0 -4
- package/dist/hooks/useFieldErrors.d.ts.map +0 -1
- package/dist/hooks/useFormErrorObserver.d.ts +0 -7
- package/dist/hooks/useFormErrorObserver.d.ts.map +0 -1
- package/dist/hooks/useFormValuesObserver.d.ts +0 -7
- package/dist/hooks/useFormValuesObserver.d.ts.map +0 -1
- package/src/components/FieldRenderer.tsx +0 -166
- package/src/hooks/useFieldErrors.ts +0 -31
- package/src/hooks/useFieldValue.ts +0 -31
- package/src/hooks/useForm.tsx +0 -50
- package/src/hooks/useFormErrorObserver.ts +0 -45
- package/src/hooks/useFormField.tsx +0 -63
- package/src/hooks/useFormValuesObserver.ts +0 -50
- package/src/hooks/useRenderControl.tsx +0 -26
- package/src/index.ts +0 -9
- package/src/utils/composeFns.ts +0 -7
- package/src/utils/groupBy.ts +0 -13
- package/tsconfig.json +0 -8
- package/vite.config.ts +0 -23
|
@@ -1,29 +1,30 @@
|
|
|
1
|
-
import { FieldPath, FormField,
|
|
1
|
+
import { DeepReadonly, FieldPath, FormField, Suppliable } from '../../../core/src';
|
|
2
2
|
import { ChangeEvent, ReactNode, Ref } from 'react';
|
|
3
3
|
import { UseForm } from '../hooks/useForm';
|
|
4
4
|
export interface RenderParams<TOutput extends object, TValue> {
|
|
5
5
|
fieldProps: {
|
|
6
6
|
ref: Ref<any | null>;
|
|
7
|
-
|
|
7
|
+
name: string;
|
|
8
|
+
value: DeepReadonly<TValue> | undefined;
|
|
8
9
|
onChange: (event: ChangeEvent<EventTarget> | TValue) => void;
|
|
9
10
|
onFocus: () => void;
|
|
10
11
|
onBlur: () => void;
|
|
11
12
|
};
|
|
12
|
-
field:
|
|
13
|
+
field: FormField<TOutput, TValue>;
|
|
13
14
|
form: UseForm<TOutput>;
|
|
14
15
|
}
|
|
15
16
|
type DefaultValueProps<TValue> = undefined extends TValue ? {
|
|
16
|
-
defaultValue?: TValue
|
|
17
|
+
defaultValue?: Suppliable<TValue>;
|
|
17
18
|
} : {
|
|
18
|
-
defaultValue: TValue
|
|
19
|
+
defaultValue: Suppliable<TValue>;
|
|
19
20
|
};
|
|
20
|
-
export type FieldRendererProps<TOutput extends object, TPath extends FieldPath.Segments> = {
|
|
21
|
+
export type FieldRendererProps<TOutput extends object, TPath extends FieldPath.Segments> = DefaultValueProps<FieldPath.Resolve<TOutput, TPath>> & {
|
|
21
22
|
form: UseForm<TOutput>;
|
|
22
23
|
path: TPath;
|
|
23
24
|
overrideInitialValue?: boolean;
|
|
24
25
|
unbindOnUnmount?: boolean;
|
|
25
|
-
render: (params: RenderParams<TOutput, FieldPath.Resolve<TOutput,
|
|
26
|
-
}
|
|
26
|
+
render: (params: RenderParams<TOutput, FieldPath.Resolve<TOutput, TPath>>) => ReactNode;
|
|
27
|
+
};
|
|
27
28
|
export declare function FieldRenderer<TOutput extends object, const TPath extends FieldPath.Segments>(props: FieldRendererProps<TOutput, TPath>): import("react/jsx-runtime").JSX.Element;
|
|
28
29
|
export {};
|
|
29
30
|
//# sourceMappingURL=FieldRenderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldRenderer.d.ts","sourceRoot":"","sources":["../../src/components/FieldRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"FieldRenderer.d.ts","sourceRoot":"","sources":["../../src/components/FieldRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,SAAS,EACT,SAAS,EACT,UAAU,EACX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,EAAqB,MAAM,OAAO,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM;IAC1D,UAAU,EAAE;QACV,GAAG,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;QAErB,IAAI,EAAE,MAAM,CAAC;QAEb,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;QAExC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,WAAW,CAAC,GAAG,MAAM,KAAK,IAAI,CAAC;QAC7D,OAAO,EAAE,MAAM,IAAI,CAAC;QACpB,MAAM,EAAE,MAAM,IAAI,CAAC;KACpB,CAAC;IAEF,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAElC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACxB;AAED,KAAK,iBAAiB,CAAC,MAAM,IAAI,SAAS,SAAS,MAAM,GACrD;IAAE,YAAY,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;CAAE,GACrC;IAAE,YAAY,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAEzC,MAAM,MAAM,kBAAkB,CAC5B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,IAC9B,iBAAiB,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,GAAG;IACzD,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACvB,IAAI,EAAE,KAAK,CAAC;IACZ,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,CACN,MAAM,EAAE,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,KAC7D,SAAS,CAAC;CAChB,CAAC;AAEF,wBAAgB,aAAa,CAC3B,OAAO,SAAS,MAAM,EACtB,KAAK,CAAC,KAAK,SAAS,SAAS,CAAC,QAAQ,EACtC,KAAK,EAAE,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,2CAqF1C"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { FieldPath } from '../../../core/src';
|
|
2
|
+
import { UseForm } from './useForm';
|
|
3
|
+
export declare function useFieldIssues<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath): import("@standard-schema/spec").StandardSchemaV1.Issue[];
|
|
4
|
+
//# sourceMappingURL=useFieldIssues.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFieldIssues.d.ts","sourceRoot":"","sources":["../../src/hooks/useFieldIssues.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,wBAAgB,cAAc,CAC5B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,EAChC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,4DAiCpC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { FieldPath } from '../../../core/src';
|
|
2
2
|
import { UseForm } from '../hooks/useForm';
|
|
3
|
-
export declare function useFieldValue<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath): FieldPath.Resolve<TOutput, TPath
|
|
3
|
+
export declare function useFieldValue<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath): import('../../../core/src').DeepReadonly<FieldPath.Resolve<TOutput, TPath>> | undefined;
|
|
4
4
|
//# sourceMappingURL=useFieldValue.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFieldValue.d.ts","sourceRoot":"","sources":["../../src/hooks/useFieldValue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"useFieldValue.d.ts","sourceRoot":"","sources":["../../src/hooks/useFieldValue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAG3C,wBAAgB,aAAa,CAC3B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,EAChC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,4FAoCpC"}
|
package/dist/hooks/useForm.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FormController } from '../../../core/src';
|
|
2
2
|
export declare function useForm<TOutput extends object>(formConfigs: FormController.Configs<TOutput>, hookConfigs?: {
|
|
3
3
|
validateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
4
4
|
revalidateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
@@ -6,7 +6,6 @@ export declare function useForm<TOutput extends object>(formConfigs: FormControl
|
|
|
6
6
|
watchValues?: boolean;
|
|
7
7
|
}): {
|
|
8
8
|
formConfigs: FormController.Configs<TOutput>;
|
|
9
|
-
paths: FieldPathBuilder<TOutput>;
|
|
10
9
|
hookConfigs: {
|
|
11
10
|
validateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
12
11
|
revalidateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
@@ -14,6 +13,23 @@ export declare function useForm<TOutput extends object>(formConfigs: FormControl
|
|
|
14
13
|
watchValues?: boolean;
|
|
15
14
|
} | undefined;
|
|
16
15
|
controller: FormController<TOutput>;
|
|
16
|
+
path: import('../../../core/src').FieldPathBuilder<TOutput>;
|
|
17
|
+
watchValues: () => import('../../../core/src').DeepReadonly<import('../../../core/src').DeepPartial<TOutput>>;
|
|
18
|
+
watchIssues: () => readonly import("@standard-schema/spec").StandardSchemaV1.Issue[];
|
|
19
|
+
watchEvent: <E extends "fieldTouchUpdated" | "submissionStatusChange" | "validationStatusChange" | "fieldRegistered" | "fieldUnregistered" | "fieldDirtyUpdated" | "fieldIssuesUpdated" | "fieldReset" | "elementBound" | "elementUnbound" | "fieldValidationTriggered" | "fieldValueChanged">(eventName: E, listener?: NonNullable<Partial<{
|
|
20
|
+
submissionStatusChange: ((isSubmitting: boolean) => void)[];
|
|
21
|
+
validationStatusChange: ((isValidating: boolean) => void)[];
|
|
22
|
+
fieldRegistered: ((fieldPath: import("@goodie-forms/core").FieldPath.Segments) => void)[];
|
|
23
|
+
fieldUnregistered: ((fieldPath: import("@goodie-forms/core").FieldPath.Segments) => void)[];
|
|
24
|
+
fieldTouchUpdated: ((path: import("@goodie-forms/core").FieldPath.Segments) => void)[];
|
|
25
|
+
fieldDirtyUpdated: ((path: import("@goodie-forms/core").FieldPath.Segments) => void)[];
|
|
26
|
+
fieldIssuesUpdated: ((fieldPath: import("@goodie-forms/core").FieldPath.Segments) => void)[];
|
|
27
|
+
fieldReset: ((fieldPath: import("@goodie-forms/core").FieldPath.Segments) => void)[];
|
|
28
|
+
elementBound: ((fieldPath: import("@goodie-forms/core").FieldPath.Segments, el: HTMLElement) => void)[];
|
|
29
|
+
elementUnbound: ((fieldPath: import("@goodie-forms/core").FieldPath.Segments) => void)[];
|
|
30
|
+
fieldValidationTriggered: ((fieldPath: import("@goodie-forms/core").FieldPath.Segments) => void)[];
|
|
31
|
+
fieldValueChanged: ((fieldPath: import("@goodie-forms/core").FieldPath.Segments, newValue: {} | undefined, oldValue: {} | undefined) => void)[];
|
|
32
|
+
}>[E]>[number]) => undefined;
|
|
17
33
|
};
|
|
18
34
|
export type UseForm<TOutput extends object> = ReturnType<typeof useForm<TOutput>>;
|
|
19
35
|
//# sourceMappingURL=useForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../src/hooks/useForm.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../src/hooks/useForm.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAKpD,wBAAgB,OAAO,CAAC,OAAO,SAAS,MAAM,EAC5C,WAAW,EAAE,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,EAC5C,WAAW,CAAC,EAAE;IACZ,YAAY,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;IAClD,cAAc,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;IACpD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;;;uBAJgB,UAAU,GAAG,QAAQ,GAAG,UAAU;yBAChC,UAAU,GAAG,QAAQ,GAAG,UAAU;sBACrC,OAAO;sBACP,OAAO;;;;;;iBA0CA,CAAC,4RACX,CAAC,aACD,WAAW;;;;;;;;;;;;;UAAsC,CAAC,MAAM,CAAC;EAqBvE;AAED,MAAM,MAAM,OAAO,CAAC,OAAO,SAAS,MAAM,IAAI,UAAU,CACtD,OAAO,OAAO,CAAC,OAAO,CAAC,CACxB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { FieldPath } from '../../../core/src';
|
|
1
|
+
import { FieldPath, FormField } from '../../../core/src';
|
|
2
2
|
import { UseForm } from '../hooks/useForm';
|
|
3
|
-
export declare function useFormField<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath
|
|
3
|
+
export declare function useFormField<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath): FormField<TOutput, FieldPath.Resolve<TOutput, TPath>> | undefined;
|
|
4
|
+
export declare function useFormField<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath, bindingConfig: Parameters<typeof form.controller.registerField<TPath>>[1]): FormField<TOutput, FieldPath.Resolve<TOutput, TPath>>;
|
|
4
5
|
//# sourceMappingURL=useFormField.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFormField.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormField.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"useFormField.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormField.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAG3C,wBAAgB,YAAY,CAC1B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,EAEhC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EACtB,IAAI,EAAE,KAAK,GACV,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC;AAErE,wBAAgB,YAAY,CAC1B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,EAEhC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EACtB,IAAI,EAAE,KAAK,EACX,aAAa,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GACxE,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSyncMutableStore.d.ts","sourceRoot":"","sources":["../../src/hooks/useSyncMutableStore.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,SAAS,EAAE,CAAC,eAAe,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,EACtD,QAAQ,EAAE,MAAM,CAAC,KAqBlB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export * from './hooks/useForm';
|
|
2
2
|
export * from './hooks/useFormField';
|
|
3
3
|
export * from './hooks/useFieldValue';
|
|
4
|
-
export * from './hooks/
|
|
5
|
-
export * from './hooks/useFormValuesObserver';
|
|
6
|
-
export * from './hooks/useFormErrorObserver';
|
|
4
|
+
export * from './hooks/useFieldIssues';
|
|
7
5
|
export * from './hooks/useRenderControl';
|
|
8
6
|
export * from './components/FieldRenderer';
|
|
9
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AAEzC,cAAc,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,200 +1,195 @@
|
|
|
1
|
-
import { FormController as
|
|
2
|
-
import {
|
|
3
|
-
import { jsx as
|
|
4
|
-
function
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}));
|
|
13
|
-
};
|
|
14
|
-
return {
|
|
15
|
-
renderCount: n.current,
|
|
16
|
-
forceRerender: o
|
|
17
|
-
};
|
|
1
|
+
import { FormController as q, FieldPath as o } from "@goodie-forms/core";
|
|
2
|
+
import { useRef as m, useCallback as f, useSyncExternalStore as a, useState as F, startTransition as I, useEffect as V } from "react";
|
|
3
|
+
import { jsx as R, Fragment as U } from "react/jsx-runtime";
|
|
4
|
+
function b(n, t) {
|
|
5
|
+
const e = m(0), s = f(
|
|
6
|
+
(l) => n(() => {
|
|
7
|
+
e.current++, l();
|
|
8
|
+
}),
|
|
9
|
+
[n]
|
|
10
|
+
), u = f(() => e.current, []);
|
|
11
|
+
return a(s, u, u), t();
|
|
18
12
|
}
|
|
19
|
-
function
|
|
13
|
+
function v(...n) {
|
|
20
14
|
return () => {
|
|
21
|
-
for (const
|
|
22
|
-
|
|
15
|
+
for (const t of n)
|
|
16
|
+
t();
|
|
23
17
|
};
|
|
24
18
|
}
|
|
25
|
-
function
|
|
26
|
-
const [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
function h(e, n, t) {
|
|
51
|
-
const o = a(), [r, l] = f(() => {
|
|
52
|
-
let d = e.controller.getField(n);
|
|
53
|
-
return d == null && t != null && (d = e.controller.bindField(n, t)), d;
|
|
54
|
-
});
|
|
55
|
-
return c(() => {
|
|
56
|
-
const { events: d } = e.controller;
|
|
57
|
-
return l(e.controller.getField(n)), i(
|
|
58
|
-
d.on("fieldBound", (s) => {
|
|
59
|
-
u.equals(s, n) && l(e.controller.getField(n));
|
|
60
|
-
}),
|
|
61
|
-
d.on("fieldUnbound", (s) => {
|
|
62
|
-
u.equals(s, n) && l(void 0);
|
|
63
|
-
}),
|
|
64
|
-
d.on("valueChanged", (s) => {
|
|
65
|
-
(u.equals(s, n) || u.isDescendant(s, n)) && o.forceRerender();
|
|
66
|
-
}),
|
|
67
|
-
d.on("fieldTouchUpdated", (s) => {
|
|
68
|
-
u.equals(s, n) && o.forceRerender();
|
|
69
|
-
}),
|
|
70
|
-
d.on("fieldDirtyUpdated", (s) => {
|
|
71
|
-
u.equals(s, n) && o.forceRerender();
|
|
72
|
-
}),
|
|
73
|
-
d.on("fieldIssuesUpdated", (s) => {
|
|
74
|
-
u.equals(s, n) && o.forceRerender();
|
|
75
|
-
})
|
|
76
|
-
);
|
|
77
|
-
}, []), r;
|
|
78
|
-
}
|
|
79
|
-
function w(e, n) {
|
|
80
|
-
const t = a(), o = e.controller.getField(n)?.value;
|
|
81
|
-
return c(() => i(
|
|
82
|
-
e.controller.events.on("fieldBound", (r) => {
|
|
83
|
-
u.equals(n, r) && t.forceRerender();
|
|
19
|
+
function E(n, t) {
|
|
20
|
+
const [e] = F(() => new q(n)), s = f(
|
|
21
|
+
(r) => {
|
|
22
|
+
const d = () => {
|
|
23
|
+
};
|
|
24
|
+
return v(
|
|
25
|
+
e.events.on("submissionStatusChange", r),
|
|
26
|
+
t?.watchIssues ? e.events.on("fieldIssuesUpdated", r) : d,
|
|
27
|
+
t?.watchValues ? e.events.on("fieldValueChanged", r) : d
|
|
28
|
+
);
|
|
29
|
+
},
|
|
30
|
+
[e, t?.watchIssues, t?.watchValues]
|
|
31
|
+
);
|
|
32
|
+
b(s, () => e);
|
|
33
|
+
const u = () => a(
|
|
34
|
+
(r) => e.events.on("fieldValueChanged", r),
|
|
35
|
+
() => e.data,
|
|
36
|
+
() => e.data
|
|
37
|
+
), l = () => a(
|
|
38
|
+
(r) => e.events.on("fieldIssuesUpdated", r),
|
|
39
|
+
() => e.issues,
|
|
40
|
+
() => e.issues
|
|
41
|
+
), i = (r, d) => b(
|
|
42
|
+
(c) => e.events.on(r, (...g) => {
|
|
43
|
+
d?.(...g), c();
|
|
84
44
|
}),
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
45
|
+
() => {
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
return {
|
|
49
|
+
formConfigs: n,
|
|
50
|
+
hookConfigs: t,
|
|
51
|
+
controller: e,
|
|
52
|
+
path: e.path,
|
|
53
|
+
watchValues: u,
|
|
54
|
+
watchIssues: l,
|
|
55
|
+
watchEvent: i
|
|
56
|
+
};
|
|
89
57
|
}
|
|
90
|
-
function
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
58
|
+
function w(n, t, e) {
|
|
59
|
+
const { controller: s } = n, u = m(0);
|
|
60
|
+
F(() => (!s.getField(t) && e && s.registerField(t, e), null));
|
|
61
|
+
const l = f(
|
|
62
|
+
(r) => {
|
|
63
|
+
const { events: d } = s;
|
|
64
|
+
return v(
|
|
65
|
+
d.on("fieldRegistered", (c) => {
|
|
66
|
+
o.equals(c, t) && (u.current++, r());
|
|
67
|
+
}),
|
|
68
|
+
d.on("fieldUnregistered", (c) => {
|
|
69
|
+
o.equals(c, t) && (u.current++, r());
|
|
70
|
+
}),
|
|
71
|
+
d.on("fieldValueChanged", (c) => {
|
|
72
|
+
(o.equals(c, t) || o.isDescendant(c, t)) && (u.current++, r());
|
|
73
|
+
}),
|
|
74
|
+
d.on("fieldTouchUpdated", (c) => {
|
|
75
|
+
o.equals(c, t) && (u.current++, r());
|
|
76
|
+
}),
|
|
77
|
+
d.on("fieldDirtyUpdated", (c) => {
|
|
78
|
+
o.equals(c, t) && (u.current++, r());
|
|
79
|
+
}),
|
|
80
|
+
d.on("fieldIssuesUpdated", (c) => {
|
|
81
|
+
o.equals(c, t) && (u.current++, r());
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
},
|
|
85
|
+
[s, t]
|
|
86
|
+
), i = f(() => u.current, [s, t]);
|
|
87
|
+
return a(l, i, i), s.getField(t);
|
|
100
88
|
}
|
|
101
|
-
function
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
e
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
89
|
+
function h(n, t) {
|
|
90
|
+
const { controller: e } = n, s = f(
|
|
91
|
+
(l) => {
|
|
92
|
+
const { events: i } = e;
|
|
93
|
+
return v(
|
|
94
|
+
i.on("fieldRegistered", (r) => {
|
|
95
|
+
o.equals(t, r) && l();
|
|
96
|
+
}),
|
|
97
|
+
i.on("fieldUnregistered", (r) => {
|
|
98
|
+
o.equals(t, r) && l();
|
|
99
|
+
}),
|
|
100
|
+
i.on("fieldValueChanged", (r) => {
|
|
101
|
+
(o.equals(r, t) || o.isDescendant(r, t)) && l();
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
},
|
|
105
|
+
[e, t]
|
|
106
|
+
), u = f(() => e.getField(t)?.value, [e, t]);
|
|
107
|
+
return a(s, u, u);
|
|
119
108
|
}
|
|
120
|
-
function
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
109
|
+
function D(n, t) {
|
|
110
|
+
const { controller: e } = n, s = f(
|
|
111
|
+
(l) => {
|
|
112
|
+
const { events: i } = e;
|
|
113
|
+
return v(
|
|
114
|
+
i.on("fieldRegistered", (r) => {
|
|
115
|
+
o.equals(t, r) && l();
|
|
116
|
+
}),
|
|
117
|
+
i.on("fieldUnregistered", (r) => {
|
|
118
|
+
o.equals(t, r) && l();
|
|
119
|
+
}),
|
|
120
|
+
i.on("fieldIssuesUpdated", (r) => {
|
|
121
|
+
o.equals(t, r) && l();
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
},
|
|
125
|
+
[e, t]
|
|
126
|
+
), u = f(() => e.getField(t)?.issues ?? [], [e, t]);
|
|
127
|
+
return a(s, u, u);
|
|
127
128
|
}
|
|
128
|
-
function
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
);
|
|
143
|
-
}, []), q(
|
|
144
|
-
o,
|
|
145
|
-
(r) => r.path == null ? "$" : u.toStringPath(u.normalize(r.path))
|
|
146
|
-
);
|
|
129
|
+
function W() {
|
|
130
|
+
const [, n] = F(0), t = m(0), e = m(!1);
|
|
131
|
+
t.current++;
|
|
132
|
+
const s = () => {
|
|
133
|
+
e.current || (e.current = !0, queueMicrotask(() => {
|
|
134
|
+
I(() => {
|
|
135
|
+
n((u) => u + 1);
|
|
136
|
+
}), e.current = !1;
|
|
137
|
+
}));
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
renderCount: t.current,
|
|
141
|
+
forceRerender: s
|
|
142
|
+
};
|
|
147
143
|
}
|
|
148
|
-
function
|
|
149
|
-
const
|
|
150
|
-
overrideInitialValue:
|
|
151
|
-
defaultValue:
|
|
152
|
-
}),
|
|
144
|
+
function S(n) {
|
|
145
|
+
const t = m(null), e = w(n.form, n.path, {
|
|
146
|
+
overrideInitialValue: n.overrideInitialValue ?? !0,
|
|
147
|
+
defaultValue: n.defaultValue
|
|
148
|
+
}), s = n.form.controller.triedSubmitting ? n.form.hookConfigs?.revalidateMode ?? n.form.hookConfigs?.validateMode : n.form.hookConfigs?.validateMode, u = n.render({
|
|
153
149
|
fieldProps: {
|
|
154
|
-
ref:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
150
|
+
ref: t,
|
|
151
|
+
name: e.stringPath,
|
|
152
|
+
value: e.value,
|
|
153
|
+
onChange(l) {
|
|
154
|
+
let i;
|
|
155
|
+
if (typeof l == "object" && "target" in l) {
|
|
156
|
+
const { target: r } = l;
|
|
157
|
+
if (r !== e.boundElement || !("value" in r) || typeof r.value != "string") return;
|
|
158
|
+
i = r.value;
|
|
162
159
|
} else
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
i = l;
|
|
161
|
+
e.setValue(i, {
|
|
165
162
|
shouldTouch: !0,
|
|
166
163
|
shouldMarkDirty: !0
|
|
167
164
|
});
|
|
168
165
|
},
|
|
169
166
|
onFocus() {
|
|
170
|
-
|
|
167
|
+
e.touch();
|
|
171
168
|
},
|
|
172
169
|
onBlur() {
|
|
173
|
-
(e.
|
|
170
|
+
(e.issues.length !== 0 || s === "onBlur" || s === "onChange") && n.form.controller.validateField(n.path);
|
|
174
171
|
}
|
|
175
172
|
},
|
|
176
|
-
field:
|
|
177
|
-
form:
|
|
173
|
+
field: e,
|
|
174
|
+
form: n.form
|
|
178
175
|
});
|
|
179
|
-
return
|
|
180
|
-
const { events:
|
|
181
|
-
return
|
|
182
|
-
|
|
183
|
-
!
|
|
176
|
+
return V(() => {
|
|
177
|
+
const { events: l } = n.form.controller;
|
|
178
|
+
return v(
|
|
179
|
+
l.on("fieldValueChanged", (i) => {
|
|
180
|
+
!o.equals(i, n.path) && !o.isDescendant(i, n.path) || (e.issues.length !== 0 || s === "onChange") && n.form.controller.validateField(n.path);
|
|
184
181
|
})
|
|
185
182
|
);
|
|
186
|
-
}, []),
|
|
187
|
-
|
|
188
|
-
}), []), /* @__PURE__ */
|
|
183
|
+
}, [s]), V(() => (e.bindElement(t.current), () => {
|
|
184
|
+
n.unbindOnUnmount && n.form.controller.unregisterField(n.path);
|
|
185
|
+
}), []), /* @__PURE__ */ R(U, { children: u });
|
|
189
186
|
}
|
|
190
187
|
export {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
y as useFormValuesObserver,
|
|
198
|
-
a as useRenderControl
|
|
188
|
+
S as FieldRenderer,
|
|
189
|
+
D as useFieldIssues,
|
|
190
|
+
h as useFieldValue,
|
|
191
|
+
E as useForm,
|
|
192
|
+
w as useFormField,
|
|
193
|
+
W as useRenderControl
|
|
199
194
|
};
|
|
200
195
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/hooks/useRenderControl.tsx","../src/utils/composeFns.ts","../src/hooks/useForm.tsx","../src/hooks/useFormField.tsx","../src/hooks/useFieldValue.ts","../src/hooks/useFieldErrors.ts","../src/hooks/useFormValuesObserver.ts","../src/utils/groupBy.ts","../src/hooks/useFormErrorObserver.ts","../src/components/FieldRenderer.tsx"],"sourcesContent":["import { startTransition, useRef, useState } from \"react\";\r\n\r\nexport function useRenderControl() {\r\n const [, rerender] = useState(0);\r\n const renderCount = useRef(0);\r\n const renderScheduled = useRef(false);\r\n renderCount.current++;\r\n\r\n const scheduleRerender = () => {\r\n if (renderScheduled.current) return;\r\n renderScheduled.current = true;\r\n\r\n queueMicrotask(() => {\r\n startTransition(() => {\r\n rerender((i) => i + 1);\r\n });\r\n\r\n renderScheduled.current = false;\r\n });\r\n };\r\n\r\n return {\r\n renderCount: renderCount.current,\r\n forceRerender: scheduleRerender,\r\n };\r\n}\r\n","export function composeFns<TFns extends (() => void)[]>(...fns: TFns) {\r\n return () => {\r\n for (const fn of fns) {\r\n fn();\r\n }\r\n };\r\n}\r\n","import { FieldPathBuilder, FormController } from \"@goodie-forms/core\";\r\nimport { useEffect, useState } from \"react\";\r\nimport { useRenderControl } from \"../hooks/useRenderControl\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useForm<TOutput extends object>(\r\n formConfigs: FormController.Configs<TOutput>,\r\n hookConfigs?: {\r\n validateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n revalidateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n watchIssues?: boolean;\r\n watchValues?: boolean;\r\n },\r\n) {\r\n const [controller] = useState(() => new FormController(formConfigs));\r\n const [paths] = useState(() => new FieldPathBuilder<TOutput>());\r\n\r\n const renderControl = useRenderControl();\r\n\r\n useEffect(() => {\r\n const noop = () => {};\r\n\r\n return composeFns(\r\n controller.events.on(\"submissionStatusChange\", () => {\r\n renderControl.forceRerender();\r\n }),\r\n hookConfigs?.watchIssues\r\n ? controller.events.on(\"fieldIssuesUpdated\", () =>\r\n renderControl.forceRerender(),\r\n )\r\n : noop,\r\n hookConfigs?.watchValues\r\n ? controller.events.on(\"valueChanged\", () =>\r\n renderControl.forceRerender(),\r\n )\r\n : noop,\r\n );\r\n }, [controller]);\r\n\r\n return {\r\n formConfigs,\r\n paths,\r\n hookConfigs,\r\n controller,\r\n };\r\n}\r\n\r\nexport type UseForm<TOutput extends object> = ReturnType<\r\n typeof useForm<TOutput>\r\n>;\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useEffect, useState } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useRenderControl } from \"../hooks/useRenderControl\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n bindingConfig?: Parameters<typeof form.controller.bindField<TPath>>[1],\r\n) {\r\n const renderControl = useRenderControl();\r\n\r\n const [field, setField] = useState(() => {\r\n let field = form.controller.getField(path);\r\n if (field == null && bindingConfig != null) {\r\n field = form.controller.bindField(path, bindingConfig);\r\n }\r\n return field;\r\n });\r\n\r\n useEffect(() => {\r\n const { events } = form.controller;\r\n\r\n setField(form.controller.getField(path));\r\n\r\n return composeFns(\r\n events.on(\"fieldBound\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n setField(form.controller.getField(path));\r\n }),\r\n events.on(\"fieldUnbound\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n setField(undefined);\r\n }),\r\n events.on(\"valueChanged\", (changedPath) => {\r\n if (\r\n FieldPath.equals(changedPath, path) ||\r\n FieldPath.isDescendant(changedPath, path)\r\n ) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n events.on(\"fieldTouchUpdated\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n renderControl.forceRerender();\r\n }),\r\n events.on(\"fieldDirtyUpdated\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n renderControl.forceRerender();\r\n }),\r\n events.on(\"fieldIssuesUpdated\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n renderControl.forceRerender();\r\n }),\r\n );\r\n }, []);\r\n\r\n return field;\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useEffect } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useRenderControl } from \"../hooks/useRenderControl\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFieldValue<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(form: UseForm<TOutput>, path: TPath) {\r\n const renderControl = useRenderControl();\r\n\r\n const value = form.controller.getField(path)?.value;\r\n\r\n useEffect(() => {\r\n return composeFns(\r\n form.controller.events.on(\"fieldBound\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n form.controller.events.on(\"valueChanged\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n );\r\n }, []);\r\n\r\n return value;\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useEffect } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useRenderControl } from \"../hooks/useRenderControl\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFieldErrors<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(form: UseForm<TOutput>, path: TPath) {\r\n const renderControl = useRenderControl();\r\n\r\n const issues = form.controller.getField(path)?.issues;\r\n\r\n useEffect(() => {\r\n return composeFns(\r\n form.controller.events.on(\"fieldBound\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n form.controller.events.on(\"fieldIssuesUpdated\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n );\r\n }, []);\r\n\r\n return issues;\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useEffect } from \"react\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\nimport type { UseForm } from \"./useForm\";\r\nimport { useRenderControl } from \"./useRenderControl\";\r\n\r\n/** @deprecated */\r\nexport function useFormValuesObserver<\r\n TOutput extends object,\r\n TPaths extends FieldPath.Segments[] | undefined = undefined,\r\n>(\r\n form: UseForm<TOutput>,\r\n options?: {\r\n include?: TPaths;\r\n },\r\n) {\r\n const renderControl = useRenderControl();\r\n\r\n const observedValues =\r\n options?.include == null\r\n ? form.controller._data\r\n : options.include.reduce((data, path) => {\r\n const value = FieldPath.getValue(\r\n form.controller._data as TOutput,\r\n path,\r\n )!;\r\n FieldPath.setValue(data, path, value);\r\n return data;\r\n }, {} as TOutput);\r\n\r\n useEffect(() => {\r\n const { events } = form.controller;\r\n\r\n return composeFns(\r\n events.on(\"valueChanged\", (changedPath) => {\r\n const watchingChange =\r\n options?.include == null\r\n ? true\r\n : options.include.some(\r\n (path) =>\r\n FieldPath.equals(path, changedPath) ||\r\n FieldPath.isDescendant(path, changedPath),\r\n );\r\n if (watchingChange) renderControl.forceRerender();\r\n }),\r\n );\r\n }, []);\r\n\r\n return observedValues;\r\n}\r\n","export function groupBy<T, K extends PropertyKey>(\r\n items: readonly T[],\r\n key: (item: T) => K,\r\n): Record<K, T[]> {\r\n const result = {} as Record<K, T[]>;\r\n\r\n for (const item of items) {\r\n const k = key(item);\r\n (result[k] ??= []).push(item);\r\n }\r\n\r\n return result;\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { groupBy } from \"../utils/groupBy\";\r\nimport { useEffect } from \"react\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\nimport type { UseForm } from \"./useForm\";\r\nimport { useRenderControl } from \"./useRenderControl\";\r\n\r\n/** @deprecated */\r\nexport function useFormErrorObserver<\r\n TOutput extends object,\r\n TInclude extends FieldPath.Segments[] | undefined = undefined,\r\n>(\r\n form: UseForm<TOutput>,\r\n options?: {\r\n include?: TInclude;\r\n },\r\n) {\r\n const renderControl = useRenderControl();\r\n\r\n const observedIssues = form.controller._issues.filter((issue) => {\r\n if (options?.include == null) return true;\r\n const normalizedIssuePath = FieldPath.normalize(issue.path);\r\n return options.include.some((path) =>\r\n FieldPath.equals(path, normalizedIssuePath),\r\n );\r\n });\r\n\r\n useEffect(() => {\r\n const { events } = form.controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldIssuesUpdated\", (path) => {\r\n if (options?.include?.includes?.(path) ?? true) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n );\r\n }, []);\r\n\r\n return groupBy(observedIssues, (issue) =>\r\n issue.path == null\r\n ? \"$\"\r\n : FieldPath.toStringPath(FieldPath.normalize(issue.path)),\r\n );\r\n}\r\n","import { FieldPath, FormField, NonnullFormField } from \"@goodie-forms/core\";\r\nimport { ChangeEvent, ReactNode, Ref, useEffect, useRef } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useFormField } from \"../hooks/useFormField\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport interface RenderParams<TOutput extends object, TValue> {\r\n fieldProps: {\r\n ref: Ref<any | null>;\r\n\r\n value: TValue | undefined;\r\n\r\n onChange: (event: ChangeEvent<EventTarget> | TValue) => void;\r\n onFocus: () => void;\r\n onBlur: () => void;\r\n };\r\n\r\n field: undefined extends TValue\r\n ? FormField<TOutput, TValue>\r\n : NonnullFormField<TOutput, TValue>;\r\n\r\n form: UseForm<TOutput>;\r\n}\r\n\r\ntype DefaultValueProps<TValue> = undefined extends TValue\r\n ? { defaultValue?: TValue | (() => TValue) }\r\n : { defaultValue: TValue | (() => TValue) };\r\n\r\nexport type FieldRendererProps<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n> = {\r\n form: UseForm<TOutput>;\r\n path: TPath;\r\n overrideInitialValue?: boolean;\r\n unbindOnUnmount?: boolean;\r\n render: (\r\n params: RenderParams<TOutput, FieldPath.Resolve<TOutput, NoInfer<TPath>>>,\r\n ) => ReactNode;\r\n} & DefaultValueProps<FieldPath.Resolve<TOutput, NoInfer<TPath>>>;\r\n\r\nexport function FieldRenderer<\r\n TOutput extends object,\r\n const TPath extends FieldPath.Segments,\r\n>(props: FieldRendererProps<TOutput, TPath>) {\r\n type TValue = FieldPath.Resolve<TOutput, TPath>;\r\n\r\n const elementRef = useRef<HTMLElement>(null);\r\n\r\n const field = useFormField(props.form, props.path, {\r\n overrideInitialValue: props.overrideInitialValue ?? true,\r\n defaultValue:\r\n typeof props.defaultValue === \"function\"\r\n ? (props.defaultValue as any)()\r\n : props.defaultValue,\r\n })!;\r\n\r\n const renderedJsx = props.render({\r\n fieldProps: {\r\n ref: elementRef,\r\n value: field.value,\r\n onChange(arg) {\r\n let newValue: TValue;\r\n\r\n if (\"target\" in arg) {\r\n const { target } = arg;\r\n if (target !== field.boundElement) return;\r\n if (!(\"value\" in target)) return;\r\n if (typeof target.value !== \"string\") return;\r\n newValue = target.value as TValue;\r\n } else {\r\n newValue = arg;\r\n }\r\n\r\n field.setValue(newValue, {\r\n shouldTouch: true,\r\n shouldMarkDirty: true,\r\n });\r\n },\r\n onFocus() {\r\n field.touch();\r\n },\r\n onBlur() {\r\n if (\r\n props.form.hookConfigs?.validateMode === \"onBlur\" ||\r\n props.form.hookConfigs?.validateMode === \"onChange\"\r\n ) {\r\n props.form.controller.validateField(props.path);\r\n }\r\n },\r\n },\r\n field: field as any,\r\n form: props.form,\r\n });\r\n\r\n useEffect(() => {\r\n const { events } = props.form.controller;\r\n\r\n return composeFns(\r\n events.on(\"valueChanged\", (_path) => {\r\n if (\r\n !FieldPath.equals(_path, props.path) &&\r\n !FieldPath.isDescendant(_path, props.path)\r\n ) {\r\n return;\r\n }\r\n\r\n if (props.form.hookConfigs?.validateMode === \"onChange\") {\r\n props.form.controller.validateField(props.path);\r\n }\r\n }),\r\n );\r\n }, []);\r\n\r\n useEffect(() => {\r\n field.bindElement(elementRef.current!);\r\n\r\n return () => {\r\n if (props.unbindOnUnmount) {\r\n props.form.controller.unbindField(props.path);\r\n }\r\n };\r\n }, []);\r\n\r\n return <>{renderedJsx}</>;\r\n}\r\n\r\n/* ---- TESTS ---------------- */\r\n\r\n// function TestComp() {\r\n// const form = useForm<{ a?: { b: 99 } }>({});\r\n\r\n// const jsx = (\r\n// <>\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a.b)}\r\n// defaultValue={() => 99 as const}\r\n// render={({ fieldProps, field }) => {\r\n// // ^?\r\n// return <input {...fieldProps} />;\r\n// }}\r\n// />\r\n\r\n// {/* defaultField olmayabilir, çünkü \"a\" nullable */}\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a)}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromStringPath(\"a.b\")}\r\n// defaultValue={() => 99 as const}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n// </>\r\n// );\r\n// }\r\n"],"names":["useRenderControl","rerender","useState","renderCount","useRef","renderScheduled","scheduleRerender","startTransition","i","composeFns","fns","fn","useForm","formConfigs","hookConfigs","controller","FormController","paths","FieldPathBuilder","renderControl","useEffect","noop","useFormField","form","path","bindingConfig","field","setField","events","_path","FieldPath","changedPath","useFieldValue","value","fieldPath","useFieldErrors","issues","useFormValuesObserver","options","observedValues","data","groupBy","items","key","result","item","k","useFormErrorObserver","observedIssues","issue","normalizedIssuePath","FieldRenderer","props","elementRef","renderedJsx","arg","newValue","target"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/hooks/useSyncMutableStore.ts","../src/utils/composeFns.ts","../src/hooks/useForm.tsx","../src/hooks/useFormField.tsx","../src/hooks/useFieldValue.ts","../src/hooks/useFieldIssues.ts","../src/hooks/useRenderControl.tsx","../src/components/FieldRenderer.tsx"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from \"react\";\r\n\r\nexport function useSyncMutableStore<T>(\r\n subscribe: (onVersionChange: () => void) => () => void,\r\n getValue: () => T,\r\n) {\r\n const versionRef = useRef(0);\r\n\r\n const subscribeWithVersion = useCallback(\r\n (onStoreChange: () => void) => {\r\n return subscribe(() => {\r\n versionRef.current++;\r\n onStoreChange();\r\n });\r\n },\r\n [subscribe],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n return versionRef.current;\r\n }, []);\r\n\r\n useSyncExternalStore(subscribeWithVersion, getSnapshot, getSnapshot);\r\n\r\n return getValue();\r\n}\r\n","export function composeFns<TFns extends (() => void)[]>(...fns: TFns) {\r\n return () => {\r\n for (const fn of fns) {\r\n fn();\r\n }\r\n };\r\n}\r\n","import { FormController } from \"@goodie-forms/core\";\r\nimport { useCallback, useState, useSyncExternalStore } from \"react\";\r\nimport { useSyncMutableStore } from \"../hooks/useSyncMutableStore\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useForm<TOutput extends object>(\r\n formConfigs: FormController.Configs<TOutput>,\r\n hookConfigs?: {\r\n validateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n revalidateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n watchIssues?: boolean;\r\n watchValues?: boolean;\r\n },\r\n) {\r\n const [controller] = useState(() => new FormController(formConfigs));\r\n\r\n const subscribe = useCallback(\r\n (onVersionChange: () => void) => {\r\n const noop = () => {};\r\n\r\n return composeFns(\r\n controller.events.on(\"submissionStatusChange\", onVersionChange),\r\n hookConfigs?.watchIssues\r\n ? controller.events.on(\"fieldIssuesUpdated\", onVersionChange)\r\n : noop,\r\n hookConfigs?.watchValues\r\n ? controller.events.on(\"fieldValueChanged\", onVersionChange)\r\n : noop,\r\n );\r\n },\r\n [controller, hookConfigs?.watchIssues, hookConfigs?.watchValues],\r\n );\r\n\r\n useSyncMutableStore(subscribe, () => controller);\r\n\r\n const useWatchValues = () => {\r\n return useSyncExternalStore(\r\n (onStoreChange) =>\r\n controller.events.on(\"fieldValueChanged\", onStoreChange),\r\n () => controller.data,\r\n () => controller.data,\r\n );\r\n };\r\n\r\n const useWatchIssues = () => {\r\n return useSyncExternalStore(\r\n (onStoreChange) =>\r\n controller.events.on(\"fieldIssuesUpdated\", onStoreChange),\r\n () => controller.issues,\r\n () => controller.issues,\r\n );\r\n };\r\n\r\n const useWatchEvent = <E extends keyof typeof controller.events.events>(\r\n eventName: E,\r\n listener?: NonNullable<(typeof controller.events.events)[E]>[number],\r\n ) => {\r\n return useSyncMutableStore(\r\n (onVersionChange) =>\r\n controller.events.on(eventName, (...args: any[]) => {\r\n (listener as any)?.(...args);\r\n onVersionChange();\r\n }),\r\n () => undefined,\r\n );\r\n };\r\n\r\n return {\r\n formConfigs,\r\n hookConfigs,\r\n controller,\r\n path: controller.path,\r\n watchValues: useWatchValues,\r\n watchIssues: useWatchIssues,\r\n watchEvent: useWatchEvent,\r\n };\r\n}\r\n\r\nexport type UseForm<TOutput extends object> = ReturnType<\r\n typeof useForm<TOutput>\r\n>;\r\n","import { FieldPath, FormField } from \"@goodie-forms/core\";\r\nimport { useCallback, useRef, useState, useSyncExternalStore } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n): FormField<TOutput, FieldPath.Resolve<TOutput, TPath>> | undefined;\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n bindingConfig: Parameters<typeof form.controller.registerField<TPath>>[1],\r\n): FormField<TOutput, FieldPath.Resolve<TOutput, TPath>>;\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n bindingConfig?: Parameters<typeof form.controller.registerField<TPath>>[1],\r\n) {\r\n const { controller } = form;\r\n\r\n const version = useRef(0);\r\n\r\n useState(() => {\r\n let existing = controller.getField(path);\r\n\r\n if (!existing && bindingConfig) {\r\n controller.registerField(path, bindingConfig);\r\n }\r\n\r\n return null;\r\n });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const { events } = controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldRegistered\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldUnregistered\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldValueChanged\", (changedPath) => {\r\n if (\r\n FieldPath.equals(changedPath, path) ||\r\n FieldPath.isDescendant(changedPath, path)\r\n ) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldTouchUpdated\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldDirtyUpdated\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldIssuesUpdated\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n );\r\n },\r\n [controller, path],\r\n );\r\n\r\n const getSnapshot = useCallback(() => version.current, [controller, path]);\r\n\r\n useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n\r\n return controller.getField(path);\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useCallback, useSyncExternalStore } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFieldValue<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(form: UseForm<TOutput>, path: TPath) {\r\n const { controller } = form;\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const { events } = controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldRegistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldUnregistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldValueChanged\", (changedPath) => {\r\n if (\r\n FieldPath.equals(changedPath, path) ||\r\n FieldPath.isDescendant(changedPath, path)\r\n ) {\r\n onStoreChange();\r\n }\r\n }),\r\n );\r\n },\r\n [controller, path],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n return controller.getField(path)?.value;\r\n }, [controller, path]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useCallback, useSyncExternalStore } from \"react\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\nimport { UseForm } from \"./useForm\";\r\n\r\nexport function useFieldIssues<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(form: UseForm<TOutput>, path: TPath) {\r\n const { controller } = form;\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const { events } = controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldRegistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldUnregistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldIssuesUpdated\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n );\r\n },\r\n [controller, path],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n return controller.getField(path)?.issues ?? [];\r\n }, [controller, path]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n","import { startTransition, useRef, useState } from \"react\";\r\n\r\nexport function useRenderControl() {\r\n const [, rerender] = useState(0);\r\n const renderCount = useRef(0);\r\n const renderScheduled = useRef(false);\r\n renderCount.current++;\r\n\r\n const scheduleRerender = () => {\r\n if (renderScheduled.current) return;\r\n renderScheduled.current = true;\r\n\r\n queueMicrotask(() => {\r\n startTransition(() => {\r\n rerender((i) => i + 1);\r\n });\r\n\r\n renderScheduled.current = false;\r\n });\r\n };\r\n\r\n return {\r\n renderCount: renderCount.current,\r\n forceRerender: scheduleRerender,\r\n };\r\n}\r\n","import {\r\n DeepReadonly,\r\n FieldPath,\r\n FormField,\r\n Suppliable,\r\n} from \"@goodie-forms/core\";\r\nimport { ChangeEvent, ReactNode, Ref, useEffect, useRef } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useFormField } from \"../hooks/useFormField\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport interface RenderParams<TOutput extends object, TValue> {\r\n fieldProps: {\r\n ref: Ref<any | null>;\r\n\r\n name: string;\r\n\r\n value: DeepReadonly<TValue> | undefined;\r\n\r\n onChange: (event: ChangeEvent<EventTarget> | TValue) => void;\r\n onFocus: () => void;\r\n onBlur: () => void;\r\n };\r\n\r\n field: FormField<TOutput, TValue>;\r\n\r\n form: UseForm<TOutput>;\r\n}\r\n\r\ntype DefaultValueProps<TValue> = undefined extends TValue\r\n ? { defaultValue?: Suppliable<TValue> }\r\n : { defaultValue: Suppliable<TValue> };\r\n\r\nexport type FieldRendererProps<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n> = DefaultValueProps<FieldPath.Resolve<TOutput, TPath>> & {\r\n form: UseForm<TOutput>;\r\n path: TPath;\r\n overrideInitialValue?: boolean;\r\n unbindOnUnmount?: boolean;\r\n render: (\r\n params: RenderParams<TOutput, FieldPath.Resolve<TOutput, TPath>>,\r\n ) => ReactNode;\r\n};\r\n\r\nexport function FieldRenderer<\r\n TOutput extends object,\r\n const TPath extends FieldPath.Segments,\r\n>(props: FieldRendererProps<TOutput, TPath>) {\r\n type TValue = FieldPath.Resolve<TOutput, TPath>;\r\n\r\n const elementRef = useRef<HTMLElement>(null);\r\n\r\n const field = useFormField(props.form, props.path, {\r\n overrideInitialValue: props.overrideInitialValue ?? true,\r\n defaultValue: props.defaultValue,\r\n })!;\r\n\r\n const currentValidateMode = props.form.controller.triedSubmitting\r\n ? (props.form.hookConfigs?.revalidateMode ??\r\n props.form.hookConfigs?.validateMode)\r\n : props.form.hookConfigs?.validateMode;\r\n\r\n const renderedJsx = props.render({\r\n fieldProps: {\r\n ref: elementRef,\r\n name: field.stringPath,\r\n value: field.value,\r\n onChange(arg) {\r\n let newValue: TValue;\r\n\r\n if (typeof arg === \"object\" && \"target\" in arg) {\r\n const { target } = arg;\r\n if (target !== field.boundElement) return;\r\n if (!(\"value\" in target)) return;\r\n if (typeof target.value !== \"string\") return;\r\n newValue = target.value as TValue;\r\n } else {\r\n newValue = arg;\r\n }\r\n\r\n field.setValue(newValue, {\r\n shouldTouch: true,\r\n shouldMarkDirty: true,\r\n });\r\n },\r\n onFocus() {\r\n field.touch();\r\n },\r\n onBlur() {\r\n if (\r\n field.issues.length !== 0 ||\r\n currentValidateMode === \"onBlur\" ||\r\n currentValidateMode === \"onChange\"\r\n ) {\r\n props.form.controller.validateField(props.path);\r\n }\r\n },\r\n },\r\n field: field as any,\r\n form: props.form,\r\n });\r\n\r\n useEffect(() => {\r\n const { events } = props.form.controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldValueChanged\", (_path) => {\r\n if (\r\n !FieldPath.equals(_path, props.path) &&\r\n !FieldPath.isDescendant(_path, props.path)\r\n ) {\r\n return;\r\n }\r\n\r\n if (field.issues.length !== 0 || currentValidateMode === \"onChange\") {\r\n props.form.controller.validateField(props.path);\r\n }\r\n }),\r\n );\r\n }, [currentValidateMode]);\r\n\r\n useEffect(() => {\r\n field.bindElement(elementRef.current!);\r\n\r\n return () => {\r\n if (props.unbindOnUnmount) {\r\n props.form.controller.unregisterField(props.path);\r\n }\r\n };\r\n }, []);\r\n\r\n return <>{renderedJsx}</>;\r\n}\r\n\r\n/* ---- TESTS ---------------- */\r\n\r\n// function TestComp() {\r\n// const form = useForm<{ a?: { b: 99 } }>({});\r\n\r\n// const jsx = (\r\n// <>\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a.b)}\r\n// defaultValue={() => 99 as const}\r\n// render={({ fieldProps, field }) => {\r\n// // ^?\r\n// return <input {...fieldProps} />;\r\n// }}\r\n// />\r\n\r\n// {/* defaultField olmayabilir, çünkü \"a\" nullable */}\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a)}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromStringPath(\"a.b\")}\r\n// defaultValue={() => 99 as const}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n// </>\r\n// );\r\n// }\r\n"],"names":["useSyncMutableStore","subscribe","getValue","versionRef","useRef","subscribeWithVersion","useCallback","onStoreChange","getSnapshot","useSyncExternalStore","composeFns","fns","fn","useForm","formConfigs","hookConfigs","controller","useState","FormController","onVersionChange","noop","useWatchValues","useWatchIssues","useWatchEvent","eventName","listener","args","useFormField","form","path","bindingConfig","version","events","_path","FieldPath","changedPath","useFieldValue","fieldPath","useFieldIssues","useRenderControl","rerender","renderCount","renderScheduled","scheduleRerender","startTransition","i","FieldRenderer","props","elementRef","field","currentValidateMode","renderedJsx","arg","newValue","target","useEffect"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodie-forms/react",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.6-alpha",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
"default": "./dist/index.js"
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
13
16
|
"publishConfig": {
|
|
14
17
|
"access": "public"
|
|
15
18
|
},
|
|
@@ -18,7 +21,7 @@
|
|
|
18
21
|
"react-dom": "^18 || ^19"
|
|
19
22
|
},
|
|
20
23
|
"dependencies": {
|
|
21
|
-
"@goodie-forms/core": "1.2.
|
|
24
|
+
"@goodie-forms/core": "1.2.6-alpha"
|
|
22
25
|
},
|
|
23
26
|
"devDependencies": {
|
|
24
27
|
"@types/react": "^19.2.9",
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { FieldPath } from '../../../core/src';
|
|
2
|
-
import { UseForm } from '../hooks/useForm';
|
|
3
|
-
export declare function useFieldErrors<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath): import("@standard-schema/spec").StandardSchemaV1.Issue[] | undefined;
|
|
4
|
-
//# sourceMappingURL=useFieldErrors.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useFieldErrors.d.ts","sourceRoot":"","sources":["../../src/hooks/useFieldErrors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,wBAAgB,cAAc,CAC5B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,EAChC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,wEAqBpC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { FieldPath } from '../../../core/src';
|
|
2
|
-
import { UseForm } from './useForm';
|
|
3
|
-
/** @deprecated */
|
|
4
|
-
export declare function useFormErrorObserver<TOutput extends object, TInclude extends FieldPath.Segments[] | undefined = undefined>(form: UseForm<TOutput>, options?: {
|
|
5
|
-
include?: TInclude;
|
|
6
|
-
}): Record<string, import("@standard-schema/spec").StandardSchemaV1.Issue[]>;
|
|
7
|
-
//# sourceMappingURL=useFormErrorObserver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useFormErrorObserver.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormErrorObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,kBAAkB;AAClB,wBAAgB,oBAAoB,CAClC,OAAO,SAAS,MAAM,EACtB,QAAQ,SAAS,SAAS,CAAC,QAAQ,EAAE,GAAG,SAAS,GAAG,SAAS,EAE7D,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EACtB,OAAO,CAAC,EAAE;IACR,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,4EA6BF"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { FieldPath } from '../../../core/src';
|
|
2
|
-
import { UseForm } from './useForm';
|
|
3
|
-
/** @deprecated */
|
|
4
|
-
export declare function useFormValuesObserver<TOutput extends object, TPaths extends FieldPath.Segments[] | undefined = undefined>(form: UseForm<TOutput>, options?: {
|
|
5
|
-
include?: TPaths;
|
|
6
|
-
}): import('../../../core/src').DeepPartial<TOutput>;
|
|
7
|
-
//# sourceMappingURL=useFormValuesObserver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useFormValuesObserver.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormValuesObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,kBAAkB;AAClB,wBAAgB,qBAAqB,CACnC,OAAO,SAAS,MAAM,EACtB,MAAM,SAAS,SAAS,CAAC,QAAQ,EAAE,GAAG,SAAS,GAAG,SAAS,EAE3D,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EACtB,OAAO,CAAC,EAAE;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,qDAmCF"}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { FieldPath, FormField, NonnullFormField } from "@goodie-forms/core";
|
|
2
|
-
import { ChangeEvent, ReactNode, Ref, useEffect, useRef } from "react";
|
|
3
|
-
import { UseForm } from "../hooks/useForm";
|
|
4
|
-
import { useFormField } from "../hooks/useFormField";
|
|
5
|
-
import { composeFns } from "../utils/composeFns";
|
|
6
|
-
|
|
7
|
-
export interface RenderParams<TOutput extends object, TValue> {
|
|
8
|
-
fieldProps: {
|
|
9
|
-
ref: Ref<any | null>;
|
|
10
|
-
|
|
11
|
-
value: TValue | undefined;
|
|
12
|
-
|
|
13
|
-
onChange: (event: ChangeEvent<EventTarget> | TValue) => void;
|
|
14
|
-
onFocus: () => void;
|
|
15
|
-
onBlur: () => void;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
field: undefined extends TValue
|
|
19
|
-
? FormField<TOutput, TValue>
|
|
20
|
-
: NonnullFormField<TOutput, TValue>;
|
|
21
|
-
|
|
22
|
-
form: UseForm<TOutput>;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
type DefaultValueProps<TValue> = undefined extends TValue
|
|
26
|
-
? { defaultValue?: TValue | (() => TValue) }
|
|
27
|
-
: { defaultValue: TValue | (() => TValue) };
|
|
28
|
-
|
|
29
|
-
export type FieldRendererProps<
|
|
30
|
-
TOutput extends object,
|
|
31
|
-
TPath extends FieldPath.Segments,
|
|
32
|
-
> = {
|
|
33
|
-
form: UseForm<TOutput>;
|
|
34
|
-
path: TPath;
|
|
35
|
-
overrideInitialValue?: boolean;
|
|
36
|
-
unbindOnUnmount?: boolean;
|
|
37
|
-
render: (
|
|
38
|
-
params: RenderParams<TOutput, FieldPath.Resolve<TOutput, NoInfer<TPath>>>,
|
|
39
|
-
) => ReactNode;
|
|
40
|
-
} & DefaultValueProps<FieldPath.Resolve<TOutput, NoInfer<TPath>>>;
|
|
41
|
-
|
|
42
|
-
export function FieldRenderer<
|
|
43
|
-
TOutput extends object,
|
|
44
|
-
const TPath extends FieldPath.Segments,
|
|
45
|
-
>(props: FieldRendererProps<TOutput, TPath>) {
|
|
46
|
-
type TValue = FieldPath.Resolve<TOutput, TPath>;
|
|
47
|
-
|
|
48
|
-
const elementRef = useRef<HTMLElement>(null);
|
|
49
|
-
|
|
50
|
-
const field = useFormField(props.form, props.path, {
|
|
51
|
-
overrideInitialValue: props.overrideInitialValue ?? true,
|
|
52
|
-
defaultValue:
|
|
53
|
-
typeof props.defaultValue === "function"
|
|
54
|
-
? (props.defaultValue as any)()
|
|
55
|
-
: props.defaultValue,
|
|
56
|
-
})!;
|
|
57
|
-
|
|
58
|
-
const renderedJsx = props.render({
|
|
59
|
-
fieldProps: {
|
|
60
|
-
ref: elementRef,
|
|
61
|
-
value: field.value,
|
|
62
|
-
onChange(arg) {
|
|
63
|
-
let newValue: TValue;
|
|
64
|
-
|
|
65
|
-
if ("target" in arg) {
|
|
66
|
-
const { target } = arg;
|
|
67
|
-
if (target !== field.boundElement) return;
|
|
68
|
-
if (!("value" in target)) return;
|
|
69
|
-
if (typeof target.value !== "string") return;
|
|
70
|
-
newValue = target.value as TValue;
|
|
71
|
-
} else {
|
|
72
|
-
newValue = arg;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
field.setValue(newValue, {
|
|
76
|
-
shouldTouch: true,
|
|
77
|
-
shouldMarkDirty: true,
|
|
78
|
-
});
|
|
79
|
-
},
|
|
80
|
-
onFocus() {
|
|
81
|
-
field.touch();
|
|
82
|
-
},
|
|
83
|
-
onBlur() {
|
|
84
|
-
if (
|
|
85
|
-
props.form.hookConfigs?.validateMode === "onBlur" ||
|
|
86
|
-
props.form.hookConfigs?.validateMode === "onChange"
|
|
87
|
-
) {
|
|
88
|
-
props.form.controller.validateField(props.path);
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
field: field as any,
|
|
93
|
-
form: props.form,
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
const { events } = props.form.controller;
|
|
98
|
-
|
|
99
|
-
return composeFns(
|
|
100
|
-
events.on("valueChanged", (_path) => {
|
|
101
|
-
if (
|
|
102
|
-
!FieldPath.equals(_path, props.path) &&
|
|
103
|
-
!FieldPath.isDescendant(_path, props.path)
|
|
104
|
-
) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (props.form.hookConfigs?.validateMode === "onChange") {
|
|
109
|
-
props.form.controller.validateField(props.path);
|
|
110
|
-
}
|
|
111
|
-
}),
|
|
112
|
-
);
|
|
113
|
-
}, []);
|
|
114
|
-
|
|
115
|
-
useEffect(() => {
|
|
116
|
-
field.bindElement(elementRef.current!);
|
|
117
|
-
|
|
118
|
-
return () => {
|
|
119
|
-
if (props.unbindOnUnmount) {
|
|
120
|
-
props.form.controller.unbindField(props.path);
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
}, []);
|
|
124
|
-
|
|
125
|
-
return <>{renderedJsx}</>;
|
|
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={({ fieldProps, field }) => {
|
|
140
|
-
// // ^?
|
|
141
|
-
// return <input {...fieldProps} />;
|
|
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
|
-
// }
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { FieldPath } from "@goodie-forms/core";
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
import { UseForm } from "../hooks/useForm";
|
|
4
|
-
import { useRenderControl } from "../hooks/useRenderControl";
|
|
5
|
-
import { composeFns } from "../utils/composeFns";
|
|
6
|
-
|
|
7
|
-
export function useFieldErrors<
|
|
8
|
-
TOutput extends object,
|
|
9
|
-
TPath extends FieldPath.Segments,
|
|
10
|
-
>(form: UseForm<TOutput>, path: TPath) {
|
|
11
|
-
const renderControl = useRenderControl();
|
|
12
|
-
|
|
13
|
-
const issues = form.controller.getField(path)?.issues;
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
return composeFns(
|
|
17
|
-
form.controller.events.on("fieldBound", (fieldPath) => {
|
|
18
|
-
if (FieldPath.equals(path, fieldPath)) {
|
|
19
|
-
renderControl.forceRerender();
|
|
20
|
-
}
|
|
21
|
-
}),
|
|
22
|
-
form.controller.events.on("fieldIssuesUpdated", (fieldPath) => {
|
|
23
|
-
if (FieldPath.equals(path, fieldPath)) {
|
|
24
|
-
renderControl.forceRerender();
|
|
25
|
-
}
|
|
26
|
-
}),
|
|
27
|
-
);
|
|
28
|
-
}, []);
|
|
29
|
-
|
|
30
|
-
return issues;
|
|
31
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { FieldPath } from "@goodie-forms/core";
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
import { UseForm } from "../hooks/useForm";
|
|
4
|
-
import { useRenderControl } from "../hooks/useRenderControl";
|
|
5
|
-
import { composeFns } from "../utils/composeFns";
|
|
6
|
-
|
|
7
|
-
export function useFieldValue<
|
|
8
|
-
TOutput extends object,
|
|
9
|
-
TPath extends FieldPath.Segments,
|
|
10
|
-
>(form: UseForm<TOutput>, path: TPath) {
|
|
11
|
-
const renderControl = useRenderControl();
|
|
12
|
-
|
|
13
|
-
const value = form.controller.getField(path)?.value;
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
return composeFns(
|
|
17
|
-
form.controller.events.on("fieldBound", (fieldPath) => {
|
|
18
|
-
if (FieldPath.equals(path, fieldPath)) {
|
|
19
|
-
renderControl.forceRerender();
|
|
20
|
-
}
|
|
21
|
-
}),
|
|
22
|
-
form.controller.events.on("valueChanged", (fieldPath) => {
|
|
23
|
-
if (FieldPath.equals(path, fieldPath)) {
|
|
24
|
-
renderControl.forceRerender();
|
|
25
|
-
}
|
|
26
|
-
}),
|
|
27
|
-
);
|
|
28
|
-
}, []);
|
|
29
|
-
|
|
30
|
-
return value;
|
|
31
|
-
}
|
package/src/hooks/useForm.tsx
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
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,45 +0,0 @@
|
|
|
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
|
-
/** @deprecated */
|
|
9
|
-
export function useFormErrorObserver<
|
|
10
|
-
TOutput extends object,
|
|
11
|
-
TInclude extends FieldPath.Segments[] | undefined = undefined,
|
|
12
|
-
>(
|
|
13
|
-
form: UseForm<TOutput>,
|
|
14
|
-
options?: {
|
|
15
|
-
include?: TInclude;
|
|
16
|
-
},
|
|
17
|
-
) {
|
|
18
|
-
const renderControl = useRenderControl();
|
|
19
|
-
|
|
20
|
-
const observedIssues = form.controller._issues.filter((issue) => {
|
|
21
|
-
if (options?.include == null) return true;
|
|
22
|
-
const normalizedIssuePath = FieldPath.normalize(issue.path);
|
|
23
|
-
return options.include.some((path) =>
|
|
24
|
-
FieldPath.equals(path, normalizedIssuePath),
|
|
25
|
-
);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
const { events } = form.controller;
|
|
30
|
-
|
|
31
|
-
return composeFns(
|
|
32
|
-
events.on("fieldIssuesUpdated", (path) => {
|
|
33
|
-
if (options?.include?.includes?.(path) ?? true) {
|
|
34
|
-
renderControl.forceRerender();
|
|
35
|
-
}
|
|
36
|
-
}),
|
|
37
|
-
);
|
|
38
|
-
}, []);
|
|
39
|
-
|
|
40
|
-
return groupBy(observedIssues, (issue) =>
|
|
41
|
-
issue.path == null
|
|
42
|
-
? "$"
|
|
43
|
-
: FieldPath.toStringPath(FieldPath.normalize(issue.path)),
|
|
44
|
-
);
|
|
45
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { FieldPath } from "@goodie-forms/core";
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
import { composeFns } from "../utils/composeFns";
|
|
4
|
-
import type { UseForm } from "./useForm";
|
|
5
|
-
import { useRenderControl } from "./useRenderControl";
|
|
6
|
-
|
|
7
|
-
/** @deprecated */
|
|
8
|
-
export function useFormValuesObserver<
|
|
9
|
-
TOutput extends object,
|
|
10
|
-
TPaths extends FieldPath.Segments[] | undefined = undefined,
|
|
11
|
-
>(
|
|
12
|
-
form: UseForm<TOutput>,
|
|
13
|
-
options?: {
|
|
14
|
-
include?: TPaths;
|
|
15
|
-
},
|
|
16
|
-
) {
|
|
17
|
-
const renderControl = useRenderControl();
|
|
18
|
-
|
|
19
|
-
const observedValues =
|
|
20
|
-
options?.include == null
|
|
21
|
-
? form.controller._data
|
|
22
|
-
: options.include.reduce((data, path) => {
|
|
23
|
-
const value = FieldPath.getValue(
|
|
24
|
-
form.controller._data as TOutput,
|
|
25
|
-
path,
|
|
26
|
-
)!;
|
|
27
|
-
FieldPath.setValue(data, path, value);
|
|
28
|
-
return data;
|
|
29
|
-
}, {} as TOutput);
|
|
30
|
-
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
const { events } = form.controller;
|
|
33
|
-
|
|
34
|
-
return composeFns(
|
|
35
|
-
events.on("valueChanged", (changedPath) => {
|
|
36
|
-
const watchingChange =
|
|
37
|
-
options?.include == null
|
|
38
|
-
? true
|
|
39
|
-
: options.include.some(
|
|
40
|
-
(path) =>
|
|
41
|
-
FieldPath.equals(path, changedPath) ||
|
|
42
|
-
FieldPath.isDescendant(path, changedPath),
|
|
43
|
-
);
|
|
44
|
-
if (watchingChange) renderControl.forceRerender();
|
|
45
|
-
}),
|
|
46
|
-
);
|
|
47
|
-
}, []);
|
|
48
|
-
|
|
49
|
-
return observedValues;
|
|
50
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { startTransition, useRef, useState } from "react";
|
|
2
|
-
|
|
3
|
-
export function useRenderControl() {
|
|
4
|
-
const [, rerender] = useState(0);
|
|
5
|
-
const renderCount = useRef(0);
|
|
6
|
-
const renderScheduled = useRef(false);
|
|
7
|
-
renderCount.current++;
|
|
8
|
-
|
|
9
|
-
const scheduleRerender = () => {
|
|
10
|
-
if (renderScheduled.current) return;
|
|
11
|
-
renderScheduled.current = true;
|
|
12
|
-
|
|
13
|
-
queueMicrotask(() => {
|
|
14
|
-
startTransition(() => {
|
|
15
|
-
rerender((i) => i + 1);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
renderScheduled.current = false;
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
renderCount: renderCount.current,
|
|
24
|
-
forceRerender: scheduleRerender,
|
|
25
|
-
};
|
|
26
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export * from "./hooks/useForm";
|
|
2
|
-
export * from "./hooks/useFormField";
|
|
3
|
-
export * from "./hooks/useFieldValue";
|
|
4
|
-
export * from "./hooks/useFieldErrors";
|
|
5
|
-
export * from "./hooks/useFormValuesObserver";
|
|
6
|
-
export * from "./hooks/useFormErrorObserver";
|
|
7
|
-
export * from "./hooks/useRenderControl";
|
|
8
|
-
|
|
9
|
-
export * from "./components/FieldRenderer";
|
package/src/utils/composeFns.ts
DELETED
package/src/utils/groupBy.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export function groupBy<T, K extends PropertyKey>(
|
|
2
|
-
items: readonly T[],
|
|
3
|
-
key: (item: T) => K,
|
|
4
|
-
): Record<K, T[]> {
|
|
5
|
-
const result = {} as Record<K, T[]>;
|
|
6
|
-
|
|
7
|
-
for (const item of items) {
|
|
8
|
-
const k = key(item);
|
|
9
|
-
(result[k] ??= []).push(item);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return result;
|
|
13
|
-
}
|
package/tsconfig.json
DELETED
package/vite.config.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vite";
|
|
2
|
-
import react from "@vitejs/plugin-react";
|
|
3
|
-
import dts from "vite-plugin-dts";
|
|
4
|
-
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
plugins: [react(), dts({ entryRoot: "src" })],
|
|
7
|
-
build: {
|
|
8
|
-
lib: {
|
|
9
|
-
entry: "src/index.ts",
|
|
10
|
-
formats: ["es"],
|
|
11
|
-
fileName: "index",
|
|
12
|
-
},
|
|
13
|
-
rollupOptions: {
|
|
14
|
-
external: [
|
|
15
|
-
"react",
|
|
16
|
-
"react-dom",
|
|
17
|
-
"react/jsx-runtime",
|
|
18
|
-
"@goodie-forms/core",
|
|
19
|
-
],
|
|
20
|
-
},
|
|
21
|
-
sourcemap: true,
|
|
22
|
-
},
|
|
23
|
-
});
|