import AbstractContentItem from './AbstractContentItem'; import { Splitter } from '../controls'; import type LayoutManager from '../LayoutManager'; import type { ColumnItemConfig, ItemConfig, RowItemConfig } from '../config'; export default class RowOrColumn extends AbstractContentItem { isRow: boolean; isColumn: boolean; childElementContainer: JQuery; parent: AbstractContentItem | null; private _splitter; private _intersectionSplitter; private _splitterSize; private _splitterGrabSize; private _isColumn; private _dimension; private _splitterPosition; private _splitterMinPosition; private _splitterMaxPosition; private _isIntersectionDragging; private _activeFourWayPartner; private _activeFourWaySharedCenterMin; private _activeFourWaySharedCenterMax; private _activeFourWayBaseCenter; private _activeFourWayPartnerBaseCenter; constructor(isColumn: true, layoutManager: LayoutManager, config: ColumnItemConfig, parent: AbstractContentItem | null); constructor(isColumn: false, layoutManager: LayoutManager, config: RowItemConfig, parent: AbstractContentItem | null); /** * Add a new contentItem to the Row or Column * * @param contentItem * @param index The position of the new item within the Row or Column. * If no index is provided the item will be added to the end * @param _$suspendResize If true the items won't be resized. This will leave the item in * an inconsistent state and is only intended to be used if multiple * children need to be added in one go and resize is called afterwards */ addChild(contentItem: AbstractContentItem | ItemConfig, index?: number, _$suspendResize?: boolean): void; /** * Removes a child of this element * * @param contentItem * @param keepChild If true the child will be removed, but not destroyed */ removeChild(contentItem: AbstractContentItem, keepChild: boolean): void; /** * Replaces a child of this Row or Column with another contentItem * * @param oldChild The old child to replace * @param newChild The new child to take the old child's place * @param destroyOldChild If the old child should be destroyed or not */ replaceChild(oldChild: AbstractContentItem, newChild: AbstractContentItem, destroyOldChild?: boolean): void; /** * Called whenever the dimensions of this item or one of its parents change */ setSize(): void; /** * Invoked recursively by the layout manager. AbstractContentItem.init appends * the contentItem's DOM elements to the container, RowOrColumn init adds splitters * in between them */ _$init(): void; /** * Turns the relative sizes calculated by _calculateRelativeSizes into * absolute pixel values and applies them to the children's DOM elements * * Assigns additional pixels to counteract Math.floor */ _setAbsoluteSizes(): void; /** * Calculates the absolute sizes of all of the children of this Item. * @returns {object} - Set with absolute sizes and additional pixels. */ _calculateAbsoluteSizes(): { itemSizes: number[]; additionalPixel: number; totalWidth: number; totalHeight: number; }; /** * Calculates the relative sizes of all children of this Item. The logic * is as follows: * * - Add up the total size of all items that have a configured size * * - If the total == 100 (check for floating point errors) * Excellent, job done * * - If the total is > 100, * set the size of items without set dimensions to 1/3 and add this to the total * set the size off all items so that the total is hundred relative to their original size * * - If the total is < 100 * If there are items without set dimensions, distribute the remainder to 100 evenly between them * If there are no items without set dimensions, increase all items sizes relative to * their original size so that they add up to 100 */ _calculateRelativeSizes(): void; /** * Adjusts the column widths to respect the dimensions minItemWidth if set. */ _respectMinItemWidth(): void; /** * Instantiates a new lm.controls.Splitter, binds events to it and adds * it to the array of splitters at the position specified as the index argument * * What it doesn't do though is append the splitter to the DOM * * @param index The position of the splitter * @returns The created splitter */ _createSplitter(index: number): Splitter; /** * Locates the instance of lm.controls.Splitter in the array of * registered splitters and returns a map containing the contentItem * before and after the splitters, both of which are affected if the * splitter is moved * * @param splitter * * @returns A map of contentItems that the splitter affects */ _getItemsForSplitter(splitter: Splitter): { before: AbstractContentItem; after: AbstractContentItem; }; /** * Gets the minimum dimensions for the given item configuration array * @param item * @private */ _getMinimumDimensions(arr: { minWidth?: number; minHeight?: number; }[]): { horizontal: number; vertical: number; }; /** * Invoked when a splitter's dragListener fires dragStart. Calculates the splitters * movement area once (so that it doesn't need calculating on every mousemove event) * * @param splitter */ _onSplitterDragStart(splitter: Splitter): void; /** * Invoked when a splitter's DragListener fires drag. Updates the splitters DOM position, * but not the sizes of the elements the splitter controls in order to minimize resize events * * @param splitter * @param offsetX Relative pixel values to the splitters original position. Can be negative * @param offsetY Relative pixel values to the splitters original position. Can be negative */ _onSplitterDrag(splitter: Splitter, offsetX: number, offsetY: number): void; /** * Invoked when a splitter's DragListener fires dragStop. Resets the splitters DOM position, * and applies the new sizes to the elements before and after the splitter and their children * on the next animation frame * * @param {lm.controls.Splitter} splitter */ _onSplitterDragStop(splitter: Splitter): void; /** * Applies drag-stop updates for one splitter without scheduling layout. */ private _applySplitterDragStop; /** * Schedules a full descendant size update on the next animation frame. */ private _scheduleSetSize; /** * Schedule intersection handle refresh after layout and browser positioning settle. */ private _scheduleIntersectionRefresh; /** * Schedule an intersection handle refresh on every RowOrColumn ancestor so * crossing handles stay aligned after a drag that only resized descendants. */ private _scheduleAncestorIntersectionRefresh; /** * Create intersection splitters at the crossing points between this * RowOrColumn's splitters and the splitters of any perpendicular child. * * Each handle is appended into this RowOrColumn's container and positioned * with JS (via `_positionIntersectionSplitter`) during refresh so it stays * aligned as the layout changes. Handles are keyed by their splitter indices * so existing ones are reused rather than recreated. * * @returns The set of crossing keys that currently exist, so callers can * sweep handles whose crossing no longer exists. */ private _createIntersectionSplitters; /** * Collect every perpendicular splitter line within `item`'s subtree that * reaches the shared edge with one of this row/column's splitter bars, so a * crossing handle can be created for it. Lines can be nested arbitrarily deep, * so descend until the edge is no longer shared. * * @param item The subtree root to search. * @param nearEdge true when the bar sits at the start of `item` along the bar * main axis (junction at the near end), false when at the end. * @param path Dot/colon-delimited string uniquely identifying this stem within * the layout tree, used as part of the intersection handle key. * @returns Array of stem descriptors for each crossing found in the subtree. */ private _collectEdgeStemSplitters; /** * Recreate intersection splitters based on current splitter topology. * This keeps handles aligned and present after layout tree mutations. */ private _refreshIntersectionSplitters; /** * Destroy all previously created intersection splitters. */ private _destroyIntersectionSplitters; /** * Tear down splitters (including intersection handles and their document-level * drag listeners) before delegating to the base destroy logic. */ _$destroy(): void; /** * Whether any golden-layout drag that should suppress intersection hover * affordances is in progress. Covers a 1D splitter drag or a panel drag * (both signalled by `lm_dragging` on the body) and the 2D intersection drag * itself (`lm_intersection_dragging`). During these the handle must not light * up its cross as the pointer passes over a crossing. * * @returns True when a golden-layout drag is active. */ private static _isAnyDragInProgress; /** * Create a single intersection splitter anchored in this row/column overlay * at the given coordinates. * * @param key Unique key identifying this crossing (parent splitter index plus * the stem's tree path), used to reuse an existing handle instead * of creating a duplicate. * @param parentSplitterIndex Index into this row/column's `_splitter` array of * the "bar" splitter that owns the crossing. * @param stemOwner The RowOrColumn (possibly a descendant) that owns the * perpendicular "stem" splitter crossing the bar. * @param stemSplitterIndex Index into `stemOwner._splitter` of the stem * splitter. * @param junctionAtNearEdge True when the stem meets the bar at the stem * owner's near edge, false at its far edge. */ private _ensureIntersectionSplitter; /** * Move an intersection handle to the current centre of its crossing. * * @param record The intersection handle record to reposition. */ private _positionIntersectionSplitter; /** * Compute intersection coordinates (the centre of the crossing) relative to * this row/column container. * * Uses `getBoundingClientRect` for the container and both splitter elements * rather than jQuery `.position()`. `.position()` is relative to each * element's offset parent, which varies with nesting and `position: relative` * on intermediate items, so adding those values together mis-places the * handle at some crossings. Rect-based deltas are independent of the offset * parent chain and always land on the visual crossing. * * @param record The intersection handle record to locate. * @returns The `{ left, top }` crossing centre relative to this row/column * container, or null when the geometry is unavailable. */ private _getIntersectionPosition; /** * Toggle the active-line highlight on both splitters that meet at an * intersection. Reuses the standard `.lm_dragging` line style so the 2D * affordance is visually identical to the existing 1D drag affordance, and * adds `.lm_intersection_line` to lift the lines above pane content so an * offset junction renders cleanly instead of being clipped by a neighbour. * * @param record The intersection handle whose two perpendicular lines to * toggle. * @param highlighted True to add the highlight, false to remove it. */ private _setIntersectionHighlight; /** * Find a nearby sibling intersection on the same parent splitter so a * near-aligned 4-way corner can be dragged as one. * * @param record The intersection handle to find a partner for. * @returns The closest sibling handle within tolerance, or null if none. */ private _findNearFourWayPartner; /** * Clamp and apply one splitter visual drag offset on the owner's active axis. * * @param owner The RowOrColumn that owns the splitter and its min/max bounds. * @param splitter The splitter whose visual position to move. * @param offset The desired pixel offset along the owner's active axis; * clamped to the owner's min/max drag range before applying. */ private _setSplitterDragOffset; /** * Get the splitter line center on the owner's active drag axis. * * @param owner The RowOrColumn that determines the active axis. * @param splitter The splitter to measure. * @returns The line centre in client coordinates on the active axis, or null * when the element is unavailable. */ private _getSplitterAxisCenter; /** * Invoked when an intersection splitter's DragListener fires dragStart. * Calculates movement bounds for both axes (via the existing 1D logic) so the * drag stays within valid ranges, and highlights both perpendicular lines. * * @param record The intersection handle that started dragging. */ private _onIntersectionSplitterDragStart; /** * Invoked when an intersection splitter's DragListener fires drag. Moves both * splitter lines by delegating to the existing 1D logic, which clamps each * axis to its own valid range. The lines moving form the 2D drag affordance. * * The stem line spans the full extent of its owner along the parent axis, so * when the parent line moves the junction would otherwise detach. The stem is * stretched to follow the parent line while its far tip stays anchored. * * The stretch is applied with a CSS `transform: scale(...)` about the far tip * rather than by changing the line's `width`/`height`/`top`/`left`. Splitter * lines are real in-flow elements (floated / `position: relative`), so * mutating their box size reflows sibling panes and headers (tabs jump, * content shifts, gaps appear). A transform is painted without affecting * layout, so the affordance stretches cleanly even for deeply nested grids. * * @param record The intersection handle being dragged. * @param offsetX Horizontal pixels moved from the drag origin. Can be negative. * @param offsetY Vertical pixels moved from the drag origin. Can be negative. */ private _onIntersectionSplitterDrag; /** * Invoked when an intersection splitter's DragListener fires dragStop. * Applies both axis updates atomically (via the existing 1D logic), clears the * highlight unless the pointer is still over the handle, then relayouts once. * * @param record The intersection handle that finished dragging. */ private _onIntersectionSplitterDragStop; } //# sourceMappingURL=RowOrColumn.d.ts.map