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

selection.mddocs/

Selection and Ranges

Text selection, range management, and cursor positioning utilities with cross-browser selection handling, position calculations, and comprehensive range operations.

Capabilities

Selection Management

Core selection operations for getting and setting text selections in browser windows.

/**
 * Get current selection from window
 * @param win - Window to get selection from
 * @returns Current selection if one exists
 */
function get(win: SugarElement<Window>): Optional<SimSelection>;

/**
 * Set selection in window
 * @param win - Window to set selection in
 * @param selection - Selection to apply
 */
function set(win: SugarElement<Window>, selection: SimSelection): void;

/**
 * Clear selection in window
 * @param win - Window to clear selection from
 */
function clear(win: SugarElement<Window>): void;

/**
 * Get selection from element's owner window
 * @param element - Element to get selection context from
 * @returns Current selection if one exists
 */
function getFromElement(element: SugarElement<Node>): Optional<SimSelection>;

/**
 * Set selection using element's owner window
 * @param element - Element providing selection context
 * @param selection - Selection to apply
 */
function setToElement(element: SugarElement<Node>, selection: SimSelection): void;

Usage Examples:

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

const win = SugarElement.fromDom(window);

// Get current selection
const currentSelection = WindowSelection.get(win);
currentSelection.each(selection => {
  console.log('Found selection');
});

// Set new selection
const newSelection = SimSelection.exact(
  startElement, 0,
  endElement, 5
);
WindowSelection.set(win, newSelection);

// Clear selection
WindowSelection.clear(win);

SimRange - Simple Range Objects

Simplified range representation for cross-browser compatibility.

/**
 * Create simple range object
 * @param start - Starting element
 * @param soffset - Starting offset within element
 * @param finish - Ending element
 * @param foffset - Ending offset within element
 * @returns Range object
 */
function create(
  start: SugarElement<Node>, 
  soffset: number, 
  finish: SugarElement<Node>, 
  foffset: number
): SimRange;

interface SimRange {
  readonly start: SugarElement<Node>;
  readonly soffset: number;
  readonly finish: SugarElement<Node>;
  readonly foffset: number;
}

Usage Examples:

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

const startElement = SugarElement.fromText('Hello world');
const endElement = SugarElement.fromText('Goodbye');

// Create range from start of first text to end of second
const range = SimRange.create(startElement, 0, endElement, 7);

console.log('Range starts at:', range.start.dom.textContent);
console.log('Range starts at offset:', range.soffset);
console.log('Range ends at:', range.finish.dom.textContent);  
console.log('Range ends at offset:', range.foffset);

SimSelection - Unified Selection API

Unified selection interface handling multiple selection types with pattern matching.

/**
 * Create selection from DOM Range object
 * @param rng - Native DOM Range
 * @returns SimSelection wrapping the range
 */
function domRange(rng: Range): SimSelection;

/**
 * Create selection from relative positions
 * @param startSitu - Starting position
 * @param finishSitu - Ending position
 * @returns SimSelection for relative positions
 */
function relative(startSitu: Situ, finishSitu: Situ): SimSelection;

/**
 * Create selection from exact element positions
 * @param start - Starting element
 * @param soffset - Starting offset
 * @param finish - Ending element  
 * @param foffset - Ending offset
 * @returns SimSelection for exact positions
 */
function exact(
  start: SugarElement<Node>, 
  soffset: number, 
  finish: SugarElement<Node>, 
  foffset: number
): SimSelection;

/**
 * Create selection from SimRange object
 * @param simRange - Range object to convert
 * @returns SimSelection wrapping the range
 */
function exactFromRange(simRange: SimRange): SimSelection;

/**
 * Get window associated with selection
 * @param selection - Selection to get window for
 * @returns Window element for the selection
 */
function getWin(selection: SimSelection): SugarElement<Window>;

interface SimSelection {
  /** Pattern matching for different selection types */
  fold: <U>(
    domRange: (rng: Range) => U,
    relative: (startSitu: Situ, finishSitu: Situ) => U,
    exact: (start: SugarElement<Node>, soffset: number, finish: SugarElement<Node>, foffset: number) => U
  ) => U;
  
  /** Alternative pattern matching syntax */
  match: <U>(branches: {
    domRange: (rng: Range) => U;
    relative: (startSitu: Situ, finishSitu: Situ) => U;
    exact: (start: SugarElement<Node>, soffset: number, finish: SugarElement<Node>, foffset: number) => U;
  }) => U;
  
