UNPKG

element-crafter

Version:

A zero-dependency TypeScript library for creating HTML elements in both SSR and client-side environments

250 lines (249 loc) 8.52 kB
/** * Supported attribute value types for HTML elements. */ export type AttributeValue = string | number | boolean | null | undefined; /** * Event handler function type for DOM events. */ export type EventHandler = (event: Event) => void; /** * HTML element attributes including event handlers. */ export interface Attributes { [key: string]: AttributeValue | EventHandler; } /** * Content that can be rendered as HTML. */ export type RenderableContent = string | number | Node | null | undefined | RenderableContent[]; /** * Configuration for the HTML builder. */ export interface BuilderConfig { /** Whether to generate SSR-compatible HTML strings */ isSsr: boolean; /** * Whether to escape HTML content by default. * * @remarks * - For SSR, set to `true` to escape all content by default (prevents XSS). * - For client-side, set to `false` if you trust the content source (DOM APIs are safe). * - Smart escaping: Tags like `script`, `style`, `pre`, `code`, and `textarea` automatically disable escaping regardless of this setting. * - You can override escaping behavior for specific elements using the `escapeContent` option in `CreateElementOptions`. * - Always escape user-generated content, but markup, CSS, or JS code is automatically handled correctly. */ escapeContent?: boolean; /** Whether to validate attributes */ validateAttributes?: boolean; /** Custom void tags (in addition to standard HTML5 void tags) */ customVoidTags?: Set<string>; } /** * Options for creating HTML elements. */ export interface CreateElementOptions { /** * Whether to escape the content of this specific element. * * @remarks * - Overrides the global `escapeContent` setting for this element. * - For SSR, set to `false` for elements containing raw HTML, CSS, or JS. * - For user-generated content, set to `true` to prevent XSS. * - Note: Tags like `script`, `style`, `pre`, `code`, and `textarea` automatically disable escaping unless explicitly overridden. */ escapeContent?: boolean; /** Whether to validate attributes for this specific element */ validateAttributes?: boolean; } /** * Universal HTML builder for SSR and client-side rendering. * * @remarks * Provides a consistent API for creating HTML elements and managing content * across different rendering environments. Supports attribute validation, * content escaping, and performance optimizations. * * @example * ```typescript * // SSR usage * const ssrBuilder = new HtmlBuilder({ isSsr: true }); * const html = ssrBuilder.createElement('div', { class: 'container' }, 'Content'); * * // Client usage * const clientBuilder = new HtmlBuilder({ isSsr: false }); * const element = clientBuilder.createElement('button', { onclick: handleClick }, 'Click me'); * ``` */ export declare class HtmlBuilder { private readonly config; /** Standard HTML5 void elements */ private static readonly STANDARD_VOID_TAGS; /** Boolean attributes that don't need values */ private static readonly BOOLEAN_ATTRIBUTES; /** Tags that typically contain raw content and should not be escaped by default */ private static readonly NO_ESCAPE_TAGS; /** * Creates a new HTML builder instance. * * @param config - Builder configuration */ constructor(config: BuilderConfig); /** * Gets whether the builder is in SSR mode. */ get isSsr(): boolean; /** * Gets all void tags (standard + custom). */ private get voidTags(); /** * Escapes HTML content to prevent XSS attacks. * * @param content - Content to escape * @returns Escaped content */ static escapeHtml(content: unknown): string; /** * Determines whether content should be escaped based on tag name and explicit options. * * @param tagName - HTML tag name * @param explicitEscape - Explicit escape option from CreateElementOptions * @returns Whether content should be escaped * * @remarks * This method implements smart tag-based auto-escaping: * - Explicit options always take precedence * - Tags like script, style, pre, code automatically disable escaping * - Other tags use the global escapeContent setting */ private shouldEscapeContent; /** * Validates attribute name and value. * * @param name - Attribute name. * @param value - Attribute value. * @throws {TypeError} If the attribute name is invalid. * @throws {DOMException} If the attribute value is potentially unsafe. */ private validateAttribute; /** * Builds attribute string for SSR. * * @param attributes - Element attributes * @returns Formatted attribute string */ private buildAttributeString; /** * Flattens nested content arrays. * * @param content - Content to flatten * @returns Flattened content array */ private flattenContent; /** * Processes content for rendering. * * @param content - Raw content * @param escapeContent - Whether to escape content * @returns Processed content string */ private processContent; /** * Creates an HTML element. * * @param tagName - HTML tag name * @param attributes - Element attributes * @param options - Creation options * @param children - Child content * @returns DOM element or HTML string */ createElement<K extends keyof HTMLElementTagNameMap>(tagName: K, attributes?: Attributes, options?: CreateElementOptions, ...children: RenderableContent[]): HTMLElementTagNameMap[K] | string; /** * Creates an element for SSR (returns HTML string). */ private createElementSSR; /** * Creates an element for client-side (returns DOM element). */ private createElementClient; /** * Creates a text node or text content. * * @param text - Text content * @param escape - Whether to escape the text * @returns Text node or escaped string */ createText(text: string, escape?: boolean): Text | string | { __escaped: true; value: string; }; /** * Creates a document fragment or concatenated HTML. * * @param children - Child content * @returns Document fragment or HTML string */ createFragment(...children: RenderableContent[]): DocumentFragment | string; } /** * Page builder utilities for creating complete HTML documents. * * @remarks * Provides utilities for building complete HTML pages with proper structure, * meta tags, and content integration. */ export declare class PageBuilder { /** * Builds a complete HTML page with proper document structure. * * @param options - Page configuration options * @returns Complete HTML document string * * @example * ```typescript * const html = PageBuilder.buildPage({ * title: 'My App', * head: '<meta name="description" content="My awesome app">', * body: '<div class="app">Hello World</div>', * scripts: '<script src="/app.js"></script>' * }); * ``` */ static buildPage(options: { title: string; head?: string; body: string; scripts?: string; lang?: string; charset?: string; }): string; /** * Builds an HTML page using template replacement. * * @param templateContent - The HTML template content with placeholders * @param replacements - Object containing placeholder replacements * @returns Processed HTML string * * @example * ```typescript * const html = PageBuilder.buildFromTemplate(templateHtml, { * '{{TITLE}}': 'My App', * '{{CONTENT}}': '<div>Hello World</div>' * }); * ``` */ static buildFromTemplate(templateContent: string, replacements: Record<string, string>): string; } /** * Creates a new HTML builder instance. */ export declare function createHtmlBuilder(config: BuilderConfig): HtmlBuilder; /** * Creates an HTML builder configured for server-side rendering. */ export declare function createSSRBuilder(options?: Omit<BuilderConfig, "isSsr">): HtmlBuilder; /** * Creates an HTML builder configured for client-side rendering. */ export declare function createClientBuilder(options?: Omit<BuilderConfig, "isSsr">): HtmlBuilder; export default HtmlBuilder;