or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

dom.mdevents.mdindex.mdnode.mdproperties.mdsearch.mdselection.mdtag.mdview.md
tile.json

events.mddocs/

Event Handling

Comprehensive event management system providing type-safe event binding, custom event objects, specialized mouse/keyboard handlers, and async event utilities.

Capabilities

Core Event Binding

Bind and unbind event listeners with full type safety and consistent event object structure.

/**
 * Bind event listener to element
 * @param element - Element to attach listener to
 * @param event - Event type to listen for
 * @param handler - Event handler function
 * @returns Unbinder object to remove the listener
 */
function bind<K extends keyof HTMLElementEventMap, T extends Node | Window = Node>(
  element: SugarElement<EventTarget>, 
  event: K, 
  handler: EventHandler<HTMLElementEventMap[K], T>
): EventUnbinder;

/**
 * Bind capturing event listener to element
 * @param element - Element to attach listener to
 * @param event - Event type to listen for
 * @param handler - Event handler function  
 * @returns Unbinder object to remove the listener
 */
function capture<K extends keyof HTMLElementEventMap, T extends Node | Window = Node>(
  element: SugarElement<EventTarget>, 
  event: K, 
  handler: EventHandler<HTMLElementEventMap[K], T>
): EventUnbinder;

/**
 * Convert raw DOM event to Sugar event format
 * @param rawEvent - Native DOM event
 * @returns Sugar-formatted event arguments
 */
function fromRawEvent<E extends Event>(rawEvent: E): EventArgs<E>;

Usage Examples:

import { SugarElement, DomEvent } from "@ephox/sugar";

const button = SugarElement.fromTag('button');

// Basic click handler
const unbindClick = DomEvent.bind(button, 'click', (evt) => {
  console.log('Clicked at:', evt.x, evt.y);
  evt.prevent(); // Prevent default action
  evt.stop(); // Stop propagation
});

// Capturing listener for early event interception
const unbindCapture = DomEvent.capture(document.body, 'keydown', (evt) => {
  if (evt.raw.key === 'Escape') {
    evt.kill(); // Stop and prevent
  }
});

// Clean up when done
unbindClick.unbind();
unbindCapture.unbind();

Specialized Mouse Events

Pre-configured mouse event handlers for common interaction patterns.

/**
 * Real (non-synthetic) click event handler
 */
interface RealClickHandler {
  bind(element: SugarElement<EventTarget>, handler: EventHandler<MouseEvent>): EventUnbinder;
}

/**
 * Left mouse button down event handler  
 */
interface LeftDownHandler {
  bind(element: SugarElement<EventTarget>, handler: EventHandler<MouseEvent>): EventUnbinder;
}

/**
 * Mouse over event with left button pressed
 */
interface LeftPressedOverHandler {
  bind(element: SugarElement<EventTarget>, handler: EventHandler<MouseEvent>): EventUnbinder;
}

/**
 * Left mouse button up event handler
 */
interface LeftUpHandler {
  bind(element: SugarElement<EventTarget>, handler: EventHandler<MouseEvent>): EventUnbinder;
}

// Pre-configured mouse event objects
const realClick: RealClickHandler;
const leftDown: LeftDownHandler;  
const leftPressedOver: LeftPressedOverHandler;
const leftUp: LeftUpHandler;

Usage Examples:

import { MouseEvents, SugarElement } from "@ephox/sugar";

const canvas = SugarElement.fromTag('canvas');

// Handle mouse dragging
let isDragging = false;

MouseEvents.leftDown.bind(canvas, (evt) => {
  isDragging = true;
  console.log('Drag started at:', evt.x, evt.y);
});

MouseEvents.leftPressedOver.bind(canvas, (evt) => {
  if (isDragging) {
    console.log('Dragging to:', evt.x, evt.y);
  }
});

MouseEvents.leftUp.bind(document.body, (evt) => {
  if (isDragging) {
    isDragging = false;
    console.log('Drag ended at:', evt.x, evt.y);
  }
});

Readiness and Loading

Handle document and resource loading states with promises and callbacks.

