import * as React from 'react';
import React__default from 'react';

type IsFunction<T> = T extends () => unknown ? true : T extends (...args: any[]) => unknown ? true : false;
type FlattenedKeysOf<T extends object, TArrayLike extends boolean = false> = {
    [Key in keyof T & (string | number)]: IsFunction<T[Key]> extends true ? TArrayLike extends false ? `${Key}` : never : T[Key] extends object ? T[Key] extends Array<unknown> ? // Arrays should have both array and objects by indicies and length properties
    `${Key}` | `${Key}.${FlattenedKeysOf<T[Key], true>}` : `${Key}.${FlattenedKeysOf<T[Key], TArrayLike>}` : `${Key}`;
}[keyof T & (string | number)];
type FlattenedObjectOf<T extends object, K extends FlattenedKeysOf<T> = FlattenedKeysOf<T>> = {
    [Key in K]: Key extends keyof T ? T[Key] : Key extends `${infer First}${'.'}${infer Rest}` ? First extends keyof T ? T[First] extends object ? FlattenedObjectOf<T[First]> extends object ? Rest extends keyof FlattenedObjectOf<T[First]> ? FlattenedObjectOf<T[First]>[Rest] : never : never : never : T extends Array<infer AT> ? Rest extends keyof AT ? AT[Rest] : never : never : T extends Array<infer AT> ? AT : never;
};
type TObservableObject<TValue extends Record<string, unknown>> = TValue & {
    subscribe: <TProp extends FlattenedKeysOf<TValue>>(prop: TProp, listener: () => void) => () => void;
};

/**
 * Creates a new React Context with the provided object as the initial value.
 * The context will support subscribing to changes and notifications when the value changes.
 * @param obj
 * @returns
 */
declare const createContext: <T>(obj: T) => React__default.Context<TObservableObject<NonNullable<T>> | undefined>;

/**
 * Creates a new object that allows for subscribing to changes
 * @param initialValue Initial value of the object.
 * @returns The object that can be used as a object where we can read/write values.
 */
declare const makeObservable: <TInitialValue extends Record<string, unknown>>(initialValue: TInitialValue) => TObservableObject<TInitialValue>;

/**
 * Creates a selector that subscribes to parts of the observable and returns the value of observed properties.
 * @param observable Observable to subscribe to
 * @param props Props to subscribe to (can be nested like a.b.c)
 * @returns An array of the values that will be updated if any of the properties change.
 */
declare const useObserver: <TValue extends Record<string, unknown>, TObservable extends TObservableObject<TValue>, TFlattened extends FlattenedObjectOf<TObservable>, TKeys extends Exclude<keyof TFlattened, "subscribe">>(observable: TObservable, ...props: TKeys[]) => Pick<Pick<FlattenedObjectOf<TObservable>, FlattenedKeysOf<TObservable, false>>, TKeys>;

/**
 * Creates a new observable from the given value. The observable can be
 * used to subscribe to changes. The initial value is used as the initial
 * value of the observable, and subsequent changes to the initial value will
 * not result in the observable being updated.
 * @param initialValue Initial value to create the observable from
 * @returns A new observable
 */
declare const useObservable: <T extends Record<string, unknown>>(initialValue: T) => TObservableObject<T>;

declare const Observable: {
    createContext: <T>(obj: T) => React.Context<TObservableObject<NonNullable<T>> | undefined>;
    makeObservable: <TInitialValue extends Record<string, unknown>>(initialValue: TInitialValue) => TObservableObject<TInitialValue>;
    useObserver: <TValue extends Record<string, unknown>, TObservable extends TObservableObject<TValue>, TFlattened extends FlattenedObjectOf<TObservable>, TKeys extends Exclude<keyof TFlattened, "subscribe">>(observable: TObservable, ...props: TKeys[]) => Pick<Pick<FlattenedObjectOf<TObservable>, FlattenedKeysOf<TObservable, false>>, TKeys>;
    useObservable: <T_1 extends Record<string, unknown>>(initialValue: T_1) => TObservableObject<T_1>;
};

export { FlattenedKeysOf, Observable, createContext, Observable as default, makeObservable, useObservable, useObserver };
