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

view.mddocs/

Layout and Positioning

Viewport calculations, element dimensions, scroll position management, and coordinate system utilities for responsive layouts and precise positioning.

Capabilities

Element Dimensions

Comprehensive dimension measurement utilities for elements with different box model considerations.

/**
 * Get inner width of element (content area, excluding padding/border/scrollbar)
 * @param element - Element to measure
 * @returns Inner width in pixels
 */
function getInnerWidth(element: SugarElement<HTMLElement>): number;

/**
 * Get inner height of element (content area, excluding padding/border/scrollbar) 
 * @param element - Element to measure
 * @returns Inner height in pixels
 */
function getInnerHeight(element: SugarElement<HTMLElement>): number;

/**
 * Get outer width of element (includes padding and border)
 * @param element - Element to measure
 * @returns Outer width in pixels
 */
function getOuterWidth(element: SugarElement<HTMLElement>): number;

/**
 * Get outer height of element (includes padding and border)
 * @param element - Element to measure
 * @returns Outer height in pixels
 */
function getOuterHeight(element: SugarElement<HTMLElement>): number;

/**
 * Get client width of element (content + padding, excluding border/scrollbar)
 * @param element - Element to measure
 * @returns Client width in pixels
 */
function getClientWidth(element: SugarElement<HTMLElement>): number;

/**
 * Get client height of element (content + padding, excluding border/scrollbar)
 * @param element - Element to measure  
 * @returns Client height in pixels
 */
function getClientHeight(element: SugarElement<HTMLElement>): number;

/**
 * Get scroll width of element (total scrollable content width)
 * @param element - Element to measure
 * @returns Scroll width in pixels
 */
function getScrollWidth(element: SugarElement<HTMLElement>): number;

/**
 * Get scroll height of element (total scrollable content height)
 * @param element - Element to measure
 * @returns Scroll height in pixels
 */
function getScrollHeight(element: SugarElement<HTMLElement>): number;

Usage Examples:

import { Height, Width, Dimension, SugarElement } from "@ephox/sugar";

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

// Get various dimension measurements
const innerWidth = Dimensions.getInnerWidth(element);    // Content only
const outerWidth = Dimensions.getOuterWidth(element);    // Content + padding + border
const clientWidth = Dimensions.getClientWidth(element);  // Content + padding

console.log(`Element dimensions:
  Inner: ${innerWidth}x${Dimensions.getInnerHeight(element)}
  Outer: ${outerWidth}x${Dimensions.getOuterHeight(element)}
  Client: ${clientWidth}x${Dimensions.getClientHeight(element)}`);

// Check if element has scrollable content
const scrollWidth = Dimensions.getScrollWidth(element);
const scrollHeight = Dimensions.getScrollHeight(element);
const hasHorizontalScroll = scrollWidth > clientWidth;
const hasVerticalScroll = scrollHeight > Dimensions.getClientHeight(element);

Position Calculation

Calculate absolute and relative positions with viewport awareness.

/**
 * Get absolute position of element relative to document
 * @param element - Element to get position for
 * @returns Position coordinates relative to document
 */
function absolute(element: SugarElement<HTMLElement>): SugarPosition;

/**
 * Get position of element relative to another element
 * @param element - Element to get position for
 * @param target - Target element to calculate relative to
 * @returns Position coordinates relative to target
 */
function relative(element: SugarElement<HTMLElement>, target: SugarElement<HTMLElement>): SugarPosition;

/**
 * Get viewport-relative position of element
 * @param element - Element to get position for
 * @returns Position coordinates relative to viewport
 */
function viewport(element: SugarElement<HTMLElement>): SugarPosition;

/**
 * Calculate center point of element
 * @param element - Element to find center for
 * @returns Position of element's center point
 */
function center(element: SugarElement<HTMLElement>): SugarPosition;

/**
 * Get bounding box of element
 * @param element - Element to get bounds for
 * @returns Rectangle containing element bounds
 */
function bounds(element: SugarElement<HTMLElement>): SugarRectangle;

Usage Examples:

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

const element = SugarElement.fromTag('div');
const container = SugarElement.fromTag('div');

// Get different position measurements
const absolutePos = Position.absolute(element);
const relativePos = Position.relative(element, container);
const viewportPos = Position.viewport(element);

console.log(`Element positions:
  Absolute: (${absolutePos.left}, ${absolutePos.top})
  Relative to container: (${relativePos.left}, ${relativePos.top})
  Viewport: (${viewportPos.left}, ${viewportPos.top})`);

