import { compare, Destructor } from '@synnaxlabs/x';
import { PropsWithChildren, ReactElement } from 'react';
import { z } from 'zod';
import { Input } from '../input';
import { state } from '../state';
import { status } from '../status/aether';
/** Props for the @see useField hook */
export interface UseFieldProps<I, O = I> {
    path: string;
    optional?: false;
    onChange?: (value: O, extra: ContextValue & {
        path: string;
    }) => void;
}
export interface UseNullableFieldProps<I, O = I> extends Omit<UseFieldProps<I, O>, "optional"> {
    optional: true;
}
/** Return type for the @see useField hook */
export interface UseFieldReturn<I extends Input.Value, O extends Input.Value = I> extends FieldState<I> {
    onChange: (value: O) => void;
    setStatus: (status: status.CrudeSpec) => void;
    status: status.CrudeSpec;
    variant?: Input.Variant;
}
interface UseField {
    <I extends Input.Value, O extends Input.Value = I>(props: UseFieldProps<I, O>): UseFieldReturn<I, O>;
    <I extends Input.Value, O extends Input.Value = I>(props: UseNullableFieldProps<I, O>): UseFieldReturn<I, O> | null;
}
/**
 * Hook for managing a particular field in a form.
 *
 * @param props - The props for the hook
 * @param props.path - The path to the field in the form.
 */
export declare const useField: UseField;
export interface UseFieldValue {
    <I extends Input.Value, O extends Input.Value = I, Z extends z.ZodTypeAny = any>(path: string, optional?: false, ctx?: ContextValue<Z>): O;
    <I extends Input.Value, O extends Input.Value = I, Z extends z.ZodTypeAny = any>(path: string, optional: true, ctx?: ContextValue<Z>): O | null;
}
export interface UseFieldState {
    <I extends Input.Value, O extends Input.Value = I, Z extends z.ZodTypeAny = z.ZodTypeAny>(path: string, optional?: false, ctx?: ContextValue<Z>): FieldState<O>;
    <I extends Input.Value, O extends Input.Value = I, Z extends z.ZodTypeAny = z.ZodTypeAny>(path: string, optional: true, ctx?: ContextValue<Z>): FieldState<O> | null;
}
export declare const useFieldState: <I extends Input.Value, O extends Input.Value = I>(path: string, optional?: boolean, ctx?: ContextValue) => FieldState<O> | null;
export declare const useFieldValue: UseFieldValue;
export declare const useFieldValid: (path: string) => boolean;
export interface UseFieldListenerProps<I extends Input.Value, Z extends z.ZodTypeAny = z.ZodTypeAny> {
    ctx?: ContextValue<Z>;
    path: string;
    onChange: (state: FieldState<I>, extra: ContextValue<Z>) => void;
}
export declare const useFieldListener: <I extends Input.Value, Z extends z.ZodTypeAny = z.ZodTypeAny>({ path, ctx: override, onChange, }: UseFieldListenerProps<I, Z>) => void;
export interface UseChildFieldValuesProps {
    path: string;
    optional?: false;
}
export interface UseNullableChildFieldValuesProps {
    path: string;
    optional: true;
}
export interface UseChildFieldValues {
    <V extends unknown = unknown>(props: UseChildFieldValuesProps): V;
    <V extends unknown = unknown>(props: UseNullableChildFieldValuesProps): V | null;
}
export declare const useChildFieldValues: UseChildFieldValues;
export interface UseFieldArrayProps {
    path: string;
    updateOnChildren?: boolean;
    ctx?: ContextValue<any>;
}
export interface FieldArrayUtils<V> {
    push: (value: V | V[], sort?: compare.CompareF<V>) => void;
    add: (value: V | V[], start: number) => void;
    remove: (index: number | number[]) => void;
    keepOnly: (indices: number | number[]) => void;
    set: (values: state.SetArg<V[]>) => void;
    sort?: (compareFn: compare.CompareF<V>) => void;
}
export declare const fieldArrayUtils: <V extends unknown = unknown>(ctx: ContextValue<any>, path: string) => FieldArrayUtils<V>;
export interface UseFieldArrayReturn<V extends unknown> {
    value: V[];
    push: (value: V | V[]) => void;
    add: (value: V | V[], start: number) => void;
    remove: (index: number | number[]) => void;
    keepOnly: (indices: number | number[]) => void;
    set: (values: state.SetArg<V[]>) => void;
}
export declare const useFieldArray: <V extends unknown = unknown>({ path, updateOnChildren, ctx: pCtx, }: UseFieldArrayProps) => UseFieldArrayReturn<V>;
export type Listener<V = unknown> = (state: FieldState<V>) => void;
export interface FieldState<V = unknown> {
    value: V;
    status: status.CrudeSpec;
    touched: boolean;
    required: boolean;
}
interface RequiredGetOptions<O extends boolean | undefined = boolean | undefined> {
    optional?: O;
}
interface GetFunc {
    <V extends Input.Value>(path: string, opts: RequiredGetOptions<true>): FieldState<V> | null;
    <V extends Input.Value>(path: string, opts?: RequiredGetOptions<boolean | undefined>): FieldState<V>;
}
type RemoveFunc = (path: string) => void;
interface SetOptions {
    validateChildren?: boolean;
}
type SetFunc = (path: string, value: unknown, opts?: SetOptions) => void;
interface BindProps<V = unknown> {
    path: string;
    onChange: Listener<V>;
    listenToChildren?: boolean;
}
type BindFunc = <V = unknown>(props: BindProps<V>) => Destructor;
type Mode = "normal" | "preview";
export interface ContextValue<Z extends z.ZodTypeAny = z.ZodTypeAny> {
    mode: Mode;
    bind: BindFunc;
    set: SetFunc;
    reset: (values: z.output<Z>) => void;
    get: GetFunc;
    remove: RemoveFunc;
    value: () => z.output<Z>;
    validate: (path?: string) => boolean;
    validateAsync: (path?: string) => Promise<boolean>;
    has: (path: string) => boolean;
    setStatus: (path: string, status: status.CrudeSpec) => void;
    clearStatuses: () => void;
}
export declare const Context: import('react').Context<ContextValue<z.ZodTypeAny>>;
export declare const useContext: <Z extends z.ZodTypeAny = z.ZodTypeAny>(override?: ContextValue<Z>) => ContextValue<Z>;
export interface OnChangeProps<Z extends z.ZodTypeAny> {
    /** The values in the form AFTER the change. */
    values: z.output<Z>;
    /** The path that was changed. */
    path: string;
    /** The previous value at the path. */
    prev: unknown;
    /** Whether validation succeeded. */
    valid: boolean;
}
export interface UseProps<Z extends z.ZodTypeAny> {
    values: z.output<Z>;
    mode?: Mode;
    sync?: boolean;
    onChange?: (props: OnChangeProps<Z>) => void;
    schema?: Z;
}
export type UseReturn<Z extends z.ZodTypeAny> = ContextValue<Z>;
export declare const use: <Z extends z.ZodTypeAny>({ values, sync, schema, mode, onChange, }: UseProps<Z>) => UseReturn<Z>;
export declare const Form: (props: PropsWithChildren<ContextValue>) => ReactElement;
export {};
//# sourceMappingURL=Form.d.ts.map