import { AutocompleteProps } from '@mui/material';
import { CheckboxProps } from '@mui/material';
import { DatePickerProps } from '@mui/x-date-pickers';
import { DateTimePickerProps } from '@mui/x-date-pickers';
import { EasyCascaderInput } from 'mui-easy-cascader';
import { EasyCascaderInputProps } from 'mui-easy-cascader';
import { EasyNode } from 'mui-easy-cascader';
import { EasyTreeInput } from 'mui-easy-cascader';
import { EasyTreeInputProps } from 'mui-easy-cascader';
import { FieldValues } from 'react-hook-form';
import { FormControlLabelProps } from '@mui/material';
import { ForwardedRef } from 'react';
import { ForwardRefExoticComponent } from 'react';
import { JSX } from 'react/jsx-runtime';
import { Path } from 'react-hook-form';
import { RadioProps } from '@mui/material';
import { ReactNode } from 'react';
import { RefAttributes } from 'react';
import { SliderProps } from '@mui/material';
import { SwitchProps } from '@mui/material';
import { TextFieldProps } from '@mui/material';
import { TimePickerProps } from '@mui/x-date-pickers';
import { UseControllerProps } from 'react-hook-form';
import { UseFormReturn } from 'react-hook-form';

declare type Base<OptionT, Multiple extends boolean = false> = Omit<AutocompleteProps<OptionT, Multiple, undefined, undefined>, 'value' | 'onChange' | 'multiple' | 'renderOption' | 'defaultValue' | 'renderInput'> & {
    /**
     * used to compare option and value, typeof value === typeof option
     *
     * Example:
     * value: { id: 1 }
     * option: { id: 1, name: 'a', age: 18 }
     */
    isOptionEqual?: (optionValue: OptionT, value: OptionT | null) => boolean;
    checkbox?: boolean;
    search?: boolean;
} & Pick<OptionsProps<OptionT>, 'renderOption'>;

export declare function CascaderField<ValueT extends FieldValues, OptionT extends EasyNode>(props: CascaderFieldProps<ValueT, OptionT>): JSX.Element;

export declare type CascaderFieldProps<ValueT extends FieldValues, OptionT extends EasyNode> = FieldPropsWrapper<EasyCascaderInputProps<OptionT>, ValueT>;

export declare const CascaderIO: typeof EasyCascaderInput;

export declare type CascaderIOProps<T extends EasyNode> = EasyCascaderInputProps<T>;

export declare function CheckboxField<T extends FieldValues>(props: CheckboxFieldProps<T>): JSX.Element;

export declare type CheckboxFieldProps<T extends FieldValues> = FieldPropsWrapper<CheckboxIOProps, T>;

export declare function CheckboxGroupField<T extends FieldValues, OptionT>(props: CheckboxGroupFieldProps<T, OptionT>): JSX.Element;

export declare type CheckboxGroupFieldProps<ValueT extends FieldValues, OptionT> = FieldPropsWrapper<CheckboxGroupIOProps<OptionT>, ValueT>;

export declare function CheckboxGroupIO<T>(props: CheckboxGroupIOProps<T>): JSX.Element;

export declare type CheckboxGroupIOProps<T> = ControlledProps<T[]> & Omit<CheckboxProps, 'value' | 'onChange'> & OptionsProps<T> & {
    /**
     * determine the color for a given option
     */
    getOptionColor?: (value: T) => CheckboxProps['color'];
    FormControlLabelProps?: FormControlLabelProps;
    row?: boolean;
};

export declare function CheckboxIO(props: CheckboxIOProps): JSX.Element;

export declare type CheckboxIOProps = ControlledProps<boolean> & Omit<CheckboxProps, 'value' | 'onChange'>;

export declare type CommonFormControlProps = {
    label?: ReactNode;
    helperText?: ReactNode;
    error?: boolean;
    required?: boolean;
    disabled?: boolean;
};

/**
 * wrapper for IOs
 * 1. add value and onChange
 * 2. add common FormControlProps
 */
export declare type ControlledProps<Value> = {
    /**
     * null is empty value
     */
    value: Value | null;
    onChange: (nextValue: Value | null) => void;
} & CommonFormControlProps;

export declare function DateField<T extends FieldValues>(props: DateFieldProps<T>): JSX.Element;

export declare type DateFieldProps<T extends FieldValues> = FieldPropsWrapper<DateIOProps, T>;

