/**
 * Types exposed through the public API
 */
import type { VectorSettings } from "../components/Vector/vector-types.js";
import { StoreType, Data, DataInput } from "./internal.js";
import type { BeautifyUnionType, UnionToIntersection } from "./utils.js";
export type RenderFn = (get: (key: string) => any) => boolean;
/**
 * Utility types that joins a value with its settings
 */
export type InputWithSettings<V extends unknown, Settings = {}, K extends string = 'value'> = {
    [key in K]: V;
} & {
    type?: LevaInputs;
} & Settings;
/**
 * Either the raw value, either the value with its settings
 * In other words => value || { value, ...settings }
 */
export type MergedInputWithSettings<V, Settings = {}, K extends string = 'value'> = V | InputWithSettings<V, Settings, K>;
/**
 * Special Inputs
 */
export declare enum SpecialInputs {
    BUTTON = "BUTTON",
    BUTTON_GROUP = "BUTTON_GROUP",
    MONITOR = "MONITOR",
    FOLDER = "FOLDER"
}
export declare enum LevaInputs {
    SELECT = "SELECT",
    IMAGE = "IMAGE",
    NUMBER = "NUMBER",
    COLOR = "COLOR",
    STRING = "STRING",
    BOOLEAN = "BOOLEAN",
    INTERVAL = "INTERVAL",
    VECTOR3D = "VECTOR3D",
    VECTOR2D = "VECTOR2D"
}
export type ButtonSettings = {
    disabled?: boolean;
};
export type ButtonInput = {
    type: SpecialInputs.BUTTON;
    onClick: (get: (path: string) => any) => void;
    settings: ButtonSettings;
};
export type ButtonGroupOpts = {
    [title: string]: (get: (path: string) => any) => void;
};
export type ButtonGroupInputOpts = ButtonGroupOpts | {
    label?: string | React.JSX.Element | null;
    opts: ButtonGroupOpts;
};
export type ButtonGroupInput = {
    type: SpecialInputs.BUTTON_GROUP;
    opts: ButtonGroupInputOpts;
};
export type MonitorSettings = {
    graph?: boolean;
    interval?: number;
};
export type MonitorInput = {
    type: SpecialInputs.MONITOR;
    objectOrFn: React.MutableRefObject<any> | Function;
    settings: MonitorSettings;
};
export type SpecialInput = MonitorInput | ButtonInput | ButtonGroupInput;
export type FolderSettings = {
    collapsed?: boolean;
    render?: RenderFn;
    color?: string;
    /** works similar to css order property */
    order?: number;
};
export type NumberSettings = {
    min?: number;
    max?: number;
    step?: number;
};
export type VectorObj = Record<string, number>;
export type Vector2dArray = [number, number];
export type Vector2d = Vector2dArray | VectorObj;
export type Vector2dSettings = VectorSettings<Vector2d, 'x' | 'y'> & {
    joystick?: boolean | 'invertY';
    lock?: boolean;
};
export type Vector2dInput = MergedInputWithSettings<Vector2d, Vector2dSettings>;
export type Vector3dArray = [number, number, number];
export type Vector3d = Vector3dArray | VectorObj;
export type Vector3dSettings = VectorSettings<Vector3d, 'x' | 'y' | 'z'> & {
    lock?: boolean;
};
export type Vector3dInput = MergedInputWithSettings<Vector3d, Vector3dSettings>;
export type IntervalInput = {
    value: [number, number];
    min: number;
    max: number;
};
export type ImageInput = {
    image: undefined | string;
};
type SelectInput = {
    options: any[] | Record<string, any>;
    value?: any;
};
type SelectWithValueInput<T, K> = {
    options: T[] | Record<string, T>;
    value: K;
};
type SelectWithoutValueInput<T> = {
    options: T[] | Record<string, T>;
};
type ColorRgbaInput = {
    r: number;
    g: number;
    b: number;
    a?: number;
};
type ColorHslaInput = {
    h: number;
    s: number;
    l: number;
    a?: number;
};
type ColorHsvaInput = {
    h: number;
    s: number;
    v: number;
    a?: number;
};
export type ColorVectorInput = ColorRgbaInput | ColorHslaInput | ColorHsvaInput;
type BooleanInput = boolean;
type StringSettings = {
    rows?: boolean | number;
    editable?: boolean;
};
type StringInput = InputWithSettings<string, StringSettings>;
export type FolderInput<Schema> = {
    type: SpecialInputs.FOLDER;
    schema: Schema;
    settings: FolderSettings;
};
export type CustomInput<Value> = {
    type: string;
    __customInput: Value;
};
type SchemaItem = InputWithSettings<number, NumberSettings> | InputWithSettings<boolean> | InputWithSettings<string> | IntervalInput | ColorVectorInput | Vector2dInput | Vector3dInput | ImageInput | SelectInput | BooleanInput | StringInput | CustomInput<unknown>;
type GenericSchemaItemOptions = {
    render?: RenderFn;
    label?: string | React.JSX.Element;
    hint?: string;
    order?: number;
};
type OnHandlerContext = DataInput & {
    get(path: string): any;
};
type OnChangeHandlerContext = OnHandlerContext & {
    /**
     * Whether the onChange handler is invoked initially.
     */
    initial: boolean;
};
export type OnChangeHandler = (value: any, path: string, context: OnChangeHandlerContext) => void;
type TransientOnChangeSchemaItemOptions = {
    onChange: OnChangeHandler;
    transient?: true;
};
type NonTransientOnChangeSchemaItemOptions = {
    onChange: OnChangeHandler;
    transient: false;
};
type NoOnChangeSchemaItemOptions = {
    onChange?: undefined;
    transient?: undefined;
};
type OnChangeSchemaItemOptions = TransientOnChangeSchemaItemOptions | NonTransientOnChangeSchemaItemOptions | NoOnChangeSchemaItemOptions;
export type InputOptions = GenericSchemaItemOptions & OnChangeSchemaItemOptions & {
    optional?: boolean;
    disabled?: boolean;
    onEditStart?: (value: any, path: string, context: OnHandlerContext) => void;
    onEditEnd?: (value: any, path: string, context: OnHandlerContext) => void;
};
type SchemaItemWithOptions = number | boolean | string | (SchemaItem & InputOptions) | (SpecialInput & GenericSchemaItemOptions) | FolderInput<unknown>;
export type Schema = Record<string, SchemaItemWithOptions>;
/**
 * Dummy type used internally to flag non compatible input types.
 * @internal
 */
