import { ButtonPropsType } from '../../../general';
import { IReducerAction } from '../../../types';
import React from 'react';
import { IntlShape } from 'react-intl';
export type InputValues = string | number | boolean | null;
export type MultipleInputValues = InputValues[];
export type FormValues = InputValues | MultipleInputValues | undefined;
export type InputTypes = 'text' | 'textarea' | 'email' | 'url' | 'checkbox' | 'checkboxes' | 'select' | 'radio' | 'password' | 'autocomplete' | 'number' | 'multiple-inputs';
export interface ILabel {
    /** The element to be used, defaulting to `label` */
    element?: string;
    /** Optional class for the label */
    className?: string;
    /** The ID of the input to be labelled */
    htmlFor?: string;
}
export type FormActionTypes = 'addError' | 'formSubmitted' | 'formSubmittedAndReset' | 'removeError' | 'submitForm' | 'updateValue';
export type FieldValidationConditions = boolean | 'no-numbers' | 'required' | 'valid-email' | 'valid-url' | 'custom-validation' | ((arg: IFormValues) => boolean | null | string);
export interface IFieldOption {
    /** The ID of the option */
    id: string;
    /** The label text of the option */
    label: string | React.ReactNode;
    /** The value of the option */
    value?: InputValues;
    /** Whether the option is disabled */
    disabled?: boolean;
}
export type PayloadValues = InputValues | MultipleInputValues | (() => void) | string | boolean;
export interface IFormPayload {
    /** The key of the data to update in state */
    key?: string | number;
    /** The value of the data to update in state */
    value?: PayloadValues;
    /** An array describing the fields for the form */
    fields?: IField[];
    /** The dispatch function to update the form state */
    dispatch?: React.Dispatch<IFormReducerAction>;
    /** The internationalisation object */
    intl?: IntlShape;
    /** Function to call when everything succeeds */
    onSuccess?: (arg: IFormValues) => void;
    /** Function to call when something fails */
    onFailure?: (arg: IFormValues, arg2?: FormValues) => void;
}
interface IFormErrors {
    [key: string]: (() => void) | FormValues;
}
export interface IFormReducerAction extends IReducerAction<IFormPayload> {
}
export interface IFormReducerState {
    'custom-validation'?: string | boolean;
    errors?: IFormErrors;
    formSubmitted: boolean;
    isSubmitting: boolean;
    values?: IFormValues;
}
export interface IFormValues {
    [key: string]: FormValues;
}
export interface IFieldValidation {
    condition: FieldValidationConditions;
    error?: string;
}
export type FieldOnChange = (arg1: FormValues, arg2?: ({ type, payload, }: {
    type: string;
    payload?: {
        [key: string]: string | boolean;
    };
}) => void) => void;
export interface IFieldFunctions {
    /** The function to call when the field changes */
    onChange: FieldOnChange;
    /** The function to call when the field is submitted */
    onMultiSelectSubmit?: (arg1: FormValues) => void;
    /** The function to call when the field is blurred */
    onBlur?: () => void;
    /** The function to call when the field is focused */
    onFocus?: () => void;
    /** The function to call when a key is pressed */
    onKeyInput?: <T>(arg1: FormValues) => Promise<T>;
    /** The function to call when a key is pressed */
    onKeyDown?: (e: React.KeyboardEvent<HTMLElement>) => void;
    /** The function to call when the form is submitted from a field */
    submitForm?: (arg: IFormValues) => void;
}
export interface IField {
    /** Additional accessibility configuration */
    accessibilityOptions?: {
        /** Additional options for checkboxes */
        checkboxes?: {
            /** Whether the field should be navigable with arrow keys */
            navigateWithArrowKeys?: boolean;
        };
    };
    /** Optional ID of the element which describes this field, for screen readers */
    'aria-describedby'?: string;
    /** Optional ID of the element which provides an error message for this field */
    'aria-errormessage'?: string;
    /** Optional data for screen readers on if the field content is invalid */
    'aria-invalid'?: boolean;
    /** Optional data for screen readers on if the field is required */
    'aria-required'?: boolean;
    /** Whether the field can be automatically filled */
    autoComplete?: string;
    /** Whether the field should autofocus */
    autoFocus?: boolean;
    /** Additional classes to be added to the field */
    className?: string;
    /** The component to render, instead of rendering a field (e.g. for when we need a component like `EmailHelperTextBox` in the middle of a form). Please specify props when passing in. */
    component?: any;
    /** The data attribute describing the character limit of the field */
    'data-character-limit'?: number;
    /** The test ID of the field, for Jest */
    'data-testid'?: string;
    /** Whether the field is disabled */
    disabled?: boolean;
    /** What element to render the field as, defaulting to `input` */
    element?: string;
    /** The functions being passed to the field */
    functions?: IFieldFunctions;
    /** The Google Tag Manager data to be passed to the field */
    gtm?: {
        /** The context of the event for GTM */
        context?: string;
        /** The event description for GTM */
        event?: string;
    };
    /** The ID of the field */
    id?: string;
    /** The initial value of the field, for dropdown fields */
    initialValue?: FormValues;
    /** An optional `ref` for the field, in case we need to interact with it in another file */
    inputRef?: React.RefObject<HTMLInputElement>;
    /** The internationalisation path for the field */
    intlPath?: string | false;
    /** The label for the field */
    label?: string | React.ReactNode | false;
    /** An optional character limit, for textareas */
    limit?: number;
    /** Whether the field can have multiple values, for checkboxes */
    multiSelect?: boolean;
    /** The additional options for multiselect, for dropdowns */
    multiSelectOptions?: {
        /** Whether to display the topbar in the dropdown - this includes a total of the checked boxes and an option to select all or none */
        topbar?: boolean;
        /** Whether to display the submit button in the dropdown - this allows the user to submit the dropdown only */
        submitSection?: boolean;
    };
    /** The additional options for multiple options, for checkboxes */
    multipleOptions?: {
        /** The limit of the number of options that can be selected */
        limit?: number;
    };
    /** Props for the inputs rendered in a `multiple` field */
    multipleInputs?: {
        /** Whether or not to show the number of filled in inputs in the legend */
        showCount?: boolean;
        /** The template text for each label */
        label?: string;
        /** The number of inputs to show by default, without a remove button */
        defaultInputs?: number;
        /** How many inputs can be added in total */
        maxInputs: number;
        /** Whether to add options with a button */
        hasButton?: false | ButtonPropsType;
        /** Whether we can have the same value across multiple input fields */
        allowDuplicateValues?: boolean;
    };
    /** The name of the field */
    name?: string;
    /** The options for the field, for checkboxes and dropdowns */
    options?: IFieldOption[];
    /** The placeholder text for the field */
    placeholder?: string;
    /** Additional props to be passed to the field */
    props?: {
        [key: string]: string | boolean | number | object | (() => void) | React.RefObject<any>;
    };
    /** Whether the field is required */
    required?: boolean;
    /** The selected value for checkboxes */
    shownValue?: InputValues;
    /** Whether hitting enter on the field should submit the form */
    submitOnEnter?: boolean;
    styling?: {
        /** Whether the input should automatically resize to fit; only works on `textarea` types */
        autosizeToFit?: boolean;
        /** Whether to display options for the multiselect as pills */
        displayOptionsAsPills?: boolean;
    };
    /** The type of the input */
    type?: InputTypes;
    /** The validation for the field */
    validation?: IFieldValidation[];
    /** The value of the field */
    value?: FormValues;
}
export interface FormCancelButtonPropsType extends ButtonPropsType {
    /** The text to show on the button */
    text?: string;
}
export interface FormButtonPropsType extends ButtonPropsType {
    /** A custom component to render when the form is submitting */
    customOnSubmit?: React.ReactNode | false;
    /** The text to show on the button. If a string is passed in, it's just the default text. If we want to control the submitting/submitted text, we can pass an object, with `default` as the default text. */
    text?: string | {
        default?: string;
        submitting?: string;
        submitted?: string;
    };
    /** The option to not have the submit button at all */
    hideButton?: boolean;
}
export interface IFormMeta {
    /** Whether the form should reset after submission */
    shouldReset?: boolean;
    /** Whether the form should hide after submission */
    shouldHide?: boolean;
    /** Whether the form should show required labels */
    showRequiredLabels?: boolean;
    /** Whether the form should show success message*/
    showSuccessMessage?: boolean | string;
    /** Whether the form should show cancel button */
    shouldShowCancelButton?: boolean;
    /** Whether the form should scroll up when there are no errors */
    shouldScrollOnSuccess?: boolean;
}
export interface IFormProps {
    /** The form submit button */
    button?: FormButtonPropsType;
    /** The button to cancel the form (can be used to redirects user to another url or close modal) */
    secondaryActionButton?: FormCancelButtonPropsType;
    /** The classes to add to the form */
    className?: string;
    /** The type of element to render. This is in case we need to render a separate form inside the first, e.g. rendering the link form on the rich text editor inside the discussion form. */
    element?: 'form' | 'fieldset';
    /** The fields to render in the form */
    fields: IField[];
    /** An optional `ref` for the form, in case we need to interact with it in another file */
    formRef?: React.RefObject<HTMLFormElement>;
    /** The functions being passed to the form */
    functions: {
        /** The function to call when onSuccess fails */
        onCatch?: (error?: unknown) => void;
        /** The function to call when the form submission fails */
        onFailure?: (arg: IFormValues, arg2?: FormValues) => void;
        /** The function to call when the form is successfully submitted */
        onSuccess?: (arg: IFormValues) => Promise<void>;
        /** The function to call when the cancel button is clicked */
        onCancel?: () => void;
    };
    /** The Google Tag Manager data to be passed to the field */
    gtm?: {
        /** The context of the event for GTM */
        context?: string;
        /** The event description for GTM */
        event?: string;
    };
    /** The id of the form */
    id: string;
    /** The internationalisation path for text in the form */
    intlPath?: string | false;
    /** Data about the form */
    meta?: IFormMeta;
    /** Optional children */
    children?: React.ReactNode;
    /** An ID for jest tests */
    'data-testid'?: string;
}
export interface IFieldWrapper extends IField {
    /** The error to show */
    error: string | IFormErrors | undefined;
    /** Whether the field wrapper should show required labels */
    showRequiredLabels?: boolean;
    /** The value of the field */
    value?: FormValues;
    /** The setter to amend the fields to validate; this is needed for multiple inputs, to give each input its own error handling */
    fieldData?: {
        fields: IField[];
        multipleInputs: (string | undefined)[];
        setFields: React.Dispatch<React.SetStateAction<{
            fieldsToValidate: IField[];
            multipleInputs: (string | undefined)[];
        }>>;
        dispatch: React.Dispatch<IFormReducerAction>;
    };
    /** Optional siblings to render alongside component */
    siblings?: React.ReactNode;
}
export {};