// Find element center
const centerPos = Position.center(element);
console.log(`Element center: (${centerPos.left}, ${centerPos.top})`);

// Get bounding box
const elementBounds = Position.bounds(element);
console.log(`Element bounds: ${elementBounds.width}x${elementBounds.height} at (${elementBounds.left}, ${elementBounds.top})`);

Scroll Position Management

Control and monitor scroll positions of elements and viewports.

/**
 * Get current scroll position of element
 * @param element - Element to read scroll position from
 * @returns Current scroll coordinates
 */
function get(element: SugarElement<HTMLElement>): SugarPosition;

/**
 * Set scroll position of element
 * @param element - Element to scroll
 * @param position - Target scroll coordinates
 */
function set(element: SugarElement<HTMLElement>, position: SugarPosition): void;

/**
 * Get scroll left position
 * @param element - Element to read from
 * @returns Horizontal scroll offset in pixels
 */
function getScrollLeft(element: SugarElement<HTMLElement>): number;

/**
 * Set scroll left position
 * @param element - Element to scroll
 * @param left - Horizontal scroll offset in pixels
 */
function setScrollLeft(element: SugarElement<HTMLElement>, left: number): void;

/**
 * Get scroll top position
 * @param element - Element to read from
 * @returns Vertical scroll offset in pixels  
 */
function getScrollTop(element: SugarElement<HTMLElement>): number;

/**
 * Set scroll top position
 * @param element - Element to scroll
 * @param top - Vertical scroll offset in pixels
 */
function setScrollTop(element: SugarElement<HTMLElement>, top: number): void;

/**
 * Scroll element into view
 * @param element - Element to scroll into view
 * @param options - Scroll behavior options
 */
function scrollIntoView(element: SugarElement<HTMLElement>, options?: ScrollIntoViewOptions): void;

/**
 * Scroll to top of element
 * @param element - Element to scroll
 */
function scrollToTop(element: SugarElement<HTMLElement>): void;

/**
 * Scroll to bottom of element
 * @param element - Element to scroll
 */
function scrollToBottom(element: SugarElement<HTMLElement>): void;

/**
 * Check if element is scrollable horizontally
 * @param element - Element to check
 * @returns True if element can scroll horizontally
 */
function isScrollableX(element: SugarElement<HTMLElement>): boolean;

/**
 * Check if element is scrollable vertically
 * @param element - Element to check
 * @returns True if element can scroll vertically
 */
function isScrollableY(element: SugarElement<HTMLElement>): boolean;

Usage Examples:

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

const scrollContainer = SugarElement.fromTag('div');
const targetElement = SugarElement.fromTag('p');

// Get current scroll position
const scrollPos = Scroll.get(scrollContainer);
console.log(`Current scroll: (${scrollPos.left}, ${scrollPos.top})`);

// Set scroll position
const newPos = SugarPosition(100, 200);
Scroll.set(scrollContainer, newPos);

// Individual axis control
Scroll.setScrollTop(scrollContainer, 150);
Scroll.setScrollLeft(scrollContainer, 50);

const currentTop = Scroll.getScrollTop(scrollContainer);
const currentLeft = Scroll.getScrollLeft(scrollContainer);

// Scroll element into view
Scroll.scrollIntoView(targetElement, { behavior: 'smooth', block: 'center' });

// Utility methods
Scroll.scrollToTop(scrollContainer);
Scroll.scrollToBottom(scrollContainer);

// Check scrollability
if (Scroll.isScrollableY(scrollContainer)) {
  console.log('Container can scroll vertically');
}

Viewport Information

Get viewport dimensions and properties for responsive calculations.

/**
 * Get viewport width
 * @param win - Window element to measure (defaults to current window)
 * @returns Viewport width in pixels
 */
function getViewportWidth(win?: SugarElement<Window>): number;

/**
 * Get viewport height  
 * @param win - Window element to measure (defaults to current window)
 * @returns Viewport height in pixels
 */
function getViewportHeight(win?: SugarElement<Window>): number;

/**
 * Get viewport dimensions
 * @param win - Window element to measure (defaults to current window)
 * @returns Viewport width and height
 */
function getViewportSize(win?: SugarElement<Window>): { width: number; height: number };

/**
 * Get document dimensions
 * @param doc - Document element to measure (defaults to current document)
 * @returns Total document width and height
 */
function getDocumentSize(doc?: SugarElement<Document>): { width: number; height: number };

