CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ephox--sugar

A comprehensive DOM manipulation library providing type-safe, functional utilities for elements, events, properties, and selections.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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;
}

Install with Tessl CLI

npx tessl i tessl/npm-ephox--sugar

docs

dom.md

events.md

index.md

node.md

properties.md

search.md

selection.md

tag.md

view.md

tile.json