watch-selector
Version:
Runs a function when a selector is added to dom
375 lines • 18.2 kB
TypeScript
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