import { MaybePromiseProps, MergeHead, BaseBodyAttributes, HtmlAttributes as HtmlAttributes$1, Meta as Meta$1, Stringable, Merge, Base as Base$1, DefinedValueOrEmptyObject, LinkBase, HttpEventAttributes, DataKeys, Style as Style$1, ScriptBase, Noscript as Noscript$1, BodyEvents, MetaFlatInput } from 'zhead';
export { BodyEvents, DataKeys, DefinedValueOrEmptyObject, MergeHead, MetaFlatInput, SpeculationRules } from 'zhead';
import { NestedHooks, Hookable } from 'hookable';

type HookResult = Promise<void> | void;
interface SSRHeadPayload {
    headTags: string;
    bodyTags: string;
    bodyTagsOpen: string;
    htmlAttrs: string;
    bodyAttrs: string;
}
interface EntryResolveCtx<T> {
    tags: HeadTag[];
    entries: HeadEntry<T>[];
}
interface DomRenderTagContext {
    id: string;
    $el: Element;
    shouldRender: boolean;
    tag: HeadTag;
    entry?: HeadEntry<any>;
    markSideEffect: (key: string, fn: () => void) => void;
}
interface DomBeforeRenderCtx extends ShouldRenderContext {
    /**
     * @deprecated will always be empty, prefer other hooks
     */
    tags: DomRenderTagContext[];
}
interface ShouldRenderContext {
    shouldRender: boolean;
}
interface SSRRenderContext {
    tags: HeadTag[];
    html: SSRHeadPayload;
}
interface HeadHooks {
    'init': (ctx: Unhead<any>) => HookResult;
    'entries:updated': (ctx: Unhead<any>) => HookResult;
    'entries:resolve': (ctx: EntryResolveCtx<any>) => HookResult;
    'tag:normalise': (ctx: {
        tag: HeadTag;
        entry: HeadEntry<any>;
        resolvedOptions: CreateHeadOptions;
    }) => HookResult;
    'tags:beforeResolve': (ctx: {
        tags: HeadTag[];
    }) => HookResult;
    'tags:resolve': (ctx: {
        tags: HeadTag[];
    }) => HookResult;
    'dom:beforeRender': (ctx: DomBeforeRenderCtx) => HookResult;
    'dom:renderTag': (ctx: DomRenderTagContext, document: Document, track: any) => HookResult;
    'dom:rendered': (ctx: {
        renders: DomRenderTagContext[];
    }) => HookResult;
    'ssr:beforeRender': (ctx: ShouldRenderContext) => HookResult;
    'ssr:render': (ctx: {
        tags: HeadTag[];
    }) => HookResult;
    'ssr:rendered': (ctx: SSRRenderContext) => HookResult;
}

/**
 * Side effects are mapped with a key and their cleanup function.
 *
 * For example, `meta:data-h-4h46h465`: () => { document.querySelector('meta[data-h-4h46h465]').remove() }
 */
type SideEffectsRecord = Record<string, () => void>;
type RuntimeMode = 'server' | 'client';
interface HeadEntry<Input> {
    /**
     * User provided input for the entry.
     */
    input: Input;
    /**
     * Optional resolved input which will be used if set.
     */
    resolvedInput?: Input;
    /**
     * The mode that the entry should be used in.
     *
     * @internal
     */
    mode?: RuntimeMode;
    /**
     * Transformer function for the entry.
     *
     * @internal
     */
    transform?: (input: Input) => Promise<Input> | Input;
    /**
     * Head entry index
     *
     * @internal
     */
    _i: number;
    /**
     * Default tag position.
     *
     * @internal
     */
    tagPosition?: TagPosition['tagPosition'];
    /**
     * Default tag priority.
     *
     * @internal
     */
    tagPriority?: TagPriority['tagPriority'];
}
type HeadPluginOptions = Omit<CreateHeadOptions, 'plugins'> & {
    mode?: RuntimeMode;
};
type HeadPlugin = HeadPluginOptions | ((head: Unhead) => HeadPluginOptions);
/**
 * An active head entry provides an API to manipulate it.
 */