  /** Debug logging */
  log: (label: string) => void;
}

Usage Examples:

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

// Create different types of selections
const domSelection = SimSelection.domRange(document.getSelection().getRangeAt(0));
const exactSelection = SimSelection.exact(startEl, 0, endEl, 5);

// Use pattern matching to handle different selection types
exactSelection.fold(
  (domRange) => {
    console.log('DOM Range:', domRange.toString());
    return 'dom';
  },
  (startSitu, finishSitu) => {
    console.log('Relative selection');
    return 'relative';
  },
  (start, soffset, finish, foffset) => {
    console.log(`Exact: ${start.dom.textContent}[${soffset}] to ${finish.dom.textContent}[${foffset}]`);
    return 'exact';
  }
);

// Alternative match syntax
const selectionType = exactSelection.match({
  domRange: () => 'native-range',
  relative: () => 'relative-position',
  exact: () => 'exact-position'
});

Situ - Position Objects

Position objects representing locations before, on, or after elements.

/**
 * Create position before an element
 * @param element - Element to position before
 * @returns Position object
 */
function before(element: SugarElement<Node>): Situ;

/**
 * Create position at specific offset within element
 * @param element - Element containing the position
 * @param offset - Offset within the element
 * @returns Position object
 */
function on(element: SugarElement<Node>, offset: number): Situ;

/**
 * Create position after an element
 * @param element - Element to position after
 * @returns Position object
 */
function after(element: SugarElement<Node>): Situ;

/**
 * Pattern match on position type
 * @param subject - Position to match on
 * @param onBefore - Handler for before positions
 * @param onOn - Handler for on positions
 * @param onAfter - Handler for after positions
 * @returns Result of handler function
 */
function cata<U>(
  subject: Situ, 
  onBefore: (element: SugarElement<Node>) => U,
  onOn: (element: SugarElement<Node>, offset: number) => U,
  onAfter: (element: SugarElement<Node>) => U
): U;

/**
 * Get element from position
 * @param situ - Position to extract element from
 * @returns Element referenced by position
 */
function getStart(situ: Situ): SugarElement<Node>;

interface Situ {
  /** Pattern matching for position types */
  fold: <U>(
    before: (element: SugarElement<Node>) => U,
    on: (element: SugarElement<Node>, offset: number) => U,
    after: (element: SugarElement<Node>) => U
  ) => U;
  
  /** Alternative pattern matching syntax */
  match: <U>(branches: {
    before: (element: SugarElement<Node>) => U;
    on: (element: SugarElement<Node>, offset: number) => U;
    after: (element: SugarElement<Node>) => U;
  }) => U;
  
  /** Debug logging */
  log: (label: string) => void;
}

Usage Examples:

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

const element = SugarElement.fromTag('p');

// Create different position types
const beforePos = Situ.before(element);
const onPos = Situ.on(element, 5);
const afterPos = Situ.after(element);

// Use pattern matching
const description = onPos.fold(
  (el) => `Before ${el.dom.tagName}`,
  (el, offset) => `At offset ${offset} in ${el.dom.tagName}`,
  (el) => `After ${el.dom.tagName}`
);

// Extract element from position
const posElement = Situ.getStart(onPos);
console.log('Position element:', posElement.dom.tagName);

// Use in selection creation
const selection = SimSelection.relative(beforePos, afterPos);

Rectangle and Bounds

Geometric utilities for selection bounds and element positioning.

/**
 * Get bounding rectangle for selection
 * @param selection - Selection to get bounds for
 * @returns Rectangle bounds if calculable
 */
function getBounds(selection: SimSelection): Optional<StructRect>;

/**
 * Get bounding rectangle for range
 * @param range - Range to get bounds for
 * @returns Rectangle bounds if calculable
 */
function getRangeRect(range: SimRange): Optional<StructRect>;

/**
 * Get bounding rectangle for element
 * @param element - Element to get bounds for
 * @returns Element's bounding rectangle
 */
function getElementRect(element: SugarElement<Element>): StructRect;

interface StructRect {
  left: () => number;
  top: () => number;
  right: () => number;
  bottom: () => number;
  width: () => number;
  height: () => number;
}

interface RawRect {
  left: number;
  top: number;
  right: number;
  bottom: number;
  width: number;
  height: number;
}

/**
 * Convert structured rectangle to raw object
 * @param sr - Structured rectangle
 * @returns Raw rectangle object
 */
