UNPKG

watch-selector

Version:

Runs a function when a selector is added to dom

375 lines 18.2 kB
import type { ElementFn, ElementFromSelector, TypedGeneratorContext } from "../types"; /** * Type guard to check if a value is an HTMLElement. * * This is a utility function that provides type-safe checking for HTMLElement instances. * It's particularly useful when working with dynamic values or when you need to ensure * type safety in your DOM manipulation code. * * @param value - The value to check * @returns True if the value is an HTMLElement, false otherwise * * @example * ```typescript * import { isElement } from 'watch-selector'; * * const maybeElement = document.querySelector('button'); * if (isElement(maybeElement)) { * // TypeScript now knows maybeElement is HTMLElement * maybeElement.click(); * } * * // Use in filtering arrays * const elements = [div, null, span, undefined].filter(isElement); * // elements is now HTMLElement[] * ``` */ export declare function isElement(value: any): value is HTMLElement; /** * Type guard to check if a value can be used as an element reference. * * This function checks if a value is either an HTMLElement or a string (CSS selector). * It's useful for functions that accept both direct element references and CSS selectors. * * @param value - The value to check * @returns True if the value is an HTMLElement or string, false otherwise * * @example Direct element validation * ```typescript * import { isElementLike } from 'watch-selector'; * * function processElement(target: unknown) { * if (isElementLike(target)) { * // TypeScript knows target is HTMLElement | string * const element = resolveElement(target); * if (element) { * element.focus(); * } * } * } * * processElement(document.getElementById('my-button')); // Valid * processElement('#my-button'); // Valid * processElement(123); // Invalid - won't pass type guard * ``` * * @example Array filtering * ```typescript * import { isElementLike } from 'watch-selector'; * * const mixed = [ * document.getElementById('btn1'), * '#btn2', * null, * '.btn3', * undefined, * document.querySelector('.btn4') * ]; * * const validTargets = mixed.filter(isElementLike); * // validTargets is now (HTMLElement | string)[] * ``` */ export declare function isElementLike(value: any): value is HTMLElement | string; /** * Resolves an element-like value to an actual HTMLElement. * * This function takes either an HTMLElement or a CSS selector string and returns * the corresponding HTMLElement. If a string is provided, it uses querySelector * to find the element. This is the core utility function used throughout the * library for element resolution. * * @param elementLike - Either an HTMLElement or a CSS selector string * @returns The resolved HTMLElement, or null if not found or invalid * * @example Direct element reference * ```typescript * import { resolveElement } from 'watch-selector'; * * const button = document.getElementById('my-button'); * const resolved = resolveElement(button); // Returns the button element directly * * console.log(resolved === button); // true * ``` * * @example CSS selector resolution * ```typescript * import { resolveElement } from 'watch-selector'; * * const resolved1 = resolveElement('#my-button'); // Finds and returns the element * const resolved2 = resolveElement('.not-found'); // Returns null if not found * const resolved3 = resolveElement('button:first-child'); // Complex selectors work * * if (resolved1) { * resolved1.click(); // Safe to use after null check * } * ``` * * @example Safe usage pattern * ```typescript * import { resolveElement } from 'watch-selector'; * * function safeClick(target: HTMLElement | string) { * const element = resolveElement(target); * if (element) { * element.click(); // Type-safe usage * } else { * console.warn('Element not found:', target); * } * } * * // Works with both patterns * safeClick('#submit-btn'); // CSS selector * safeClick(buttonElement); // Direct element * ``` * * @example Error handling for invalid selectors * ```typescript * import { resolveElement } from 'watch-selector'; * * // Invalid selector syntax is safely handled * const result = resolveElement('>>invalid<<selector'); // Returns null * console.log(result); // null - no exception thrown * ``` */ export declare function resolveElement(elementLike: HTMLElement | string): HTMLElement | null; /** * Gets or sets the text content of an element using the dual API pattern. * * This function provides a versatile way to manipulate text content that works both * directly with elements and within watch generators. It supports multiple usage patterns: * direct element manipulation, CSS selector-based manipulation, and generator-based * manipulation for use within watch functions. * * The function automatically handles type safety and provides different return types * based on the usage pattern. When used in generator mode, it returns an ElementFn * that can be yielded within a watch generator. * * @param element - HTMLElement to manipulate (direct API) * @param content - Text content to set * @returns void when setting, string when getting, ElementFn when in generator mode * * @example Direct API - Setting text * ```typescript * import { text } from 'watch-selector'; * * const button = document.getElementById('my-button'); * text(button, 'Click me!'); // Sets text content directly * * // Using CSS selector * text('#my-button', 'Click me!'); // Finds element and sets text * ``` * * @example Direct API - Getting text * ```typescript * import { text } from 'watch-selector'; * * const button = document.getElementById('my-button'); * const content = text(button); // Returns current text content * * // Using CSS selector * const content2 = text('#my-button'); // Returns text or null if not found * ``` * * @example Generator API - Within watch functions * ```typescript * import { watch, text, click } from 'watch-selector'; * * watch('button', function* () { * // Set initial text * yield text('Ready'); * * let count = 0; * yield click(function* () { * count++; * yield text(`Clicked ${count} times`); * }); * }); * ``` * * @example Generator API - Reading text in generators * ```typescript * import { watch, text, self } from 'watch-selector'; * * watch('.status', function* () { * // Get current text content * const currentText = yield text(); * console.log('Current status:', currentText); * * // Update based on current content * if (currentText === 'idle') { * yield text('active'); * } * }); * ``` * * @example Advanced usage with form elements * ```typescript * import { watch, text, input } from 'watch-selector'; * * watch('.character-counter', function* () { * const input = self().querySelector('input'); * * yield input(function* (event) { * const length = (event.target as HTMLInputElement).value.length; * yield text(`${length}/100 characters`); * }); * }); * ``` */ export declare function text<El extends HTMLElement = HTMLElement>(content: string): ElementFn<El>; export declare function text<El extends HTMLElement = HTMLElement>(): ElementFn<El, string>; export declare function text(element: HTMLElement, content: string): void; export declare function text(element: HTMLElement): string; export declare function text(selector: string, content: string): void; export declare function text(selector: string): string | null; export declare function html<El extends HTMLElement = HTMLElement>(content: string): ElementFn<El>; export declare function html<El extends HTMLElement = HTMLElement>(): ElementFn<El, string>; export declare function html(element: HTMLElement, content: string): void; export declare function html(element: HTMLElement): string; export declare function html(selector: string, content: string): void; export declare function html(selector: string): string | null; /** * Sets sanitized HTML content on an element to prevent XSS attacks. * Removes dangerous elements like script, iframe, and event handlers. * * @param args - Overloaded parameters supporting multiple usage patterns * @returns void, ElementFn, or the element depending on usage * * @example Direct element usage * ```typescript * const div = document.getElementById('content'); * safeHtml(div, userGeneratedContent); * ``` * * @example Selector usage * ```typescript * safeHtml('#content', untrustedHtml); * ``` * * @example Generator usage * ```typescript * watch('.user-content', function* () { * yield safeHtml(userInput); * }); * ``` */ export declare function safeHtml<El extends HTMLElement = HTMLElement>(...args: any[]): any; export declare function addClass<El extends HTMLElement = HTMLElement>(...classNames: string[]): ElementFn<El>; export declare function addClass(element: HTMLElement, ...classNames: string[]): void; export declare function addClass(selector: string, ...classNames: string[]): void; export declare function removeClass<El extends HTMLElement = HTMLElement>(...classNames: string[]): ElementFn<El>; export declare function removeClass(element: HTMLElement, ...classNames: string[]): void; export declare function removeClass(selector: string, ...classNames: string[]): void; export declare function toggleClass<El extends HTMLElement = HTMLElement>(className: string, force?: boolean): ElementFn<El, boolean>; export declare function toggleClass(element: HTMLElement, className: string, force?: boolean): boolean; export declare function toggleClass(selector: string, className: string, force?: boolean): boolean; export declare function hasClass<El extends HTMLElement = HTMLElement>(className: string): ElementFn<El, boolean>; export declare function hasClass(element: HTMLElement, className: string): boolean; export declare function hasClass(selector: string, className: string): boolean; export declare function style<El extends HTMLElement = HTMLElement>(styles: Partial<CSSStyleDeclaration> | Record<string, string>): ElementFn<El>; export declare function style<El extends HTMLElement = HTMLElement>(property: string, value: string): ElementFn<El>; export declare function style(element: HTMLElement, property: string): string; export declare function style(element: HTMLElement, styles: Partial<CSSStyleDeclaration> | Record<string, string>): void; export declare function style(element: HTMLElement, property: string, value: string): void; export declare function style(selector: string, property: string): string | null; export declare function style(selector: string, styles: Partial<CSSStyleDeclaration> | Record<string, string>): void; export declare function style(selector: string, property: string, value: string): void; export declare const attr: (...args: any[]) => any; export declare const prop: (...args: any[]) => any; export declare const data: (...args: any[]) => any; export declare function removeAttr<El extends HTMLElement = HTMLElement>(...names: string[]): ElementFn<El>; export declare function removeAttr(element: HTMLElement, names: string[]): void; export declare function removeAttr(element: HTMLElement, ...names: string[]): void; export declare function removeAttr(selector: string, names: string[]): void; export declare function removeAttr(selector: string, ...names: string[]): void; export declare function hasAttr<El extends HTMLElement = HTMLElement>(name: string): ElementFn<El, boolean>; export declare function hasAttr(element: HTMLElement, name: string): boolean; export declare function hasAttr(selector: string, name: string): boolean; export declare function value<El extends HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement = HTMLInputElement>(value: string): ElementFn<El>; export declare function value<El extends HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement = HTMLInputElement>(): ElementFn<El, string>; export declare function value(element: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, value: string): void; export declare function value(element: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement): string; export declare function value(selector: string, value: string): void; export declare function value(selector: string): string | null; export declare function checked<El extends HTMLInputElement = HTMLInputElement>(val: boolean): ElementFn<El>; export declare function checked<El extends HTMLInputElement = HTMLInputElement>(): ElementFn<El, boolean>; export declare function checked(element: HTMLInputElement, val: boolean): void; export declare function checked(element: HTMLInputElement): boolean; export declare function checked(selector: string, val: boolean): void; export declare function checked(selector: string): boolean; export declare function focus<El extends HTMLElement = HTMLElement>(): ElementFn<El>; export declare function focus<El extends HTMLElement>(element: El): void; export declare function blur<El extends HTMLElement = HTMLElement>(): ElementFn<El>; export declare function blur<El extends HTMLElement>(element: El): void; export declare function show<El extends HTMLElement = HTMLElement>(): ElementFn<El>; export declare function show<El extends HTMLElement>(element: El): void; export declare function hide<El extends HTMLElement = HTMLElement>(): ElementFn<El>; export declare function hide<El extends HTMLElement>(element: El): void; export declare function query<T extends HTMLElement = HTMLElement>(selector: string): ElementFn<HTMLElement, T | null>; export declare function query<T extends HTMLElement = HTMLElement>(element: HTMLElement, selector: string): T | null; export declare function queryAll<T extends HTMLElement = HTMLElement>(selector: string): ElementFn<HTMLElement, T[]>; export declare function queryAll<T extends HTMLElement = HTMLElement>(element: HTMLElement, selector: string): T[]; export declare function parent<T extends HTMLElement = HTMLElement>(selector?: string): ElementFn<HTMLElement, T | null>; export declare function parent<T extends HTMLElement = HTMLElement>(element: HTMLElement, selector?: string): T | null; export declare function children<T extends HTMLElement = HTMLElement>(selector?: string): ElementFn<HTMLElement, T[]>; export declare function children<T extends HTMLElement = HTMLElement>(element: HTMLElement, selector?: string): T[]; export declare function siblings<T extends HTMLElement = HTMLElement>(selector?: string): ElementFn<HTMLElement, T[]>; export declare function siblings<T extends HTMLElement = HTMLElement>(element: HTMLElement, selector?: string): T[]; /** * Creates a child watcher that applies a generator behavior to matching child elements. * * This function sets up a MutationObserver to watch for child elements matching * the given selector and applies the generator behavior to each matching element. * It returns a Map containing the APIs returned by each child's generator. * * @param selector - CSS selector for child elements to watch * @param generator - Generator function to apply to each matching child * @returns Map of child elements to their returned APIs * * @example * ```typescript * watch('.container', function* () { * const childApis = yield createChildWatcher('.item', function* () { * yield addClass('item-enhanced'); * return { * highlight: () => addClass('highlighted'), * getId: () => self().id * }; * }); * * // Access child APIs * childApis.forEach((api, element) => { * console.log('Child ID:', api.getId()); * }); * }); * ``` */ export declare function createChildWatcher<S extends string, ChildEl extends HTMLElement = ElementFromSelector<S>, T = any>(selector: S, generator: (ctx: TypedGeneratorContext<ChildEl>) => Generator<any, T, unknown> | AsyncGenerator<any, T, unknown>): ElementFn<HTMLElement, Map<ChildEl, T>>; export declare function createChildWatcher<S extends string, ChildEl extends HTMLElement = ElementFromSelector<S>, T = any>(element: HTMLElement, selector: S, generator: (ctx: TypedGeneratorContext<ChildEl>) => Generator<any, T, unknown> | AsyncGenerator<any, T, unknown>): Map<ChildEl, T>; export declare function createChildWatcher<S extends string, ChildEl extends HTMLElement = ElementFromSelector<S>, T = any>(selector: S, generator: (ctx: TypedGeneratorContext<ChildEl>) => Generator<any, T, unknown> | AsyncGenerator<any, T, unknown>, ctx: TypedGeneratorContext<any>): Map<ChildEl, T>; /** * Shorthand for createChildWatcher - creates a child watcher with a more concise syntax. * * @param selector - CSS selector for child elements * @param generator - Generator function to apply to each child * @returns Map of child elements to their APIs * * @example * ```typescript * watch('.list', function* () { * const items = yield child('.item', function* () { * yield addClass('item-ready'); * return { id: self().dataset.id }; * }); * }); * ``` */ export declare function child<S extends string, ChildEl extends HTMLElement = ElementFromSelector<S>, T = any>(selector: S, generator: (ctx: TypedGeneratorContext<ChildEl>) => Generator<any, T, unknown> | AsyncGenerator<any, T, unknown>): ElementFn<HTMLElement, Map<ChildEl, T>>; export declare function child<S extends string, ChildEl extends HTMLElement = ElementFromSelector<S>, T = any>(element: HTMLElement, selector: S, generator: (ctx: TypedGeneratorContext<ChildEl>) => Generator<any, T, unknown> | AsyncGenerator<any, T, unknown>): Map<ChildEl, T>; export declare function child<S extends string, ChildEl extends HTMLElement = ElementFromSelector<S>, T = any>(selector: S, generator: (ctx: TypedGeneratorContext<ChildEl>) => Generator<any, T, unknown> | AsyncGenerator<any, T, unknown>, ctx: TypedGeneratorContext<any>): Map<ChildEl, T>; export declare function batchAll(elements: (HTMLElement | string)[], operations: ElementFn<HTMLElement>[]): void; export declare function batchAll(elements: (HTMLElement | string)[], operations: ElementFn<HTMLElement>[]): ElementFn<HTMLElement, void>; export declare const el: typeof query; export declare const all: typeof queryAll; //# sourceMappingURL=dom.d.ts.map