interface ActiveHeadEntry<Input> {
    /**
     * Updates the entry with new input.
     *
     * Will first clear any side effects for previous input.
     */
    patch: (input: Input) => void;
    /**
     * Dispose the entry, removing it from the active head.
     *
     * Will queue side effects for removal.
     */
    dispose: () => void;
}
interface CreateHeadOptions {
    domDelayFn?: (fn: () => void) => void;
    document?: Document;
    plugins?: HeadPlugin[];
    hooks?: NestedHooks<HeadHooks>;
}
interface HeadEntryOptions extends TagPosition, TagPriority, ProcessesTemplateParams {
    mode?: RuntimeMode;
    transform?: (input: unknown) => unknown;
    head?: Unhead;
}
interface Unhead<Input extends {} = Head> {
    /**
     * The active head entries.
     */
    headEntries: () => HeadEntry<Input>[];
    /**
     * Create a new head entry.
     */
    push: (entry: Input, options?: HeadEntryOptions) => ActiveHeadEntry<Input>;
    /**
     * Resolve tags from head entries.
     */
    resolveTags: () => Promise<HeadTag[]>;
    /**
     * Exposed hooks for easier extension.
     */
    hooks: Hookable<HeadHooks>;
    /**
     * Resolved options
     */
    resolvedOptions: CreateHeadOptions;
    /**
     * Use a head plugin, loads the plugins hooks.
     */
    use: (plugin: HeadPlugin) => void;
    /**
     * Is it a server-side render context.
     */
    ssr: boolean;
    /**
     * @internal
     */
    _dom?: DomState;
    /**
     * @internal
     */
    _domUpdatePromise?: Promise<void>;
    /**
     * @internal
     */
    dirty: boolean;
}
interface DomState {
    pendingSideEffects: SideEffectsRecord;
    sideEffects: SideEffectsRecord;
    elMap: Record<string, Element>;
}

interface ResolvesDuplicates {
    /**
     * By default, tags which share the same unique key `name`, `property` are de-duped. To allow duplicates
     * to be made you can provide a unique key for each entry.
     */
    key?: string;
    /**
     * The strategy to use when a duplicate tag is encountered.
     *
     * - `replace` - Replace the existing tag with the new tag
     * - `merge` - Merge the existing tag with the new tag
     *
     * @default 'replace' (some tags will default to 'merge', such as htmlAttr)
     */
    tagDuplicateStrategy?: 'replace' | 'merge';
    /**
     * @deprecated Use `key` instead
     */
    hid?: string;
    /**
     * @deprecated Use `key` instead
     */
    vmid?: string;
}
type ValidTagPositions = 'head' | 'bodyClose' | 'bodyOpen';
interface TagPosition {
    /**
     * Specify where to render the tag.
     *
     * @default 'head'
     */
    tagPosition?: ValidTagPositions;
}
type InnerContentVal = string | Record<string, any>;
interface InnerContent {
    /**
     * Text content of the tag.
     *
     * Warning: This is not safe for XSS. Do not use this with user input, use `textContent` instead.
     */
    innerHTML?: InnerContentVal;
    /**
     * Sets the textContent of an element. Safer for XSS.
     */
    textContent?: InnerContentVal;
    /**
     * Sets the textContent of an element.
     *
     * @deprecated Use `textContent` or `innerHTML`.
     */
    children?: InnerContentVal;
}
interface TagPriority {
    /**
     * The priority for rendering the tag, without this all tags are rendered as they are registered
     * (besides some special tags).
     *
     * The following special tags have default priorities:
     * -2 `<meta charset ...>`
     * -1 `<base>`
     * 0 `<meta http-equiv="content-security-policy" ...>`
     *
     * All other tags have a default priority of 10: `<meta>`, `<script>`, `<link>`, `<style>`, etc
     */
    tagPriority?: number | 'critical' | 'high' | 'low' | `before:${string}` | `after:${string}`;
}
type TagUserProperties = TagPriority & TagPosition & MaybePromiseProps<InnerContent> & ResolvesDuplicates & ProcessesTemplateParams;
type TagKey = keyof Head;
type TemplateParams = {
    separator?: string;
} & Record<string, null | string | Record<string, string>>;
interface ProcessesTemplateParams {
    processTemplateParams?: boolean;
}
interface HasTemplateParams {
    templateParams?: TemplateParams;
}
interface HeadTag extends TagPriority, TagPosition, ResolvesDuplicates, HasTemplateParams {
    tag: TagKey;
    props: Record<string, string>;
    processTemplateParams?: boolean;
    innerHTML?: string;
    textContent?: string;
    /**
     * Entry ID
     * @internal
     */
    _e?: number;
    /**
     * Position
     * @internal
     */
    _p?: number;
    /**
     * Dedupe key
     * @internal
     */
    _d?: string;
    /**
     * Hash code used to represent the tag.
     * @internal
     */
    _h?: string;
    /**
     * @internal
     */
    _m?: RuntimeMode;
}
type HeadTagKeys = (keyof HeadTag)[];