type NotAPrimitiveType = {
    ____: 'NotAPrimitiveType';
};
type PrimitiveToValue<P> = P extends CustomInput<infer CustomValue> ? BeautifyUnionType<CustomValue> : P extends ImageInput ? string | undefined : P extends SelectWithValueInput<infer SelectValue, infer Options> ? SelectValue | Options : P extends SelectWithoutValueInput<infer Options> ? Options : P extends IntervalInput ? [number, number] : P extends {
    value: infer Value;
} ? PrimitiveToValue<Value> : P extends VectorObj ? P : P extends Vector3dArray ? [number, number, number] : P extends Vector2dArray ? [number, number] : P extends number ? number : P extends string ? string : P extends boolean ? boolean : NotAPrimitiveType;
export type SchemaToValues<Schema, IncludeTransient extends boolean = false> = BeautifyUnionType<UnionToIntersection<Tree<IncludeTransient, Schema>>>;
type EndLeaf = {
    ___leaf: 'leaf';
};
type Join<Leaf1, Leaf1Key extends keyof Leaf1, Leaf2> = EndLeaf extends Leaf2 ? {
    [i in Leaf1Key]: Leaf1[Leaf1Key];
} : Leaf2;
type Tree<IncludeTransient extends boolean, Leaf, LeafKey extends string | number | symbol = ''> = {
    0: Leaf extends {
        schema: infer Schema;
    } ? {
        [Key in keyof Schema]: Join<Schema, Key, Schema[Key]>;
    } : never;
    1: never;
    2: {
        [Key in LeafKey]: Leaf extends {
            optional: true;
        } | {
            disabled: true;
        } ? PrimitiveToValue<Leaf> | undefined : PrimitiveToValue<Leaf>;
    };
    3: {
        [Key in keyof Leaf]: Join<Leaf, Key, Tree<IncludeTransient, Leaf[Key], Key>>;
    }[keyof Leaf];
    4: EndLeaf;
}[LeafKey extends '' ? 3 : Leaf extends FolderInput<unknown> ? 0 : Leaf extends SpecialInput ? 1 : PrimitiveToValue<Leaf> extends NotAPrimitiveType ? Leaf extends object ? 3 : 4 : Leaf extends TransientOnChangeSchemaItemOptions ? IncludeTransient extends true ? 2 : 1 : 2];
/**
 * If P is '' then T is the whole schema and we shouldn't run any type check
 * on the schema, to the risk that { a: 1, b: 2 } is recognized as Vector
 * instead of a two number inputs.
 */
