import type { ReadableSignal } from '@amadeus-it-group/tansu';
import type { AttributeValue, Directive, DirectivesAndOptParam, SSRHTMLElement, StyleKey, StyleValue } from '../types';
import { type ClassValue } from 'clsx';
/**
 * On a browser environment, returns true if the given element is an HTMLElement.
 * On a server environment, always returns false.
 * @param element - The element to check.
 * @returns true in a browser environment if the given element is an HTMLElement, otherwise false.
 */
export declare const isBrowserHTMLElement: (element: SSRHTMLElement) => element is HTMLElement;
/**
 * A higher-order directive function that conditionally applies a directive based on the environment.
 * If running in a browser environment, it applies the given directive to the node.
 * If not in a browser environment, it returns a no-op function.
 *
 * @template T - The type of the directive's argument.
 * @template U - The type of the HTML element the directive is applied to.
 * @param directive - The directive to be conditionally applied.
 * @returns - A directive that applies the given directive in a browser environment, or a no-op in a non-browser environment.
 */
export declare const browserDirective: <T, U extends HTMLElement>(directive: Directive<T, U>) => Directive<T, SSRHTMLElement>;
/**
 * Binds the given directive to a store that provides its argument.
 *
 * @remarks
 *
 * The returned directive can be used without argument, it will ignore any argument passed to it
 * and will call the provided directive with the content of the provided store as its argument,
 * calling its update method when the content of the store changes.
 *
 * @template T - The type of the directive argument.
 * @template U - The type of the SSRHTMLElement, defaults to SSRHTMLElement.
 * @param directive - The directive to bind to the element.
 * @param directiveArg$ - The signal to subscribe to for directive updates.
 * @returns A directive that manages the lifecycle of the bound directive.
 */
export declare const bindDirective: <T, U extends SSRHTMLElement = SSRHTMLElement>(directive: Directive<T, U>, directiveArg$: ReadableSignal<T>) => Directive<void, U>;
/**
 * Returns a directive that ignores any argument passed to it and calls the provided directive without any
 * argument.
 *
 * @template T - The type of the directive's argument.
 * @template U - The type of the SSRHTMLElement, defaults to SSRHTMLElement.
 * @param directive - The directive to bind without arguments.
 * @returns A new directive that does not require any arguments.
 */
export declare const bindDirectiveNoArg: <T, U extends SSRHTMLElement = SSRHTMLElement>(directive: Directive<T, U>) => Directive<void, U>;
/**
 * Maps the argument of a directive to a new value using a provided function.
 *
 * @template T - The type of the original argument.
 * @template U - The type of the mapped argument.
 * @template V - The type of the SSRHTMLElement, defaults to SSRHTMLElement.
 *
 * @param directive - The original directive to be mapped.
 * @param fn - The function to map the original argument to the new argument.
 * @returns A new directive with the mapped argument.
 */
export declare const mapDirectiveArg: <T, U, V extends SSRHTMLElement = SSRHTMLElement>(directive: Directive<U, V>, fn: (arg: T) => U) => Directive<T, V>;
/**
 * Returns a directive that subscribes to the given store while it is used on a DOM element,
 * and that unsubscribes from it when it is no longer used.
 *
 * @param store - store on which there will be an active subscription while the returned directive is used.
 * @param asyncUnsubscribe - true if unsubscribing from the store should be done asynchronously (which is the default), and
 * false if it should be done synchronously when the directive is destroyed
 * @returns The resulting directive.
 */
export declare const directiveSubscribe: (store: ReadableSignal<any>, asyncUnsubscribe?: boolean) => Directive;
/**
 * Returns a directive that calls the provided function with the arguments passed to the directive
 * on initialization and each time they are updated.
 *
 * @template T - The type of the argument that the update function accepts.
 * @param update - Function called with the directive argument when the directive is initialized and when its argument is updated.
 * @returns The resulting directive.
 */
export declare const directiveUpdate: <T>(update: (arg: T) => void) => Directive<T>;
/**
 * Creates a registration array that allows elements to be added and removed.
 *
 * @template T - The type of elements in the array.
 * @returns An object that includes a readable signal of the array and a register function.
 *
 * The returned object has the following properties:
 * - `register`: A function to add an element to the array. It takes an element of type `T` as a parameter and returns a function to remove the element from the array.
 */