/**
 * Check if element is visible in viewport
 * @param element - Element to check
 * @param threshold - Optional visibility threshold (0-1, defaults to 0)
 * @returns True if element is visible in viewport
 */
function isInViewport(element: SugarElement<HTMLElement>, threshold?: number): boolean;

/**
 * Get percentage of element visible in viewport
 * @param element - Element to check
 * @returns Percentage of element visible (0-1)
 */
function getVisibilityPercentage(element: SugarElement<HTMLElement>): number;

Position Utilities

Utility classes and helper functions for position calculations.

/**
 * Create position object
 * @param left - Horizontal coordinate
 * @param top - Vertical coordinate
 * @returns Position object with utility methods
 */
function SugarPosition(left: number, top: number): SugarPosition;

interface SugarPosition {
  readonly left: number;
  readonly top: number;
  /** Translate position by offset amounts */
  readonly translate: (x: number, y: number) => SugarPosition;
  /** Add another position to this one */
  readonly add: (other: SugarPosition) => SugarPosition;
  /** Subtract another position from this one */
  readonly subtract: (other: SugarPosition) => SugarPosition;
  /** Calculate distance to another position */
  readonly distanceTo: (other: SugarPosition) => number;
  /** Convert to plain object */
  readonly toObject: () => { left: number; top: number };
}

/**
 * Create rectangle object
 * @param left - Left coordinate
 * @param top - Top coordinate  
 * @param width - Rectangle width
 * @param height - Rectangle height
 * @returns Rectangle object with utility methods
 */
function SugarRectangle(left: number, top: number, width: number, height: number): SugarRectangle;

interface SugarRectangle {
  readonly left: number;
  readonly top: number;
  readonly width: number;
  readonly height: number;
  readonly right: number;
  readonly bottom: number;
  /** Check if rectangle contains point */
  readonly contains: (position: SugarPosition) => boolean;
  /** Check if rectangle overlaps with another */
  readonly overlaps: (other: SugarRectangle) => boolean;
  /** Get intersection with another rectangle */
  readonly intersect: (other: SugarRectangle) => Optional<SugarRectangle>;
  /** Get center point of rectangle */
  readonly center: () => SugarPosition;
}

Usage Examples:

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

// Viewport information
const viewportSize = Viewport.getViewportSize();
console.log(`Viewport: ${viewportSize.width}x${viewportSize.height}`);

const documentSize = Viewport.getDocumentSize();
console.log(`Document: ${documentSize.width}x${documentSize.height}`);

// Element visibility
const element = SugarElement.fromTag('div');
const isVisible = Viewport.isInViewport(element);
const visibilityPercent = Viewport.getVisibilityPercentage(element);
console.log(`Element visible: ${isVisible}, ${(visibilityPercent * 100).toFixed(1)}% shown`);

// Position calculations
const pos1 = SugarPosition(10, 20);
const pos2 = SugarPosition(30, 40);
const combined = pos1.add(pos2);        // (40, 60)
const translated = pos1.translate(5, 10); // (15, 30)
const distance = pos1.distanceTo(pos2);   // ~28.28

// Rectangle operations
const rect1 = SugarRectangle(0, 0, 100, 100);
const rect2 = SugarRectangle(50, 50, 100, 100);

const overlaps = rect1.overlaps(rect2);           // true
const intersection = rect1.intersect(rect2);      // Rectangle(50, 50, 50, 50)
const center = rect1.center();                   // Position(50, 50)
const containsPoint = rect1.contains(SugarPosition(25, 75)); // true

Measurement Utilities

Utilities for measuring text, images, and other content.

/**
 * Measure text dimensions with specific font
 * @param text - Text content to measure
 * @param font - Font specification (CSS font shorthand)
 * @returns Text width and height in pixels
 */
function measureText(text: string, font: string): { width: number; height: number };

/**
 * Get natural dimensions of image
 * @param image - Image element to measure
 * @returns Natural width and height of image
 */
function getImageDimensions(image: SugarElement<HTMLImageElement>): { width: number; height: number };

/**
 * Calculate optimal font size to fit text in container
 * @param text - Text to fit
 * @param container - Container element
 * @param maxSize - Maximum font size to consider
 * @returns Optimal font size in pixels
 */
function calculateFontSize(text: string, container: SugarElement<HTMLElement>, maxSize: number): number;

Platform and Touch Detection

Detect device capabilities and screen sizes for responsive behavior.

/**
 * Check if device supports touch input
 * @returns True if touch is available
 */