type Never<T> = {
    [P in keyof T]?: never;
};
type UserTagConfigWithoutInnerContent = TagPriority & TagPosition & ResolvesDuplicates & Never<InnerContent> & {
    processTemplateParams?: false;
};
type UserAttributesConfig = ResolvesDuplicates & TagPriority & Never<InnerContent & TagPosition>;
interface SchemaAugmentations extends MergeHead {
    title: TagPriority;
    titleTemplate: TagPriority;
    base: UserAttributesConfig;
    htmlAttrs: UserAttributesConfig;
    bodyAttrs: UserAttributesConfig;
    link: UserTagConfigWithoutInnerContent;
    meta: UserTagConfigWithoutInnerContent;
    style: TagUserProperties;
    script: TagUserProperties;
    noscript: TagUserProperties;
}
type MaybeArray<T> = T | T[];
type BaseBodyAttr = BaseBodyAttributes;
type BaseHtmlAttr = HtmlAttributes$1;
interface BodyAttr extends Omit<BaseBodyAttr, 'class'> {
    /**
     * The class global attribute is a space-separated list of the case-sensitive classes of the element.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class
     */
    class?: MaybeArray<string> | Record<string, boolean>;
}
interface HtmlAttr extends Omit<HtmlAttributes$1, 'class'> {
    /**
     * The class global attribute is a space-separated list of the case-sensitive classes of the element.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class
     */
    class?: MaybeArray<string> | Record<string, boolean>;
}
interface BaseMeta extends Omit<Meta$1, 'content'> {
    /**
     * This attribute contains the value for the http-equiv, name or property attribute, depending on which is used.
     *
     * You can provide an array of values to create multiple tags sharing the same name, property or http-equiv.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta#attr-content
     */
    content?: MaybeArray<Stringable> | null;
}
type EntryAugmentation = undefined | Record<string, any>;
type MaybeFunctionEntries<T> = {
    [key in keyof T]?: T[key] | ((e: Event) => void);
};
type TitleTemplateResolver = string | ((title?: string) => string | null);
type Title = MaybePromiseProps<string | ({
    textContent: string;
} & SchemaAugmentations['title']) | null>;
type TitleTemplate = TitleTemplateResolver | null | ({
    textContent: TitleTemplateResolver;
} & SchemaAugmentations['titleTemplate']);
type Base<E extends EntryAugmentation = {}> = Partial<Merge<SchemaAugmentations['base'], MaybePromiseProps<Base$1>>> & DefinedValueOrEmptyObject<E>;
type Link<E extends EntryAugmentation = {}> = MaybePromiseProps<LinkBase> & MaybeFunctionEntries<HttpEventAttributes> & DataKeys & SchemaAugmentations['link'] & DefinedValueOrEmptyObject<E>;
type Meta<E extends EntryAugmentation = {}> = MaybePromiseProps<BaseMeta> & DataKeys & SchemaAugmentations['meta'] & DefinedValueOrEmptyObject<E>;
type Style<E extends EntryAugmentation = {}> = MaybePromiseProps<Style$1> & DataKeys & SchemaAugmentations['style'] & DefinedValueOrEmptyObject<E>;
type Script<E extends EntryAugmentation = {}> = MaybePromiseProps<ScriptBase> & MaybeFunctionEntries<HttpEventAttributes> & DataKeys & SchemaAugmentations['script'] & DefinedValueOrEmptyObject<E>;
type Noscript<E extends EntryAugmentation = {}> = MaybePromiseProps<Noscript$1> & DataKeys & SchemaAugmentations['noscript'] & DefinedValueOrEmptyObject<E>;
type HtmlAttributes<E extends EntryAugmentation = {}> = MaybePromiseProps<HtmlAttr> & DataKeys & SchemaAugmentations['htmlAttrs'] & DefinedValueOrEmptyObject<E>;
type BodyAttributes<E extends EntryAugmentation = {}> = MaybePromiseProps<BodyAttr> & MaybeFunctionEntries<BodyEvents> & DataKeys & SchemaAugmentations['bodyAttrs'] & DefinedValueOrEmptyObject<E>;
interface HeadUtils {
    /**
     * Generate the title from a template.
     *
     * Should include a `%s` placeholder for the title, for example `%s - My Site`.
     */
    titleTemplate?: TitleTemplate;
    /**
     * Variables used to substitute in the title and meta content.
     */
    templateParams?: TemplateParams;
}
interface Head<E extends MergeHead = SchemaAugmentations> extends HeadUtils {
    /**
     * The `<title>` HTML element defines the document's title that is shown in a browser's title bar or a page's tab.
     * It only contains text; tags within the element are ignored.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title
     */
    title?: Title | Promise<Title>;
    /**
     * The `<base>` HTML element specifies the base URL to use for all relative URLs in a document.
     * There can be only one <base> element in a document.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
     */
    base?: Base<E['base']>;
    /**
     * The `<link>` HTML element specifies relationships between the current document and an external resource.
     * This element is most commonly used to link to stylesheets, but is also used to establish site icons
     * (both "favicon" style icons and icons for the home screen and apps on mobile devices) among other things.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-as
     */
    link?: Link<E['link']>[];
    /**
     * The `<meta>` element represents metadata that cannot be expressed in other HTML elements, like `<link>` or `<script>`.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta
     */
    meta?: Meta<E['meta']>[];
    /**
     * The `<style>` HTML element contains style information for a document, or part of a document.
     * It contains CSS, which is applied to the contents of the document containing the `<style>` element.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style
     */
    style?: (Style<E['style']> | string)[];
    /**
     * The `<script>` HTML element is used to embed executable code or data; this is typically used to embed or refer to JavaScript code.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
     */
    script?: (Script<E['script']> | string)[];
    /**
     * The `<noscript>` HTML element defines a section of HTML to be inserted if a script type on the page is unsupported
     * or if scripting is currently turned off in the browser.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/noscript
     */
    noscript?: (Noscript<E['noscript']> | string)[];
    /**
     * Attributes for the `<html>` HTML element.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html
     */
    htmlAttrs?: HtmlAttributes<E['htmlAttrs']>;
    /**
     * Attributes for the `<body>` HTML element.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body
     */
    bodyAttrs?: BodyAttributes<E['bodyAttrs']>;
}
type UseSeoMetaInput = MetaFlatInput & {
    title?: Title;
    titleTemplate?: TitleTemplate;
};

