@tempots/dom
Version:
Fully-typed frontend framework alternative to React and Angular
323 lines (322 loc) • 12.8 kB
TypeScript
import { Clear, ProviderMark, Providers } from '../types/domain';
import { Primitive } from '@tempots/core';
import { DOMContext, HandlerOptions } from './dom-context';
import { HeadlessContext } from './headless-context';
/**
* Browser implementation of DOMContext for real DOM manipulation in web browsers.
*
* BrowserContext provides a comprehensive API for creating, manipulating, and managing
* DOM elements in a browser environment. It handles element creation, text nodes,
* event listeners, styling, and provider management while maintaining immutability
* through context chaining.
*
* The context uses a reference system to track insertion points within sibling elements,
* allowing precise control over where new elements are inserted in the DOM tree.
*
* @example
* ```typescript
* // Create a context for the document body
* const ctx = BrowserContext.of(document.body, undefined, {})
*
* // Create child elements
* const divCtx = ctx.makeChildElement('div', undefined)
* const textCtx = divCtx.makeChildText('Hello, World!')
*
* // Add event listeners
* divCtx.on('click', (event, ctx) => {
* console.log('Div clicked!', event.target)
* })
* ```
*
* @example
* ```typescript
* // Working with providers
* const themeProvider = makeProviderMark<string>('theme')
* const ctxWithProvider = ctx.setProvider(themeProvider, 'dark', undefined)
*
* // Later retrieve the provider
* const { value: theme } = ctxWithProvider.getProvider(themeProvider)
* ```
*
* @example
* ```typescript
* // Portal to different DOM location
* const modalCtx = ctx.makePortal('#modal-root')
* const modalContent = modalCtx.makeChildElement('div', undefined)
* ```
*
* @public
*/
export declare class BrowserContext implements DOMContext {
/**
* The `Document` instance associated with this context.
*/
readonly document: Document;
/**
* The `Element` instance associated with this context.
*/
readonly element: HTMLElement;
/**
* An optional `Node` instance that serves as a reference for this context.
*/
readonly reference: Node | undefined;
/**
* The `Providers` instance associated with this context.
*/
readonly providers: Providers;
/**
* Creates a new `DOMContext` instance for the given `Element` and optional reference `Node`.
*
* @param element - The `HTMLElement` to create the `DOMContext` for.
* @param ref - A reference `Node` to associate with the `DOMContext` or undefined .
* @param providers - The providers to associate with the `DOMContext`.
* @returns A new `DOMContext` instance.
*/
static of(element: HTMLElement, ref: Node | undefined, providers: Providers): DOMContext;
/**
* Constructs a new `DOMContext` instance.
*
* @param document - The `Document` instance associated with this context.
* @param element - The `Element` instance associated with this context.
* @param reference - An optional `Node` instance that serves as a reference for this context.
* @param providers - The `Providers` instance associated with this context.
* @param isFirstLevel - A boolean value indicating whether this context is at the first level, meaning the outermost node in the generated DOM.
*/
constructor(
/**
* The `Document` instance associated with this context.
*/
document: Document,
/**
* The `Element` instance associated with this context.
*/
element: HTMLElement,
/**
* An optional `Node` instance that serves as a reference for this context.
*/
reference: Node | undefined,
/**
* The `Providers` instance associated with this context.
*/
providers: Providers);
/**
* Creates a new DOM element (eg: HTML or SVG) with the specified tag name and namespace.
*
* @param tagName - The tag name of the element to create.
* @param namespace - The namespace URI to create the element in, or `undefined` to create a standard HTML element.
* @returns The newly created element.
*/
createElement(tagName: string, namespace: string | undefined): HTMLElement;
/**
* Creates a new child element and appends it to the current element, returning a new context.
*
* This method creates a new DOM element with the specified tag name and namespace,
* appends it to the current element, and returns a new DOMContext focused on the
* newly created child element. This is the primary method for building DOM trees.
*
* @example
* ```typescript
* // Create HTML elements
* const divCtx = ctx.makeChildElement('div', undefined)
* const spanCtx = divCtx.makeChildElement('span', undefined)
*
* // Create SVG elements
* const svgCtx = ctx.makeChildElement('svg', 'http://www.w3.org/2000/svg')
* const circleCtx = svgCtx.makeChildElement('circle', 'http://www.w3.org/2000/svg')
* ```
*
* @param tagName - The tag name of the element to create (e.g., 'div', 'span', 'svg')
* @param namespace - The namespace URI for the element, or undefined for HTML elements
* @returns A new DOMContext focused on the newly created child element
*/
makeChildElement(tagName: string, namespace: string | undefined): DOMContext;
/**
* Creates a new text node with the specified text content.
* @param text - The text content for the new text node.
* @returns A new `Text` node with the specified text content.
*/
createText(text: Primitive): Text;
/**
* Creates a new text node with the specified text content and appends it to the current element.
* @param text - The text content for the new text node. Primitives are coerced to strings by the DOM.
* @returns A new `DOMContext` with a reference to the new text node.
*/
makeChildText(text: Primitive): DOMContext;
/**
* Sets the text content of the current element.
* @param text - The text content to set. Primitives are coerced to strings by the DOM.
*/
setText(text: Primitive): void;
/**
* Gets the text content of the current element or text node.
* @returns The text content of the current element or text node.
*/
getText(): string;
/**
* Creates a new `DOMContext` with a reference to a newly created Comment node.
* The Comment node is appended or inserted to the current `DOMContext`.
* The new `DOMContext` with the reference is returned.
*/
makeRef(): DOMContext;
/**
* Creates a lightweight Comment marker node and appends/inserts it.
* Used as boundary references for keyed list items and conditional renderables.
*/
makeMarker(): DOMContext;
/**
* Appends or inserts a child node to the element, depending on whether a reference node is provided.
*
* @param child - The child node to append or insert.
*/
appendOrInsert(child: Node): void;
/**
* Creates a new `DOMContext` instance with the provided `element`.
* @param element - The DOM element to use in the new `DOMContext` instance.
* @returns A new `DOMContext` instance with the provided `element`.
*/
withElement(element: HTMLElement): BrowserContext;
/**
* Creates a portal to render content in a different part of the DOM tree.
*
* Portals allow you to render child components into a DOM node that exists outside
* the parent component's DOM hierarchy. This is useful for modals, tooltips,
* dropdowns, and other UI elements that need to break out of their container's
* styling or z-index context.
*
* @example
* ```typescript
* // Portal to a modal container
* const modalCtx = ctx.makePortal('#modal-root')
* const modal = modalCtx.makeChildElement('div', undefined)
*
* // Add modal content
* modal.makeChildText('This renders in #modal-root')
* ```
*
* @example
* ```typescript
* // Portal to an existing element reference
* const tooltipContainer = document.getElementById('tooltip-container')!
* const tooltipCtx = ctx.makePortal(tooltipContainer)
*
* // Render tooltip content
* const tooltip = tooltipCtx.makeChildElement('div', undefined)
* tooltip.addClasses(['tooltip', 'tooltip-top'])
* ```
*
* @example
* ```typescript
* // Portal for dropdown menu
* const dropdownCtx = ctx.makePortal('body') // Render at body level
* const dropdown = dropdownCtx.makeChildElement('div', undefined)
* dropdown.addClasses(['dropdown-menu'])
* dropdown.setStyle('position', 'absolute')
* dropdown.setStyle('top', '100px')
* dropdown.setStyle('left', '50px')
* ```
*
* @param selector - CSS selector string or HTMLElement reference for the portal target
* @returns A new DOMContext focused on the portal target element
* @throws {Error} When the selector doesn't match any element in the document
*/
makePortal(selector: string | HTMLElement): DOMContext;
/**
* Creates a new `DOMContext` instance with the specified reference.
*
* @param reference - The optional `Node` to use as the reference for the new `DOMContext`.
* @returns A new `DOMContext` instance with the specified reference.
*/
withReference(reference: Node | undefined): DOMContext;
/**
* Sets a provider for the given provider mark.
*
* @param mark - The provider mark to set the provider for.
* @param value - The provider to set for the given mark.
* @returns A new `DOMContext` instance with the specified provider.
*/
setProvider<T>(mark: ProviderMark<T>, value: T, onUse: undefined | (() => void)): DOMContext;
/**
* Retrieves a provider for the given provider mark.
*
* @param mark - The provider mark to retrieve the provider for.
* @returns The provider for the given mark.
* @throws Throws `ProviderNotFoundError` if the provider for the given mark is not found.
*/
getProvider<T>(mark: ProviderMark<T>): {
value: T;
onUse: (() => void) | undefined;
};
tryGetProvider<T>(mark: ProviderMark<T>): {
value: T;
onUse: (() => void) | undefined;
} | undefined;
clear(removeTree: boolean): void;
/**
* Adds classes to the element.
* @param tokens - The class names to add.
*/
addClasses(tokens: string[]): void;
/**
* Removes classes from the element.
* @param tokens - The class names to remove.
*/
removeClasses(tokens: string[]): void;
/**
* Gets the classes of the element.
* @returns The classes of the element.
*/
getClasses(): string[];
/**
* Adds an event listener to the element.
* @param event - The event to listen for.
* @param listener - The listener to call when the event occurs.
* @param options - The options for the event listener.
* @returns A function to remove the event listener.
*/
on<E>(event: string, listener: (event: E, ctx: BrowserContext) => void, options?: HandlerOptions): Clear;
/**
* Returns `true` if the context is a browser DOM context.
* @returns `true` if the context is a browser DOM context.
* @deprecated Use `isBrowser()` instead.
*/
isBrowserDOM(): this is BrowserContext;
/**
* Returns `true` if the context is a browser context.
* @returns `true` if the context is a browser context.
*/
isBrowser(): this is BrowserContext;
/**
* Returns `true` if the context is a headless DOM context.
* @returns `true` if the context is a headless DOM context.
*/
isHeadlessDOM(): this is HeadlessContext;
/**
* Returns `true` if the context is a headless context.
* @returns `true` if the context is a headless context.
*/
isHeadless(): this is HeadlessContext;
/**
* Sets the style of the element.
* @param name - The name of the style to set.
* @param value - The value of the style to set.
*/
setStyle(name: string, value: string): void;
/**
* Gets the style of the element.
* @param name - The name of the style to get.
* @returns The value of the style.
*/
getStyle(name: string): string;
makeAccessors(name: string): {
get: () => any;
set: (value: unknown) => void;
};
getWindow(): Window & typeof globalThis;
moveRangeBefore(startRef: DOMContext, endRef: DOMContext, targetRef: DOMContext): void;
removeRange(startRef: DOMContext, endRef: DOMContext): void;
removeAllBefore(ref: DOMContext): void;
private _detachedParent;
private _detachedNext;
detach(): void;
reattach(): void;
}