UNPKG

@ckeditor/ckeditor5-utils

Version:

Miscellaneous utilities used by CKEditor 5.

212 lines (211 loc) 8.01 kB
/** * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ import Rect, { type RectSource } from './rect.js'; /** * Calculates the `position: absolute` coordinates of a given element so it can be positioned with respect to the * target in the visually most efficient way, taking various restrictions like viewport or limiter geometry * into consideration. * * **Note**: If there are no position coordinates found that meet the requirements (arguments of this helper), * `null` is returned. * * ```ts * // The element which is to be positioned. * const element = document.body.querySelector( '#toolbar' ); * * // A target to which the element is positioned relatively. * const target = document.body.querySelector( '#container' ); * * // Finding the optimal coordinates for the positioning. * const { left, top, name } = getOptimalPosition( { * element: element, * target: target, * * // The algorithm will chose among these positions to meet the requirements such * // as "limiter" element or "fitInViewport", set below. The positions are considered * // in the order of the array. * positions: [ * // * // [ Target ] * // +-----------------+ * // | Element | * // +-----------------+ * // * targetRect => ( { * top: targetRect.bottom, * left: targetRect.left, * name: 'mySouthEastPosition' * } ), * * // * // +-----------------+ * // | Element | * // +-----------------+ * // [ Target ] * // * ( targetRect, elementRect ) => ( { * top: targetRect.top - elementRect.height, * left: targetRect.left, * name: 'myNorthEastPosition' * } ) * ], * * // Find a position such guarantees the element remains within visible boundaries of <body>. * limiter: document.body, * * // Find a position such guarantees the element remains within visible boundaries of the browser viewport. * fitInViewport: true * } ); * * // The best position which fits into document.body and the viewport. May be useful * // to set proper class on the `element`. * console.log( name ); // -> "myNorthEastPosition" * * // Using the absolute coordinates which has been found to position the element * // as in the diagram depicting the "myNorthEastPosition" position. * element.style.top = top; * element.style.left = left; * ``` * * @param options The input data and configuration of the helper. */ export declare function getOptimalPosition({ element, target, positions, limiter, fitInViewport, viewportOffsetConfig }: Options): DomPoint | null; /** * A position object which instances are created and used by the {@link module:utils/dom/position~getOptimalPosition} helper. * * {@link module:utils/dom/position~DomPoint#top} and {@link module:utils/dom/position~DomPoint#left} properties of the position instance * translate directly to the `top` and `left` properties in CSS "`position: absolute` coordinate system". If set on the positioned element * in DOM, they will make it display it in the right place in the viewport. */ export interface DomPoint { /** * Position name. */ readonly name?: string; /** * Additional position configuration, as passed from the {@link module:utils/dom/position~PositioningFunction positioning function}. * * This object can be use, for instance, to pass through presentation options used by the consumer of the * {@link module:utils/dom/position~getOptimalPosition} helper. */ readonly config?: object; /** * The left value in pixels in the CSS `position: absolute` coordinate system. * Set it on the positioned element in DOM to move it to the position. */ readonly left: number; /** * The top value in pixels in the CSS `position: absolute` coordinate system. * Set it on the positioned element in DOM to move it to the position. */ readonly top: number; } /** * The `getOptimalPosition()` helper options. */ export interface Options { /** * Element that is to be positioned. */ readonly element: HTMLElement; /** * Target with respect to which the `element` is to be positioned. */ readonly target: RectSource | (() => RectSource); /** * An array of positioning functions. * * **Note**: Positioning functions are processed in the order of preference. The first function that works * in the current environment (e.g. offers the complete fit in the viewport geometry) will be picked by * `getOptimalPosition()`. * * **Note**: Any positioning function returning `null` is ignored. */ readonly positions: ReadonlyArray<PositioningFunction>; /** * When set, the algorithm will chose position which fits the most in the * limiter's bounding rect. */ readonly limiter?: RectSource | (() => (RectSource | null)) | null; /** * When set, the algorithm will chose such a position which fits `element` * the most inside visible viewport. */ readonly fitInViewport?: boolean; /** * Viewport offset config object. It restricts the visible viewport available to the `getOptimalPosition()` from each side. * * ```ts * { * top: 50, * right: 50, * bottom: 50, * left: 50 * } * ``` */ readonly viewportOffsetConfig?: { readonly top?: number; readonly right?: number; readonly bottom?: number; readonly left?: number; }; } /** * A positioning function which, based on positioned element and target {@link module:utils/dom/rect~Rect Rects}, returns rect coordinates * representing the geometrical relation between them. Used by the {@link module:utils/dom/position~getOptimalPosition} helper. * * ```ts * // This simple position will place the element directly under the target, in the middle: * // * // [ Target ] * // +-----------------+ * // | Element | * // +-----------------+ * // * const position = ( targetRect, elementRect, [ viewportRect ] ) => ( { * top: targetRect.bottom, * left: targetRect.left + targetRect.width / 2 - elementRect.width / 2, * name: 'bottomMiddle', * * // Note: The config is optional. * config: { * zIndex: '999' * } * } ); * ``` * * @param elementRect The rect of the element to be positioned. * @param targetRect The rect of the target the element (its rect) is relatively positioned to. * @param viewportRect The rect of the visual browser viewport. * @returns When the function returns `null`, it will not be considered by {@link module:utils/dom/position~getOptimalPosition}. */ export type PositioningFunction = (elementRect: Rect, targetRect: Rect, viewportRect: Rect, limiterRect?: Rect) => PositioningFunctionResult | null; /** * The result of {@link module:utils/dom/position~PositioningFunction}. */ export interface PositioningFunctionResult { /** * The `top` value of the element rect that would represent the position. */ top: number; /** * The `left` value of the element rect that would represent the position. */ left: number; /** * The name of the position. It helps the user of the {@link module:utils/dom/position~getOptimalPosition} * helper to recognize different positioning function results. It will pass through to the {@link module:utils/dom/position~DomPoint} * returned by the helper. */ name?: string; /** * An optional configuration that will pass-through the {@link module:utils/dom/position~getOptimalPosition} helper * to the {@link module:utils/dom/position~DomPoint} returned by this helper. * This configuration may, for instance, let the user of {@link module:utils/dom/position~getOptimalPosition} know that this particular * position comes with a certain presentation. */ config?: object; }