export declare const registrationArray: <T>() => ReadableSignal<T[]> & {
    register: (element: T) => () => void;
};
/**
 * Returns a directive and a store. The store contains at any time the array of all the DOM elements on which the directive is
 * currently used.
 *
 * @remarks
 * It is the same as {@link createBrowserStoreArrayDirective}, but the returned directive is also executed in a server environment
 * and the type of the elements is {@link SSRHTMLElement} instead of HTMLElement.
 *
 * If the directive is intended to be used on a single element element, it may be more appropriate to use
 * {@link createStoreDirective} instead.
 *
 * @returns An object with two properties: the `directive` property that is the directive to use on some DOM elements,
 * and the `elements$` property that is the store containing an array of all the elements on which the directive is currently
 * used.
 */
export declare const createStoreArrayDirective: () => {
    directive: Directive;
    elements$: ReadableSignal<SSRHTMLElement[]>;
};
/**
 * Returns a directive and a store. The store contains at any time the array of all the DOM elements on which the directive is
 * currently used.
 *
 * @remarks
 * It is the same as {@link createStoreArrayDirective}, but the returned directive is only executed in a browser environment
 * and the type of the elements is HTMLElement instead of {@link SSRHTMLElement}.
 *
 * If the directive is intended to be used on a single element element, it may be more appropriate to use
 * {@link createBrowserStoreDirective} instead.
 *
 * @returns An object with two properties: the `directive` property that is the directive to use on some DOM elements,
 * and the `elements$` property that is the store containing an array of all the elements on which the directive is currently
 * used.
 */
export declare const createBrowserStoreArrayDirective: () => {
    directive: Directive<void, SSRHTMLElement>;
    elements$: ReadableSignal<HTMLElement[]>;
};
/**
 * Returns a directive and a store. When the directive is used on a DOM element, the store contains that DOM element.
 * When the directive is not used, the store contains null.
 *
 * @remarks
 * It is the same as {@link createBrowserStoreDirective}, but the returned directive is also executed in a server environment
 * and the type of the element is {@link SSRHTMLElement} instead of HTMLElement.
 *
 * If the directive is used on more than one element, an error is displayed in the console and the element is ignored.
 * If the directive is intended to be used on more than one element, please use {@link createStoreArrayDirective} instead.
 *
 * @returns An object with two properties: the `directive` property that is the directive to use on one DOM element,
 * and the `element$` property that is the store containing the element on which the directive is currently used (or null
 * if the store is not currently used).
 */
export declare const createStoreDirective: () => {
    directive: Directive;
    element$: ReadableSignal<SSRHTMLElement | null>;
};
/**
 * Returns a directive and a store. When the directive is used on a DOM element, the store contains that DOM element.
 * When the directive is not used, the store contains null.
 *
 * @remarks
 * It is the same as {@link createStoreDirective}, but the returned directive is only executed in a browser environment
 * and the type of the element is HTMLElement instead of {@link SSRHTMLElement}.
 *
 * If the directive is used on more than one element, an error is displayed in the console and the element is ignored.
 * If the directive is intended to be used on more than one element, please use {@link createStoreArrayDirective} instead.
 *
 * @returns An object with two properties: the `directive` property that is the directive to use on one DOM element,
 * and the `element$` property that is the store containing the element on which the directive is currently used (or null
 * if the store is not currently used).
 */
export declare const createBrowserStoreDirective: () => {
    directive: Directive<void, SSRHTMLElement>;
    element$: ReadableSignal<HTMLElement | null>;
};
/**
 * Merges multiple directives into a single directive that executes all of them when called.
 *
 * @remarks
 * All directives receive the same argument upon initialization and update.
 * Directives are created and updated in the same order as they appear in the arguments list,
 * they are destroyed in the reverse order.
 * All calls to the directives (to create, update and destroy them) are wrapped in a call to the
 * batch function of tansu
 *
 * @template T - The type of the argument passed to the directive.
 * @template U - The type of the SSRHTMLElement, defaults to SSRHTMLElement.
 * @param args - The directives to merge.
 * @returns A new directive that applies all the given directives.
 *
 * The returned directive has the following lifecycle methods:
 * - `update(arg)`: Updates all merged directives with the given argument.
 * - `destroy()`: Destroys all merged directives in reverse order.
 */
export declare const mergeDirectives: <T, U extends SSRHTMLElement = SSRHTMLElement>(...args: (Directive<T, U> | Directive<void, U>)[]) => Directive<T, U>;
/**
 * Applies multiple directives to a given SSRHTMLElement and provides methods to update or destroy them.
 *
 * @template T - A tuple type representing the arguments for each directive.
 * @template U - The type of the SSRHTMLElement, defaults to SSRHTMLElement.
 *
 * @param element - The SSRHTMLElement to which the directives will be applied.
 * @param directives - An array of directives and their optional parameters.
 *
 * @returns An object containing:
 * - `update`: A function to update the directives with new parameters.
 * - `destroy`: A function to destroy all applied directives.
 */