/**
 * Execute callback when document is ready
 * @param f - Function to execute when document ready
 */
function document(f: () => void): void;

/**
 * Wait for image to load completely
 * @param image - Image element to monitor
 * @returns Promise that resolves when image loads
 */
function image(image: SugarElement<HTMLImageElement>): Promise<SugarElement<HTMLImageElement>>;

Usage Examples:

import { Ready, SugarElement } from "@ephox/sugar";

// Wait for document ready
Ready.document(() => {
  console.log('Document is ready for manipulation');
  // Initialize application
});

// Wait for specific image
const img = SugarElement.fromTag('img');
img.dom.src = 'large-image.jpg';

Ready.image(img).then((loadedImg) => {
  console.log('Image loaded successfully');
  // Proceed with image-dependent operations
}).catch((error) => {
  console.error('Image failed to load');
});

Element Resize Monitoring

Monitor element size changes with ResizeObserver-based detection.

/**
 * Start monitoring element for resize changes
 * @param element - Element to monitor
 * @param handler - Callback function for resize events
 */
function bind(element: SugarElement<HTMLElement>, handler: () => void): void;

/**
 * Stop monitoring element for resize changes
 * @param element - Element to stop monitoring
 * @param handler - Handler function to remove
 */
function unbind(element: SugarElement<Node>, handler: () => void): void;

Scroll Change Detection

Monitor scroll position changes across the document.

/**
 * Monitor scroll position changes on document
 * @param doc - Document to monitor
 * @param handler - Callback receiving new scroll position
 * @returns Unbinder to stop monitoring
 */
function bind(doc: SugarElement<Document>, handler: (pos: SugarPosition) => void): EventUnbinder;

Visibility Detection

Execute callbacks when elements become visible or hidden.

/**
 * Execute callback when element becomes visible in viewport
 * @param element - Element to monitor for visibility
 * @param f - Callback to execute when visible
 * @returns Function to stop monitoring
 */
function onShow(element: SugarElement<HTMLElement>, f: () => void): () => void;

Async Event Utilities

Wait for specific events to occur with timeout support.

/**
 * Wait for event to occur with timeout (lazy evaluation)
 * @param element - Element to listen on
 * @param eventType - Type of event to wait for
 * @param timeout - Timeout in milliseconds
 * @returns Lazy value that resolves to event result
 */
function cWaitFor(
  element: SugarElement<EventTarget>, 
  eventType: string, 
  timeout: number
): LazyValue<Result<EventArgs, string>>;

/**
 * Wait for event to occur with timeout (immediate future)
 * @param element - Element to listen on
 * @param eventType - Type of event to wait for  
 * @param timeout - Timeout in milliseconds
 * @returns Future that resolves to event result
 */
function waitFor(
  element: SugarElement<EventTarget>, 
  eventType: string, 
  timeout: number
): Future<Result<EventArgs, string>>;

Usage Examples:

import { DomFuture, SugarElement } from "@ephox/sugar";

const button = SugarElement.fromTag('button');

// Wait for click with timeout
DomFuture.waitFor(button, 'click', 5000).get((result) => {
  result.fold(
    (eventArgs) => {
      console.log('Button was clicked!', eventArgs);
    },
    (error) => {
      console.log('Timeout waiting for click:', error);
    }
  );
});

Asynchronous Event Handling

Future-based event utilities for waiting on specific events with timeouts.

/**
 * Wait for an event with timeout, returns a Future
 * @param element - Element to listen on
 * @param eventType - Event type to wait for
 * @param timeout - Timeout in milliseconds
 * @returns Future that resolves with event or error on timeout
 */
function waitFor(
  element: SugarElement<EventTarget>, 
  eventType: string, 
  timeout: number
): Future<Result<EventArgs, string>>;

/**
 * Create a lazy evaluator that waits for an event with timeout
 * @param element - Element to listen on
 * @param eventType - Event type to wait for  
 * @param timeout - Timeout in milliseconds
 * @returns LazyValue that can be evaluated to wait for the event
 */
