Viewport calculations, element dimensions, scroll position management, and coordinate system utilities for responsive layouts and precise positioning.
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);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})`);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');
}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;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)); // trueUtilities 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;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();
}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();// 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';
}