/** * @doeixd/dom * ========================================== * A production-grade, target-first, type-safe DOM library. * * ----------------------------------------------------------------------------- * 🧠 DESIGN PHILOSOPHY * ----------------------------------------------------------------------------- * 1. Target-First: `Action(Element)(Config)` pattern for intuitive chaining. * 2. Curried: Functions return closures for composition/piping. * 3. Null-Safe: All functions fail gracefully on `null`/`undefined` targets. * 4. Type-Safe: Full Generics for HTML Elements, Events, and Return types. * * ----------------------------------------------------------------------------- * 📚 API DIRECTORY (27 MODULES) * ----------------------------------------------------------------------------- * * 🟢 DOM CORE * 1. Querying ......... find, findAll, closest * 2. Events ........... on, onDelegated, dispatch * 3. Manipulation ..... modify, css, tempStyle * 4. Structure ........ append, prepend, after, before, remove, wrap, mount * 5. Creation ......... el, html, htmlMany, clone * * 🔵 STATE & ATTRIBUTES * 6. Classes .......... cls (add/remove/toggle), watchClass * 7. Attributes ....... Data (get/set/read/bind), watchAttr, watchText * 12. Objects ......... Obj (clone, isEqual, pick, omit) * 14. Refs ............ refs, groupRefs (data-ref handling) * 16. Cycling ......... cycleClass (State machines) * * 🟡 LIFECYCLE & OBSERVATION * 8. Lifecycle ........ onReady, onMount, waitFor * 17. Cleanup ......... stripListeners, instantiate, cloneMany * 20. Timing .......... debounce, throttle * 25. Groups .......... createListenerGroup (Batch cleanup) * 26. Signals ......... Signal (AbortController wrappers) * * 🟣 LAYOUT & NAVIGATION * 10. Navigation ...... Traverse (parent, children, siblings, next, prev, parents, nextAll, prevAll, closestAll) * 11. CSS Utils ....... CssVar, computed, injectStyles, waitTransition * 15. Color ........... toColorSpace (Color mix utils) * 18. Geometry ........ rect, offset, isVisible * 19. Scroll/Focus .... scrollInto, focus, blur * * 🟠 DATA & NETWORK * 9. URL/Form ......... Params, Form (serialize/populate) * 13. Collections ..... batch, groupBy * 21. Storage ......... Local, Session (Typed wrappers) * 22. Cookies ......... Cookie (get/set/remove) * 23. Network ......... Http (get/post/put/delete) * 24. PWA ............. SW (Service Worker reg/post) * 27. Pub/Sub ......... createBus (Typed Event Emitter) * * @module fdom * @author Patrick Glenn * @license MIT */ /** * Infers a DOM element type from a CSS selector string. * * Supports: * - Tag names: `'div'` → `HTMLDivElement` * - SVG tags: `'svg'` → `SVGSVGElement` * - ID selectors: `'#app'` → `HTMLElement` * - Class selectors: `'.card'` → `HTMLElement` * - Complex selectors: `'div.card'` → `HTMLElement` * * @template S - The selector string literal type * * @example * ```typescript * type ButtonEl = ParseSelector<'button'>; // HTMLButtonElement * type AnchorEl = ParseSelector<'a'>; // HTMLAnchorElement * type SvgEl = ParseSelector<'svg'>; // SVGSVGElement * ``` */ export type ParseSelector = S extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[S] : S extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[S] : S extends `#${string}` ? HTMLElement : S extends `.${string}` ? HTMLElement : HTMLElement; /** * Input that can be an element, selector string, function returning element, or null. * Used by selector-enabled utilities to accept flexible input types. */ export type ElementInput = ParseSelector | S | (() => ParseSelector | null) | null; /** * Function signature for selector-enabled utilities with dual-mode support. * Supports both immediate execution and curried application. */ export type SelectorFunction<_T extends HTMLElement, A extends any[], R> = { /** Immediate mode: all arguments provided at once */ (input: ElementInput, ...args: A): R; /** Curried mode: input provided first, returns function accepting remaining args */ (input: ElementInput): (...args: A) => R; }; /** * A cleanup/unsubscribe function returned by event listeners and subscriptions. * * Call this function to remove the listener and free resources. * * @example * ```typescript * const cleanup = on(button)('click', handler); * // Later... * cleanup(); // Removes the event listener * ``` */ export type Unsubscribe = () => void; /** * Event map for HTML elements, extensible for custom events. * * @template T - Additional custom event mappings * * @example * ```typescript * type MyEvents = EventMap<{ * 'custom:save': CustomEvent<{ id: number }>; * 'custom:delete': CustomEvent<{ id: number }>; * }>; * ``` */ export type EventMap = {}> = HTMLElementEventMap & T; /** * Extracts the detail type from a CustomEvent. * * @template T - The CustomEvent type * * @example * ```typescript * type SaveEvent = CustomEvent<{ id: number }>; * type Detail = ExtractEventDetail; // { id: number } * ``` */ export type ExtractEventDetail = T extends CustomEvent ? D : never; /** * Properties for creating/modifying elements. * * Supports declarative configuration of: * - Text content * - HTML content * - Inline styles * - Data attributes * - CSS classes * - HTML attributes * - Form element properties * * @example * ```typescript * const props: ElementProps = { * text: 'Click me', * class: { active: true, disabled: false }, * dataset: { userId: 123, role: 'admin' }, * style: { color: 'red', fontSize: '16px' }, * attr: { 'aria-label': 'Submit button' } * }; * ``` */ export interface ElementProps { /** Sets innerText (safer than html) */ text?: string; /** Sets innerHTML (use with caution - XSS risk) */ html?: string; /** Inline CSS styles */ style?: Partial; /** Data attributes (data-*) - auto-converts to kebab-case */ dataset?: Record; /** CSS classes with boolean toggles */ class?: Record; /** HTML attributes */ attr?: Record; /** Value for form inputs */ value?: string | number; /** Disabled state for form inputs */ disabled?: boolean; } /** * Strict element properties with element-specific validation. * * Provides better type safety by constraining properties based on element type. * * @template T - The HTML element type * * @example * ```typescript * const inputProps: StrictElementProps = { * value: 'test', * disabled: true, * attr: { type: 'text', placeholder: 'Enter name' } * }; * ``` */ export type StrictElementProps = ElementProps & { value?: T extends HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement ? string | number : never; disabled?: T extends HTMLInputElement | HTMLButtonElement | HTMLSelectElement | HTMLTextAreaElement ? boolean : never; }; /** * Makes all properties in T deeply readonly. * * @template T - The type to make readonly */ export type DeepReadonly = { readonly [P in keyof T]: T[P] extends object ? DeepReadonly : T[P]; }; /** * Makes all properties in T deeply partial. * * @template T - The type to make partial */ export type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; }; /** * SVG element tag names that require special namespace handling in h() proxy. */ export type SVGElementTags = 'svg' | 'g' | 'path' | 'circle' | 'rect' | 'line' | 'polygon' | 'polyline' | 'ellipse' | 'text' | 'tspan' | 'defs' | 'clipPath' | 'linearGradient' | 'radialGradient' | 'stop' | 'mask' | 'pattern' | 'marker' | 'symbol' | 'use' | 'image' | 'foreignObject'; /** * Extended ElementProps that includes dataRef support for h() proxy. * * @example * ```typescript * const props: HElementProps = { * class: { active: true }, * dataRef: 'myElement' // Will set data-ref="myElement" * }; * ``` */ export interface HElementProps extends ElementProps { /** Reference name for element extraction via refs() */ dataRef?: string; } /** * Options for configuring a List instance. * * @template T - The data item type * * @example * ```typescript * // Simple list (default blow-away mode) * const options: ListOptions = { * render: (item) => h.li({}, [item]) * }; * * // Keyed list (efficient diffing) * const options: ListOptions = { * key: user => user.id, * render: (user) => h.li({}, [user.name]), * update: (el, user) => { el.textContent = user.name; } * }; * ``` */ export interface ListOptions { /** Function to render each item to an element (required) */ render: (item: T, index: number) => HTMLElement; /** Optional key function - if provided, enables keyed reconciliation */ key?: (item: T) => string | number; /** Optional update function for efficient keyed updates */ update?: (element: HTMLElement, item: T, index: number) => void; /** Optional lifecycle hooks */ onRemove?: (element: HTMLElement, item: T) => void; onAdd?: (element: HTMLElement, item: T) => void; /** * Optional custom reconciliation function for full control. * When provided, this function is responsible for all DOM updates. * * @example * ```typescript * // Use morphdom for custom reconciliation * reconcile: (oldItems, newItems, container, renderFn) => { * const newHtml = newItems.map(renderFn).map(el => el.outerHTML).join(''); * morphdom(container, '
' + newHtml + '
'); * } * ``` */ reconcile?: (oldItems: T[], newItems: T[], container: HTMLElement, renderFn: (item: T, index: number) => HTMLElement) => void; } /** * Bound list instance with reactive update methods. * * @template T - The data item type */ export interface BoundList { /** Replace entire list with new items */ set(items: T[]): void; /** Append items to end of list */ append(items: T[]): void; /** Prepend items to start of list */ prepend(items: T[]): void; /** Insert items at specific index */ insert(index: number, items: T[]): void; /** Remove items matching predicate */ remove(predicate: (item: T) => boolean): void; /** Update items matching predicate */ update(predicate: (item: T) => boolean, updater: (item: T) => T): void; /** Clear all items */ clear(): void; /** Get current items array (readonly) */ items(): readonly T[]; /** Get current elements array (readonly) */ elements(): readonly HTMLElement[]; /** Destroy the list and cleanup */ destroy(): void; } /** * Options for configuring a viewRefs template instance. */ export interface ViewRefsOptions { /** Optional root element class names */ className?: string | string[]; /** Optional root element ID */ id?: string; /** Optional initial properties for root element */ props?: ElementProps; } /** * Context passed to viewRefs template factory. * * @template R - The refs shape */ export interface ViewRefsContext> { /** Extracted refs object (populated after template execution) */ refs: R; } /** * Instance returned by viewRefs factory. * * @template R - The refs shape */ export interface ViewRefsInstance> { /** The root element */ element: HTMLElement; /** Typed refs object */ refs: R; /** Update root element properties */ update(props: ElementProps): void; /** Update individual refs with smart value handling */ updateRefs(updates: Partial<{ [K in keyof R]: any; }>): void; /** Get a setter function for a specific ref */ bind(key: K): (value: any) => void; /** Destroy element and cleanup */ destroy(): void; } /** * Schema defining how refs map to setters. * * @template R - The refs shape */ export type BinderSchema> = { [K in keyof R]: Setter; }; /** * Infers the data shape from a binder schema. * * @template S - The binder schema type */ export type InferBinderData>> = { [K in keyof S]: S[K] extends Setter ? T : never; }; /** * Enhanced binder with batch updates and type-safe setters. * * @template R - The refs shape */ export interface EnhancedBinder> { /** Call with data object to update multiple refs */ (data: Partial>>): void; /** Individual setter functions */ set: BinderSchema; /** Batch multiple updates into single operation */ batch(fn: () => void): void; /** Get current refs object */ refs(): R; } /** * Primitive binding functions for common DOM operations. */ export interface BindPrimitives { /** Bind to textContent */ text(el: HTMLElement | null): Setter; /** Bind to innerHTML */ html(el: HTMLElement | null): Setter; /** Bind to attribute */ attr(name: string): (el: HTMLElement | null) => Setter; /** Bind to property */ prop(name: K): (el: HTMLElement | null) => Setter; /** Bind to CSS class toggle */ toggle(className: string): (el: HTMLElement | null) => Setter; /** Bind to multiple CSS classes */ classes(el: HTMLElement | null): Setter>; /** Bind to style properties */ style(el: HTMLElement | null): Setter>; /** Bind to form input value */ value(el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null): Setter; /** Bind to element visibility */ show(el: HTMLElement | null): Setter; } /** * Hybrid Function Builder. * Creates a function that supports both Curried and Imperative usage. * * @template T - The Target type (Element, string, etc) * @template A - The Arguments tuple type * @template R - The Return type * * @example * const add = def((el: HTMLElement, cls: string) => el.classList.add(cls)); * * // Usage 1: Imperative (Cleaner DX) * add(div, 'active'); * * // Usage 2: Curried (Pipeline friendly) * pipe( * find('.btn'), * el => add(el)('active') * ); */ export declare const def: (fn: (target: T | null, ...args: A) => R) => { (target: T | null, ...args: A): R; (target: T | null): (...args: A) => R; }; /** * Finds the first element matching the selector. * * Overloads allow calling in two ways: * 1. `find(root)(selector)` — search within a specific root (default: document) * 2. `find(selector)` — root is implicitly `document` * * @template S - CSS selector (literal string for best inference) * * @overload * @param selector - The selector to search for within `document` * @returns The matched element or `null`, inferred from selector * * @example * // String-first API * const btn = find("button"); // HTMLButtonElement | null * const app = find("#app"); // HTMLElement | null * * @overload * @param root - The root to search within (defaults to document) * @returns A function that accepts a selector and returns the matched element * * @example * // Curried API * const findIn = find(document.querySelector(".card")!); * const title = findIn("h1"); // HTMLHeadingElement | null */ export declare function find(selector: S): ParseSelector | null; export declare function find(root?: ParentNode): (selector: S) => ParseSelector | null; /** * Finds an element or throws if not found. * * @template S - CSS selector * @param selector - The selector to search for * @param root - The root to search within (default: document) * @returns The matched element * @throws Error if element not found */ export declare function require(selector: S, root?: ParentNode): ParseSelector; /** * Finds all elements matching the selector. * * Supports two call styles: * 1. `findAll(selector)` — searches `document` * 2. `findAll(root)(selector)` — searches a specific root * * @template S - CSS selector (literal string for best inference) * * @overload * @param selector - Selector to search for within `document` * @returns Array of matched elements (empty if none) * * @example * const items = findAll("li"); // HTMLLIElement[] * * @overload * @param root - The root to search within (defaults to document) * @returns Function that accepts a selector and returns an array of elements * * @example * const findInside = findAll(container); * const inputs = findInside("input"); // HTMLInputElement[] */ export declare function findAll(selector: S): ParseSelector[]; export declare function findAll(root?: ParentNode): (selector: S) => ParseSelector[]; /** * Finds the closest ancestor (including self) matching the selector. * * Supports: * 1. `closest(selector)` — uses `document.documentElement` as the starting point * 2. `closest(element)(selector)` — starts from a specific element * * Note: Using `closest(selector)` alone is rarely useful unless you * intentionally want to search from the root element. * * @template S - CSS selector (literal type for best inference) * * @overload * @param selector - Selector to match when starting at `document.documentElement` * @returns The matched ancestor or `null` * * @example * const htmlOrNull = closest("html"); * * @overload * @param element - Starting element (null-safe) * @returns Function accepting a selector that returns the matched ancestor * * @example * const card = closest(button)(".card"); // HTMLElement | null */ export declare function closest(selector: S): ParseSelector | null; export declare function closest(element: Element | null): (selector: S) => ParseSelector | null; /** * Checks whether an element matching the selector exists. * * Overloads: * 1. `exists(selector)` — searches `document` * 2. `exists(root)(selector)` — searches within a specific root * * @template S - CSS selector (literal for best inference) * * @overload * @param selector - Selector to test within `document` * @returns `true` if a matching element exists, otherwise `false` * * @example * exists("button"); // boolean * exists("#app"); // boolean */ export declare function exists(selector: S): boolean; export declare function exists(root?: ParentNode): (selector: S) => boolean; /** * Returns all siblings of an element (excluding the element itself). * * Overloads: * 1. `siblings(node)` — returns its siblings * 2. `siblings(root)(node)` — sibling list relative to a specific parent * * Null-safe: returns an empty array if `node` or parent is null. * * @example * const btn = document.querySelector("button"); * const sibs = siblings(btn); // Element[] * * @example * const list = document.querySelector("ul"); * const sibsOf = siblings(list); * sibsOf(list.querySelector("li")); */ export declare function siblings(node: Element | null): Element[]; export declare function siblings(root: ParentNode | null): (node: Element | null) => Element[]; /** * Checks whether a given element contains a descendant matching the selector. * * Overloads: * 1. `has(selector)` — checks within `document` * 2. `has(element)(selector)` — checks within a given element * * Null-safe: Passing `null` returns a function that always returns false. * * @template S - CSS selector string * * @overload * @param selector - Selector checked inside `document` * @returns `true` if a match exists, otherwise `false` * * @example * has(".card"); // boolean * * @overload * @param element - Element to test within (null-safe) * @returns Function testing a selector inside that element * * @example * const card = document.querySelector(".card"); * const result = has(card)("button"); */ export declare function has(selector: S): boolean; export declare function has(element: ParentNode | null): (selector: S) => boolean; /** * Returns the index of a node among its siblings. * * Overloads: * 1. `index(node)` — returns the node's index or -1 * 2. `index(root)(node)` — curries the "list parent" (rare but consistent) * * Note: When called as `index(node)`, the parent is automatically the node's * actual parent element. * * @example * const item = document.querySelector("li"); * index(item); // 0, 1, 2, ... * * @example * // Curried * const list = document.querySelector("ul"); * index(list)(someLi); */ export declare function index(node: Element | null): number; export declare function index(root: ParentNode | null): (node: Element | null) => number; /** * Handler type for events */ type EventHandler = (event: HTMLElementEventMap[K], target: T) => void; /** * Event setup stage: attach listener with event type and handler */ type EventSetup = { (eventType: K, handler: EventHandler, options?: boolean | AddEventListenerOptions): Unsubscribe; }; /** * Attaches an event listener to the target element. * * Returns a cleanup function to remove the listener. Supports all standard * DOM events with full type inference. The handler receives both the event * and the target element for convenience. * * Supports multiple calling styles: * ```typescript * // Curried * on(button)('click', handler); * * // Imperative * on(button, 'click', handler); * ``` * * @example * ```typescript * const button = find('button'); * * // Curried - great for reuse * const onButton = on(button); * onButton('click', (e, target) => console.log('Clicked!', target)); * onButton('mouseenter', (e, target) => cls.add(target)('hovered')); * * // Imperative - concise one-offs * on(button, 'click', (e, target) => { * e.preventDefault(); * submit(); * }); * * // With options * on(window, 'scroll', handler, { passive: true }); * on(button)('click', handler, { once: true }); * * // Null-safe: returns no-op cleanup if target is null * const missing = find('.missing'); * on(missing, 'click', handler); // Safe, returns () => {} * * // Type inference works throughout: * on(input, 'input', (e) => { * console.log(e.data); // e is InputEvent * }); * * on(document, 'keydown', (e) => { * if (e.key === 'Escape') close(); // e is KeyboardEvent * }); * ``` */ export declare function on(target: T | null): EventSetup; export declare function on(target: T | null, eventType: K, handler: EventHandler, options?: boolean | AddEventListenerOptions): Unsubscribe; /** * Handler type for delegated events */ type DelegatedHandler = (event: HTMLElementEventMap[K], match: ParseSelector) => void; /** * Final stage: attach event listener */ type DelegatedEventSetup = { (eventType: K, handler: DelegatedHandler, options?: boolean | AddEventListenerOptions): Unsubscribe; }; /** * Middle stage: select target elements * Supports both curried and imperative styles */ type DelegatedSelectorSetup = { (selector: S): DelegatedEventSetup; (selector: S, eventType: K, handler: DelegatedHandler, options?: boolean | AddEventListenerOptions): Unsubscribe; }; /** * Attaches a **Delegated Event Listener** using event bubbling. * * Supports multiple calling styles: * ```typescript * // Fully curried * onDelegated(root)('li')('click', handler); * * // Partially curried * onDelegated(root, 'li')('click', handler); * onDelegated(root)('li', 'click', handler); * * // Fully imperative * onDelegated(root, 'li', 'click', handler); * ``` * * @example * ```typescript * const list = find('#user-list'); * * // Curried - great for reuse * const onListItem = onDelegated(list)('li'); * onListItem('click', (e, li) => console.log(li.textContent)); * onListItem('mouseenter', (e, li) => cls.add(li)('hovered')); * * // Imperative - concise one-offs * onDelegated(list, 'button.delete', 'click', (e, btn) => { * e.stopPropagation(); * deleteItem(btn.dataset.id); * }); * ``` */ export declare function onDelegated(root: ParentNode | null): DelegatedSelectorSetup; export declare function onDelegated(root: ParentNode | null, selector: S): DelegatedEventSetup; export declare function onDelegated(root: ParentNode | null, selector: S, eventType: K, handler: DelegatedHandler, options?: boolean | AddEventListenerOptions): Unsubscribe; /** * Dispatches a CustomEvent from the target element. * * Creates and dispatches a CustomEvent with optional detail data. The detail * type is inferred from the provided data. By default, events bubble up the * DOM tree. * * @template T - The type of the detail data * @param target - The element to dispatch the event from (null-safe) * @returns A curried function that accepts event name, detail, and options * * @example * ```typescript * // Simple custom event * const button = document.querySelector('button'); * dispatch(button)('clicked', { timestamp: Date.now() }); * * // Typed custom events * interface SaveEvent { * id: number; * data: { name: string; email: string }; * } * dispatch(form)('save', { id: 123, data: formData } as SaveEvent); * * // Listen for custom events * on(button)('clicked' as any, (e: CustomEvent) => { * console.log('Detail:', e.detail); // { timestamp: ... } * }); * * // Non-bubbling event * dispatch(element)('custom', data, { bubbles: false }); * * // Cancelable event * dispatch(element)('beforeSave', data, { cancelable: true }); * * // Component communication pattern * const modal = document.querySelector('.modal'); * dispatch(modal)('modal:close', { reason: 'user-action' }); * * // Null-safe: does nothing if target is null * const missing = document.querySelector('.missing'); * dispatch(missing)('event', data); // Safe, no error * ``` */ export declare const dispatch: (target: EventTarget | null) => (eventName: string, detail?: T, options?: EventInit) => EventTarget | null; /** * Declaratively modifies an element's properties with full type safety. * * Provides a unified API for setting text, styles, classes, attributes, and more. * Supports three calling styles for maximum flexibility. * * @template T - The HTML element type, which is preserved. * * @overload * **1. Config-First (Curried):** `modify(props)(element)` * Best for creating reusable modifiers in functional pipelines. * @param props - The properties to apply. * @returns A function that accepts an element and returns it. * @example * ```typescript * import { Fn, find } from '@doeixd/dom'; * * const makePrimary = modify({ * class: { 'btn-primary': true }, * attr: { 'aria-disabled': false } * }); * * Fn.pipe( * find('#submit-btn'), * makePrimary * ); * ``` * * @overload * **2. Element-First (Curried):** `modify(element)(props)` * Best for applying multiple, separate modifications to the same element. * @param element - The element to modify (null-safe). * @returns A function that accepts properties and returns the element. * @example * ```typescript * const btn = find('button'); * const modifyBtn = modify(btn); * * modifyBtn({ text: 'Step 1' }); * // ... later * modifyBtn({ class: { success: true }, text: 'Complete' }); * ``` * * @overload * **3. Imperative:** `modify(element, props)` * Best for simple, one-off modifications. Cleanest syntax. * @param element - The element to modify (null-safe). * @param props - The properties to apply. * @returns The modified element. * @example * ```typescript * const btn = find('button'); * modify(btn, { text: 'Click Me' }); * ``` */ export declare function modify(props: ElementProps): (element: T | null) => T | null; export declare function modify(element: T | null, props: ElementProps): T | null; export declare function modify(element: T | null): (props: ElementProps) => T | null; /** * Sets properties on an element. * @alias modify */ export declare const set: typeof modify; /** * Applies inline CSS styles to an element. Supports multiple calling styles. * * @overload **1. Config-First:** `css(styles)(element)` * @param styles - The CSS styles to apply. * @returns A function that accepts an element. * * @overload **2. Element-First:** `css(element)(styles)` * @param element - The element to style. * @returns A function that accepts styles. * * @overload **3. Imperative:** `css(element, styles)` * @param element - The element to style. * @param styles - The CSS styles to apply. */ export declare function css(styles: Partial): (element: T | null) => T | null; export declare function css(element: T | null, styles: Partial): T | null; export declare function css(element: T | null): (styles: Partial) => T | null; /** * Applies styles temporarily and returns a revert function. * * Saves the original style values and applies new ones. The returned function * restores the original values. Useful for temporary visual states like hover * effects or loading states. * * @param element - The element to style (null-safe) * @returns A curried function that accepts styles and returns a cleanup function * * @example * ```typescript * const div = document.querySelector('div'); * * // Temporarily change opacity * const revert = tempStyle(div)({ opacity: '0.5' }); * // Later... * revert(); // Restores original opacity * * // Loading state pattern * const showLoading = () => { * const revert = tempStyle(button)({ * opacity: '0.6', * pointerEvents: 'none', * cursor: 'wait' * }); * * fetchData().finally(() => { * revert(); // Restore original styles * }); * }; * * // Animation workflow * const element = document.querySelector('.box'); * const cleanup = tempStyle(element)({ * transform: 'scale(1.2)', * transition: 'transform 0.3s' * }); * setTimeout(cleanup, 300); // Revert after animation * * // Null-safe: returns no-op if element is null * const noop = tempStyle(null)({ color: 'red' }); // () => {} * ``` */ export declare const tempStyle: (element: HTMLElement | null) => (styles: Partial) => Unsubscribe; /** * Appends content to the end of the target element. * * Accepts multiple arguments of mixed types (strings, Nodes, null, undefined). * Strings are automatically converted to text nodes. Null/undefined values are * filtered out. Returns the parent for chaining. * * @param parent - The parent element to append to (null-safe) * @returns A curried function that accepts content and returns the parent * * @example * ```typescript * const list = document.querySelector('ul'); * * // Imperative (cleaner DX) * append(list, item1, item2, item3); * * // Curried (pipeline friendly) * append(list)(item1, item2, item3); * * // Append a single element * const item = document.createElement('li'); * append(list)(item); * * // Mix elements and text * append(container)(heading, 'Some text', paragraph); * * // Append text nodes * append(div)('Hello', ' ', 'World'); * * // Null values are safely ignored * append(list)(item1, null, item2, undefined); // Only appends item1 and item2 * * // Chaining * const parent = append(container)(child1); * append(parent)(child2); * ``` */ export declare const append: { (target: HTMLElement | null, ...args: (string | Node | null | undefined)[]): HTMLElement | null; (target: HTMLElement | null): (...args: (string | Node | null | undefined)[]) => HTMLElement | null; }; /** * Prepends content to the start of the target element. * * Inserts content at the beginning, before any existing children. Accepts * multiple arguments of mixed types. Returns the parent for chaining. * * @param parent - The parent element to prepend to (null-safe) * @returns A curried function that accepts content and returns the parent * * @example * ```typescript * const list = document.querySelector('ul'); * * // Imperative (cleaner DX) * prepend(list, firstItem); * * // Curried (pipeline friendly) * prepend(list)(firstItem); * * // Add header before content * const container = document.querySelector('.container'); * const header = document.createElement('h1'); * prepend(container)(header); * ``` */ export declare const prepend: { (target: HTMLElement | null, ...args: (string | Node | null | undefined)[]): HTMLElement | null; (target: HTMLElement | null): (...args: (string | Node | null | undefined)[]) => HTMLElement | null; }; /** * Inserts content AFTER the target element as siblings. * * The content is inserted after the target in the DOM tree, at the same level. * Useful for inserting elements without modifying the target's children. * * @param target - The reference element (null-safe) * @returns A curried function that accepts content and returns the target * * @example * ```typescript * const header = document.querySelector('h1'); * const banner = document.createElement('div'); * * // Imperative (cleaner DX) * after(header, banner, notice, alert); * * // Curried (pipeline friendly) * after(header)(banner); * * // Insert multiple elements * after(header)(banner, notice, alert); * ``` */ export declare const after: { (target: Element | null, ...args: (string | Node | null | undefined)[]): Element | null; (target: Element | null): (...args: (string | Node | null | undefined)[]) => Element | null; }; /** * Inserts content BEFORE the target element as siblings. * * The content is inserted before the target in the DOM tree, at the same level. * * @param target - The reference element (null-safe) * @returns A curried function that accepts content and returns the target * * @example * ```typescript * const footer = document.querySelector('footer'); * const disclaimer = document.createElement('p'); * * // Imperative (cleaner DX) * before(footer, disclaimer); * * // Curried (pipeline friendly) * before(footer)(disclaimer); * ``` */ export declare const before: { (target: Element | null, ...args: (string | Node | null | undefined)[]): Element | null; (target: Element | null): (...args: (string | Node | null | undefined)[]) => Element | null; }; /** * Removes the target element from the DOM. * * Detaches the element from its parent. Event listeners attached via * addEventListener will be garbage collected. Always returns `null` for * type safety (prevents accidental reuse of removed elements). * * @param target - The element to remove (null-safe) * @returns Always returns `null` * * @example * ```typescript * const modal = document.querySelector('.modal'); * remove(modal); // Modal is removed from DOM * * // Conditional removal * if (shouldRemove) { * remove(element); * } * ``` */ export declare const remove: (target: Element | null) => null; /** * Removes all children from the target element. * * More efficient than `innerHTML = ''` and safer (doesn't parse HTML). * Returns the target for chaining. * * @param target - The element to empty (null-safe) * @returns The target element * * @example * ```typescript * const container = document.querySelector('.container'); * * // Clear all content * empty(container); * * // Then add new content * append(empty(container))(newContent); * ``` */ export declare const empty: (target: Element | null) => Element | null; /** * Wraps the target element with a wrapper element. * * Inserts the wrapper before the target in the DOM, then moves the target * inside the wrapper. Useful for adding container elements around existing * content. * * @param target - The element to wrap (null-safe) * @returns A curried function that accepts a wrapper and returns it * * @example * ```typescript * const img = document.querySelector('img'); * const figure = document.createElement('figure'); * * // Imperative (cleaner DX) * wrap(img, figure); * * // Curried (pipeline friendly) * wrap(img)(figure); * // DOM:
* * // Using el() helper * wrap(img)(el('figure')({})([])); * * // Add caption to wrapper * const wrapper = wrap(img)(figure); * append(wrapper)(el('figcaption')({})(['Image caption'])); * ``` */ export declare const wrap: { (target: HTMLElement | null, wrapper: HTMLElement): HTMLElement; (target: HTMLElement | null): (wrapper: HTMLElement) => HTMLElement; }; /** * Mounts a child element into a parent container. * * Appends the child to the parent and returns a cleanup function to remove it. * Useful for dynamic DOM updates, modals, popovers, and temporary UI elements. * * Supports two call styles: * 1. `mount(parent, child)` — Imperative (cleaner DX) * 2. `mount(parent)(child)` — Curried (pipeline friendly) * * @overload * @param parent - Parent element or selector (null-safe) * @param child - Child element to mount (or null for curried) * @returns Cleanup function to unmount the child, or no-op if parent not found * * @example * ```typescript * // Imperative style * const modal = document.createElement('div'); * modal.textContent = 'Hello World'; * const cleanup = mount(document.body, modal); * * // Later: remove the element * cleanup(); * * // Using selector-first API * const popup = el('div')({ class: { popup: true } })(['Content']); * const remove = mount(".container")(popup); * * // Mounting multiple elements * const list = document.querySelector('ul'); * const items = [el('li')({})(['Item 1']), el('li')({})(['Item 2'])]; * const cleanups = items.map(item => mount(list)(item)); * * // With temporary modal * const showModal = (content: string) => { * const modal = el('div')({ * class: { modal: true }, * attr: { role: 'dialog' } * })([content]); * * const cleanup = mount(document.body)(modal); * * // Auto-cleanup on button click * modal.addEventListener('click', () => cleanup()); * return cleanup; * }; * ``` */ export declare const mount: { (target: string | Element | null, child: Element | null): Unsubscribe; (target: string | Element | null): (child: Element | null) => Unsubscribe; }; export interface CreateWebComponentOptions { /** Optional custom element name (overrides class name). */ name?: string; /** Auto-define the component (default: true). */ define?: boolean; /** Options passed to `customElements.define`. */ defineOptions?: ElementDefinitionOptions; } /** * Registers a custom element with smart defaults and flexible call styles. * * Defaults to a kebab-case name derived from the class name. If the derived * name lacks a hyphen, `-el` is appended to make it valid. * * Supports both call styles: * - `createWebComponent(MyElement, options?)` * - `createWebComponent(options?)(MyElement)` * * @template T - Custom element constructor * @param ctor - Custom element class * @param options - Optional registration configuration * @returns Metadata about the registration * * @example * ```typescript * class MyButton extends HTMLElement {} * const { name } = createWebComponent(MyButton); * // name === 'my-button' * ``` * * @example * ```typescript * class FancyInput extends HTMLInputElement {} * createWebComponent(FancyInput, { * name: 'fancy-input', * defineOptions: { extends: 'input' } * }); * ``` * * @example * ```typescript * class ModalDialog extends HTMLElement {} * const register = createWebComponent({ define: false, name: 'modal-dialog' }); * const info = register(ModalDialog); * // info.defined === false * ``` */ export declare function createWebComponent(ctor: T, options?: CreateWebComponentOptions): { name: string; ctor: T; defined: boolean; }; export declare function createWebComponent(options?: CreateWebComponentOptions): (ctor: T) => { name: string; ctor: T; defined: boolean; }; /** * Creates a DOM element with full type inference. * * Supports two syntaxes: * 1. **Hyperscript-style**: `el(tag, props, children)` — cleaner, more readable * 2. **Curried**: `el(tag)(props)(children)` — composable, pipeline-friendly * * The return type is automatically inferred from the tag name. * * @template K - The HTML tag name (keyof HTMLElementTagNameMap) * @param tag - The HTML tag name (e.g., 'div', 'button', 'a') * @param props - Optional properties (text, classes, attributes, etc.) * @param children - Optional children (elements or text) * @returns The created element (Hyperscript) or curried function (Curried) * * @example * ```typescript * // Hyperscript-style (new, cleaner) * const btn = el('button', { class: { primary: true } }, ['Click me']); * // btn is typed as HTMLButtonElement * * // Nested elements (much more readable) * const card = el('div', { class: { card: true } }, [ * el('h2', {}, ['Title']), * el('p', {}, ['Description']) * ]); * * // Curried syntax (still supported for backward compatibility) * const link = el('a')({ * attr: { href: '/home' }, * class: { active: true }, * text: 'Home' * })([]); * // link is typed as HTMLAnchorElement * * // Form input with type inference * const input = el('input', { * attr: { type: 'text', placeholder: 'Enter name' }, * value: 'John' * }, []); * // input is typed as HTMLInputElement * * // Partial application for reuse (curried) * const createButton = el('button'); * const primaryBtn = createButton({ class: { primary: true } })(['Save']); * const secondaryBtn = createButton({ class: { secondary: true } })(['Cancel']); * ``` */ export declare function el(tag: K, props: ElementProps, children: (string | Node)[]): HTMLElementTagNameMap[K]; export declare function el(tag: K): (props?: ElementProps) => (children?: (string | Node)[]) => HTMLElementTagNameMap[K]; /** * Creates an element from an HTML template string. * * Uses tagged template literals for convenient HTML creation. Interpolated * values are automatically escaped. Returns the first element in the template. * * ⚠️ **XSS Warning**: Only use with trusted content. Do not interpolate * user input directly without sanitization. * * @param strings - Template string parts * @param values - Interpolated values * @returns The created HTMLElement * @throws Error if template doesn't produce an element * * @example * ```typescript * // Basic usage * const div = html`
Hello
`; * * // With interpolation * const name = 'World'; * const greeting = html`

Hello ${name}!

`; * * // Complex structure * const card = html` *
*

${title}

*

${description}

*
* `; * * // ⚠️ UNSAFE - Don't do this with user input! * // const unsafe = html`
${userInput}
`; * * // ✅ SAFE - Sanitize user input first * const safe = html`
${sanitize(userInput)}
`; * ``` */ export declare const html: (strings: TemplateStringsArray, ...values: any[]) => HTMLElement; /** * Creates a DocumentFragment from an HTML template string. * * Like `html()` but returns a DocumentFragment containing all elements * from the template. Useful for creating multiple sibling elements at once. * * ⚠️ **XSS Warning**: Only use with trusted content. * * @param strings - Template string parts * @param values - Interpolated values * @returns A DocumentFragment containing the created elements * * @example * ```typescript * // Create multiple list items * const items = htmlMany` *
  • Item 1
  • *
  • Item 2
  • *
  • Item 3
  • * `; * * const list = document.querySelector('ul'); * list.appendChild(items); * * // With interpolation * const rows = htmlMany` * ${col1}${col2} * ${col3}${col4} * `; * ``` */ export declare const htmlMany: (strings: TemplateStringsArray, ...values: any[]) => DocumentFragment; /** * Clones a node, preserving its exact type. * * Creates a copy of the node and optionally its descendants. The cloned node * has no parent and is not part of the document. Event listeners are NOT * copied. * * @template T - The node type (preserved in return type) * @param node - The node to clone (null-safe) * @returns A curried function that accepts deep flag and returns the clone * * @example * ```typescript * const button = document.querySelector('button'); * * // Deep clone (includes children) * const btnCopy = clone(button)(true); * // btnCopy is typed as HTMLButtonElement * * // Shallow clone (no children) * const btnShallow = clone(button)(false); * * // Template pattern * const template = el('div')({ class: { card: true } })([ * el('h2')({})(['Title']), * el('p')({})(['Description']) * ]); * * // Create multiple cards from template * const card1 = clone(template)(true); * const card2 = clone(template)(true); * const card3 = clone(template)(true); * * // Null-safe * const missing = document.querySelector('.missing'); * const result = clone(missing)(true); // null * ``` */ export declare const clone: (node: T | null) => (deep?: boolean) => T | null; /** * VanJS-style hyperscript proxy for element creation. * * Provides a Proxy-based API where property access creates element factories. * Supports both HTML and SVG elements with automatic namespace detection. * * **Performance Note**: The Proxy has minimal overhead (~5% vs direct el() calls). * For performance-critical loops with 1000s of elements, prefer el() directly. * * **Type Safety**: Returns `HTMLElement` rather than specific element types due to * Proxy limitations. Use type assertions if you need specific element types. * * @example * ```typescript * import { h } from '@doeixd/dom'; * * // Basic HTML elements * const card = h.div({ class: { card: true } }, [ * h.h2({}, ['Title']), * h.p({ text: 'Content' }), * h.button({ dataRef: 'submit' }, ['Submit']) * ]); * * // SVG elements (automatically use SVG namespace) * const icon = h.svg({ attr: { viewBox: '0 0 24 24', width: '24', height: '24' } }, [ * h.path({ attr: { d: 'M12 2L2 7v10c0 5.5 3.8 10.7 10 12 6.2-1.3 10-6.5 10-12V7l-10-5z' } }) * ]); * * // Nested structures * const list = h.ul({ class: { 'todo-list': true } }, [ * h.li({}, ['Item 1']), * h.li({}, ['Item 2']), * h.li({}, ['Item 3']) * ]); * * // With refs for later access * const form = h.form({}, [ * h.input({ dataRef: 'name', attr: { type: 'text', placeholder: 'Name' } }), * h.input({ dataRef: 'email', attr: { type: 'email', placeholder: 'Email' } }), * h.button({ dataRef: 'submit', attr: { type: 'submit' } }, ['Submit']) * ]); * * // Extract refs * const formRefs = refs(form); * console.log(formRefs.name, formRefs.email, formRefs.submit); * ``` */ export declare const h: Record HTMLElement>; /** * Alias for `h` proxy. Provides alternative naming for hyperscript-style element creation. * * Some developers prefer `tags` as it's more explicit about creating HTML tags. * Functionally identical to `h`. * * @example * ```typescript * import { tags } from '@doeixd/dom'; * * const page = tags.div({ class: { container: true } }, [ * tags.header({}, [tags.h1({}, ['My App'])]), * tags.main({}, [tags.p({}, ['Content'])]), * tags.footer({}, [tags.small({}, ['© 2024'])]) * ]); * ``` */ export declare const tags: Record HTMLElement>; /** * Utilities for manipulating CSS classes on elements. * * All methods are null-safe and return the element for chaining (except `has`). * Provides a functional API for common classList operations. * * @example * ```typescript * const button = document.querySelector('button'); * * // Add multiple classes * cls.add(button)('btn', 'btn-primary', 'active'); * * // Remove classes * cls.remove(button)('disabled', 'loading'); * * // Toggle with optional force * cls.toggle(button)('active'); // Toggles * cls.toggle(button)('active', true); // Forces add * cls.toggle(button)('active', false); // Forces remove * * // Replace a class * cls.replace(button)('btn-primary', 'btn-secondary'); * * // Check for class * if (cls.has(button)('active')) { * console.log('Button is active'); * } * * // Chaining * cls.add(button)('btn'); * cls.toggle(button)('active'); * ``` */ export declare const cls: { /** * Adds one or more CSS classes to the element. * * @param el - The element to add classes to (null-safe) * @returns A curried function that accepts class names and returns the element * * @example * ```typescript * // Imperative (cleaner DX) * cls.add(btn, 'active', 'shadow'); * * // Curried (pipeline friendly) * cls.add(btn)('active', 'shadow'); * * // Add single class * cls.add(div)('active'); * * // Add multiple classes * cls.add(div)('card', 'shadow', 'rounded'); * * // Null-safe * cls.add(null)('active'); // Returns null * ``` */ add: { (target: Element | null, ...args: string[]): Element | null; (target: Element | null): (...args: string[]) => Element | null; }; /** * Removes one or more CSS classes from the element. * * @param el - The element to remove classes from (null-safe) * @returns A curried function that accepts class names and returns the element * * @example * ```typescript * // Imperative (cleaner DX) * cls.remove(btn, 'active', 'shadow'); * * // Curried (pipeline friendly) * cls.remove(btn)('active', 'shadow'); * * // Remove single class * cls.remove(div)('active'); * * // Remove multiple classes * cls.remove(div)('loading', 'disabled', 'error'); * * // Safe if class doesn't exist * cls.remove(div)('nonexistent'); // No error * ``` */ remove: { (target: Element | null, ...args: string[]): Element | null; (target: Element | null): (...args: string[]) => Element | null; }; /** * Toggles a CSS class on the element. * * @param el - The element to toggle the class on (null-safe) * @returns A curried function that accepts class name and optional force flag * * @example * ```typescript * // Imperative (cleaner DX) * cls.toggle(btn, 'active'); * cls.toggle(btn, 'active', true); // Force add * * // Curried (pipeline friendly) * cls.toggle(btn)('active'); // Adds if absent, removes if present * cls.toggle(btn)('active', true); // Always adds * cls.toggle(btn)('active', false); // Always removes * * // Conditional toggle * cls.toggle(button)('disabled', isLoading); * ``` */ toggle: { (target: Element | null, className: string, force?: boolean | undefined): Element | null; (target: Element | null): (className: string, force?: boolean | undefined) => Element | null; }; /** * Replaces an old class with a new class. * * @param el - The element to modify (null-safe) * @returns A curried function that accepts old and new class names * * @example * ```typescript * // Imperative (cleaner DX) * cls.replace(btn, 'btn-primary', 'btn-secondary'); * * // Curried (pipeline friendly) * cls.replace(btn)('btn-primary', 'btn-secondary'); * * // Replace theme class * cls.replace(div)('theme-light', 'theme-dark'); * * // No effect if old class doesn't exist * cls.replace(div)('nonexistent', 'new'); // No change * ``` */ replace: { (target: Element | null, oldClass: string, newClass: string): Element | null; (target: Element | null): (oldClass: string, newClass: string) => Element | null; }; /** * Checks if the element has a specific class. * * @param el - The element to check (null-safe) * @returns A curried function that accepts a class name and returns boolean * * @example * ```typescript * const button = document.querySelector('button'); * * // Check for class * if (cls.has(button)('active')) { * console.log('Button is active'); * } * * // Conditional logic * const isDisabled = cls.has(button)('disabled'); * * // Null-safe: returns false if element is null * cls.has(null)('active'); // false * ``` */ has: (el: Element | null) => (className: string) => boolean; }; /** * Observes changes to a specific class on an element. * * Uses MutationObserver to watch for class attribute changes. The callback * fires only when the specified class is added or removed (not on other class * changes). Returns a cleanup function to stop observing. * * **Performance**: Uses attribute filtering for efficiency. Consider debouncing * the callback if rapid changes are expected. * * @param target - The element to observe (null-safe) * @returns A curried function that accepts class name and callback, returns cleanup function * * @example * ```typescript * const modal = document.querySelector('.modal'); * * // Imperative (cleaner DX) * const cleanup = watchClass(modal, 'open', (isPresent, el) => { * if (isPresent) { * console.log('Modal opened'); * document.body.style.overflow = 'hidden'; * } else { * console.log('Modal closed'); * document.body.style.overflow = ''; * } * }); * * // Curried (pipeline friendly) * const cleanup = watchClass(modal)('open', (isPresent, el) => { * if (isPresent) { * console.log('Modal opened'); * document.body.style.overflow = 'hidden'; * } else { * console.log('Modal closed'); * document.body.style.overflow = ''; * } * }); * * // Later: stop watching * cleanup(); * * // Watch loading state * watchClass(button)('loading', (isLoading) => { * button.disabled = isLoading; * }); * * // Sync state between elements * watchClass(sidebar)('collapsed', (isCollapsed) => { * cls.toggle(mainContent)('expanded', isCollapsed); * }); * * // Null-safe: returns no-op cleanup * const noop = watchClass(null)('active', callback); // () => {} * ``` */ export declare const watchClass: { (target: Element | null, className: string, callback: (isPresent: boolean, el: Element) => void): Unsubscribe; (target: Element | null): (className: string, callback: (isPresent: boolean, el: Element) => void) => Unsubscribe; }; /** * Utilities for working with data attributes (data-*). * * Provides a functional API for getting, setting, and observing data attributes. * Automatically handles type conversion (numbers, booleans, JSON) and camelCase * to kebab-case conversion. * * @example * ```typescript * const div = document.querySelector('div'); * * // Set data attributes * Data.set(div)('userId', 123); // data-user-id="123" * Data.set(div)('isActive', true); // data-is-active="true" * Data.set(div)('config', { a: 1 }); // data-config='{"a":1}' * * // Get raw string value * const userId = Data.get(div)('userId'); // "123" * * // Read with type inference * const id = Data.read(div)('userId'); // 123 (number) * const active = Data.read(div)('isActive'); // true (boolean) * const config = Data.read(div)('config'); // { a: 1 } (object) * * // React to changes * Data.bind(div)('count', (value) => { * console.log('Count changed:', value); * }); * ``` */ export declare const Data: { /** * Gets the raw string value of a data attribute. * * Returns the value as-is from the dataset. For type conversion, use `read()`. * * @template T - The element type (inferred) * @param el - The element to get data from (null-safe) * @returns A curried function that accepts a key and returns the value or undefined * * @example * ```typescript * const div = document.querySelector('div'); * div.dataset.userId = '123'; * * // Get raw value * const userId = Data.get(div)('userId'); // "123" (string) * * // CamelCase key * const userName = Data.get(div)('userName'); // Accesses data-user-name * * // Missing attribute * const missing = Data.get(div)('missing'); // undefined * * // Null-safe * Data.get(null)('userId'); // undefined * ``` */ get: (el: HTMLElement | null) => (key: string) => string | undefined; /** * Sets a data attribute value. * * Automatically converts objects to JSON strings and handles null/undefined * by removing the attribute. CamelCase keys are converted to kebab-case. * * @template T - The element type (inferred) * @param el - The element to set data on (null-safe) * @returns A curried function that accepts key and value, returns the element * * @example * ```typescript * const div = document.querySelector('div'); * * // Imperative (cleaner DX) * Data.set(div, 'userId', '123'); * * // Curried (pipeline friendly) * Data.set(div)('userId', '123'); * * // Set number (converted to string) * Data.set(div)('count', 42); // data-count="42" * * // Set boolean * Data.set(div)('isActive', true); // data-is-active="true" * * // Set object (JSON stringified) * Data.set(div)('config', { theme: 'dark', size: 'lg' }); * // data-config='{"theme":"dark","size":"lg"}' * * // Remove attribute (null or undefined) * Data.set(div)('userId', null); // Removes data-user-id * * // CamelCase to kebab-case * Data.set(div)('userName', 'John'); // Sets data-user-name="John" * * // Chaining * Data.set(div)('id', 1); * Data.set(div)('name', 'Item'); * ``` */ set: { (target: HTMLElement | null, key: string, val: any): HTMLElement | null; (target: HTMLElement | null): (key: string, val: any) => HTMLElement | null; }; /** * Reads a data attribute with automatic type inference. * * Intelligently parses the value: * - `"true"` → `true` (boolean) * - `"false"` → `false` (boolean) * - `"null"` → `null` * - `"123"` → `123` (number) * - `'{"a":1}'` → `{a:1}` (parsed JSON) * - Other → string * * @template T - The expected return type * @param el - The element to read from (null-safe) * @returns A curried function that accepts a key and returns the parsed value * * @example * ```typescript * const div = document.querySelector('div'); * * // Boolean parsing * div.dataset.isActive = 'true'; * Data.read(div)('isActive'); // true (boolean) * * // Number parsing * div.dataset.count = '42'; * Data.read(div)('count'); // 42 (number) * * // JSON parsing * div.dataset.config = '{"theme":"dark"}'; * Data.read(div)('config'); // { theme: 'dark' } * * // String fallback * div.dataset.name = 'John'; * Data.read(div)('name'); // "John" (string) * * // Missing attribute * Data.read(div)('missing'); // undefined * * // Type-safe usage * interface Config { theme: string; size: string; } * const config = Data.read(div)('config'); * ``` */ read: (el: HTMLElement | null) => (key: string) => any; /** * Observes changes to a data attribute and fires a callback. * * Uses MutationObserver to watch for attribute changes. The callback fires * immediately with the current value, then on every change. Values are * automatically parsed using `Data.read()`. * * @template T - The expected value type * @param el - The element to observe (null-safe) * @returns A curried function that accepts key and callback, returns cleanup function * * @example * ```typescript * const div = document.querySelector('div'); * * // Imperative (cleaner DX) * const cleanup = Data.bind(div, 'count', (value, el) => { * console.log('Count is now:', value); * }); * * // Curried (pipeline friendly) * const cleanup = Data.bind(div)('count', (value, el) => { * console.log('Count is now:', value); * // Fires immediately with current value * // Then fires on every change * }); * * // Later: stop watching * cleanup(); * * // Form validation example * Data.bind(input)('validationError', (error) => { * if (error) { * errorDisplay.textContent = error; * errorDisplay.style.display = 'block'; * } else { * errorDisplay.style.display = 'none'; * } * }); * * // Sync state between components * Data.bind(slider)('value', (value) => { * valueDisplay.textContent = String(value); * }); * * // Null-safe: returns no-op cleanup * const noop = Data.bind(null)('key', callback); // () => {} * ``` */ bind: { (target: HTMLElement | null, key: string, callback: (val: any, el: HTMLElement) => void): Unsubscribe; (target: HTMLElement | null): (key: string, callback: (val: any, el: HTMLElement) => void) => Unsubscribe; }; }; /** * Observes changes to one or more attributes on an element. * * Uses MutationObserver to watch for attribute changes. The callback fires * whenever any of the specified attributes change, receiving the new value * and attribute name. Returns a cleanup function to stop observing. * * **Performance**: Uses attribute filtering for efficiency. The observer only * watches the specified attributes, not all attribute changes. * * @param target - The element to observe (null-safe) * @returns A curried function that accepts attributes and callback, returns cleanup function * * @example * ```typescript * const input = document.querySelector('input'); * * // Imperative (cleaner DX) * const cleanup = watchAttr(input, 'disabled', (value, attrName) => { * console.log(`${attrName} changed to:`, value); * }); * * // Curried (pipeline friendly) * const cleanup = watchAttr(input)('disabled', (value, attrName) => { * console.log(`${attrName} changed to:`, value); * // value is the new attribute value (string | null) * }); * * // Watch multiple attributes * watchAttr(input)(['value', 'placeholder', 'type'], (value, attrName) => { * console.log(`${attrName} = ${value}`); * }); * * // Form validation * watchAttr(input)('aria-invalid', (value) => { * if (value === 'true') { * input.classList.add('error'); * } else { * input.classList.remove('error'); * } * }); * * // Sync attributes between elements * watchAttr(sourceElement)('title', (value) => { * if (value) targetElement.setAttribute('title', value); * }); * * // Later: stop watching * cleanup(); * * // Null-safe: returns no-op cleanup * const noop = watchAttr(null)('disabled', callback); // () => {} * ``` */ export declare const watchAttr: { (target: Element | null, attrs: string | string[], callback: (val: string | null, attr: string) => void): Unsubscribe; (target: Element | null): (attrs: string | string[], callback: (val: string | null, attr: string) => void) => Unsubscribe; }; /** * Observes changes to the text content of an element. * * Uses MutationObserver to watch for text content changes. The callback fires * whenever the element's textContent changes, receiving the new text value. * Returns a cleanup function to stop observing. * * **Performance**: Watches both characterData (direct text node changes) and * childList (when text nodes are added/removed) with subtree enabled. * * @param target - The element to observe (null-safe) * @returns A curried function that accepts a callback, returns cleanup function * * @example * ```typescript * const div = document.querySelector('div'); * * // Imperative (cleaner DX) * const cleanup = watchText(div, (newText) => { * console.log('Text changed to:', newText); * }); * * // Curried (pipeline friendly) * const cleanup = watchText(div)((newText) => { * console.log('Text changed to:', newText); * }); * * // Later: stop watching * cleanup(); * * // Use in reactive UI * const counter = document.querySelector('#counter'); * watchText(counter)((text) => { * const count = parseInt(text); * if (count > 100) alert('Limit exceeded!'); * }); * * // Null-safe: returns no-op cleanup * const noop = watchText(null)(callback); // () => {} * ``` */ export declare const watchText: { (target: Element | null, callback: (text: string) => void): Unsubscribe; (target: Element | null): (callback: (text: string) => void) => Unsubscribe; }; /** * Gets or sets an attribute on an element. * * Overloads: * 1. attr("data-id") — gets attribute from documentElement * 2. attr(el)("data-id") — gets attribute from the element * 3. attr(el)("data-id", "123") — sets attribute * * Getter returns `string | null` * Setter returns `void` */ export declare function attr(attribute: string): string | null; export declare function attr(el: Element | null): (attribute: string) => string | null; export declare function attr(el: Element | null): (attribute: string, value: string) => void; /** * Gets or sets a DOM property. * * Works like `attr` but for real JS properties. * * Overloads: * 1. prop("value") — gets from document.documentElement * 2. prop(el)("value") — getter * 3. prop(el)("value", newValue) — setter * * Getter: returns the property type of the element if known. * Setter: void */ export declare function prop(prop: K): HTMLElement[K]; export declare function prop(el: T | null): (prop: K) => T[K]; export declare function prop(el: T | null): (prop: K, value: T[K]) => void; /** * Executes a callback when the DOM is fully loaded and parsed. * * If the DOM is already ready, the callback executes immediately (synchronously). * Otherwise, it waits for the DOMContentLoaded event. This is safer than placing * scripts at the end of the body, as it guarantees DOM availability. * * **Timing Guarantee**: The callback will execute exactly once, either immediately * or when DOMContentLoaded fires. External resources (images, stylesheets) may * still be loading. * * **SSR Considerations**: In server-side rendering contexts, ensure this code * only runs in the browser (check for `typeof document !== 'undefined'`). * * @param fn - The callback to execute when the DOM is ready * @returns void * * @example * ```typescript * // Basic usage * onReady(() => { * console.log('DOM is ready!'); * const app = document.querySelector('#app'); * // Safe to manipulate DOM here * }); * * // Initialize app * onReady(() => { * const form = document.querySelector('form'); * on(form)('submit', handleSubmit); * * const buttons = findAll(document)('button'); * buttons.forEach(btn => { * on(btn)('click', handleClick); * }); * }); * * // Multiple callbacks (each executes independently) * onReady(() => console.log('First')); * onReady(() => console.log('Second')); * * // SSR-safe usage * if (typeof document !== 'undefined') { * onReady(() => { * // Client-side only code * }); * } * * // Difference from window.onload: * // - onReady: Fires when DOM is parsed (faster) * // - window.onload: Fires when all resources loaded (slower) * ``` */ export declare const onReady: (fn: () => void) => void; /** * Promise-based DOM lifecycle utilities for different timing needs. * * Type-safe, composable methods for waiting on specific lifecycle phases: * - `dom()` — waits until DOM is parsed (DOMContentLoaded) * - `micro()` — waits until microtask queue is empty * - `raf()` — waits until next requestAnimationFrame * * @example * ```typescript * // Wait for DOM to be parsed * await ready.dom(); * const app = document.querySelector('#app'); * * // Wait for microtasks to flush * await ready.micro(); * * // Wait for next paint * await ready.raf(); * * // Chain multiple lifecycle waits * await ready.dom(); * await ready.micro(); * await ready.raf(); * // Now safe to interact with layout * ``` */ export declare const ready: { /** * Waits until the DOM is parsed and interactive (DOMContentLoaded). * Resolves immediately if DOM is already loaded. * * @returns Promise that resolves when DOM is ready */ dom: () => Promise; /** * Waits until the microtask queue is flushed (after current JS execution). * Useful for ensuring Promise chains and MutationObserver callbacks have run. * * @returns Promise that resolves on next microtask */ micro: () => Promise; /** * Waits until the next requestAnimationFrame (next paint cycle). * Useful for deferring layout-dependent code. * * @returns Promise that resolves on next frame */ raf: () => Promise; }; /** * Observes when elements matching a selector are added to the DOM. * * Uses MutationObserver to watch for new elements. The handler fires for: * 1. Elements already in the DOM (initial check) * 2. Elements added dynamically after setup * * Each element is tracked using WeakSet to prevent duplicate handler calls. * Returns a cleanup function to stop observing. * * **Performance**: Uses WeakSet for O(1) duplicate checking without memory leaks. * The observer watches the entire subtree by default. * * **SPA Navigation**: Perfect for handling dynamically loaded content in single-page * applications where elements appear/disappear without full page reloads. * * @template S - The CSS selector string * @param selector - CSS selector to match elements * @returns A curried function that accepts handler, root, and once flag * * @example * ```typescript * // Imperative (cleaner DX) * const cleanup = onMount('.modal', (modal) => { * console.log('Modal added:', modal); * modal.classList.add('initialized'); * }); * * // Curried (pipeline friendly) * const cleanup = onMount('.modal')((modal) => { * console.log('Modal added:', modal); * modal.classList.add('initialized'); * * // Setup modal-specific behavior * const closeBtn = modal.querySelector('.close'); * on(closeBtn)('click', () => modal.remove()); * }); * * // Later: stop observing * cleanup(); * * // Watch within a specific container * const container = document.querySelector('#app'); * onMount('.dynamic-card')((card) => { * console.log('Card added'); * }, container); * * // One-time handler (stops after first match) * onMount('#splash-screen')((splash) => { * setTimeout(() => splash.remove(), 3000); * }, document, true); // once = true * * // SPA route handling * onMount('[data-page]')((page) => { * const pageName = page.getAttribute('data-page'); * console.log('Page loaded:', pageName); * * // Initialize page-specific features * initializeAnalytics(pageName); * loadPageData(pageName); * }); * * // Lazy-load images as they're added * onMount('img[data-src]')((img) => { * const src = img.getAttribute('data-src'); * if (src) { * img.setAttribute('src', src); * img.removeAttribute('data-src'); * } * }); * * // Component initialization pattern * onMount('[data-component="tooltip"]')((el) => { * new Tooltip(el); // Initialize tooltip component * }); * ``` */ export declare const onMount: { (target: string | null, handler: (el: Element) => void, root?: ParentNode | undefined, once?: any): Unsubscribe; (target: string | null): (handler: (el: Element) => void, root?: ParentNode | undefined, once?: any) => Unsubscribe; }; /** * Waits for a condition to become true on an element. * * Returns a Promise that resolves when the predicate returns true. Uses * MutationObserver to watch for changes. The predicate is checked immediately, * then on every mutation until it returns true. * * **Timeout Recommendation**: Consider adding a timeout wrapper to prevent * infinite waiting: * ```typescript * Promise.race([ * waitFor(el, predicate), * wait(5000).then(() => { throw new Error('Timeout'); }) * ]); * ``` * * **Memory Leak Prevention**: The observer automatically disconnects when the * condition is met. If the element is null, the promise never resolves (consider * null-checking before calling). * * @param target - The element to observe (null-unsafe: promise won't resolve if null) * @returns A curried function that accepts a predicate and returns a Promise * * @example * ```typescript * const button = document.querySelector('button'); * * // Imperative (cleaner DX) * await waitFor(button, (el) => el.classList.contains('ready')); * console.log('Button is ready!'); * * // Curried (pipeline friendly) * await waitFor(button)((el) => el.classList.contains('ready')); * console.log('Button is ready!'); * * // Wait for specific attribute value * await waitFor(input)((el) => el.getAttribute('data-loaded') === 'true'); * console.log('Data loaded!'); * * // Wait for child count * const list = document.querySelector('ul'); * await waitFor(list)((el) => el.children.length >= 10); * console.log('List has at least 10 items'); * * // Wait for text content * await waitFor(status)((el) => el.textContent?.includes('Complete')); * console.log('Status is complete'); * * // With timeout (recommended) * try { * await Promise.race([ * waitFor(element)((el) => el.classList.contains('loaded')), * wait(5000).then(() => { throw new Error('Timeout waiting for element'); }) * ]); * console.log('Element loaded in time'); * } catch (e) { * console.error('Timed out:', e); * } * * // Animation completion * element.classList.add('animating'); * await waitFor(element)((el) => !el.classList.contains('animating')); * console.log('Animation complete'); * * // Form validation * await waitFor(form)((el) => { * const inputs = el.querySelectorAll('input[required]'); * return Array.from(inputs).every(input => input.value.length > 0); * }); * console.log('All required fields filled'); * ``` */ export declare const waitFor: { (target: Element | null, predicate: (el: Element) => boolean): Promise; (target: Element | null): (predicate: (el: Element) => boolean) => Promise; }; /** * Utilities for working with URL query parameters. * * Provides a functional API for reading and modifying URL search parameters. * Supports both 'soft' navigation (using pushState) and 'hard' navigation * (full page reload). * * **URL Encoding**: Values are automatically URL-encoded when set. * * @example * ```typescript * // URL: https://example.com?page=1&sort=name * * // Get single parameter * const page = Params.get('page'); // "1" * const missing = Params.get('missing'); // null * * // Get multiple values (for array parameters) * // URL: ?tags=js&tags=ts&tags=react * const tags = Params.getAll('tags'); // ["js", "ts", "react"] * * // Set parameter (soft navigation - no reload) * Params.set('page')('2')(); // Updates URL without reload * // URL becomes: ?page=2&sort=name * * // Set parameter (hard navigation - full reload) * Params.set('page')('2')('hard'); // Reloads page with new URL * * // Chaining for multiple updates * Params.set('page')('1')(); * Params.set('sort')('date')(); * Params.set('filter')('active')(); * ``` */ export declare const Params: { /** * Gets a single query parameter value. * * @param key - The parameter name * @returns The parameter value or null if not found * * @example * ```typescript * // URL: ?id=123&name=John * const id = Params.get('id'); // "123" * const name = Params.get('name'); // "John" * const missing = Params.get('missing'); // null * ``` */ get: (key: string) => string | null; /** * Gets all values for a query parameter (for array-like parameters). * * @param key - The parameter name * @returns Array of all values for that parameter * * @example * ```typescript * // URL: ?tags=js&tags=ts&tags=react * const tags = Params.getAll('tags'); // ["js", "ts", "react"] * * // URL: ?filter=active * const filters = Params.getAll('filter'); // ["active"] * * // Missing parameter * const missing = Params.getAll('missing'); // [] * ``` */ getAll: (key: string) => string[]; /** * Sets a query parameter value. * * @param key - The parameter name * @returns A curried function that accepts value and navigation type * * @example * ```typescript * // Soft navigation (no page reload) * Params.set('page')('2')(); // Default: soft * Params.set('page')('2')('soft'); * * // Hard navigation (full page reload) * Params.set('page')('2')('hard'); * * // Pagination example * const nextPage = () => { * const current = parseInt(Params.get('page') || '1'); * Params.set('page')(String(current + 1))(); * }; * * // Filter example * const applyFilter = (filter: string) => { * Params.set('filter')(filter)(); * Params.set('page')('1')(); // Reset to page 1 * loadData(); // Fetch filtered data * }; * ``` */ set: (key: string) => (val: string) => (type?: "soft" | "hard") => void; }; /** * Utilities for working with form data. * * Provides serialization and population of form fields. Automatically handles * different input types (text, checkbox, radio, number, select, textarea). * * **FormData Compatibility**: For native FormData support, use `new FormData(form)`. * This utility provides a plain object representation. * * @example * ```typescript * const form = document.querySelector('form'); * * // Serialize form to object * const data = Form.serialize(form); * // { username: "john", email: "john@example.com", age: 25, subscribe: true } * * // Populate form from object * Form.populate(form)({ * username: "jane", * email: "jane@example.com", * age: 30, * subscribe: false * }); * * // Save/load form state * const saveForm = () => { * const data = Form.serialize(form); * Local.set('formDraft')(data); * }; * * const loadForm = () => { * const data = Local.get('formDraft'); * if (data) Form.populate(form)(data); * }; * ``` */ export interface FormSerializeOptions { /** Use dot-notation to create nested objects. */ nested?: boolean; /** Include FileList values from file inputs. */ includeFiles?: boolean; /** Include disabled fields (default: false). */ includeDisabled?: boolean; } export declare const Form: { /** * Serializes form inputs into a plain object. * * Handles: * - Text inputs → string * - Number inputs → number * - Checkboxes → boolean * - Radio buttons → string (only checked value) * - Select → string * - Textarea → string * * Options: * - `nested`: Supports dot-notation for nested objects * - `includeFiles`: Includes FileList values * - `includeDisabled`: Includes disabled inputs * * Only includes inputs with a `name` attribute. * * @param root - The form or container element * @param options - Serialization options * @returns Object with field names as keys and values * * @example * ```typescript * const form = document.querySelector('form'); * const data = Form.serialize(form); * * // Submit to API * await Http.post('/api/submit')(data); * * // Validate before submit * on(form)('submit', (e) => { * e.preventDefault(); * const data = Form.serialize(form); * if (validate(data)) { * submitForm(data); * } * }); * * // Auto-save draft * const inputs = form.querySelectorAll('input, textarea'); * inputs.forEach(input => { * on(input)('input', debounce(() => { * const data = Form.serialize(form); * Local.set('draft')(data); * }, 500)); * }); * ``` */ serialize: (root: HTMLElement | null, options?: FormSerializeOptions) => Record; /** * Populates form inputs from a plain object. * * Matches object keys to input `name` attributes and sets values accordingly. * * @param root - The form or container element * @returns A curried function that accepts data object and returns the root * * @example * ```typescript * const form = document.querySelector('form'); * * // Imperative (cleaner DX) * Form.populate(form, { * username: 'john', * email: 'john@example.com', * notifications: true * }); * * // Curried (pipeline friendly) * Form.populate(form)({ * username: user.username, * email: user.email, * bio: user.bio, * notifications: user.preferences.notifications * }); * * // Load saved data * const savedData = Local.get('formData'); * if (savedData) Form.populate(form)(savedData); * * // Reset form to defaults * Form.populate(form)({ * theme: 'light', * language: 'en', * notifications: true * }); * ``` */ populate: { (target: HTMLElement | null, data: Record): HTMLElement | null; (target: HTMLElement | null): (data: Record) => HTMLElement | null; }; }; /** * Waits for a specified number of milliseconds. * * Returns a Promise that resolves after the delay. Useful for adding delays * in async functions or creating timeouts. * * @param ms - The number of milliseconds to wait * @returns A Promise that resolves after the delay * * @example * ```typescript * // Simple delay * await wait(1000); // Wait 1 second * console.log('Done waiting'); * * // Delay in async function * async function showMessage() { * console.log('Loading...'); * await wait(2000); * console.log('Done!'); * } * * // Animation timing * async function animate() { * element.classList.add('fade-in'); * await wait(300); * element.classList.remove('fade-in'); * } * * // Retry with delay * async function retryFetch(url: string, retries = 3) { * for (let i = 0; i < retries; i++) { * try { * return await fetch(url); * } catch (e) { * if (i < retries - 1) await wait(1000 * (i + 1)); * } * } * } * ``` */ export declare const wait: (ms: number) => Promise; /** * Waits for the next animation frame. * * Returns a Promise that resolves on the next requestAnimationFrame callback. * Useful for ensuring DOM updates are rendered before proceeding. * * @returns A Promise that resolves on the next frame * * @example * ```typescript * // Ensure DOM update is rendered * element.style.opacity = '0'; * await nextFrame(); * element.style.transition = 'opacity 0.3s'; * element.style.opacity = '1'; * * // Batch DOM reads after writes * element.style.width = '100px'; * await nextFrame(); * const width = element.offsetWidth; // Avoids layout thrashing * * // Smooth animation sequence * async function animateSequence() { * element.classList.add('step-1'); * await nextFrame(); * element.classList.add('step-2'); * await nextFrame(); * element.classList.add('step-3'); * } * ``` */ export declare const nextFrame: () => Promise; /** CSS Template Literal for highlighting */ export declare const cssTemplate: (strings: TemplateStringsArray, ...values: any[]) => string; /** * Flexible, type-aware DOM traversal utilities. * * Each method supports three invocation styles: * * 1. **Element-first** (immediate): * Traverse.next(el) → Element | null * * 2. **Selector-first**: * Traverse.next(".item") → Element | null * * 3. **Curried**: * Traverse.next(el)("span.highlight") → Element | null * * All operations are: * - **Null-safe**: All functions gracefully return `null` or `[]`. * - **Type-preserving**: Passing `HTMLDivElement` returns `HTMLDivElement | null`. * - **Selector-aware**: Passing a selector filters the returned element(s). */ export declare const Traverse: { /** * Get the parent element, optionally filtered by a selector. * * @example * // Element-first * const parent = Traverse.parent(el); //
    | null * * // Selector-first * const parent = Traverse.parent("#child"); // parent of #child * * // Curried * const specific = Traverse.parent(el)(".box"); */ parent(elOrSelector?: Element | string | null): HTMLElement | ((selector?: string) => Element | null) | null; /** * Get the next sibling element. * * @example * Traverse.next(el); //
  • | null * Traverse.next(".active"); // next of .active * Traverse.next(el)("button"); // next button sibling */ next(elOrSelector?: Element | string | null): Element | ((selector?: string) => Element | null) | null; /** * Get the previous sibling element. * * @example * Traverse.prev(el); * Traverse.prev(".selected"); * Traverse.prev(el)(".item"); */ prev(elOrSelector?: Element | string | null): Element | ((selector?: string) => Element | null) | null; /** * Get child elements, with optional selector filtering. * * @example * Traverse.children(el); // Element[] * Traverse.children(".list"); // children of element matching .list * Traverse.children(el)("li"); // only
  • children */ children(elOrSelector?: Element | string | null): Element[] | ((selector?: string) => Element[]); /** * Get sibling elements (excluding the original element). * * @example * Traverse.siblings(el); * Traverse.siblings("#active"); * Traverse.siblings(el)(".item"); */ siblings(elOrSelector?: Element | string | null): Element[] | ((selector?: string) => Element[]); /** * Get all ancestor elements up to the document root. * * Optionally stops at an element matching a selector. * * @example * Traverse.parents(el); // All ancestors * Traverse.parents("#child"); // Ancestors of #child * Traverse.parents(el, ".section"); // Ancestors until .section match * Traverse.parents(el)(".container"); // Curried: ancestors matching .container */ parents(elOrSelector?: Element | string | null, until?: string | ((el: Element) => boolean)): Element[]; /** * Get all following sibling elements. * * Optionally filtered by a selector. * * @example * Traverse.nextAll(el); // All following siblings * Traverse.nextAll(".selected"); // Following siblings of .selected * Traverse.nextAll(el)(".item"); // Following siblings matching .item */ nextAll(elOrSelector?: Element | string | null, selector?: string): Element[]; /** * Get all preceding sibling elements. * * Optionally filtered by a selector. * * @example * Traverse.prevAll(el); // All preceding siblings * Traverse.prevAll(".selected"); // Preceding siblings of .selected * Traverse.prevAll(el)(".item"); // Preceding siblings matching .item */ prevAll(elOrSelector?: Element | string | null, selector?: string): Element[]; /** * Get all ancestors including the element itself, up to document root. * * Optionally filtered by a selector. * * @example * Traverse.closestAll(el); // Element + all ancestors * Traverse.closestAll("#child"); // Self + ancestors of #child * Traverse.closestAll(el)(".box"); // Self + ancestors matching .box */ closestAll(elOrSelector?: Element | string | null, selector?: string): Element[]; }; /** * Utilities for working with CSS custom properties (variables). * * Provides a functional API for getting and setting CSS variables on elements. * Variables can be set at any level (element, :root, etc.) and will cascade * according to CSS specificity rules. * * **Fallback Values**: When getting variables, you can provide fallback values * using standard CSS syntax: `var(--color, blue)`. * * @example * ```typescript * const element = document.querySelector('.card'); * * // Set CSS variable * CssVar.set(element)('--primary-color', '#007bff'); * CssVar.set(element)('--spacing', '1rem'); * * // Get CSS variable * const color = CssVar.get(element)('--primary-color'); // "#007bff" * * // Set on :root for global theme * CssVar.set(document.documentElement)('--theme', 'dark'); * * // Dynamic theming * const setTheme = (theme: 'light' | 'dark') => { * const root = document.documentElement; * if (theme === 'dark') { * CssVar.set(root)('--bg', '#1a1a1a'); * CssVar.set(root)('--text', '#ffffff'); * } else { * CssVar.set(root)('--bg', '#ffffff'); * CssVar.set(root)('--text', '#000000'); * } * }; * ``` */ export declare const CssVar: { /** * Sets a CSS custom property (variable) on an element. * * @param el - The element to set the variable on (null-safe) * @returns A curried function that accepts name and value, returns the element * * @example * ```typescript * const div = document.querySelector('div'); * * // Set single variable * CssVar.set(div)('--color', 'red'); * * // Set multiple variables * CssVar.set(div)('--width', '100px'); * CssVar.set(div)('--height', '100px'); * * // Global theme variables * const root = document.documentElement; * CssVar.set(root)('--primary', '#007bff'); * CssVar.set(root)('--secondary', '#6c757d'); * * // Dynamic values * CssVar.set(element)('--progress', `${percentage}%`); * * // Null-safe * CssVar.set(null)('--color', 'red'); // Returns null * ``` */ set: (el: HTMLElement | null) => (name: string, value: string) => HTMLElement | null; /** * Gets the computed value of a CSS custom property. * * Returns the computed value, which may be inherited from a parent element * or :root. The value is trimmed of whitespace. * * @param el - The element to get the variable from (null-safe) * @returns A curried function that accepts name and returns the value * * @example * ```typescript * const div = document.querySelector('div'); * * // Get variable value * const color = CssVar.get(div)('--primary-color'); * * // Get inherited variable * const spacing = CssVar.get(div)('--spacing'); // May come from parent * * // Use in calculations * const width = parseInt(CssVar.get(element)('--width')); * * // Check if variable is set * const hasTheme = CssVar.get(document.documentElement)('--theme') !== ''; * * // Null-safe * CssVar.get(null)('--color'); // "" * ``` */ get: (el: HTMLElement | null) => (name: string) => string; }; /** * Reads a computed CSS property value from an element. * * Gets the final computed value of any CSS property, including inherited values, * cascaded values, and browser defaults. Useful for reading actual rendered values * rather than inline styles. * * **Unit Parsing**: The returned value includes units (e.g., "16px", "1.5em"). * Parse with `parseInt()` or `parseFloat()` if you need numeric values. * * **Computed vs Inline**: This reads computed styles (what's actually rendered), * not inline styles. Use `element.style.property` for inline styles only. * * @param el - The element to read from (null-safe) * @returns A curried function that accepts a property name and returns the value * * @example * ```typescript * const div = document.querySelector('div'); * * // Get computed width (includes padding, border if box-sizing) * const width = computed(div)('width'); // "200px" * * // Get font size * const fontSize = computed(div)('fontSize'); // "16px" * * // Get color (returns rgb/rgba) * const color = computed(div)('color'); // "rgb(0, 0, 0)" * * // Parse numeric values * const widthNum = parseInt(computed(div)('width')); // 200 * * // Check display state * const isHidden = computed(div)('display') === 'none'; * * // Get inherited values * const lineHeight = computed(div)('lineHeight'); * * // Null-safe * computed(null)('width'); // "" * ``` */ export declare const computed: (el: HTMLElement | null) => (prop: keyof CSSStyleDeclaration) => string; /** * Injects CSS styles into the document. * * Creates a