function cWaitFor(
  element: SugarElement<EventTarget>, 
  eventType: string, 
  timeout: number
): LazyValue<Result<EventArgs, string>>;

Usage Examples:

import { DomFuture, SugarElement } from "@ephox/sugar";

const button = SugarElement.fromTag('button');

// Wait for click with 5 second timeout
DomFuture.waitFor(button, 'click', 5000).get((result) => {
  result.fold(
    (eventArgs) => console.log('Button clicked!', eventArgs),
    (error) => console.log('Timeout:', error)
  );
});

// Lazy evaluation approach
const clickWaiter = DomFuture.cWaitFor(button, 'click', 3000);
// Later when needed:
clickWaiter.get().fold(
  (eventArgs) => console.log('Got click'),
  (error) => console.log('Timed out')
);

Scroll Change Detection

Enhanced scroll event handling that only fires when scroll position actually changes.

/**
 * Bind scroll event listener that only fires on actual position changes
 * @param doc - Document element to monitor for scroll
 * @param handler - Callback function receiving scroll position
 * @returns Event unbinder
 */
function bind(doc: SugarElement<Document>, handler: (pos: SugarPosition) => void): EventUnbinder;

Usage Examples:

import { ScrollChange, SugarDocument } from "@ephox/sugar";

const doc = SugarDocument.getDocument();

// Monitor scroll changes
const unbindScroll = ScrollChange.bind(doc, (pos) => {
  console.log('Scroll position changed:', pos.left, pos.top);
  
  // Update floating header position
  if (pos.top > 100) {
    floatingHeader.classList.add('fixed');
  } else {
    floatingHeader.classList.remove('fixed');
  }
});

// Clean up when done
unbindScroll.unbind();

Element Visibility Monitoring

Monitor elements for visibility changes using MutationObserver or polling fallback.

/**
 * Execute callback when element becomes visible
 * @param element - Element to monitor for visibility
 * @param callback - Function to execute when element becomes visible
 * @returns Function to stop monitoring
 */
function onShow(element: SugarElement<HTMLElement>, callback: () => void): () => void;

Usage Examples:

import { Viewable, SugarElement } from "@ephox/sugar";

const modal = SugarElement.fromTag('div');
modal.dom.style.display = 'none';

// Setup visibility monitoring
const stopMonitoring = Viewable.onShow(modal, () => {
  console.log('Modal is now visible!');
  // Initialize modal content, start animations, etc.
});

// Later, show the modal
modal.dom.style.display = 'block'; // Callback will fire

// Stop monitoring when done
stopMonitoring();

Types

/**
 * Normalized event object with consistent structure across browsers
 */
interface EventArgs<E = Event, T extends Node | Window = Node> {
  /** Element that received the event */
  readonly target: SugarElement<T>;
  /** X coordinate for mouse events, undefined for others */
  readonly x: E extends { clientX: number } ? number : undefined;
  /** Y coordinate for mouse events, undefined for others */
  readonly y: E extends { clientY: number } ? number : undefined;
  /** Stop event propagation */
  readonly stop: () => void;
  /** Prevent default action */
  readonly prevent: () => void; 
  /** Stop propagation and prevent default */
  readonly kill: () => void;
  /** Original native event object */
  readonly raw: E;
}

/**
 * Event handler function type
 */
type EventHandler<E = Event, T extends Node | Window = Node> = (evt: EventArgs<E, T>) => void;

/**
 * Event filter predicate function
 */
type EventFilter<E = Event> = (evt: E) => boolean;

/**
 * Object returned by event binding functions for cleanup
 */
interface EventUnbinder {
  unbind: () => void;
}

// Position type from view package
interface SugarPosition {
  readonly left: number;
  readonly top: number;
  readonly translate: (x: number, y: number) => SugarPosition;
}

// Async utility types from @ephox/katamari
interface LazyValue<T> {
  get(): T;
}

interface Future<T> {
  get(callback: (value: T) => void): void;
}

interface Result<T, E> {
  fold<U>(success: (value: T) => U, failure: (error: E) => U): U;
}