import { type ObjectConfig } from "./config"; import { type ObjectState } from "./fields/objectField"; export type Query = { data: I; loading: boolean; error?: any; }; export type InputAndMap = { input: I; map?: (input: Exclude) => T; ifUndefined?: T; onlyOnce?: boolean; }; export type QueryAndMap = { query: Query; map: (input: Exclude) => T; ifUndefined?: T; }; /** * The opts has for `useFormState`. * * @typeparam T the form type, which is usually as close as possible to your *GraphQL input* * @typeparam I the *form input* type, which is usually the *GraphQL output* type, i.e. the type of the response from your GraphQL query */ export type UseFormStateOpts = { /** The form configuration, should be a module-level const or useMemo'd. */ config: ObjectConfig; /** * Provides the form's initial value. * * User's can either: * * - Provide no initial value (don't set `init` at all) * - Provide an initial value that already matches the form type `T` (i.e. set `init: data`) * - Provide an initial value from an object that _almost_ matches the form type `T`, * but needs to be mapped from it's input type `I` to the form type * (i.e. set `init: { input: data, map: (data) => ...}`). * * The value of using the 3rd option is that: a) we internally `useMemo` on the identity of the * `init.input` (i.e. a response from an Apollo hook) and don't require the `map` function * to have a stable identity, and also b) we will null-check/undefined-check `init.input` and * only call `init.map` if it's set, otherwise we'll use `init.ifDefined` or `{}`, saving you * from having to null check within your `init.map` function. */ init?: InputAndMap | QueryAndMap; /** * A hook to add custom, cross-field validation rules that can be difficult to setup directly in the config DSL. * * Does not need to be stable/useMemo'd. */ addRules?: (state: ObjectState) => void; /** Whether the form should be read only, when changed it won't re-create the whole form. */ readOnly?: boolean; /** * Whether the form is loading. * * Note that we also will infer loading from `init.input === undefined` or `init.query.loading`, * so you only need to set this directly if you're not using either of those conventions. */ loading?: boolean; /** * Fired when the form should auto-save, i.e. after a) blur and b) all fields are valid. * * Does not need to be stable/useMemo'd. */ autoSave?: (state: ObjectState) => Promise; }; export type FormObjectState = ObjectState & { /** * Refreshes the form with a server-acked value, i.e. `form.update(savedAuthor)`. * * This is intended for save callbacks that need `form.dirty` to become `false` immediately, before the * normal query/cache refresh has a chance to rerender `useFormState`. Pass the value returned by the * server so the form can map it through `init.map` and then do a field-by-field refresh of only the * changes the server has acknowledged. */ update(input: Exclude): void; }; /** * Creates a formState instance for editing in a form. */ export declare function useFormState(opts: UseFormStateOpts): FormObjectState;