function toRaw(sr: StructRect): RawRect;

Usage Examples:

import { Edge, RawRect, StructRect, SugarElement } from "@ephox/sugar";

// Get selection bounds
const selection = WindowSelection.get(window);
selection.each(sel => {
  const bounds = SelectionBounds.getBounds(sel);
  bounds.each(rect => {
    const raw = Rect.toRaw(rect);
    console.log(`Selection bounds: ${raw.width}x${raw.height} at (${raw.left}, ${raw.top})`);
  });
});

// Get element bounds
const element = SugarElement.fromTag('div');
const elementRect = SelectionBounds.getElementRect(element);
console.log(`Element dimensions: ${elementRect.width()}x${elementRect.height()}`);

Selection Utilities

Advanced selection operations and manipulations.

/**
 * Expand selection to word boundaries
 * @param selection - Selection to expand
 * @returns Expanded selection
 */
function expandToWord(selection: SimSelection): SimSelection;

/**
 * Collapse selection to start position
 * @param selection - Selection to collapse
 * @returns Collapsed selection at start
 */
function collapseToStart(selection: SimSelection): SimSelection;

/**
 * Collapse selection to end position
 * @param selection - Selection to collapse
 * @returns Collapsed selection at end
 */
function collapseToEnd(selection: SimSelection): SimSelection;

/**
 * Check if selection is collapsed (zero width)
 * @param selection - Selection to check
 * @returns True if selection has zero width
 */
function isCollapsed(selection: SimSelection): boolean;

/**
 * Get text content of selection
 * @param selection - Selection to extract text from
 * @returns Text content within selection
 */
function getText(selection: SimSelection): string;

/**
 * Replace selection content with text
 * @param selection - Selection to replace
 * @param text - Text to insert
 * @returns New selection after replacement
 */
function replaceWith(selection: SimSelection, text: string): SimSelection;

/**
 * Delete selection content
 * @param selection - Selection to delete
 * @returns New collapsed selection after deletion
 */
function deleteContents(selection: SimSelection): SimSelection;

Range Conversion

Convert between different range representations.

/**
 * Convert SimSelection to native DOM Range
 * @param selection - Selection to convert
 * @returns Native DOM Range object
 */
function toRange(selection: SimSelection): Range;

/**
 * Convert native DOM Range to SimSelection
 * @param range - Native range to convert
 * @returns SimSelection wrapping the range
 */
function fromRange(range: Range): SimSelection;

/**
 * Convert SimRange to SimSelection
 * @param simRange - Simple range to convert
 * @returns SimSelection for the range
 */
function fromSimRange(simRange: SimRange): SimSelection;

/**
 * Convert SimSelection to SimRange (if possible)
 * @param selection - Selection to convert
 * @returns Simple range if selection can be converted
 */
function toSimRange(selection: SimSelection): Optional<SimRange>;

Types

// Core selection types
interface SimRange {
  readonly start: SugarElement<Node>;
  readonly soffset: number;
  readonly finish: SugarElement<Node>;
  readonly foffset: number;
}

interface SimSelection {
  fold: <U>(
    domRange: (rng: Range) => U,
    relative: (startSitu: Situ, finishSitu: Situ) => U,
    exact: (start: SugarElement<Node>, soffset: number, finish: SugarElement<Node>, foffset: number) => U
  ) => U;
  match: <U>(branches: {
    domRange: (rng: Range) => U;
    relative: (startSitu: Situ, finishSitu: Situ) => U;
    exact: (start: SugarElement<Node>, soffset: number, finish: SugarElement<Node>, foffset: number) => U;
  }) => U;
  log: (label: string) => void;
}

interface Situ {
  fold: <U>(
    before: (element: SugarElement<Node>) => U,
    on: (element: SugarElement<Node>, offset: number) => U,
    after: (element: SugarElement<Node>) => U
  ) => U;
  match: <U>(branches: {
    before: (element: SugarElement<Node>) => U;
    on: (element: SugarElement<Node>, offset: number) => U;
    after: (element: SugarElement<Node>) => U;
  }) => U;
  log: (label: string) => void;
}

// Rectangle types for bounds calculation
interface StructRect {
  left: () => number;
  top: () => number;
  right: () => number;
  bottom: () => number;
  width: () => number;
  height: () => number;
}

interface RawRect {
  left: number;
  top: number;
  right: number;
  bottom: number;
  width: number;
  height: number;
}