import type { ChildDom, State, StateView, Van } from 'vanjs-core';
import { type AttributeConverter } from './property-utils';
export type { AttributeConverter } from './property-utils';
export type { ChildDom, State, StateView, Van };
/**
 * Configuration options for VanJS Reactive Element
 * @example
 * const vanRE = createVanRE({
 *   van: { add: van.add, state: van.state },
 *   rxScope: van.derive // Optional: custom reactive scope
 * })
 */
export interface VanREOptions {
    /** Reactive scope function for managing component lifecycle */
    rxScope?: (fn: () => void | (() => void)) => () => void;
    /** VanJS instance with required methods */
    van: {
        add: Van['add'];
        state: Van['state'];
    };
}
/**
 * Type Usage Quick Reference:
 *
 * 1. Class Components:
 * ```typescript
 * class MyElement extends VanReactiveElement {
 *   declare name: State<string>;
 *   declare count: State<number>;
 *   declare data: State<{ foo: string }>;  // All properties are reactive
 *
 *   static properties = {
 *     name: { type: String, default: 'World' },
 *     count: { type: Number, default: 0 },
 *     data: { attribute: false, default: { foo: 'bar' } }
 *   };
 * }
 * ```
 *
 * 2. Functional Components with options object:
 * ```typescript
 * define('my-component', {
 *   // Attributes (all get StateView - read-only)
 *   // Must specify type for proper serialization
 *   attributes: {
 *     name: { type: String, default: 'John' },
 *     count: { type: Number, default: 0 },
 *     active: { type: Boolean, reflect: true },
 *     label: { type: String }  // No default is fine
 *   },
 *
 *   // Internal properties (all get State - read-write)
 *   // MUST be simple values, not PropertyOptions
 *   properties: {
 *     data: { foo: 'bar' },    // Object literal
 *     cache: [],               // Empty array
 *     loading: false,          // Boolean
 *     message: ''              // Empty string
 *   },
 *
 *   // Optional styles
 *   styles: `
 *     :host { display: block; }
 *     button { padding: 8px; }
 *   `
 * }, (element) => {
 *   // Attribute properties are StateView (read-only)
 *   const name = element.name.val;          // ✓ Can read
 *   // element.name.val = 'Jane';           // ✗ Error: readonly
 *
 *   // Internal properties are State (read-write)
 *   element.data.val = { foo: 'new' };      // ✓ Can modify
 *   element.cache.val.push('item');         // ✓ Direct mutation
 *   element.loading.val = true;             // ✓ Direct assignment
 *
 *   // Setting properties using setProperty method
 *   element.setProperty('name', 'Jane');              // ✓ Attributes
 *   element.setProperty('data', { foo: 'bar' });      // ✓ Properties
 *
 *   // Return the render function
 *   return () => button(
 *     { onclick: () => element.setProperty('count', element.count.val + 1) },
 *     element.label, ': ', element.count
 *   );
 * });
 *
 * // With custom shadow root options and styles
 * define('closed-component', {
 *   attributes: { name: { type: String, default: 'Shadow' } },
 *   properties: { internal: 'state' },
 *   shadowRootOptions: { mode: 'closed', delegatesFocus: true },
 *   styles: `:host { display: inline-block; }`
 * }, (element) => {
 *   return () => span(element.name);
 * });
 * ```
 *
 * 3. Direct State assignment in class components:
 * ```typescript
 * class MyElement extends VanReactiveElement {
 *   static properties = { count: 0 };
 *
 *   increment() {
 *     // Runtime accepts both State<T> and plain values
 *     this.count = van.state(100);  // Assign State directly
 *     this.count = 50;              // Assign plain value
 *     this.count.val = 75;          // Modify via .val
 *   }
 * }
 * ```
 */
export type PropertyType = StringConstructor | NumberConstructor | BooleanConstructor | ObjectConstructor | ArrayConstructor | Function;
/**
 * Property configuration options
 * @template T - The type of the property value
 *
 * Type inference priority:
 * 1. Explicit type parameter in PropertyOptions<T>
 * 2. Default value type
 * 3. Type property (String, Number, Boolean, Object, Array)
 *
 * @example
 * // Type inferred from default value
 * count: { type: Number, default: 0 }  // → State<number>
 *
 * @example
 * // Type inferred from 'type' property when no default
 * isActive: {
 *   type: Boolean,
 *   attribute: 'data-active',
 *   reflect: true
 * }  // → State<boolean>
 *
 * @example
 * // Simple type-only definition
 * enabled: { type: Boolean }  // → State<boolean>
 *
 * @example
 * // Explicit type takes precedence
 * internal: { type: Object, attribute: false } as PropertyOptions<User>  // → State<User>
 */