/**
 * Interface to build a plugin.
 *
 * @public
 */
export interface Plugin<Input, Value = Input, InternalSettings = {}> {
    /**
     * The component that shows the input value;
     */
    component: React.ComponentType;
    /**
     * Normalizes the input into a { value, settings } object.
     *
     * @example
     * Let's consider a color with an inverted settings option that computes the negative
     * of that color. The plugin could look something like:
     * ```ts
     * myColorPlugin({ color: '#fff', inverted: true })
     * ```
     *
     * In that case, your normalize funciton would be something like:
     * ```ts
     * function normalize({ color, inverted }) {
     *   return { value: color, settings: { inverted }}
     * }
     * ```
     */
    normalize?: (input: Input, path: string, data: Data) => {
        value: Value;
        settings?: InternalSettings;
    };
    /**
     * Sanitizes the user value before registering it to the store. For
     * example, the Number plugin would santize "3.00" into 3. If the provided
     * value isn't formatted properly, the sanitize function should throw.
     */
    sanitize?: (value: any, settings: InternalSettings, prevValue: any, path: string, store: StoreType) => Value;
    /**
     * Formats the value into the value that will be displayed by the component.
     * If the input value of the Number plugin, then format will add proper
     * padding and show "3.00".
     * (Prop name in useInputContext context hook is `displayedValue`)
     */
    format?: (value: any, settings: InternalSettings) => any;
}
export type InputContextProps = {
    id: string;
    label: string | React.JSX.Element;
    hint?: string;
    path: string;
    key: string;
    optional: boolean;
    disabled: boolean;
    disable: (flag: boolean) => void;
    storeId: string;
    value: unknown;
    displayValue: unknown;
    onChange: React.Dispatch<any>;
    emitOnEditStart: () => void;
    emitOnEditEnd: () => void;
    onUpdate: (v: any | ((v: any) => any)) => void;
    settings: unknown;
    setSettings: (v: any) => void;
};
/**
 * Interface consumed by the useInputContext hook so that its returned values
 * are properly typed.
 *
 * @example
 * ```ts
 *  useInputContext<LevaInputProps<boolean>>()
 * ```
 * @public
 */
export interface LevaInputProps<V, InternalSettings = {}, DisplayValue = V> {
    path?: string;
    id?: string;
    hint?: string;
    disabled?: boolean;
    displayValue: DisplayValue;
    value: V;
    onChange: React.Dispatch<any>;
    emitOnEditStart: () => void;
    emitOnEditEnd: () => void;
    onUpdate: (v: any | ((v: any) => any)) => void;
    settings: InternalSettings;
    setSettings: (v: Partial<InternalSettings>) => void;
}
export {};