export declare function DateIO(props: DateIOProps): JSX.Element;

export declare type DateIOProps = ControlledProps<number> & Omit<DatePickerProps<number>, 'value' | 'onChange'>;

export declare function DateTimeField<T extends FieldValues>(props: DateTimeFieldProps<T>): JSX.Element;

export declare type DateTimeFieldProps<T extends FieldValues> = FieldPropsWrapper<DateTimeIOProps, T>;

export declare function DateTimeIO(props: DateTimeIOProps): JSX.Element;

export declare type DateTimeIOProps = ControlledProps<number> & Omit<DateTimePickerProps<number>, 'value' | 'onChange'>;

/**
 * wrapper for EasyFormFieldProps
 * 1. remove "value", "onChange", "defaultValue" from IO props
 * 2. add form field props
 */
export declare type FieldPropsWrapper<IOProps extends {
    helperText?: ReactNode;
}, ValueT extends FieldValues> = Omit<IOProps, 'value' | 'onChange' | 'defaultValue'> & {
    required?: boolean;
    control?: UseFormReturn<ValueT>['control'];
    name: Path<ValueT>;
    rules?: UseControllerProps<ValueT>['rules'];
    defaultValue?: UseControllerProps<ValueT>['defaultValue'];
};

/**
 * 1. label and helperText
 * 2. error, required, disabled
 * 3. pass ref to FormControl
 */
export declare const FormControlWrapper: ForwardRefExoticComponent<CommonFormControlProps & {
children: ReactNode;
inputLabel?: boolean;
} & RefAttributes<HTMLDivElement>>;

declare type Multi<OptionT, Multiple extends boolean, Value = OptionT> = ControlledProps<Value[]> & Base<OptionT, Multiple> & {
    multiple: true;
};

export declare function NumberField<T extends FieldValues>(props: NumberFieldProps<T>): JSX.Element;

export declare type NumberFieldProps<T extends FieldValues> = FieldPropsWrapper<NumberIOProps, T>;

export declare function NumberIO(props: NumberIOProps): JSX.Element;

export declare type NumberIOProps = Omit<WordIOProps, 'value' | 'onChange'> & ControlledProps<number>;

export declare type OptionsProps<T> = {
    /**
     * array of options
     * 1. key: unique key
     * 2. label: it's used to fill the list box options (and the input), if renderOption is not provided
     * 3. value
     */
    options: T[];
    /**
     * example:
     * options:[{key:1, label:'a', value:{id:1, name:'a'}}, {key:2, label:'b', value:{id:2, name:'b'}}]
     * value: {id:1}
     *
     * if you set isOptionEqual as (option, value) => a.id === b.id, then the option with key 1 will be selected
     */
    isOptionEqual?: (optionValue: T, value: T) => boolean;
    /**
     * render the option
     */
    renderOption?: (value: T) => ReactNode;
    /**
     * determine the disabled state for a given option
     */
    getOptionDisabled?: (value: T) => boolean;
};

export declare function PasswordField<T extends FieldValues>(props: PasswordFieldProps<T>): JSX.Element;

export declare type PasswordFieldProps<T extends FieldValues> = FieldPropsWrapper<PasswordIOProps, T>;

export declare const PasswordIO: ForwardRefExoticComponent<Omit<WordIOProps, "ref"> & RefAttributes<HTMLDivElement>>;

export declare type PasswordIOProps = WordIOProps;

export declare function RadioGroupField<T extends FieldValues, OptionT>(props: RadioGroupFieldProps<T, OptionT>): JSX.Element;

export declare type RadioGroupFieldProps<T extends FieldValues, OptionT> = FieldPropsWrapper<RadioGroupIOProps<OptionT>, T>;

export declare function RadioGroupIO<T>(props: RadioGroupIOProps<T>): JSX.Element;

export declare type RadioGroupIOProps<T> = ControlledProps<T> & Omit<RadioProps, 'value' | 'onChange'> & OptionsProps<T> & {
    /**
     * determine the color for a given option
     */
    getOptionColor?: (value: T) => RadioProps['color'];
    /**
     * display the options in a row
     */
    row?: boolean;
};

export declare function SelectField<T extends FieldValues, OptionT, Multiple extends boolean = false>(props: SelectFieldProps<T, OptionT, Multiple>): JSX.Element;