export interface PropertyOptions<T = unknown> {
    /** Enable attribute binding. true = kebab-case, false = disabled, string = custom name */
    attribute?: boolean | string;
    /** Custom converter for attribute serialization/deserialization */
    converter?: AttributeConverter<T>;
    /** Default value for the property */
    default?: T;
    /** Reflect property changes back to attributes */
    reflect?: boolean;
    /** Type hint for automatic conversion (String, Number, Boolean, Object, Array) */
    type?: PropertyType;
}
/**
 * Context object provided to functional component setup
 * @template E - The element type
 * @example
 * define('my-component', {
 *   attributes: { label: { type: String, default: 'Click me' } },
 *   properties: { count: 0 },
 *   styles: `
 *     :host { display: block; }
 *     button { padding: 8px; }
 *   `
 * }, (element, ctx) => {
 *   ctx.onMount(() => console.log('Component mounted'));
 *   ctx.onCleanup(() => console.log('Component cleanup'));
 *
 *   // Return the render function
 *   return () => button({
 *     onclick: () => element.setProperty('count', element.count.val + 1)
 *   }, element.label, ': ', element.count);
 * })
 */
export interface SetupContext {
    /** Disable shadow DOM (use light DOM instead) */
    noShadowDOM: () => void;
    /** Register cleanup function called on disconnect */
    onCleanup: (fn: () => void) => void;
    /** Register mount function called after initial render */
    onMount: (fn: () => void) => void;
}
/**
 * Property definitions for attributes.
 * Must use PropertyOptions with at least a type specified.
 *
 * @example
 * {
 *   // Type is required for proper serialization
 *   name: { type: String },                          // No default
 *   count: { type: Number, default: 0 },             // With default
 *   active: { type: Boolean, reflect: true },        // With reflection
 *   label: { type: String, attribute: 'aria-label' } // Custom attribute name
 * }
 */
export type PropertyDefinitions = {
    [key: string]: PropertyOptions;
};
/**
 * State definitions are simple key-value pairs
 */
export type StateDefinitions = Record<string, any>;
/**
 * Options for defining a custom element
 */
export interface DefineOptions<A extends PropertyDefinitions = PropertyDefinitions, S extends StateDefinitions = StateDefinitions> {
    /** Properties that sync with DOM attributes (become StateView) */
    attributes?: A;
    /** Internal properties on the instance (become State) */
    properties?: S;
    /** Optional shadow root configuration */
    shadowRootOptions?: ShadowRootInit;
    /** Component styles (scoped to shadow DOM) */
    styles?: string | CSSStyleSheet;
}
export type DefineFunction = <A extends PropertyDefinitions, S extends StateDefinitions>(customElementName: string, options: DefineOptions<A, S>, setup: (element: TypedElementInstance<A, S>, context: SetupContext) => (() => unknown) | void) => VanReactiveElementConstructor;
export interface VanRE {
    VanReactiveElement: VanReactiveElementConstructor;
    css: (template: TemplateStringsArray, ...values: any[]) => string;
    define: DefineFunction;
}
/**
 * Instance interface for VanReactiveElement
 */
export interface VanReactiveElement extends HTMLElement {
    renderRoot: ShadowRoot | HTMLElement | null;
    dispatchCustomEvent(typeName: string, options?: CustomEventInit): boolean;
    hasShadowDOM(): boolean;
    query(selector: string): Element | null;
    queryAll(selector: string): NodeListOf<Element>;
    registerDisposer(disposer: () => void): () => void;
    setProperties(properties: Record<string, unknown>): VanReactiveElement;
    setProperty(property: string, value: unknown): unknown;
}
/**
 * Constructor interface for VanReactiveElement
 */
export interface VanReactiveElementConstructor {
    new (): VanReactiveElement;
    readonly properties: Record<string, PropertyOptions>;
    readonly shadowRootOptions: ShadowRootInit;
    readonly styles: string | CSSStyleSheet | null;
    define(name?: string): any;
}
/**
 * Infers type from a property type constructor
 */
type InferFromType<T> = T extends StringConstructor ? string : T extends NumberConstructor ? number : T extends BooleanConstructor ? boolean : T extends ObjectConstructor ? object : T extends ArrayConstructor ? unknown[] : T extends new (...args: any[]) => infer R ? R : unknown;
/**
 * Infers attribute properties as StateView (read-only)
 * Handles PropertyOptions with default values, type hints, etc.
 */
export type InferredAttributeProperties<T> = {
    [K in keyof T]: T[K] extends {
        default: infer D;
    } ? StateView<D> : T[K] extends {
        type: infer Type;
    } ? StateView<InferFromType<Type>> : T[K] extends PropertyOptions<infer U> ? StateView<U> : StateView<T[K]>;
};
/**
 * Infers state properties as State (read-write)
 * State definitions are always simple values, not PropertyOptions
 */
export type InferredStateProperties<T> = {
    [K in keyof T]: State<T[K]>;
};
/**
 * Combined type for element instance with reactive properties.
 * This represents the element passed to the setup function, with all
 * attributes and properties typed appropriately.
 */
export type TypedElementInstance<A extends PropertyDefinitions, S extends StateDefinitions> = VanReactiveElement & InferredAttributeProperties<A> & InferredStateProperties<S>;
declare const vanRE: (options: VanREOptions) => VanRE;
export default vanRE;
