ag-charts-community
Version:
Advanced Charting / Charts supporting Javascript / Typescript / React / Angular / Vue
99 lines (98 loc) • 5.43 kB
TypeScript
import type { Size, SizeMonitor } from '../util/sizeMonitor';
type StyleProperty = '--left' | '--top' | 'height' | 'left' | 'pointer-events' | 'position-anchor' | 'top' | 'translate' | 'width';
type HtmlAttribute = 'aria-atomic' | 'aria-hidden' | 'aria-live' | 'data-axis-id' | 'data-key' | 'popover' | 'role' | 'tabindex';
type CacheKey = 'innerHTML' | 'contentStyles' | 'popover' | `p:${StyleProperty}` | `c:${string}` | `a:${HtmlAttribute}` | `d:${string}`;
export type DeferredMode = {
scheduleFlush: () => void;
};
/**
* Proxies all DOM access to a single HTMLElement.
*
* - Compare-before-write optimisation for hot paths (style properties, classes,
* attributes, innerHTML): a flat key→value cache with `===` comparison skips
* redundant writes. Callers must serialise objects before comparison.
* - Cache lifecycle: `invalidate()` clears a single key; `reset()` clears all
* cached values on hide/destroy transitions.
* - Delegated operations (events, structural mutations) pass through to the
* underlying element without caching.
*
* ## Flush behaviour (deferred mode)
*
* When created with `{ deferredMode }`, all write operations (`setProperty`,
* `toggleClass`, `setAttr`, `setInnerHTML`, `setContentStyles`) are buffered in
* a `pendingWrites` Map and `deferredMode.scheduleFlush()` is called to request
* an async flush via `DOMManager`.
*
* - **Automatic flush**: `DOMManager.setDeferring(false)` schedules a
* `setTimeout(0)` that calls `flush()` on all deferred proxies at the end of
* each render cycle.
* - **Manual flush**: `flush()` and `flushKey()` remain available for callers
* that need explicit control.
*/
export declare class DOMElementProxy {
private readonly element;
private cache;
private readonly pendingWrites;
private readonly deferredMode;
private readonly sizeMonitor;
private readonly skipInitialRead;
constructor(element: HTMLElement, opts?: {
deferredMode?: DeferredMode;
sizeMonitor?: SizeMonitor;
skipInitialRead?: boolean;
});
/** Delegates to `element.isConnected`. */
get isConnected(): boolean;
private scheduleFlush;
/** Delegates to `element.contains()`. */
contains(node: Node | null): boolean;
/** Delegates to `element.addEventListener()`. */
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
/** Delegates to `element.removeEventListener()`. */
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
/** Reads innerHTML — returns cached value when in a deferred-capable proxy since DOM may not have flushed yet. */
get innerHTML(): string;
/** Returns true if value differs from cached (uses ===). Updates cache.
* Callers comparing objects must serialise first (e.g. JSON.stringify). */
changed(key: CacheKey, value: unknown): boolean;
/** Remove a key, forcing next changed() to return true. */
invalidate(key: CacheKey): void;
/** style.setProperty(name, value), skipped if unchanged.
* Works for both standard properties and CSS custom properties. */
setProperty(name: StyleProperty, value: string): void;
/** classList.toggle(name, force), skipped if unchanged. */
toggleClass(name: string, force: boolean): void;
/** setAttribute (value != null) or removeAttribute (value == null). */
setAttr(name: HtmlAttribute, value: string | null): void;
/** element.dataset[name] = value, skipped if unchanged. */
setData(name: string, value: string): void;
/** Returns the cached data attribute value (deferred-capable proxy) or reads from the element. */
getData(name: string): string | undefined;
/** Cached innerHTML write. Returns true if the write happened. */
setInnerHTML(html: string): boolean;
/** Apply styles to the first child element, or the element itself if no children.
* Skipped if styles haven't changed (compared via JSON.stringify). */
setContentStyles(styles: Record<string, string | number | undefined>): void;
/** Flush all pending deferred writes. No-op if not in deferred mode. */
flush(): void;
/** Flush a single pending write by key. */
flushKey(key: CacheKey): void;
/**
* Delegates to element.togglePopover(force).
*
* In deferred mode, show (force=true) is buffered so that innerHTML is flushed first —
* Map insertion order guarantees setInnerHTML() runs before togglePopover(true) since
* show() always writes content before calling toggle(). Hide (force=false) executes
* immediately and cancels any pending show to avoid the element briefly appearing.
*/
togglePopover(force: boolean): void;
/** Delegates to element.appendChild(). No caching — structural mutation. */
appendChild(child: Node): void;
/** Delegates to setting element.innerText. Invalidates innerHTML cache. */
set innerText(text: string);
/** Observe the element for resize events via the shared SizeMonitor. Returns an unsubscribe function. */
addResizeListener(cb: (size: Size) => void): () => void;
/** Clear all cached values. Call on hide/destroy transitions. */
reset(): void;
}
export {};