export declare type SelectFieldProps<T extends FieldValues, OptionT, Multiple extends boolean = false> = FieldPropsWrapper<SelectIOProps<OptionT, Multiple>, T>;

export declare function SelectIO<OptionT, Multiple extends boolean = false>(props: SelectIOProps<OptionT, Multiple>): JSX.Element;

export declare type SelectIOProps<OptionT, Multiple extends boolean = false> = Multiple extends true ? Multi<OptionT, Multiple> : Single<OptionT, Multiple>;

declare type Single<OptionT, Multiple extends boolean> = ControlledProps<OptionT> & Base<OptionT, Multiple> & {
    multiple?: false;
};

export declare function SliderField<T extends FieldValues>(props: SliderFieldProps<T>): JSX.Element;

export declare type SliderFieldProps<T extends FieldValues> = FieldPropsWrapper<SliderIOProps, T>;

export declare function SliderIO(props: SliderIOProps): JSX.Element;

export declare type SliderIOProps = ControlledProps<number> & Omit<SliderProps, 'value' | 'onChange'>;

export declare function SwitchField<T extends FieldValues>(props: SwitchFieldProps<T>): JSX.Element;

export declare type SwitchFieldProps<T extends FieldValues> = FieldPropsWrapper<SwitchIOProps, T>;

export declare function SwitchIO(props: SwitchIOProps): JSX.Element;

export declare type SwitchIOProps = ControlledProps<boolean> & Omit<SwitchProps, 'value' | 'onChange'>;

export declare type TextIOAdditionProps = {
    /**
     * The icon to display in place of the default clear icon.
     */
    clearIcon?: ReactNode;
    /**
     * If true, the input will not show a clear icon
     */
    noClear?: boolean;
};

export declare function TimeField<T extends FieldValues>(props: TimeFieldProps<T>): JSX.Element;

export declare type TimeFieldProps<T extends FieldValues> = FieldPropsWrapper<TimeIOProps, T>;

export declare function TimeIO(props: TimeIOProps): JSX.Element;

export declare type TimeIOProps = ControlledProps<number> & Omit<TimePickerProps<number>, 'value' | 'onChange'>;

export declare function TreeField<ValueT extends FieldValues, OptionT extends EasyNode>(props: TreeFieldProps<ValueT, OptionT>): JSX.Element;

export declare type TreeFieldProps<ValueT extends FieldValues, OptionT extends EasyNode> = FieldPropsWrapper<EasyTreeInputProps<OptionT>, ValueT>;

export declare const TreeIO: typeof EasyTreeInput;

export declare type TreeIOProps<T extends EasyNode> = EasyTreeInputProps<T>;

export declare function useEasyFormField<IOProps extends {
    helperText?: ReactNode;
}, ValueT extends FieldValues>(props: FieldPropsWrapper<IOProps, ValueT>): IOProps;

/**
 * extract form control props from props
 */
export declare function useFormControlWrapperProps<T extends CommonFormControlProps>(props: T): {
    restProps: Omit<T, 'label' | 'helperText' | 'error' | 'disabled' | 'required'>;
    formControlWrapperProps: CommonFormControlProps & {
        ref?: ForwardedRef<HTMLDivElement>;
    };
};

export declare function WordField<T extends FieldValues>(props: WordFieldProps<T>): JSX.Element;

export declare type WordFieldProps<T extends FieldValues> = FieldPropsWrapper<WordIOProps, T>;

/**
 * WordIO let users enter and edit text.
 *
 * related components:
 * - WordField: a uncontrolled WordIO for form
 * - NumberIO: type=number
 * - PasswordIO: type=password
 *
 * It extends from TextField, so you can use all TextField props except 'value', 'onChange' and 'defaultValue' because WordIO is a controlled component.
 *
 * It also has 2 addition props:
 * - clearable: If true, the input shows a clear icon if the value is not empty.
 * - clearIcon: The icon to display in place of the default clear icon.
 *
 * For more info ,see:
 * https://bitterteasweetorange.github.io/mui-easy-form?path=/docs/io-wordio--docs
 */
export declare function WordIO(props: WordIOProps): JSX.Element;

export declare type WordIOProps = ControlledProps<string> & TextIOAdditionProps & Omit<TextFieldProps, 'value' | 'onChange' | 'defaultValue'>;

export { }
