import type { WalkontableInstance } from '../../types'; import type EventManager from '../../../../../eventManager'; import type { BorderInstanceSettings, CornerDefaultStyle, SelectionHandles, AdjustHandles, MoveZone } from './types'; /** * */ declare class Border { /** * @type {EventManager} */ eventManager: EventManager; /** * @type {WalkontableInstance} */ wot: WalkontableInstance; /** * @type {BorderInstanceSettings} */ settings: BorderInstanceSettings; /** * @type {boolean} */ mouseDown: boolean; /** * @type {HTMLDivElement | null} */ main: HTMLDivElement | null; /** * @type {HTMLElement | null} */ top: HTMLElement | null; /** * @type {HTMLElement | null} */ bottom: HTMLElement | null; /** * @type {HTMLElement | null} */ start: HTMLElement | null; /** * @type {HTMLElement | null} */ end: HTMLElement | null; /** * @type {CSSStyleDeclaration | null} */ topStyle: CSSStyleDeclaration | null; /** * @type {CSSStyleDeclaration | null} */ bottomStyle: CSSStyleDeclaration | null; /** * @type {CSSStyleDeclaration | null} */ startStyle: CSSStyleDeclaration | null; /** * @type {CSSStyleDeclaration | null} */ endStyle: CSSStyleDeclaration | null; /** * @type {CornerDefaultStyle} */ cornerDefaultStyle: CornerDefaultStyle; /** * @type {number} */ cornerCenterPointOffset: number; /** * @type {HTMLElement | null} */ corner: HTMLElement | null; /** * @type {CSSStyleDeclaration | null} */ cornerStyle: CSSStyleDeclaration | null; /** * @type {SelectionHandles} */ selectionHandles: SelectionHandles; /** * Created lazily on the first `appear()` whose visibility predicate resolves truthy, so it stays * `undefined` while the `selectionHandles` option is off. * * @type {AdjustHandles | undefined} */ adjustHandles: AdjustHandles | undefined; /** * Created lazily on the first `appear()` whose visibility predicate resolves truthy, so it stays * `undefined` while the `moveCells` option is off. * * @type {MoveZone | undefined} */ moveZone: MoveZone | undefined; /** * @type {boolean} */ disabled: boolean; /** * @param {WalkontableFacade} wotInstance The Walkontable instance. * @param {object} settings The border settings. */ constructor(wotInstance: WalkontableInstance, settings: BorderInstanceSettings); /** * Register all necessary events. */ registerListeners(): void; /** * Mouse down listener. * * @private */ onMouseDown(): void; /** * Mouse up listener. * * @private */ onMouseUp(): void; /** * Mouse enter listener for fragment selection functionality. * * @private * @param {Event} event Dom event. * @param {HTMLElement} parentElement Part of border element. */ onMouseEnter(event: MouseEvent, parentElement: HTMLElement): void; /** * Create border elements. * * @param {object} settings The border settings. */ createBorders(settings: BorderInstanceSettings): void; /** * Create multiple selector handler for mobile devices. */ createMultipleSelectorHandles(): void; /** * Creates the four edge-adjustment handle elements used by the `selectionHandles` feature. * Visual styling (size, background, border, border-radius, cursor, z-index) is driven entirely * by CSS via the `--ht-cell-selection-handle-*` tokens defined in the theme stylesheets. * JS sets only `display:none` (initial hidden state) and the positioning `top`/`left` values * during `positionAdjustHandles`. Class names (`wtSelectionHandle--`) carry orientation. * * Called lazily from `appear()` on the first draw whose `adjustHandlesVisible` predicate resolves * truthy, so the elements never exist for instances that leave `selectionHandles` off. Because * `registerListeners` has already run by then, each handle attaches its own `mousedown` listener * here. * * @returns {AdjustHandles} The created handle set, so the caller can use it without a null check. */ createAdjustHandles(): AdjustHandles; /** * Creates the four edge move-zone band elements. Each band is a thin overlay div positioned along * one selection edge. Hovering a band shows a `grab` cursor; a `mousedown` on a band calls the * `onSelectionEdgeMouseDown` Walkontable setting so the core can initiate a move drag. * * Bands sit at z-index 100 — below the resize pills (z-index 115) and below the autofill fill * handle (`.wtBorder.corner`, z-index 110), so both keep winning their own pixels in the corner * regions where the bands overlap them. All four bands are created hidden; `positionMoveZone` * + `appear` control their visibility. * * Called lazily from `appear()` on the first draw whose `moveEnabled` predicate resolves truthy, * so the bands never exist for instances that leave `moveCells` off. * * @private */ createMoveZone(): void; /** * Positions the four move-zone bands along the selection edges. Each band is `MOVE_ZONE_THICKNESS` * pixels tall (or wide for the vertical bands) and centered on its respective edge line. RTL layout * is handled by using `right` instead of `left` for the inline axis, mirroring `positionAdjustHandles`. * * @private * @param {number} top The selection border top (px, container-relative). * @param {number} inlineStart The selection border inline-start (px, container-relative). * @param {number} width The selection border width (px). * @param {number} height The selection border height (px). */ positionMoveZone(top: number, inlineStart: number, width: number, height: number): void; /** * Checks if the given coordinates are south-east of the area selection. If `true` then * the fill handler should be visible. * * @param {number} row The visual row index. * @param {number} col The visual column index. * @returns {boolean} */ isSouthEastOfAreaSelection(row: number, col: number): boolean; /** * @param {number} row The visual row index. * @param {number} col The visual column index. * @param {number} top The top position of the handler. * @param {number} left The left position of the handler. * @param {number} width The width of the handler. * @param {number} height The height of the handler. */ updateMultipleSelectionHandlesPosition(row: number, col: number, top: number, left: number, width: number, height: number): void; /** * Tells whether a selection edge lands exactly on a frozen-pane boundary and is therefore owned by * the frozen overlay. Depends only on the fixed-pane settings and the raw corner, so every overlay * evaluates it on identical inputs. * * @private * @param {'row'|'column'} axis The freeze axis to test (`row` → `fixedRowsTop`, `column` → `fixedColumnsStart`). * @param {number} fromIndex The selection's top (`row`) or inline-start (`column`) corner index. * @returns {boolean} */ isFrozenBoundaryEdge(axis: 'row' | 'column', fromIndex: number): boolean; /** * Tells whether a selection's bottom or end edge lands immediately before a top or start frozen pane. * * @private * @param {'row'|'column'} axis The freeze axis to test. * @param {number} toIndex The selection's bottom (`row`) or inline-end (`column`) corner index. * @returns {boolean} */ isFrozenStartBoundaryOppositeEdge(axis: 'row' | 'column', toIndex: number): boolean; /** * Tells whether the selection's boundary corner (the cell flush with a frozen-pane line) has * scrolled behind the frozen pane in the master viewport. The frozen overlay can't detect this * itself (its rendered range is sticky), so we consult the scroll-aware master and stop drawing the * edge once the cell is occluded by the pane. * * @private * @param {'row'|'column'} axis The freeze axis to test (`row` → vertical, `column` → horizontal). * @param {number} fromIndex The selection's boundary corner index on that axis. * @returns {boolean} `true` when the boundary corner is scrolled out (edge must not be drawn). */ isBoundaryCornerScrolledOut(axis: 'row' | 'column', fromIndex: number): boolean; /** * Mirror of {@link Border#isFrozenBoundaryEdge} for the bottom freeze line: tells whether the * selection's bottom edge lands exactly on the `fixedRowsBottom` boundary (the line between the last * non-frozen row and the first bottom-frozen row), and is therefore owned by the bottom overlay. * * @private * @param {number} toIndex The selection's bottom corner row index. * @returns {boolean} */ isFrozenBottomBoundaryEdge(toIndex: number): boolean; /** * Mirror of {@link Border#isFrozenStartBoundaryOppositeEdge} for the bottom freeze line: tells * whether the selection's top edge lands exactly on the `fixedRowsBottom` boundary (the selection * starts at the first bottom-frozen row), so the top handle sits on the freeze line and must be * suppressed there like every other frozen-seam edge. * * @private * @param {number} fromIndex The selection's top corner row index. * @returns {boolean} */ isFrozenBottomBoundaryOppositeEdge(fromIndex: number): boolean; /** * Mirror of {@link Border#isBoundaryCornerScrolledOut} for the bottom freeze line: tells whether the * selection's bottom boundary cell has scrolled behind the bottom frozen pane in the master viewport * (it then drops below the last visible master row), so the edge must not be drawn. * * @private * @param {number} toIndex The selection's bottom boundary corner row index. * @returns {boolean} `true` when the boundary corner is scrolled out (edge must not be drawn). */ isBottomBoundaryCornerScrolledOut(toIndex: number): boolean; /** * Draws the selection-border edge(s) that lie exactly on a frozen-pane boundary, where the master * renders them on the freeze line under the occluding frozen overlay. Re-draws each such edge * inside the frozen overlay(s) that own it (clamped to each overlay's rendered range), while * `appear` hides the matching master edge so exactly one line is drawn per segment. * * @param {number[]} corners The selection corners `[fromRow, fromColumn, toRow, toColumn]`. * @returns {boolean} `true` when a boundary edge was drawn (regular drawing should be skipped). */ drawFrozenBoundaryEdge(corners: number[]): boolean; /** * Shared inline-axis writer for the row/bottom freeze edges. Given the boundary cells and an * already-resolved vertical position, writes the horizontal anchor + width (RTL-aware) on the * supplied border element and reveals it. The top and bottom freeze edges differ only in which * gridline they sit on and which element they reuse, so they delegate the identical inline math * here. Cheap range/cell-lookup guards run before any reflow-forcing `geometryReader.offset()`, so non-drawing * calls leave the styles untouched. * * @private * @param {number} boundaryRow The row whose edge carries the freeze line. * @param {CSSStyleDeclaration} style The border element to position (`topStyle` or `bottomStyle`). * @param {number} firstColumn The first column index to span (clamped to the overlay). * @param {number} lastColumn The last column index to span (clamped to the overlay). * @param {boolean} isRtl Whether the grid is rendered right-to-left. * @param {number} delta The along-axis length extension (`ceil(borderWidth / 2)`). * @param {Function} resolveTop Resolves the edge's `top` (px) from the boundary cell and offsets. * @returns {boolean} `true` when the edge was drawn. */ drawHorizontalFreezeEdge(boundaryRow: number, style: CSSStyleDeclaration, firstColumn: number, lastColumn: number, isRtl: boolean, delta: number, resolveTop: (boundaryTD: HTMLElement, boundaryOffset: { top: number; left: number; }, containerTop: number) => number): boolean; /** * Draws the selection's top edge on the row freeze line across the given (clamped) column span, * anchored one pixel inside the freeze line by a constant so borders of different widths line up. * * @private * @param {number} firstColumn The first column index to span (clamped to the overlay). * @param {number} lastColumn The last column index to span (clamped to the overlay). * @param {boolean} isRtl Whether the grid is rendered right-to-left. * @param {number} delta The along-axis length extension (`ceil(borderWidth / 2)`). * @returns {boolean} `true` when the edge was drawn. */ drawRowFreezeEdge(firstColumn: number, lastColumn: number, isRtl: boolean, delta: number): boolean; /** * Mirror of {@link Border#drawRowFreezeEdge} for the bottom freeze line: draws the selection's * bottom edge on the `fixedRowsBottom` line across the given (clamped) column span. The boundary * cell is the FIRST bottom-frozen row, and the freeze line is its TOP edge (= bottom of the last * non-frozen row). Uses the `bottom` border element. * * @private * @param {number} firstColumn The first column index to span (clamped to the overlay). * @param {number} lastColumn The last column index to span (clamped to the overlay). * @param {boolean} isRtl Whether the grid is rendered right-to-left. * @param {number} delta The along-axis length extension (`ceil(borderWidth / 2)`). * @returns {boolean} `true` when the edge was drawn. */ drawRowFreezeBottomEdge(firstColumn: number, lastColumn: number, isRtl: boolean, delta: number): boolean; /** * Draws the selection's inline-start edge on the column freeze line across the given (clamped) row * span, anchored one pixel inside the freeze line by a constant so borders of different widths line * up. Guard/reflow behavior mirrors `drawRowFreezeEdge`. * * @private * @param {number} firstRow The first row index to span (clamped to the overlay). * @param {number} lastRow The last row index to span (clamped to the overlay). * @param {boolean} isRtl Whether the grid is rendered right-to-left. * @param {number} delta The along-axis length extension (`ceil(borderWidth / 2)`). * @returns {boolean} `true` when the edge was drawn. */ drawColumnFreezeEdge(firstRow: number, lastRow: number, isRtl: boolean, delta: number): boolean; /** * Shared writer for the freeze-corner squares. Draws the `borderWidth`-sized square bridging a * row/bottom edge and the inline-start edge where a selection corner lands on both freeze lines, * since that square sits in the corner overlay's frozen×frozen region that occludes both edges' * tips. Anchored one pixel inside the freeze column; the caller resolves the vertical position and * the border element to reuse. Reflow/guard behavior mirrors the freeze-edge helpers. * * @private * @param {number} boundaryRow The row whose edge carries the freeze line. * @param {CSSStyleDeclaration} style The border element to position (`topStyle` or `bottomStyle`). * @param {boolean} isRtl Whether the grid is rendered right-to-left. * @param {number} borderWidth The configured border width in pixels. * @param {Function} resolveTop Resolves the square's `top` (px) from the boundary cell and offsets. * @returns {boolean} `true` when the corner square was drawn. */ drawFreezeCorner(boundaryRow: number, style: CSSStyleDeclaration, isRtl: boolean, borderWidth: number, resolveTop: (boundaryTD: HTMLElement, boundaryOffset: { top: number; left: number; }, containerTop: number) => number): boolean; /** * Draws the corner square bridging the top and inline-start edges where a selection corner lands on * both the `fixedRowsTop` and `fixedColumnsStart` freeze lines. Reuses the `top` border element. * * @private * @param {boolean} isRtl Whether the grid is rendered right-to-left. * @param {number} borderWidth The configured border width in pixels. * @returns {boolean} `true` when the corner square was drawn. */ drawFrozenBoundaryCorner(isRtl: boolean, borderWidth: number): boolean; /** * Bottom mirror of {@link Border#drawFrozenBoundaryCorner}: draws the corner square bridging the * bottom and inline-start edges where a selection corner lands on both the `fixedRowsBottom` and * `fixedColumnsStart` freeze lines. The boundary cell is the FIRST bottom-frozen row and the bottom * freeze line is its TOP edge. Reuses the `bottom` border element. * * @private * @param {boolean} isRtl Whether the grid is rendered right-to-left. * @param {number} borderWidth The configured border width in pixels. * @returns {boolean} `true` when the corner square was drawn. */ drawFrozenBottomBoundaryCorner(isRtl: boolean, borderWidth: number): boolean; /** * Resolves the position the fill handle's overflow checks measure from, in the same space as the * trimming container they compare against: viewport coordinates when the window trims the grid, * otherwise the offset inside the scrollable content. * * A cell's own `offsetLeft`/`offsetTop` are relative to the ``, and the master shifts that * table through the spreader by the frozen-pane size and by the first rendered column/row offset. * That shift is missing from the cell offsets, so the handle could measure as "inside" while it * protruded past the content edge and forced a spurious scrollbar. The hider spans the whole * scrollable content, so measuring from it puts the shift back. * * @private * @param {HTMLElement} TD The cell that carries the fill handle (the selection's bottom-end cell). * @param {{ top: number, left: number }} TDOffset The cell's already-measured document offset. * @param {boolean} trimToWindow Whether the grid is trimmed by the window rather than an element. * @returns {{ top: number, left: number }} */ getFillHandleAnchor(TD: HTMLElement, TDOffset: { top: number; left: number; }, trimToWindow: boolean): { top: number; left: number; }; /** * Tells whether the fill handle must be pulled back inside the selection's inline-end edge instead * of straddling it. Only the grid's last column needs that, where the overhang would spill out of * the trimming container and force a scrollbar. A selection ending on the last frozen-start column * does not: the frozen overlay draws that handle itself and already lands it flush against its own * edge, which `border.spec.js` pins to the pixel — lifting it there moves it off that line. * * @private * @param {number} toColumn The selection's inline-end column index. * @param {number} anchorInlineStart The fill handle anchor's inline-start offset. * @param {HTMLElement} TD The cell that carries the fill handle. * @param {HTMLElement | Window} trimmingContainer The container that clips the grid. * @param {boolean} isRtl Whether the grid renders right-to-left. * @returns {boolean} */ isCornerLiftedAtInlineEnd(toColumn: number, anchorInlineStart: number, TD: HTMLElement, trimmingContainer: HTMLElement | Window, isRtl: boolean): boolean; /** * Block-axis mirror of {@link Border#isCornerLiftedAtInlineEnd}. Two rows pull the fill handle back * inside the selection's bottom edge: the grid's last row, where the overhang would spill out of * the trimming container, and the last scrollable row above the `fixedRowsBottom` line, where the * bottom overlay is painted above the master and would cover the overhang. The last frozen-top row * is not one of them — like the frozen-start column, that handle is drawn by the overlay itself and * already sits flush against its edge. * * @private * @param {number} toRow The selection's bottom row index. * @param {number} anchorTop The fill handle anchor's top offset. * @param {HTMLElement} TD The cell that carries the fill handle. * @param {HTMLElement | Window} trimmingContainer The container that clips the grid. * @returns {boolean} */ isCornerLiftedAtBlockEnd(toRow: number, anchorTop: number, TD: HTMLElement, trimmingContainer: HTMLElement | Window): boolean; /** * Show border around one or many cells. * * The fill handle is normally centered on the selection's bottom-end corner, so half of it hangs * past that corner. Where that overhang cannot survive — a container edge, or a frozen pane that * clips or covers it — the handle is pulled back inside instead, and `wtCornerInlineEndEdge` / * `wtCornerBlockEndEdge` pull its hit area along. See {@link Border#isCornerLiftedAtInlineEnd} and * {@link Border#isCornerLiftedAtBlockEnd} for which edges those are. * * @param {Array} corners The corner coordinates. */ appear(corners: number[]): void; /** * Check whether an entire column of cells is selected. * * @private * @param {number} startRowIndex Start row index. * @param {number} endRowIndex End row index. * @returns {boolean} */ isEntireColumnSelected(startRowIndex: number, endRowIndex: number): boolean; /** * Check whether an entire row of cells is selected. * * @private * @param {number} startColumnIndex Start column index. * @param {number} endColumnIndex End column index. * @returns {boolean} */ isEntireRowSelected(startColumnIndex: number, endColumnIndex: number): boolean; /** * Get left/top index and width/height depending on the `direction` provided. * * @private * @param {string} direction `rows` or `columns`, defines if an entire column or row is selected. * @param {number} fromIndex Start index of the selection. * @param {number} toIndex End index of the selection. * @param {number} headerIndex The header index as negative value. * @param {number} containerOffset Offset of the container. * @returns {Array|boolean} Returns an array of [headerElement, left, width] or [headerElement, top, height], depending on `direction` (`false` in case of an error getting the headers). */ getDimensionsFromHeader(direction: string, fromIndex: number, toIndex: number, headerIndex: number, containerOffset: { top: number; left: number; }): false | [HTMLElement, number, number]; /** * Positions the four edge-adjustment handles at the midpoint of each edge, hiding any handle * whose edge is flush with the grid boundary. Called at the end of `appear()` when the * `selectionHandles` feature is enabled for this highlight. * * Handle dimensions are sourced from the `--ht-cell-selection-handle-size` and * `--ht-cell-selection-handle-length` CSS tokens via a cached stylesHandler read * (no layout-forcing DOM access). Top/bottom handles are horizontal pills * (width = length, height = size); start/end handles are vertical pills (width = size, height = length). * * @private * @param {number} top The selection border top (px, container-relative). * @param {number} inlineStart The selection border inline-start (px, container-relative). * @param {number} width The selection border width (px). * @param {number} height The selection border height (px). * @param {number[]} corners The raw `[fromRow, fromColumn, toRow, toColumn]` visual corners. */ positionAdjustHandles(top: number, inlineStart: number, width: number, height: number, corners: number[]): void; /** * Change border style. * * @private * @param {string} borderElement Coordinate where add/remove border: top, bottom, start, end. * @param {object} border The border object descriptor. */ changeBorderStyle(borderElement: 'top' | 'bottom' | 'start' | 'end', border: Record): void; /** * Change border style to default. * * @private * @param {string} position The position type ("top", "bottom", "start", "end") to change. */ changeBorderToDefaultStyle(position: 'top' | 'bottom' | 'start' | 'end'): void; /** * Toggle class 'hidden' to element. * * @private * @param {string} borderElement Coordinate where add/remove border: top, bottom, start, end. * @param {boolean} [remove] Defines type of the action to perform. */ toggleHiddenClass(borderElement: 'top' | 'bottom' | 'start' | 'end', remove: boolean): void; /** * Hide border. */ disappear(): void; /** * Cleans up all the DOM state related to a Border instance. Call this prior to deleting a Border instance. */ destroy(): void; } export default Border;