function isTouch(): boolean;

/**
 * Check if screen size is large (desktop-like)
 * @returns True if screen is large
 */
function isLarge(): boolean;

/**
 * Check if device is large touch screen (tablet)
 * @returns True if large touch device
 */
function isLargeTouch(): boolean;

/**
 * Check if device is small touch screen (phone)
 * @returns True if small touch device
 */
function isSmallTouch(): boolean;

/**
 * Check if device is large desktop (wide screen)
 * @returns True if large desktop
 */
function isLargeDesktop(): boolean;

/**
 * Check if device is small Android device
 * @returns True if small Android
 */
function isSmallAndroid(): boolean;

/**
 * Choose appropriate behavior based on platform capabilities
 * @param large - Configuration for large screens
 * @param small - Configuration for small screens
 * @returns Selected configuration based on screen size
 */
function choice<T>(large: T, small: T): T;

Usage Examples:

import { Platform } from "@ephox/sugar";

// Responsive behavior based on platform
if (Platform.isTouch()) {
  // Enable touch-optimized interactions
  addTouchHandlers();
} else {
  // Enable mouse-optimized interactions  
  addMouseHandlers();
}

// Screen size specific logic
const config = Platform.choice(
  { itemsPerRow: 4, fontSize: 16 }, // Large screen config
  { itemsPerRow: 2, fontSize: 14 }  // Small screen config
);

// Platform-specific optimizations
if (Platform.isSmallAndroid()) {
  // Apply Android-specific workarounds
  enableAndroidOptimizations();
}

Visual Viewport API

Modern viewport handling for mobile browsers with on-screen keyboards and zoom.

/**
 * Get visual viewport information from window
 * @param win - Window to get viewport from
 * @returns Visual viewport data if supported
 */
function get(win: SugarElement<Window>): Optional<VisualViewport>;

/**
 * Get viewport bounds (position and size)
 * @param win - Window to get bounds from
 * @returns Viewport bounds object
 */
function getBounds(win: SugarElement<Window>): Bounds;

/**
 * Bind to visual viewport resize events
 * @param win - Window to monitor
 * @param handler - Callback for viewport changes
 * @returns Event unbinder function
 */
function bind(win: SugarElement<Window>, handler: () => void): () => void;

interface Bounds {
  readonly x: number;
  readonly y: number;
  readonly width: number;
  readonly height: number;
}

Usage Examples:

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

const win = SugarElement.fromDom(window);

// Monitor viewport changes (mobile keyboard, zoom, etc.)
const unbindViewport = WindowVisualViewport.bind(win, () => {
  const bounds = WindowVisualViewport.getBounds(win);
  console.log('Viewport changed:', bounds);
  
  // Adjust UI for mobile keyboard
  if (bounds.height < window.innerHeight * 0.7) {
    adjustForKeyboard();
  } else {
    restoreNormalLayout();
  }
});

// Get current viewport info
WindowVisualViewport.get(win).each((viewport) => {
  console.log('Visual viewport supported');
  console.log('Scale:', viewport.scale);
  console.log('Size:', viewport.width, 'x', viewport.height);
});

// Clean up when done
unbindViewport();

Types

// Position object with utility methods
interface SugarPosition {
  readonly left: number;
  readonly top: number;
  readonly translate: (x: number, y: number) => SugarPosition;
  readonly add: (other: SugarPosition) => SugarPosition;
  readonly subtract: (other: SugarPosition) => SugarPosition;
  readonly distanceTo: (other: SugarPosition) => number;
  readonly toObject: () => { left: number; top: number };
}

// Rectangle object with utility methods
interface SugarRectangle {
  readonly left: number;
  readonly top: number;
  readonly width: number;
  readonly height: number;
  readonly right: number;
  readonly bottom: number;
  readonly contains: (position: SugarPosition) => boolean;
  readonly overlaps: (other: SugarRectangle) => boolean;
  readonly intersect: (other: SugarRectangle) => Optional<SugarRectangle>;
  readonly center: () => SugarPosition;
}

// Dimension measurements
interface Dimensions {
  width: number;
  height: number;
}

// Viewport size information  
interface ViewportSize {
  width: number;
  height: number;
}

// Standard ScrollIntoViewOptions for cross-browser compatibility
interface ScrollIntoViewOptions {
  behavior?: 'auto' | 'smooth';
  block?: 'start' | 'center' | 'end' | 'nearest';
  inline?: 'start' | 'center' | 'end' | 'nearest';
}