type SafeBodyAttr = Pick<BodyAttr, 'id' | 'class'> & DataKeys;
type SafeHtmlAttr = Pick<HtmlAttr, 'id' | 'class' | 'lang' | 'dir'> & DataKeys;
type SafeMeta = Pick<Meta, 'id' | 'name' | 'property' | 'content'> & DataKeys;
type SafeLink = Pick<Link, 'color' | 'crossorigin' | 'fetchpriority' | 'href' | 'hreflang' | 'imagesizes' | 'imagesrcset' | 'integrity' | 'media' | 'referrerpolicy' | 'sizes' | 'id'> & {
    rel?: Omit<Link['rel'], 'stylesheet' | 'canonical' | 'modulepreload' | 'prerender' | 'preload' | 'prefetch'>;
    type?: 'audio/aac' | 'application/x-abiword' | 'application/x-freearc' | 'image/avif' | 'video/x-msvideo' | 'application/vnd.amazon.ebook' | 'application/octet-stream' | 'image/bmp' | 'application/x-bzip' | 'application/x-bzip2' | 'application/x-cdf' | 'application/x-csh' | 'text/csv' | 'application/msword' | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' | 'application/vnd.ms-fontobject' | 'application/epub+zip' | 'application/gzip' | 'image/gif' | 'image/vnd.microsoft.icon' | 'text/calendar' | 'application/java-archive' | 'image/jpeg' | 'application/json' | 'application/ld+json' | 'audio/midi' | 'audio/x-midi' | 'audio/mpeg' | 'video/mp4' | 'video/mpeg' | 'application/vnd.apple.installer+xml' | 'application/vnd.oasis.opendocument.presentation' | 'application/vnd.oasis.opendocument.spreadsheet' | 'application/vnd.oasis.opendocument.text' | 'audio/ogg' | 'video/ogg' | 'application/ogg' | 'audio/opus' | 'font/otf' | 'image/png' | 'application/pdf' | 'application/x-httpd-php' | 'application/vnd.ms-powerpoint' | 'application/vnd.openxmlformats-officedocument.presentationml.presentation' | 'application/vnd.rar' | 'application/rtf' | 'application/x-sh' | 'image/svg+xml' | 'application/x-tar' | 'image/tiff' | 'video/mp2t' | 'font/ttf' | 'text/plain' | 'application/vnd.visio' | 'audio/wav' | 'audio/webm' | 'video/webm' | 'image/webp' | 'font/woff' | 'font/woff2' | 'application/xhtml+xml' | 'application/vnd.ms-excel' | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | 'text/xml' | 'application/atom+xml' | 'application/xml' | 'application/vnd.mozilla.xul+xml' | 'application/zip' | 'video/3gpp' | 'audio/3gpp' | 'video/3gpp2' | 'audio/3gpp2' | (string & Record<never, never>);
} & DataKeys;
type SafeScript = Pick<Script, 'id' | 'textContent'> & {
    type: 'application/json' | 'application/ld+json';
} & DataKeys;
type SafeNoscript = Pick<Noscript, 'id' | 'textContent'> & DataKeys;
interface HeadSafe extends Pick<Head, 'title' | 'titleTemplate' | 'templateParams'> {
    meta?: SafeMeta[];
    link?: SafeLink[];
    noscript?: SafeNoscript[];
    script?: SafeScript[];
    htmlAttrs?: SafeHtmlAttr;
    bodyAttrs?: SafeBodyAttr;
}

export type { ActiveHeadEntry, Base, BaseBodyAttr, BaseHtmlAttr, BaseMeta, BodyAttr, BodyAttributes, CreateHeadOptions, DomBeforeRenderCtx, DomRenderTagContext, DomState, EntryAugmentation, EntryResolveCtx, HasTemplateParams, Head, HeadEntry, HeadEntryOptions, HeadHooks, HeadPlugin, HeadPluginOptions, HeadSafe, HeadTag, HeadTagKeys, HeadUtils, HookResult, HtmlAttr, HtmlAttributes, InnerContent, InnerContentVal, Link, MaybeArray, MaybeFunctionEntries, Meta, Never, Noscript, ProcessesTemplateParams, ResolvesDuplicates, RuntimeMode, SSRHeadPayload, SSRRenderContext, SafeBodyAttr, SafeHtmlAttr, SafeLink, SafeMeta, SafeNoscript, SafeScript, SchemaAugmentations, Script, ShouldRenderContext, SideEffectsRecord, Style, TagKey, TagPosition, TagPriority, TagUserProperties, TemplateParams, Title, TitleTemplate, Unhead, UseSeoMetaInput, UserAttributesConfig, UserTagConfigWithoutInnerContent, ValidTagPositions };