export declare const multiDirective: <T extends any[], U extends SSRHTMLElement = SSRHTMLElement>(element: U, directives: DirectivesAndOptParam<T, U>) => {
    update: (directives: DirectivesAndOptParam<any[], U>) => void;
    destroy: () => void;
};
/**
 * Properties for configuring server-side rendering directives.
 */
export interface AttributesDirectiveProps {
    /**
     * Events to be attached to an HTML element.
     * @remarks
     * Key-value pairs where keys are event types and values are event handlers.
xw
     */
    events?: Partial<{
        [K in keyof HTMLElementEventMap]: {
            handler: (this: HTMLElement, event: HTMLElementEventMap[K]) => void;
            options?: boolean | AddEventListenerOptions;
        } | ((this: HTMLElement, event: HTMLElementEventMap[K]) => void);
    }>;
    /**
     * Attributes to be added to the provided node.
     * @remarks
     * The `style` attribute must be added separately.
     */
    attributes?: Record<string, ReadableSignal<AttributeValue>>;
    /**
     * Styles to be added to an HTML element.
     * @remarks
     * Key-value pairs where keys are CSS style properties and values are style values.
     */
    styles?: Partial<Record<StyleKey, ReadableSignal<StyleValue>>>;
    /**
     * Class names to be added to an HTML element.
     * @remarks
     * Key-value pairs where keys are class names and values indicate whether the class should be added (true) or removed (false).
     */
    classNames?: Record<string, ReadableSignal<boolean>>;
}
/**
 * Creates a directive that binds attributes, styles, class names, and events to a DOM node.
 *
 * @template T - The type of the arguments passed to the directive.
 * @param propsFn - A function that takes a readable signal of type `T` and returns an object containing
 *                  attributes, styles, class names, and events to bind to the node.
 * @returns A directive function that can be used to bind the specified properties to a DOM node.
 *
 * The returned directive function takes a DOM node and arguments of type `T`, and sets up the bindings
 * specified by the `propsFn` function. It returns an object with `update` and `destroy` methods:
 * - `update(args: T)`: Updates the arguments passed to the directive.
 * - `destroy()`: Cleans up all bindings and event listeners.
 */
export declare const createAttributesDirective: <T = void>(propsFn: (arg: ReadableSignal<T>) => AttributesDirectiveProps) => Directive<T>;
/**
 * Returns an object with the attributes, style and class keys containing information derived from a list of directives.
 *
 *   - The `attributes` value is a JSON representation of key/value attributes, excepted for the `class` and `style` attributes
 *   - The `classNames` value is an array of string representing the classes to be applied
 *   - The `style` value is a JSON representation of the styles to be applied
 *
 * @template T - The type of the directives array.
 * @param directives - List of directives to generate attributes from. Each parameter can be the directive or an array with the directive and its parameter
 * @returns JSON object with the `attributes`, `class` and `style` keys.
 */
export declare const attributesData: <T extends any[]>(...directives: DirectivesAndOptParam<T>) => {
    attributes: Record<string, string>;
    classNames: string[];
    style: Partial<Record<StyleKey, StyleValue>>;
};
/**
 * Directive that takes as an argument a string, array or object containing CSS classes to be put on the HTML element.
 * The class attribute is computed using the clsx library.
 */
export declare const classDirective: Directive<ClassValue>;
/**
 * Combines multiple directives into a single attributes object.
 *
 * This function processes an array of directives and optional parameters,
 * extracting attributes, class names, and styles. It then combines these
 * into a single attributes object, where class names are joined into a
 * single string and styles are formatted as a CSS string.
 *
 * @template T - The type of the directives and optional parameters.
 * @param directives - The directives and optional parameters to process.
 * @returns An object containing the combined attributes.
 */
export declare function directiveAttributes<T extends any[]>(...directives: DirectivesAndOptParam<T>): Record<string, string>;
/**
 * Generates a record of SSR (Server-Side Rendering) attributes based on the provided directives.
 *
 * This function behaves differently depending on the environment:
 * - In a browser environment (`BROWSER` is true), it returns an empty object.
 * - In a non-browser environment, it delegates to the `directiveAttributes` function.
 *
 * @template T - A tuple type representing the directives and optional parameters.
 * @returns A record of SSR attributes.
 */
export declare const ssrAttributes: <T extends any[]>(...directives: DirectivesAndOptParam<T>) => Record<string, string>;
