import type { HeaderNodeData } from './headersTree'; import type { NodeModificationResult } from './nodeModifiers'; import type { ColumnArrangement } from './columnArrangement'; import type { ColumnVisibility } from './columnVisibility'; import type TreeNode from '../../../utils/dataStructures/tree'; /** * The state manager is a source of truth for nested headers configuration. * * @class StateManager */ export default class StateManager { #private; /** * Sets a new state for the nested headers plugin based on settings passed * directly to the plugin. * * @param {Array[]} nestedHeadersSettings The user-defined settings. * @returns {boolean} Returns `true` if the settings are processed correctly, `false` otherwise. */ setState(nestedHeadersSettings: unknown[][]): boolean; /** * Sets columns limit to the state will be trimmed. * * @param {number} columnsCount The number of columns to limit to. */ setColumnsLimit(columnsCount: number): void; /** * Sets the column arrangement the headers tree is derived against. Pass a live adapter (backed by * the column index mapper) so the rendered structure follows column moves, or `null` to fall back * to the identity arrangement (authored structure). Does not rebuild on its own - call * `rebuildState()` (or any structural mutation) to re-derive the tree. * * @param {ColumnArrangement|null} columnArrangement The arrangement to derive against, or null. */ setColumnArrangement(columnArrangement: ColumnArrangement | null): void; /** * Re-derives the headers tree from the current authored settings and column arrangement, preserving * the collapsed state and re-applying visibility. Call this when only the arrangement changed (a * column move) and no structural mutation of the authored settings is needed. * * Collapse is re-attached by authored group identity (not visual column index, which the move just * changed): a group that stayed contiguous is re-collapsed at its new position; a group split apart * by the move auto-expands (its collapse is dropped), since a non-contiguous group cannot stay * collapsed coherently. */ rebuildState(): void; /** * Merges settings with current plugin state. * * @param {object[]} settings An array of objects to merge with the current source settings. */ mergeStateWith(settings: { row: number; col: number; [key: string]: unknown; }[]): void; /** * Maps the current state with a callback. * * @param {Function} callback A function that is called for every header source settings. */ mapState(callback: (headerSettings: Record) => unknown): void; /** * Inserts `amount` columns into the source settings, then rebuilds the tree and re-derives * visibility. Headers spanning the insertion point are extended; columns inserted at a header * boundary become standalone headers. * * The authored source settings are keyed by physical column, while the collapsed state is keyed by * visual column - so the insertion takes both indexes. They are equal when no column move is active; * after a move they differ, and using each in its own space keeps headers and collapse aligned. * * @param {number} visualColumnIndex The visual index the columns were inserted at (collapse space). * @param {number} physicalColumnIndex The physical index the columns were inserted at (source space). * @param {number} amount The number of columns to insert. */ insertColumns(visualColumnIndex: number, physicalColumnIndex: number, amount: number): void; /** * Removes the given columns from the source settings, then rebuilds the tree and re-derives * visibility. Headers overlapping the removed columns are shrunk, re-anchored, or dropped when they * lose all their columns. * * The removed columns are identified by physical index (authored source settings are physical-keyed) * and may be non-contiguous after a column move; they are removed highest-index-first so the lower * indexes stay valid. The collapsed state is shifted in visual space, which an insert/remove always * changes the same way regardless of any active move. * * @param {number} visualColumnIndex The visual index the columns were removed from (collapse space). * @param {number} amount The number of columns removed (length of `physicalColumns`). * @param {number[]} physicalColumns The physical indexes of the removed columns (source space). */ removeColumns(visualColumnIndex: number, amount: number, physicalColumns: number[]): void; /** * Maps the current tree nodes with a callback. * * @param {Function} callback A function that is called for every tree node. * @returns {Array} */ mapNodes(callback: Function): unknown[]; /** * Triggers an action from the NodeModifiers module. * * @param {string} action An action name to trigger. * @param {number} headerLevel Header level index. * @param {number} columnIndex A visual column index. * @returns {object|undefined} */ triggerNodeModification(action: string, headerLevel: number, columnIndex: number): NodeModificationResult | undefined; /** * Triggers an action from the NodeModifiers module starting from the lowest header. * * @param {string} action An action name to trigger. * @param {number} columnIndex A visual column index. * @returns {object|undefined} */ triggerColumnModification(action: string, columnIndex: number): NodeModificationResult | undefined; /** * Derives tree-node visibility state (colspan, crossHiddenColumns, isHidden) from an external * ColumnVisibility port, then regenerates the state matrix. Call this whenever the hiding map * changes (HiddenColumns, CollapsibleColumns) or after column sequence changes. * * @param {ColumnVisibility} columnVisibility The visibility port. */ syncVisibility(columnVisibility: ColumnVisibility): void; /** * Re-parents the moved columns after a column move, recording membership overrides the derive uses * to keep `columnDropMode: 'adopt'` groups cohesive. Call before `rebuildState()`. * * For each moved column the deepest group level at which it was dropped strictly inside a cohesive * group is found first. From that level outward the column joins that group's ancestor chain (the * group the column visually sits inside at each enclosing level), so a splitting ancestor grows * to contain the adopted column instead of the inner run straddling its boundary. At every other * level (deeper than the adoption, or none found) the column keeps its group when still beside a * sibling, else goes standalone. The decisions are taken from the pre-update layout, then applied, * so a whole group moved together (each member adjacent to a sibling) stays intact. * * @param {number[]} movedVisualColumns - The post-move visual indexes of the columns that moved. */ reparentColumns(movedVisualColumns: number[]): void; /** * @memberof StateManager# * @function rowCoordsToLevel * * Translates row coordinates into header level. * * @param {number} rowIndex A visual row index. * @returns {number|null} Returns unsigned number. */ rowCoordsToLevel(rowIndex: number): number | null; /** * @memberof StateManager# * @function levelToRowCoords * * Translates header level into row coordinates. * * @param {number} headerLevel Header level index. * @returns {number} Returns negative number. */ levelToRowCoords(headerLevel: number): number | null; /** * Gets column header settings for a specified column and header index. * * @param {number} headerLevel Header level. * @param {number} columnIndex A visual column index. * @returns {object|null} */ getHeaderSettings(headerLevel: number, columnIndex: number): HeaderNodeData | null; /** * Gets tree data that is connected to the column header. * * @param {number} headerLevel Header level. * @param {number} columnIndex A visual column index. * @returns {object|null} */ getHeaderTreeNodeData(headerLevel: number, columnIndex: number): { [key: string]: unknown; headerLevel: number; columnIndex: number; authoredColumnIndex?: number; clonedTree?: TreeNode | null; label: string; colspan: number; origColspan: number; rowspan?: number; origRowspan?: number; collapsible: boolean; columnDropMode: import("./utils").ColumnDropMode; isCollapsed: boolean; crossHiddenColumns: number[]; isHidden: boolean; isRoot: boolean; isPlaceholder: boolean; isRowspanPlaceholder?: boolean; headerClassNames: string[]; visibleWhen?: import("./utils").HeaderVisibility; } | null; /** * Gets tree node that is connected to the column header. * * @param {number} headerLevel Header level. * @param {number} columnIndex A visual column index. * @returns {TreeNode|null} */ getHeaderTreeNode(headerLevel: number, columnIndex: number): TreeNode | null; /** * Finds the most top header level of the column header. * * @param {number} columnIndexFrom A visual column index. * @param {number} [columnIndexTo] A visual column index. * @returns {number} Returns a header level in format -1 to -N. */ findTopMostEntireHeaderLevel(columnIndexFrom: number, columnIndexTo?: number): number | null; /** * Finds the left-most column index where the nested header begins. * * @param {number} headerLevel Header level. * @param {number} columnIndex A visual column index. * @returns {number} */ findLeftMostColumnIndex(headerLevel: number, columnIndex: number): number; /** * Finds the right-most column index where the nested header ends. * * @param {number} headerLevel Header level. * @param {number} columnIndex A visual column index. * @returns {number} */ findRightMostColumnIndex(headerLevel: number, columnIndex: number): number; /** * Gets a total number of headers levels. * * @returns {number} */ getLayersCount(): number; /** * Gets the number of columns the rendered header structure spans (the visual width). This reads * the derived settings, so it matches the generated matrix and the current column arrangement. * With an identity arrangement it equals the authored column count. * * @returns {number} */ getColumnsCount(): number; /** * Computes the visual column indexes that should be hidden purely by the `visibleWhen` rules of * declarative collapsible groups (issue #10243), given each group's current `isCollapsed` state. * * A group is "declarative" when at least one of its direct children declares an explicit * `visibleWhen` ('collapsed', 'expanded', or 'always'); legacy groups (no markers) are left to the * regular first-visible-child collapse path and are skipped here. Within a declarative group a child * with no marker defaults to `'expanded'` - it is hidden when the group collapses, matching the * default collapse behavior; `'always'` is the explicit opt-in for staying visible in both states. * Only `collapsible` groups are considered. At least one column per group always stays visible so the * group's collapse indicator survives. The result is a pure function of the tree shape, the markers, * and the `isCollapsed` flags, so it stays correct across tree rebuilds. * * @returns {number[]} Visual column indexes to hide. */ getVisibleWhenHiddenColumns(): number[]; /** * Gets every currently collapsed group as its header level and the visual column span it covers * (its left-edge visual column index and original colspan). Used to detect, before a column move, * whether the move would split a collapsed group. * * @returns {Array<{headerLevel: number, columnIndex: number, origColspan: number}>} */ getCollapsedGroups(): { headerLevel: number; columnIndex: number; origColspan: number; }[]; /** * Clears the column state manager to the initial state. */ clear(): void; }