/** * Worksheet AutoFilter criteria metadata (`CT_AutoFilter` / `CT_FilterColumn` / * `CT_Filters` / `CT_Filter`). * * Citations: * - ECMA-376-1 5th ed. §18.3.1.2 `autoFilter`, §18.3.2.6 `filterColumn`, * §18.3.2.7 `filters`, §18.3.2.8 `filter` * - transitional sml.xsd `CT_AutoFilter`, `CT_FilterColumn`, `CT_Filters`, * `CT_Filter`; `CT_Worksheet` sequence: **`autoFilter`** → `sortState` → * `dataConsolidate` (~L2182–2186) * - docs/requirements/auto-filter.md; docs/specs/auto-filter.md; * docs/ooxml-mapping/auto-filter.md * - docs/api/AUTO-FILTER-PROPOSAL.md (accepted) * * This feature is the **criteria record** Excel persists for filter dropdowns * and selected values. It never hides rows, evaluates criteria against cells, * or rewrites grid data. Non-P1 choice arms (`top10`, `customFilters`, * `dynamicFilter`, `colorFilter`, `iconFilter`), `dateGroupItem`, `extLst`, and * unknown attributes round-trip opaquely in relative order. Nested * `CT_AutoFilter/sortState` is modeled as {@link AutoFilter.dataSorter} * (separate from worksheet-level {@link DataSorter}). Table-embedded * `autoFilter` stays opaque in the tables feature. */ import { CellRange } from '../address/cell-address'; import { DataSorter, SortStateModel } from './sort-state'; /** * Represents the filter settings for one column within an AutoFilter range, * letting you choose which values the column shows or hides. */ export interface FilterColumn { /** * Which column the filter applies to, counted from zero within the * filtered range — `0` is its first column. */ readonly columnIndex: number; /** * Whether the filter button appears on the column's header cell. * Default `true`. */ isButtonVisible: boolean; /** * Whether the filter button is hidden on the column's header cell. * Default `false`. */ isButtonHidden: boolean; /** * Whether blank cells are included in the filter. Default `false`. */ isBlank: boolean; /** The number of filter values defined for the column. */ readonly count: number; /** * Get the column's filter values as a list, in the order they were added. * * @returns the current filter values. */ values(): ReadonlyArray; /** * Add one value to the column's filter. Values already in the filter are * skipped, so each value appears once. * * @param value - The value to filter by, like `'Delivered'`. * @throws InvalidArgumentError when value is not a string */ addValue(value: string): void; /** * Add multiple values to the column's filter at once. Values already in * the filter are skipped. * * @param values - The values to filter by. * @throws InvalidArgumentError when values is not an array of strings */ addValues(values: ReadonlyArray): void; /** * Remove one value from the column's filter. Does nothing when the value * is not in the filter. * * @param value - The value to remove. * @throws InvalidArgumentError when value is not a string */ removeValue(value: string): void; /** * Remove the filter value at a zero-based position, in the order the * values were added. * * @param index - The zero-based position of the value to remove. * @throws InvalidArgumentError when index is out of range */ removeValueAt(index: number): void; /** * Remove every filter value from the column. The blank-cell and * filter-button settings are kept. */ clearValues(): void; } /** * Represents the filter applied to a range of cells, letting you manage which * rows are shown based on column criteria. * * A worksheet can have at most one filter. */ export interface AutoFilter { /** * Returns the cell range the filter covers, such as `A1:C20`. */ readonly range: string; /** Returns the number of columns that have filter criteria applied. */ readonly count: number; /** * Returns every column filter on the worksheet, in the order they appear * in the file. */ list(): ReadonlyArray; /** * Adds filter criteria for one column, or replaces the criteria if that * column already has a filter, and returns a handle for further changes. * Set the values and button/blank flags on the returned handle (defaults: * empty values, `isBlank` false, `isButtonVisible` true, * `isButtonHidden` false). * * @param columnIndex zero-based offset within the AutoFilter range (`@colId`) * @returns live {@link FilterColumn} * @throws InvalidAutoFilterError when columnIndex is not a finite unsigned integer */ addFilterColumn(columnIndex: number): FilterColumn; /** * Returns the column filter at the given position, counted from zero in * the order the filters were added. * @throws InvalidArgumentError when out of range */ get(index: number): FilterColumn; /** * Returns the filter applied to the given column, counted from zero * within the filter's range, or `undefined` if that column has no filter. */ getByColumnIndex(columnIndex: number): FilterColumn | undefined; /** * Removes the given column filter. Does nothing if it does not belong to * this filter. * @throws InvalidArgumentError when argument is not a column handle of this filter */ removeFilterColumn(column: FilterColumn): void; /** * Removes the column filter at the given position, counted from zero. * @throws InvalidArgumentError when out of range */ removeFilterColumnAt(index: number): void; /** Removes the filter criteria from every column; the filter itself and its range remain. */ clearFilterColumns(): void; /** * Sort settings nested under this AutoFilter (`CT_AutoFilter/sortState`), * or `undefined` when absent. Independent of worksheet-level * {@link Worksheet.dataSorter}. */ readonly dataSorter: DataSorter | undefined; /** * Author or replace the nested sort state under this AutoFilter. * * @param range - A1 range for `sortState/@ref` (often the data body under the header row) * @returns live nested {@link DataSorter} */ addDataSorter(range: string): DataSorter; /** Remove the nested sort state under this AutoFilter. */ removeDataSorter(): void; } /** * One discrete filter value (`CT_Filter`). * @private */ export interface FilterValueEntry { readonly val: string; /** Extra attributes (unknown) preserved on the filter element. */ readonly extraAttrsXml: string; } /** * Internal modeled / opaque `CT_FilterColumn` entry. * * Modeled entries carry the discrete `filters` arm. Opaque entries hold a * whole-element backup for non-filters choice arms (top10, customFilters, * …) and are not exposed in the public list. * * Tri-state booleans: `undefined` = attribute absent (XSD default); * explicit `true`/`false` round-trip their lexical form. * @private */ export interface FilterColumnEntry { /** * When true, this entry is modeled (`filters` arm). When false, `xml` * holds the whole-element opaque backup. */ readonly modeled: boolean; readonly colId: number; /** `@hiddenButton` — default false. */ readonly hiddenButton: boolean | undefined; /** `@showButton` — default true. */ readonly showButton: boolean | undefined; /** `CT_Filters/@blank` — default false. */ readonly blank: boolean | undefined; /** Discrete `filter@val` entries in document order. */ readonly values: ReadonlyArray; /** * Opaque content under `filters` after the modeled `filter` children * (typically `dateGroupItem*`), plus any unknown children of filters. */ readonly filtersExtraChildrenXml: ReadonlyArray; /** Extra attributes on `filterColumn` (unknown / invalid lexicals). */ readonly extraAttrsXml: string; /** Extra attributes on the `filters` element. */ readonly filtersExtraAttrsXml: string; /** * Whole-element backup for opaque (non-modeled) columns, or undefined for * modeled columns. */ readonly xml: string | undefined; } /** * Wire model for the worksheet-level `autoFilter` element. * @private */ export interface AutoFilterModel { readonly present: boolean; /** Parsed `CT_AutoFilter/@ref` (required for modeled present states). */ readonly range: CellRange | undefined; /** * Filter columns in document order. Modeled filters-arm entries are * public; opaque entries serialize but are hidden from public list/count. */ readonly columns: ReadonlyArray; /** * First modeled nested `sortState` under `CT_AutoFilter` (schema order: * filterColumn* → sortState? → extLst?). Unparsable / subsequent sortState * elements stay in {@link extraChildrenXml}. */ readonly sortState: SortStateModel | undefined; /** * Opaque children in relative order after filterColumn* (and after a * modeled nested sortState when present): extra `sortState`, `extLst`, * unknown elements. Relative order among themselves is kept; they always * serialize after the column list and the modeled nested sortState. */ readonly extraChildrenXml: ReadonlyArray; /** Extra attributes (unknown, plus invalid lexicals excluded from model). */ readonly extraAttrsXml: string; /** * Whole-element backup when the root `ref` is unparsable-but-preserved: * emits verbatim; public `autoFilter` reads as `undefined`. Modeled states * have `undefined`. */ readonly xml: string | undefined; } /** * Host notifications for AutoFilter mutations. * @private */ export interface AutoFilterHost { markDirty(): void; } /** * Internal AutoFilter implementation (package-owned singleton per worksheet). * Public {@link AutoFilter} identity is a generation-bound * {@link AutoFilterHandle} so replace/clear detach prior API references. * @private */ export declare class AutoFilterImpl { private model; private host; /** Generation token: bumped on whole-state replace / clear so old handles die. */ private generation; private readonly handles; /** Cached public root handle for the current generation (stable identity). */ private rootHandle; /** * Nested `CT_AutoFilter/sortState` store. Bound so mutations mark the * worksheet dirty through this AutoFilter host. Rebuilt on parse/author * and cleared with the AutoFilter. */ private nestedSort; /** Whether a modeled AutoFilter is present (public façade gate). */ readonly isPresent: boolean; /** * Bind the host that receives dirty notifications. * @private */ bindHost(host: AutoFilterHost): void; private nestedSortHost; /** * Sync nested sorter model into the AutoFilter model before serialize / * clone snapshots so nested mutations are not lost. * @private */ private flushNestedSortIntoModel; /** * Current generation-bound public handle, or `undefined` when absent. * Same object for a given generation so `sheet.autoFilter === addAutoFilter(…)`. * @private */ getPublicHandle(): AutoFilter | undefined; readonly range: string; readonly count: number; list(): ReadonlyArray; addFilterColumn(columnIndex: number): FilterColumn; get(index: number): FilterColumn; getByColumnIndex(columnIndex: number): FilterColumn | undefined; removeFilterColumn(column: FilterColumn): void; removeFilterColumnAt(index: number): void; clearFilterColumns(): void; /** * Nested sort state under this AutoFilter, or `undefined` when absent. * @private */ getNestedDataSorter(): DataSorter | undefined; /** * Author or replace nested `sortState` under this AutoFilter. * @private */ addNestedDataSorter(range: string): DataSorter; /** * Remove nested `sortState` under this AutoFilter. * @private */ removeNestedDataSorter(): void; /** * Author a fresh AutoFilter (or replace the existing record). * @private */ authorState(rangeText: string): void; /** * Remove the AutoFilter entirely. * @private */ clearState(): void; /** * Replace internal model from parse. * @private */ replaceFromParse(model: AutoFilterModel): void; /** * Snapshot for serialize. * @private */ toModel(): AutoFilterModel; /** * @private */ writeColumnMutation(colId: number, mutate: (entry: FilterColumnEntry) => FilterColumnEntry): void; /** * @private */ readColumn(colId: number): FilterColumnEntry; /** * @private */ currentGeneration(): number; /** * @private */ unregisterHandle(handle: FilterColumnHandle): void; private modeledColumns; private handleFor; private invalidateHandles; private assertLive; private modelRange; } /** * CT_Worksheet locals that appear **before** `autoFilter` after `sheetData`. */ export declare const AUTO_FILTER_PREDECESSORS: ReadonlyArray; /** * CT_Worksheet locals that appear **after** `autoFilter`. * Includes `sortState` (the immediate successor) plus sort-state successors. */ export declare const AUTO_FILTER_SUCCESSORS: ReadonlyArray; /** * Index at which to insert the serialized `autoFilter` among after-sheetData * siblings. Prefer: after the last known predecessor present; else before * the first known successor; else append. Unknown elements keep relative order. * @private */ export declare function findAutoFilterInsertIndex(afterSheetDataLocals: ReadonlyArray): number; /** * Parse a worksheet-level `autoFilter` element. * Unparsable root ref → whole-element opaque backup (`present: false`, * `xml` set) so a no-op save preserves it. * * @private */ export declare function parseAutoFilterXml(autoFilterXml: string): AutoFilterModel; /** * Serialize an AutoFilter model, or `undefined` when absent and no backup. * @private */ export declare function serializeAutoFilterXml(model: AutoFilterModel): string | undefined; /** * Generation-bound public {@link AutoFilter} handle. The worksheet keeps one * {@link AutoFilterImpl}; replace / clear / reload bump generation so prior * root handles throw {@link InvalidAutoFilterError}. * @private */ export declare class AutoFilterHandle implements AutoFilter { private readonly owner; private readonly bornGeneration; constructor(owner: AutoFilterImpl, bornGeneration: number); /** * @private */ isLiveFor(ownerGeneration: number): boolean; readonly range: string; readonly count: number; list(): ReadonlyArray; addFilterColumn(columnIndex: number): FilterColumn; get(index: number): FilterColumn; getByColumnIndex(columnIndex: number): FilterColumn | undefined; removeFilterColumn(column: FilterColumn): void; removeFilterColumnAt(index: number): void; readonly dataSorter: DataSorter | undefined; addDataSorter(range: string): DataSorter; removeDataSorter(): void; clearFilterColumns(): void; private assertLive; } /** * Live handle bound to one modeled filter column. * @private */ export declare class FilterColumnHandle implements FilterColumn { private readonly owner; private readonly colId; private readonly bornGeneration; private live; constructor(owner: AutoFilterImpl, colId: number, bornGeneration: number); readonly columnIndex: number; isButtonVisible: boolean; isButtonHidden: boolean; isBlank: boolean; readonly count: number; values(): ReadonlyArray; addValue(value: string): void; addValues(values: ReadonlyArray): void; removeValue(value: string): void; removeValueAt(index: number): void; clearValues(): void; /** * @private */ isLive(ownerGeneration: number): boolean; /** * @private */ kill(): void; private assertLive; }