@kanunilabs/pivotgrid-core 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -43,6 +43,29 @@ interface PivotDictionary {
43
43
  rawDataFormats: string;
44
44
  customExports: string;
45
45
  customPlugin: string;
46
+ saveReport: string;
47
+ saveReportDescription: string;
48
+ reportName: string;
49
+ reportNamePlaceholder: string;
50
+ setAsDefault: string;
51
+ save: string;
52
+ enterFullscreen: string;
53
+ exitFullscreen: string;
54
+ print: string;
55
+ sendToPrinter: string;
56
+ copyToClipboard: string;
57
+ tabSeparatedValues: string;
58
+ enterpriseBadge: string;
59
+ enterpriseUpgradeHint: string;
60
+ dataImportUnsupported: string;
61
+ columnFilter: string;
62
+ percentOfColumnTotal: string;
63
+ percentOfRowTotal: string;
64
+ percentDifference: string;
65
+ filterField: string;
66
+ removeFromArea: string;
67
+ removeField: string;
68
+ deletePermanently: string;
46
69
  importSuccess: string;
47
70
  importWarning: string;
48
71
  importError: string;
@@ -105,7 +128,81 @@ interface PivotDictionary {
105
128
  moveToEnd: string;
106
129
  moveToLeft: string;
107
130
  moveToRight: string;
131
+ /** Field chip a11y: caption, area, 1-based index, count. */
132
+ fieldChipLabel: string;
133
+ /** Field chip a11y: the key bindings, read as a description. */
134
+ fieldChipKeys: string;
135
+ /** Context-menu submenu that moves a field to another area. */
136
+ moveToArea: string;
137
+ /** Prefilter operator labels (#210) — shared vocabulary with DataGrid. */
138
+ opEquals: string;
139
+ opNotEquals: string;
140
+ opGreater: string;
141
+ opGreaterOrEqual: string;
142
+ opLess: string;
143
+ opLessOrEqual: string;
144
+ opContains: string;
145
+ opNotContains: string;
146
+ opStartsWith: string;
147
+ opEndsWith: string;
148
+ opIsBlank: string;
149
+ opIsNotBlank: string;
150
+ /** Prefilter builder chrome (#210) — shared with DataGrid. */
151
+ builderCombine: string;
152
+ builderAddCondition: string;
153
+ builderAddGroup: string;
154
+ builderRemoveGroup: string;
155
+ builderRemoveCondition: string;
156
+ builderEmpty: string;
157
+ builderValuePlaceholder: string;
158
+ /** Drill-down modal (#212); the pager/CSV five are shared with DataGrid. */
159
+ exportCsv: string;
160
+ pagerPage: string;
161
+ pagerOf: string;
162
+ pagerPrevious: string;
163
+ pagerNext: string;
164
+ drillDown: string;
165
+ /** `Label: {count}` — no plural engine, so no locale is ever ungrammatical. */
166
+ drillDownRecords: string;
167
+ /** Chart panel (#214); the eleven shared strings come from DataGrid. */
168
+ chart: string;
169
+ chartClose: string;
170
+ chartFullscreen: string;
171
+ chartExitFullscreen: string;
172
+ chartEmpty: string;
173
+ /** `Showing {shown} of {total}.` — used for categories AND for series. */
174
+ chartWindowed: string;
175
+ chartTypeColumn: string;
176
+ chartTypeBar: string;
177
+ chartTypeLine: string;
178
+ chartTypeArea: string;
179
+ chartTypePie: string;
180
+ chartTypeScatter: string;
181
+ chartTypePolar: string;
182
+ chartTypeCombination: string;
183
+ /** PDF export header (#215). */
184
+ exportGeneratedOn: string;
185
+ /** Designer level tiles and live formula verdict (#220). */
186
+ calcRowLevelHint: string;
187
+ calcSummaryLevelHint: string;
188
+ formulaValid: string;
189
+ calcFieldsHint: string;
190
+ /** `Uses: {fields}` — the captions the formula references. */
191
+ formulaUses: string;
108
192
  showFieldList: string;
193
+ /**
194
+ * License watermark reasons (1.3.0) — the badge shows the product name and
195
+ * one of these. Mapped to reason codes by `licenseLabelsFromDictionary`
196
+ * in @kanunilabs/licensing; the key names are that contract.
197
+ */
198
+ licenseMissing: string;
199
+ licenseExpired: string;
200
+ licenseReleaseNotCovered: string;
201
+ licenseDomainMismatch: string;
202
+ licenseRevoked: string;
203
+ licenseInvalidFormat: string;
204
+ licenseInvalidSignature: string;
205
+ licenseEngineUnavailable: string;
109
206
  editCalculation: string;
110
207
  [key: string]: string;
111
208
  }
@@ -547,7 +644,12 @@ declare function initPivotEngineAsync<TRow>(data: TRow[], rowFields: PivotField<
547
644
  * worker context, or the dataset changed) — the caller must fall back to a
548
645
  * full {@link initPivotEngineAsync}.
549
646
  */
550
- declare function reconfigurePivotEngineAsync<TRow>(data: TRow[], rowFields: PivotField<TRow>[], colFields: PivotField<TRow>[], dataFields: PivotField<TRow>[], registry?: PivotEngineRegistry): Promise<boolean>;
647
+ declare function reconfigurePivotEngineAsync<TRow>(data: TRow[], rowFields: PivotField<TRow>[], colFields: PivotField<TRow>[], dataFields: PivotField<TRow>[], registry?: PivotEngineRegistry,
648
+ /** All fields + the active prefilter, so its columns are encoded too. */
649
+ prefilterState?: {
650
+ fields: PivotField<TRow>[];
651
+ prefilter?: PivotPrefilter;
652
+ }): Promise<boolean>;
551
653
  /**
552
654
  * Send filter specs to the worker. Converts field.filterValues to
553
655
  * dictionary-encoded integer IDs so the worker can do fast integer
@@ -555,7 +657,16 @@ declare function reconfigurePivotEngineAsync<TRow>(data: TRow[], rowFields: Pivo
555
657
  */
556
658
  declare function filterPivotEngineAsync(fields: PivotField<any>[], prefilter?: PivotPrefilter): Promise<void>;
557
659
  declare function computePivotMatrixAsync(expandedPaths: string[], expandedColPaths: string[]): Promise<PivotEngineResult>;
558
- declare function getFieldDistinctValues(fieldId: string): FieldDistinctEntry[] | null;
660
+ /**
661
+ * Cached distinct values for a header filter.
662
+ *
663
+ * `gridId` is optional for backwards compatibility, but callers that know
664
+ * their own id MUST pass it: without it this resolves through the
665
+ * module-global `activeGridId` — whichever grid last ran an engine phase — so
666
+ * on a page with two grids sharing a field id, one grid's filter popup listed
667
+ * the OTHER grid's values (sweep #193).
668
+ */
669
+ declare function getFieldDistinctValues(fieldId: string, gridId?: string): FieldDistinctEntry[] | null;
559
670
 
560
671
  interface PivotReportState {
561
672
  fields: PivotField<any>[];
@@ -585,10 +696,111 @@ interface PivotReport {
585
696
  * intersection (colId). Nodes missing from the index maps are kept as-is
586
697
  * (they cannot be safely evaluated).
587
698
  */
699
+ /**
700
+ * How wide the frozen row-header block may get before it starves the data.
701
+ *
702
+ * Pinning every row-header column is fine until the block approaches the
703
+ * viewport, and then it collapses completely: the sticky headers cover the
704
+ * whole visible area and the crosstab is painted UNDERNEATH them, unreachable
705
+ * by scrolling because sticky boxes do not move (journal #201).
706
+ *
707
+ * The first attempt un-pinned the deep columns. That traded one broken rule
708
+ * for another — the row headers scrolled away with the data — and was
709
+ * rejected. The lever is WIDTH: every column stays frozen, and the block is
710
+ * compressed until the crosstab has somewhere to live.
711
+ *
712
+ * Both renderers call this. They must: the vanilla painter derives its sticky
713
+ * insets from these numbers and React sizes its left pane from them, and two
714
+ * copies of the arithmetic would be two copies to keep in step.
715
+ */
716
+ declare const ROW_HEADER_MIN_DATA_STRIP = 160;
717
+ declare const ROW_HEADER_MAX_PINNED_FRACTION = 0.6;
718
+ /** However tight it gets, a row-header column stays wide enough to read. */
719
+ declare const ROW_HEADER_MIN_COL_WIDTH = 56;
720
+ interface RowHeaderLayout {
721
+ /** Widths as PAINTED, one per row-header column. */
722
+ widths: number[];
723
+ /** Their sum — the width of the whole frozen block. */
724
+ total: number;
725
+ }
726
+ /**
727
+ * Row-header widths as painted: the configured widths, scaled down when the
728
+ * block would not leave room for the data.
729
+ *
730
+ * `viewport <= 0` means "not measured yet" — before the first layout, and in
731
+ * a hidden pane — and compresses nothing. Compressing on a guess would shrink
732
+ * every grid that has not been measured.
733
+ */
734
+ declare function computeRowHeaderWidths(configured: number[], viewport: number): RowHeaderLayout;
735
+ /**
736
+ * The configured width that, once the budget has compressed the block, paints
737
+ * column `index` at `targetPainted` — "what you drag is what you get".
738
+ *
739
+ * A resize grip lives on the PAINTED edge. Committing painted+delta as the
740
+ * CONFIGURED width is wrong under compression, and wrong in the worst way:
741
+ * eight columns configured 150 (painted 90) in a 1198px viewport, drag column
742
+ * 0 to 100, commit 100 → the configured total shrinks, the scale falls, and
743
+ * column 0 is painted 63. The user asked for wider and got narrower.
744
+ *
745
+ * The dragged column's painted width is c·budget/(c + rest), rounded, then
746
+ * floored — the scale comes from the CONFIGURED total, and the floor is
747
+ * applied per column afterwards, so the OTHER columns' floors never touch
748
+ * this one. That makes the inverse a closed form, c = t·rest/(budget − t),
749
+ * with a one-pixel correction for the rounding.
750
+ *
751
+ * What is stored matters beyond this viewport: the map persists through
752
+ * stateStoring and is painted again in wider containers. So the target is
753
+ * clamped to what a column can actually be painted at here — never below
754
+ * the floor, never past the point where the block no longer fits — and the
755
+ * returned width is the moderate one that paints there. (A first version
756
+ * bisected and returned the SMALLEST width in the floor band, i.e. 2px, and
757
+ * a ten-figure number for an unreachable target; both painted fine today
758
+ * and absurdly tomorrow.)
759
+ *
760
+ * Without compression this is the identity, so callers can use it always.
761
+ */
762
+ declare function invertRowHeaderWidth(configured: number[], index: number, targetPainted: number, viewport: number): number;
588
763
  declare function filterEmptySummaryTree(engineResult: PivotEngineResult): [PivotNode[], PivotNode[]];
589
- declare function getVisibleLeafCount(node: PivotNode, expandedColPaths: Set<string>, allExpanded?: boolean): number;
764
+ /**
765
+ * Column-axis subtotals: one extra leaf per EXPANDED node with children,
766
+ * holding that node's own aggregate.
767
+ *
768
+ * No second aggregation pass is needed and none is done. The engine already
769
+ * materialises a cell for every VISIBLE node, parents included — its
770
+ * ancestor walk keeps the parent in the chain when the parent is expanded
771
+ * (FlatPivotEngine.collectActiveAncestors), so `Electro` carries 420 while
772
+ * `Electro|Phone` carries 400 and `Electro|TV` carries 20. The column
773
+ * subtotal is therefore a LAYOUT concern: emit a leaf slot addressing the
774
+ * parent's own hash, in the right place.
775
+ *
776
+ * The three column functions below must agree cell for cell — the header
777
+ * builder, the leaf list the renderers index cells with, and the span count.
778
+ * A disagreement shifts every data cell under the wrong header, so they share
779
+ * this one options shape and a test asserts they produce the same count.
780
+ */
781
+ interface ColumnSlotOptions {
782
+ /** `layout.showColumnTotals` — per-level subtotals on the column axis. */
783
+ subTotals?: boolean;
784
+ /** Before or after the children, matching `layout.totalsPosition`. */
785
+ totalsPosition?: 'top' | 'bottom';
786
+ }
787
+ declare function getVisibleLeafCount(node: PivotNode, expandedColPaths: Set<string>, allExpanded?: boolean, opts?: ColumnSlotOptions): number;
590
788
  declare function getVisibleMaxDepth(nodes: PivotNode[], expandedColPaths: Set<string>, allExpanded?: boolean): number;
591
- declare function getVisibleColLeaves(nodes: PivotNode[], expandedColPaths: Set<string>, allExpanded?: boolean): PivotNode[];
789
+ /** One painted data column: the node whose hash addresses it, and why. */
790
+ interface ColumnSlot {
791
+ node: PivotNode;
792
+ /** True for a subtotal slot — the node's OWN aggregate beside its children. */
793
+ isSubtotal: boolean;
794
+ }
795
+ /**
796
+ * The visible data columns, in paint order.
797
+ *
798
+ * This is the list renderers index cells with, and it must line up one-for-one
799
+ * with the leaf cells `buildColumnHeaders` emits.
800
+ */
801
+ declare function getVisibleColSlots(nodes: PivotNode[], expandedColPaths: Set<string>, allExpanded?: boolean, opts?: ColumnSlotOptions): ColumnSlot[];
802
+ /** The visible data columns as bare nodes — `getVisibleColSlots` without the flags. */
803
+ declare function getVisibleColLeaves(nodes: PivotNode[], expandedColPaths: Set<string>, allExpanded?: boolean, opts?: ColumnSlotOptions): PivotNode[];
592
804
  interface ColHeaderCell {
593
805
  node: PivotNode | null;
594
806
  caption: string;
@@ -599,8 +811,26 @@ interface ColHeaderCell {
599
811
  colPath?: string;
600
812
  hasChildren?: boolean;
601
813
  isExpanded?: boolean;
814
+ /** A column-axis subtotal cell: the node's OWN aggregate beside its children. */
815
+ isSubtotal?: boolean;
816
+ /**
817
+ * Index of the first data column this cell sits above, in the FULL visible
818
+ * leaf order (already multiplied by the data-field count when measures are
819
+ * on the column axis).
820
+ *
821
+ * Renderers used to derive this by accumulating `colSpan` per header row,
822
+ * which is only correct when every row starts at leaf 0. A collapsed node
823
+ * at depth 0 appears in row 0 alone (it carries a rowSpan instead), so the
824
+ * next row holds only the expanded siblings' children — and their
825
+ * accumulator restarted at 0, addressing the collapsed sibling's column.
826
+ * The producer knows the true order, so it now states it (#194).
827
+ */
828
+ leafStart: number;
602
829
  }
603
- declare function buildColumnHeaders(colTree: PivotNode[], dataFields: PivotField[], layout: PivotLayoutState, expandedColPaths: Set<string>, allExpanded?: boolean): ColHeaderCell[][];
830
+ declare function buildColumnHeaders(colTree: PivotNode[], dataFields: PivotField[], layout: PivotLayoutState, expandedColPaths: Set<string>, allExpanded?: boolean, labels?: {
831
+ grandTotal?: string;
832
+ subTotal?: string;
833
+ }): ColHeaderCell[][];
604
834
  /**
605
835
  * A flattened row for rendering. Each row represents either:
606
836
  * - A leaf data row (values at each depth level column)
@@ -649,6 +879,52 @@ declare function flattenRowTreeTabular(nodes: PivotNode[], expandedPaths: Set<st
649
879
  */
650
880
  declare function flattenRowTreeTree(nodes: PivotNode[], expandedPaths: Set<string>, allExpanded: boolean, treeDepth: number, showRowTotals: boolean, totalsPosition: 'top' | 'bottom'): FlatRow[];
651
881
 
882
+ interface ValueRange {
883
+ min: number;
884
+ max: number;
885
+ }
886
+ /** What a cell should look like once its rules have been applied. */
887
+ interface ConditionalVisual {
888
+ /** Style properties to merge into the cell — the historical `style` object. */
889
+ style: Record<string, string | number>;
890
+ /**
891
+ * A data bar: how far to fill (0..1), in what colour, and which way. The
892
+ * renderer draws it; core will not pick a gradient syntax for everyone.
893
+ */
894
+ dataBar?: {
895
+ ratio: number;
896
+ color: string;
897
+ negative: boolean;
898
+ };
899
+ /** The icon a renderer should draw before the value, by name. */
900
+ icon?: string;
901
+ }
902
+ declare function fieldNeedsRange(field: PivotField): boolean;
903
+ /**
904
+ * The min and max of each measure across the CURRENT matrix.
905
+ *
906
+ * TOTALS ARE EXCLUDED. A grand total is an order of magnitude above the cells
907
+ * beside it, and letting it set the top of the scale flattens every real value
908
+ * into the first colour stop — the scale would technically be correct and
909
+ * visually useless. A cell is a total when either index is 0 (the root row or
910
+ * root column), which is how the matrix already addresses them.
911
+ */
912
+ declare function computeFieldRanges(engineResult: PivotEngineResult, dataFields: PivotField[]): Record<string, ValueRange>;
913
+ /** #rgb / #rrggbb / rgb(...) → [r,g,b], or null when it cannot be parsed. */
914
+ declare function parseColor(color: string | undefined): [number, number, number] | null;
915
+ /** Position of `value` inside the range, 0..1. A flat range is all zero. */
916
+ declare function rangeRatio(value: number, range: ValueRange | undefined): number;
917
+ /** Blend across two or three stops, the way a spreadsheet colour scale does. */
918
+ declare function scaleColor(ratio: number, stops: string[]): string | null;
919
+ /**
920
+ * Apply every rule on a field to one cell.
921
+ *
922
+ * `expression` keeps its exact historical behaviour, evaluation errors and
923
+ * all: a throwing formula is skipped rather than breaking the paint, which is
924
+ * what both renderers already did.
925
+ */
926
+ declare function resolveConditionalVisual(value: number | undefined, field: PivotField, cell: PivotCell | null, range?: ValueRange): ConditionalVisual;
927
+
652
928
  type ExportFormat = 'excel-list' | 'excel-pivot' | 'pdf' | 'json' | 'json-pivot' | 'json-snapshot' | 'xml' | 'csv' | 'print' | 'clipboard';
653
929
  /** Options passed to the export pipeline — all fields optional for backward compat. */
654
930
  interface ExportOptions {
@@ -704,7 +980,9 @@ declare function flattenExportRows(engineResult: PivotEngineResult, rowFields: P
704
980
  * single indented label (subtotals keep a "Total" marker so downstream
705
981
  * heuristics still recognize them); tabular mode returns one cell per depth.
706
982
  */
707
- declare function buildRowLabelCells(flatRow: FlatRow, rowFields: PivotField[], treeMode: boolean, rowLabelCols: number, locale: string): any[];
983
+ declare function buildRowLabelCells(flatRow: FlatRow, rowFields: PivotField[], treeMode: boolean, rowLabelCols: number, locale: string, labels?: {
984
+ subTotal?: string;
985
+ }): any[];
708
986
  /** Find the data field for a given column path entry. */
709
987
  declare function resolveColPath(cPathInfo: string[], dataFields: PivotField[]): {
710
988
  cHash: string;
@@ -717,7 +995,10 @@ declare function resolveColPath(cPathInfo: string[], dataFields: PivotField[]):
717
995
  * event loop every {@link AOA_CHUNK} rows, honors an AbortSignal, and reports
718
996
  * incremental progress. Returns `null` when the export was aborted mid-build.
719
997
  */
720
- declare function buildPivotAOA(engineResult: PivotEngineResult, rowFields: PivotField[], dataFields: PivotField[], layout: PivotLayoutState, expandedPaths: Set<string>, expandedColPaths: Set<string>, allExpanded?: boolean, locale?: string, applyFormatting?: boolean, colFields?: PivotField[], signal?: AbortSignal, onProgress?: (percent: number) => void): Promise<{
998
+ declare function buildPivotAOA(engineResult: PivotEngineResult, rowFields: PivotField[], dataFields: PivotField[], layout: PivotLayoutState, expandedPaths: Set<string>, expandedColPaths: Set<string>, allExpanded?: boolean, locale?: string, applyFormatting?: boolean, colFields?: PivotField[], signal?: AbortSignal, onProgress?: (percent: number) => void, labels?: {
999
+ grandTotal?: string;
1000
+ subTotal?: string;
1001
+ }): Promise<{
721
1002
  aoa: any[][];
722
1003
  styles: (ExportCellStyle | null)[][] | null;
723
1004
  } | null>;
@@ -852,14 +1133,35 @@ interface PivotField<TRow = any, TCellTemplate = PivotCellTemplate, TStyle = any
852
1133
  }
853
1134
  /** Controls pivot grid layout, totals visibility, and structural options. */
854
1135
  interface PivotLayoutState {
1136
+ /** The grand total COLUMN, at the end of every row. */
855
1137
  showColumnGrandTotals?: boolean;
1138
+ /** The grand total ROW, at the end of the grid. */
856
1139
  showRowGrandTotals?: boolean;
1140
+ /**
1141
+ * @deprecated NOT IMPLEMENTED. Subtotals on the column axis do not exist:
1142
+ * row subtotals are inserted while flattening the row tree, and the column
1143
+ * axis has no equivalent pass in the renderer. Setting this to `true`
1144
+ * explicitly reports through `onError`; it is left in the type because it
1145
+ * has always had a default of `true`, so removing it would be a breaking
1146
+ * change for a value that never did anything.
1147
+ */
857
1148
  showColumnTotals?: boolean;
1149
+ /** Per-level subtotals on the row axis. */
858
1150
  showRowTotals?: boolean;
859
1151
  /** Whether subtotals appear above or below their groups. */
860
1152
  totalsPosition?: 'top' | 'bottom';
1153
+ /**
1154
+ * Coarse form of `showRowGrandTotals` + `showColumnGrandTotals`. Bridged to
1155
+ * them at the controller boundary; an explicitly passed granular flag wins.
1156
+ */
861
1157
  showGrandTotals?: 'rows' | 'columns' | 'both' | 'none';
1158
+ /**
1159
+ * Coarse form of `showRowTotals`. Bridged for the ROW axis only — asking for
1160
+ * `'columns'` or `'both'` reports through `onError`, because column subtotals
1161
+ * are not implemented. See `showColumnTotals`.
1162
+ */
862
1163
  showSubTotals?: 'rows' | 'columns' | 'both' | 'none';
1164
+ /** Alias of `totalsPosition`, bridged at the controller boundary. */
863
1165
  totalsDisplayMode?: 'top' | 'bottom';
864
1166
  /** Row header style: 'tabular' gives one column per row field, 'tree' nests all into one column. */
865
1167
  rowHeaderLayout?: 'tabular' | 'tree';
@@ -1190,6 +1492,14 @@ declare class PivotController<TRow> {
1190
1492
  updateField(updatedField: PivotField<TRow>): void;
1191
1493
  deleteField(fieldId: string): void;
1192
1494
  changeFieldArea(fieldId: string, area: PivotArea): void;
1495
+ /**
1496
+ * Take several fields out of the chooser in ONE commit.
1497
+ *
1498
+ * The routing rule is the field chooser's checkbox rule — a number is a
1499
+ * measure, anything else describes a row — and it lives here so the vanilla
1500
+ * chooser, the React chooser and the Angular one cannot drift on it.
1501
+ */
1502
+ showFields(fieldIds: string[]): void;
1193
1503
  removeField(fieldId: string): void;
1194
1504
  moveField(fieldId: string, direction: 'start' | 'end' | 'left' | 'right'): void;
1195
1505
  sortField(fieldId: string, direction: 'asc' | 'desc' | undefined): void;
@@ -1198,6 +1508,14 @@ declare class PivotController<TRow> {
1198
1508
  applyFilter(fieldId: string, selectedValues: Set<any>, filterType: 'include' | 'exclude'): void;
1199
1509
  clearFilter(fieldId: string): void;
1200
1510
  setLayout(updates: Partial<PivotLayoutState>): void;
1511
+ private readonly unsupportedReporter;
1512
+ /**
1513
+ * Translate a whole layout arriving from outside — the `layout` prop, or a
1514
+ * controlled update — and report what could not be honoured.
1515
+ *
1516
+ * Returns `undefined` for `undefined` so callers can keep their `??` chain.
1517
+ */
1518
+ private normalizeIncomingLayout;
1201
1519
  toggleExpanded(path: string): void;
1202
1520
  expandPaths(paths: string[]): void;
1203
1521
  collapsePaths(paths: string[]): void;
@@ -1368,6 +1686,15 @@ declare class PivotEngineService<TRow> {
1368
1686
  * user expanded all nodes manually.
1369
1687
  */
1370
1688
  computeFullyExpandedSnapshot(): Promise<PivotEngineResult>;
1689
+ /**
1690
+ * Surface options the sort accepted but could not honour.
1691
+ *
1692
+ * Routed to `onError` rather than thrown: the pivot it just built is correct
1693
+ * and useful, so failing the whole compute would be worse than the problem.
1694
+ * See utils/unsupported.ts for why it is not a console warning.
1695
+ */
1696
+ private readonly unsupportedReporter;
1697
+ private reportUnsupported;
1371
1698
  private startBuildProgress;
1372
1699
  private tickBuildProgress;
1373
1700
  private advanceBuildProgress;
@@ -1408,6 +1735,24 @@ declare class PivotFieldService {
1408
1735
  static removeField<TRow>(fields: PivotField<TRow>[], fieldId: string): PivotField<TRow>[];
1409
1736
  static deleteField<TRow>(fields: PivotField<TRow>[], fieldId: string): PivotField<TRow>[];
1410
1737
  static changeFieldArea<TRow>(fields: PivotField<TRow>[], fieldId: string, area: PivotArea): PivotField<TRow>[];
1738
+ /**
1739
+ * Move several fields into areas in ONE commit.
1740
+ *
1741
+ * `changeFieldArea` in a loop is the obvious way to write "show all these
1742
+ * fields", and it is the wrong one: every call commits, which re-runs the
1743
+ * engine. On the million-row demo that is one full rebuild per field.
1744
+ *
1745
+ * The areaIndex bookkeeping is the reason this cannot just be a `map`.
1746
+ * `changeFieldArea` derives its index from CURRENT occupancy
1747
+ * (`fields.filter(c => c.area === area).length`); doing that per field
1748
+ * inside one pass would hand every arrival the same number, and
1749
+ * `normalizeAreaIndexes` sorts on that key — so an all-equal key would drop
1750
+ * the batch into whatever order `sort` happened to produce. Instead each
1751
+ * area's counter is seeded from occupancy once and then advanced, so the
1752
+ * newcomers land after the fields already there, in the order the CALLER
1753
+ * listed them (which is the order the user was looking at).
1754
+ */
1755
+ static placeFields<TRow>(fields: PivotField<TRow>[], fieldIds: string[], pick: (field: PivotField<TRow>) => PivotArea): PivotField<TRow>[];
1411
1756
  static moveFieldByDirection<TRow>(fields: PivotField<TRow>[], fieldId: string, direction: 'start' | 'end' | 'left' | 'right'): PivotField<TRow>[];
1412
1757
  static moveFieldFromDrop<TRow>(fields: PivotField<TRow>[], command: FieldDropCommand): Promise<PivotField<TRow>[]>;
1413
1758
  static calculateDropIntent(pointerX: number, pointerY: number, itemRect: DropIntentRect, previousIntent: DropIntent, isLastItem: boolean, orientation?: 'horizontal' | 'vertical'): DropIntent;
@@ -1482,7 +1827,23 @@ declare function testSafeFormula(formulaString: string, fieldMap: Map<string, st
1482
1827
  declare function filterRecords<TRow>(records: TRow[], fields: PivotField<TRow>[], prefilter?: PivotPrefilter): TRow[];
1483
1828
  declare function filterRecordsAsync<TRow>(records: TRow[], fields: PivotField<TRow>[], prefilter?: PivotPrefilter): Promise<TRow[]>;
1484
1829
 
1485
- declare function sortPivotTree(nodes: PivotNode[], fields: PivotField<any>[], engineResult: PivotEngineResult, dataFields: PivotField<any>[], isRowTree: boolean, locale?: string, cellMapCache?: Map<number, number>): void;
1830
+ /**
1831
+ * Anything the sort accepted but could not honour, so the caller can surface it
1832
+ * instead of the option being swallowed.
1833
+ *
1834
+ * `topNShowOthers` is the reason this exists. It used to report that the whole
1835
+ * feature was missing; since #200 the Others node is built, and what is
1836
+ * reported is narrower and exact: `avg` and `distinct` cannot be combined from
1837
+ * already-aggregated cells (one needs the row counts behind each value, the
1838
+ * other the values themselves), so those measures are left empty rather than
1839
+ * filled with a plausible wrong number. `sum`, `count`, `min` and `max` are
1840
+ * exact — the cut nodes are still fully aggregated in the matrix, so no second
1841
+ * pass over the source data is involved.
1842
+ */
1843
+ interface SortOutcome {
1844
+ unsupported: string[];
1845
+ }
1846
+ declare function sortPivotTree(nodes: PivotNode[], fields: PivotField<any>[], engineResult: PivotEngineResult, dataFields: PivotField<any>[], isRowTree: boolean, locale?: string, cellMapCache?: Map<number, number>, outcome?: SortOutcome): void;
1486
1847
 
1487
1848
  declare function executePostAggregationPhase<TRow>(engineResult: PivotEngineResult, dataFields: PivotField<TRow>[], registry?: PivotEngineRegistry): void;
1488
1849
  declare function executeSummaryDisplayModesPhase<TRow>(engineResult: PivotEngineResult, dataFields: PivotField<TRow>[]): void;
@@ -1875,4 +2236,4 @@ declare function coerceRecords(records: Record<string, unknown>[], onProgress?:
1875
2236
  */
1876
2237
  declare function parseCsvToRows(text: string, onProgress?: (p: CsvParseProgress) => void): Record<string, unknown>[];
1877
2238
 
1878
- export { type AdvancedExportRequest, type AdvancedExporter, type CellClickEvent, type CellPreparedEvent, type CellType, type CsvParseProgress, CsvReader, type CustomSummaryOptions, DataNormalizer, type DateFormatContext, DateFormatter, type DateGranularity, type DropIntent, type ExportFormat, type ExportOptions, ExportStreamController, type ExportingEvent, FastTrie, type FieldDistinctEntry, type FieldMoveEvent, type FilterCondition, type FilterGroup, type FilterOperator, type FlatCellMatrix, FlatPivotEngine, type FlatRow, type IFileReader, type ImportFormat, ImportManager, type ImportManagerOptions, type ImportProgress, type ImportResult, type ImportSnapshot, ImportStreamController, type ImportWorkerKind, type ImportWorkerResult, MAX_C, type ParseFileOptions, type PivotArea, type PivotCell, PivotCellAggregator, type PivotCellTemplate, type PivotCellTextAccessor, type PivotCellValueAccessor, type PivotConditionRule, PivotController, type PivotControllerCallbacks, type PivotControllerEvents, type PivotControllerOptions, type PivotControllerState, type PivotDataSource, type PivotDictionary, type PivotDragIntentState, PivotEngineRegistry, type PivotEngineResult, PivotEngineService, type PivotEngineServiceConfig, PivotEventEmitter, type PivotEventHandler, type PivotEventMap, PivotExportService, type PivotField, PivotFieldService, type PivotGridRef, type PivotGroupInterval, type PivotImportField, type PivotImportLabels, type PivotImportPreviewState, type PivotImportStatus, type PivotLayoutProfile, type PivotLayoutState, type PivotLocale, type PivotNode, type PivotPlugin, type PivotPrefilter, type PivotReport, PivotReportManager, PivotReportService, type PivotReportState, type PivotSelectionMode, PivotSelectionModel, type PivotSelectionRange, type PivotSelectionState, type PivotSelectionStats, type PivotStateListener, PivotStateStore, type PivotStateStoringConfig, type PivotSummaryDisplayMode, type PivotSummaryType, type PivotTheme, type PivotToolbarConfig, type PivotValue, type PrefilterConditionSpec, type PrefilterGroupSpec, type ProcessFileStreamingOptions, type ProcessFromUrlOptions, type ValidationResult, type WorkerComputeRequest, type WorkerFilterRequest, type WorkerFilterSpec, type WorkerInitRequest, type WorkerResponse, XmlReader, ar, buildCellLookup, buildColPathsList, buildColumnHeaders, buildPivotAOA, buildRowLabelCells, cellHash, cellHashCol, cellHashRow, classifyValue, clearFormatCache, coerceRecords, coerceValue, compileSafeFormula, computePivotMatrixAsync, conditionRuleToExcelStyle, cssColorToRgb, de, dedupeHeaders, defaultPivotLayout, destroyEngineWorker, detectDelimiter, en, es, escapeXmlText, executePostAggregationPhase, executeSummaryDisplayModesPhase, exportPivotData, extractGroupValue, filterEmptySummaryTree, filterPivotEngineAsync, filterRecords, filterRecordsAsync, flattenExportRows, flattenRowTree, flattenRowTreeTabular, flattenRowTreeTree, formatCellValue, formatCellValueCached, formatHeaderValue, fr, getAdvancedExporter, getCellVal, getFieldDistinctValues, getVisibleColLeaves, getVisibleLeafCount, getVisibleMaxDepth, inferColumnType, initPivotEngineAsync, intlFormatToExcelNumFmt, it, ja, ko, parseBoolean, parseCsvToRows, parseDelimited, parseFlexibleDate, parseLocaleNumber, pt, reconfigurePivotEngineAsync, registerAdvancedExporter, resolveColPath, ru, safeKey, sanitizeRows, setActiveEngineGrid, sortPivotTree, stripBom, testSafeFormula, tr, zhCN };
2239
+ export { type AdvancedExportRequest, type AdvancedExporter, type CellClickEvent, type CellPreparedEvent, type CellType, type ColHeaderCell, type ColumnSlot, type ColumnSlotOptions, type ConditionalVisual, type CsvParseProgress, CsvReader, type CustomSummaryOptions, DataNormalizer, type DateFormatContext, DateFormatter, type DateGranularity, type DropIntent, type ExportFormat, type ExportOptions, ExportStreamController, type ExportingEvent, FastTrie, type FieldDistinctEntry, type FieldMoveEvent, type FilterCondition, type FilterGroup, type FilterOperator, type FlatCellMatrix, FlatPivotEngine, type FlatRow, type IFileReader, type ImportFormat, ImportManager, type ImportManagerOptions, type ImportProgress, type ImportResult, type ImportSnapshot, ImportStreamController, type ImportWorkerKind, type ImportWorkerResult, MAX_C, type ParseFileOptions, type PivotArea, type PivotCell, PivotCellAggregator, type PivotCellTemplate, type PivotCellTextAccessor, type PivotCellValueAccessor, type PivotConditionRule, PivotController, type PivotControllerCallbacks, type PivotControllerEvents, type PivotControllerOptions, type PivotControllerState, type PivotDataSource, type PivotDictionary, type PivotDragIntentState, PivotEngineRegistry, type PivotEngineResult, PivotEngineService, type PivotEngineServiceConfig, PivotEventEmitter, type PivotEventHandler, type PivotEventMap, PivotExportService, type PivotField, PivotFieldService, type PivotGridRef, type PivotGroupInterval, type PivotImportField, type PivotImportLabels, type PivotImportPreviewState, type PivotImportStatus, type PivotLayoutProfile, type PivotLayoutState, type PivotLocale, type PivotNode, type PivotPlugin, type PivotPrefilter, type PivotReport, PivotReportManager, PivotReportService, type PivotReportState, type PivotSelectionMode, PivotSelectionModel, type PivotSelectionRange, type PivotSelectionState, type PivotSelectionStats, type PivotStateListener, PivotStateStore, type PivotStateStoringConfig, type PivotSummaryDisplayMode, type PivotSummaryType, type PivotTheme, type PivotToolbarConfig, type PivotValue, type PrefilterConditionSpec, type PrefilterGroupSpec, type ProcessFileStreamingOptions, type ProcessFromUrlOptions, ROW_HEADER_MAX_PINNED_FRACTION, ROW_HEADER_MIN_COL_WIDTH, ROW_HEADER_MIN_DATA_STRIP, type RowHeaderLayout, type ValidationResult, type ValueRange, type WorkerComputeRequest, type WorkerFilterRequest, type WorkerFilterSpec, type WorkerInitRequest, type WorkerResponse, XmlReader, ar, buildCellLookup, buildColPathsList, buildColumnHeaders, buildPivotAOA, buildRowLabelCells, cellHash, cellHashCol, cellHashRow, classifyValue, clearFormatCache, coerceRecords, coerceValue, compileSafeFormula, computeFieldRanges, computePivotMatrixAsync, computeRowHeaderWidths, conditionRuleToExcelStyle, cssColorToRgb, de, dedupeHeaders, defaultPivotLayout, destroyEngineWorker, detectDelimiter, en, es, escapeXmlText, executePostAggregationPhase, executeSummaryDisplayModesPhase, exportPivotData, extractGroupValue, fieldNeedsRange, filterEmptySummaryTree, filterPivotEngineAsync, filterRecords, filterRecordsAsync, flattenExportRows, flattenRowTree, flattenRowTreeTabular, flattenRowTreeTree, formatCellValue, formatCellValueCached, formatHeaderValue, fr, getAdvancedExporter, getCellVal, getFieldDistinctValues, getVisibleColLeaves, getVisibleColSlots, getVisibleLeafCount, getVisibleMaxDepth, inferColumnType, initPivotEngineAsync, intlFormatToExcelNumFmt, invertRowHeaderWidth, it, ja, ko, parseBoolean, parseColor, parseCsvToRows, parseDelimited, parseFlexibleDate, parseLocaleNumber, pt, rangeRatio, reconfigurePivotEngineAsync, registerAdvancedExporter, resolveColPath, resolveConditionalVisual, ru, safeKey, sanitizeRows, scaleColor, setActiveEngineGrid, sortPivotTree, stripBom, testSafeFormula, tr, zhCN };