@odoo/o-spreadsheet 18.0.50 → 18.0.54

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.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 18.0.50
6
- * @date 2025-12-02T05:32:00.480Z
7
- * @hash 7ed20c4
5
+ * @version 18.0.54
6
+ * @date 2026-01-14T10:00:02.287Z
7
+ * @hash c0048a0
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -5838,17 +5838,41 @@ function toCriterionDateNumber(dateValue) {
5838
5838
  const today = DateTime.now();
5839
5839
  switch (dateValue) {
5840
5840
  case "today":
5841
- return jsDateToNumber(today);
5842
- case "yesterday":
5843
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
5844
- case "tomorrow":
5845
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
5841
+ return Math.floor(jsDateToNumber(today));
5842
+ case "yesterday": {
5843
+ today.setDate(today.getDate() - 1);
5844
+ return Math.floor(jsDateToNumber(today));
5845
+ }
5846
+ case "tomorrow": {
5847
+ today.setDate(today.getDate() + 1);
5848
+ return Math.floor(jsDateToNumber(today));
5849
+ }
5846
5850
  case "lastWeek":
5847
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
5848
- case "lastMonth":
5849
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
5851
+ today.setDate(today.getDate() - 6);
5852
+ return Math.floor(jsDateToNumber(today));
5853
+ case "lastMonth": {
5854
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
5855
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
5856
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
5857
+ today.setDate(1);
5858
+ }
5859
+ else {
5860
+ today.setDate(today.getDate() + 1);
5861
+ today.setMonth(today.getMonth() - 1);
5862
+ }
5863
+ return Math.floor(jsDateToNumber(today));
5864
+ }
5850
5865
  case "lastYear":
5851
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
5866
+ // Handle leap year case
5867
+ if (today.getMonth() === 1 && today.getDate() === 29) {
5868
+ today.setDate(28);
5869
+ today.setFullYear(today.getFullYear() - 1);
5870
+ }
5871
+ else {
5872
+ today.setDate(today.getDate() + 1);
5873
+ today.setFullYear(today.getFullYear() - 1);
5874
+ }
5875
+ return Math.floor(jsDateToNumber(today));
5852
5876
  }
5853
5877
  }
5854
5878
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -18539,9 +18563,10 @@ function assertDomainLength(domain) {
18539
18563
  throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
18540
18564
  }
18541
18565
  }
18542
- function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
18566
+ function addPivotDependencies(evalContext, pivotId, forMeasures) {
18543
18567
  //TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
18544
18568
  const dependencies = [];
18569
+ const coreDefinition = evalContext.getters.getPivotCoreDefinition(pivotId);
18545
18570
  if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
18546
18571
  const { sheetId, zone } = coreDefinition.dataSet;
18547
18572
  const xc = zoneToXc(zone);
@@ -18558,8 +18583,7 @@ function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
18558
18583
  }
18559
18584
  for (const measure of forMeasures) {
18560
18585
  if (measure.computedBy) {
18561
- const formula = evalContext.getters.getMeasureCompiledFormula(measure);
18562
- dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
18586
+ dependencies.push(...evalContext.getters.getMeasureFullDependencies(pivotId, measure));
18563
18587
  }
18564
18588
  }
18565
18589
  const originPosition = evalContext.__originCellPosition;
@@ -19000,7 +19024,7 @@ const PIVOT_VALUE = {
19000
19024
  assertDomainLength(domainArgs);
19001
19025
  const pivot = this.getters.getPivot(pivotId);
19002
19026
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
19003
- addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
19027
+ addPivotDependencies(this, pivotId, coreDefinition.measures.filter((m) => m.id === _measure));
19004
19028
  pivot.init({ reload: pivot.needsReevaluation });
19005
19029
  const error = pivot.assertIsValid({ throwOnError: false });
19006
19030
  if (error) {
@@ -19033,8 +19057,7 @@ const PIVOT_HEADER = {
19033
19057
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
19034
19058
  assertDomainLength(domainArgs);
19035
19059
  const pivot = this.getters.getPivot(_pivotId);
19036
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
19037
- addPivotDependencies(this, coreDefinition, []);
19060
+ addPivotDependencies(this, _pivotId, []);
19038
19061
  pivot.init({ reload: pivot.needsReevaluation });
19039
19062
  const error = pivot.assertIsValid({ throwOnError: false });
19040
19063
  if (error) {
@@ -19088,7 +19111,7 @@ const PIVOT = {
19088
19111
  const pivotId = getPivotId(_pivotFormulaId, this.getters);
19089
19112
  const pivot = this.getters.getPivot(pivotId);
19090
19113
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
19091
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
19114
+ addPivotDependencies(this, pivotId, coreDefinition.measures);
19092
19115
  pivot.init({ reload: pivot.needsReevaluation });
19093
19116
  const error = pivot.assertIsValid({ throwOnError: false });
19094
19117
  if (error) {
@@ -40345,14 +40368,15 @@ function useHighlights(highlightProvider) {
40345
40368
  }
40346
40369
 
40347
40370
  css /* scss */ `
40348
- .o-cf-preview {
40371
+ .o-spreadsheet .o-cf-preview {
40349
40372
  &.o-cf-cursor-ptr {
40350
40373
  cursor: pointer;
40351
40374
  }
40352
40375
 
40353
40376
  border-bottom: 1px solid ${GRAY_300};
40354
- height: 60px;
40377
+ height: 80px;
40355
40378
  padding: 10px;
40379
+ box-sizing: border-box;
40356
40380
  position: relative;
40357
40381
  cursor: pointer;
40358
40382
  &:hover,
@@ -40366,7 +40390,6 @@ css /* scss */ `
40366
40390
  .o-cf-preview-icon {
40367
40391
  border: 1px solid ${GRAY_300};
40368
40392
  background-color: #fff;
40369
- position: absolute;
40370
40393
  height: 50px;
40371
40394
  width: 50px;
40372
40395
  .o-icon {
@@ -40375,12 +40398,6 @@ css /* scss */ `
40375
40398
  }
40376
40399
  }
40377
40400
  .o-cf-preview-description {
40378
- left: 65px;
40379
- margin-bottom: auto;
40380
- margin-right: 8px;
40381
- margin-top: auto;
40382
- position: relative;
40383
- width: 142px;
40384
40401
  .o-cf-preview-description-rule {
40385
40402
  margin-bottom: 4px;
40386
40403
  max-height: 2.8em;
@@ -40390,16 +40407,11 @@ css /* scss */ `
40390
40407
  font-size: 12px;
40391
40408
  }
40392
40409
  }
40393
- .o-cf-delete {
40394
- left: 90%;
40395
- top: 39%;
40396
- position: absolute;
40397
- }
40398
40410
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
40399
40411
  display: none !important;
40400
40412
  }
40401
40413
  .o-cf-drag-handle {
40402
- left: -8px;
40414
+ left: 2px;
40403
40415
  cursor: move;
40404
40416
  .o-icon {
40405
40417
  width: 6px;
@@ -41284,7 +41296,7 @@ dataValidationEvaluatorRegistry.add("dateIs", {
41284
41296
  return false;
41285
41297
  }
41286
41298
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
41287
- const today = jsDateToRoundNumber(DateTime.now());
41299
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
41288
41300
  return isDateBetween(dateValue, today, criterionValue);
41289
41301
  }
41290
41302
  return areDatesSameDay(dateValue, criterionValue);
@@ -42446,6 +42458,11 @@ class FindAndReplaceStore extends SpreadsheetStore {
42446
42458
  case "UPDATE_CELL":
42447
42459
  case "ACTIVATE_SHEET":
42448
42460
  this.isSearchDirty = true;
42461
+ if (this.searchOptions.specificRange) {
42462
+ this.searchOptions.specificRange = this.searchOptions.specificRange.clone({
42463
+ sheetId: this.getters.getActiveSheetId(),
42464
+ });
42465
+ }
42449
42466
  break;
42450
42467
  case "REPLACE_SEARCH":
42451
42468
  for (const match of cmd.matches) {
@@ -42851,9 +42868,20 @@ class FindAndReplacePanel extends Component {
42851
42868
  const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
42852
42869
  this.store.updateSearchOptions({ specificRange });
42853
42870
  }
42871
+ get specificRange() {
42872
+ const range = this.store.searchOptions.specificRange;
42873
+ return range ? this.env.model.getters.getRangeString(range, "forceSheetReference") : "";
42874
+ }
42854
42875
  get pendingSearch() {
42855
42876
  return this.updateSearchContent.isDebouncePending();
42856
42877
  }
42878
+ get selectionInputKey() {
42879
+ // Selections input are made to work with objects linked to a sheet id. They store the active sheet id at their creation,
42880
+ // and have specific behaviour linked to it (eg. go back to the initial sheet after confirmation).
42881
+ // We don't want all those behaviors here, so we force the recreation of the component when the active sheet changes.
42882
+ // The only drawback is that the input loses focus when changing sheet.
42883
+ return this.env.model.getters.getActiveSheetId();
42884
+ }
42857
42885
  }
42858
42886
 
42859
42887
  css /* scss */ `
@@ -44988,7 +45016,37 @@ pivotRegistry.add("SPREADSHEET", {
44988
45016
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
44989
45017
  isMeasureCandidate: (field) => !["datetime", "boolean"].includes(field.type),
44990
45018
  isGroupable: () => true,
45019
+ adaptRanges: (getters, definition, applyChange) => {
45020
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
45021
+ return definition;
45022
+ }
45023
+ const { sheetId, zone } = definition.dataSet;
45024
+ const range = getters.getRangeFromZone(sheetId, zone);
45025
+ const adaptedRange = adaptPivotRange(range, applyChange);
45026
+ if (adaptedRange === range) {
45027
+ return definition;
45028
+ }
45029
+ const dataSet = adaptedRange && {
45030
+ sheetId: adaptedRange.sheetId,
45031
+ zone: adaptedRange.zone,
45032
+ };
45033
+ return { ...definition, dataSet };
45034
+ },
44991
45035
  });
45036
+ function adaptPivotRange(range, applyChange) {
45037
+ if (!range) {
45038
+ return undefined;
45039
+ }
45040
+ const change = applyChange(range);
45041
+ switch (change.changeType) {
45042
+ case "NONE":
45043
+ return range;
45044
+ case "REMOVE":
45045
+ return undefined;
45046
+ default:
45047
+ return change.range;
45048
+ }
45049
+ }
44992
45050
 
44993
45051
  class PivotSidePanelStore extends SpreadsheetStore {
44994
45052
  pivotId;
@@ -46875,21 +46933,20 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
46875
46933
  this.highlightStore.register(this);
46876
46934
  }
46877
46935
  get highlights() {
46878
- let zone;
46879
46936
  const position = this.model.getters.getActivePosition();
46880
- const cell = this.getters.getEvaluatedCell(position);
46881
46937
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
46882
- zone = spreader
46938
+ const zone = spreader
46883
46939
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
46884
46940
  : this.model.getters.getSpreadZone(position, { ignoreSpillError: true });
46885
46941
  if (!zone) {
46886
46942
  return [];
46887
46943
  }
46944
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
46888
46945
  return [
46889
46946
  {
46890
46947
  sheetId: position.sheetId,
46891
46948
  zone,
46892
- dashed: cell.value === CellErrorType.SpilledBlocked,
46949
+ dashed: isArrayFormulaBlocked,
46893
46950
  color: "#17A2B8",
46894
46951
  noFill: true,
46895
46952
  thinLine: true,
@@ -54950,6 +55007,7 @@ function rangeToMerge(mergeId, range) {
54950
55007
  class RangeAdapter {
54951
55008
  getters;
54952
55009
  providers = [];
55010
+ isAdaptingRanges = false;
54953
55011
  constructor(getters) {
54954
55012
  this.getters = getters;
54955
55013
  }
@@ -54978,6 +55036,9 @@ class RangeAdapter {
54978
55036
  }
54979
55037
  beforeHandle(command) { }
54980
55038
  handle(cmd) {
55039
+ if (this.isAdaptingRanges) {
55040
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
55041
+ }
54981
55042
  switch (cmd.type) {
54982
55043
  case "REMOVE_COLUMNS_ROWS": {
54983
55044
  let start = cmd.dimension === "COL" ? "left" : "top";
@@ -55133,10 +55194,12 @@ class RangeAdapter {
55133
55194
  return adaptedRange;
55134
55195
  }
55135
55196
  executeOnAllRanges(adaptRange, sheetId) {
55197
+ this.isAdaptingRanges = true;
55136
55198
  const func = this.verifyRangeRemoved(adaptRange);
55137
55199
  for (const provider of this.providers) {
55138
55200
  provider(func, sheetId);
55139
55201
  }
55202
+ this.isAdaptingRanges = false;
55140
55203
  }
55141
55204
  /**
55142
55205
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -57155,6 +57218,7 @@ class PivotCorePlugin extends CorePlugin {
57155
57218
  "getMeasureCompiledFormula",
57156
57219
  "getPivotName",
57157
57220
  "isExistingPivot",
57221
+ "getMeasureFullDependencies",
57158
57222
  ];
57159
57223
  nextFormulaId = 1;
57160
57224
  pivots = {};
@@ -57237,15 +57301,32 @@ class PivotCorePlugin extends CorePlugin {
57237
57301
  }
57238
57302
  case "UPDATE_PIVOT": {
57239
57303
  this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
57240
- this.compileCalculatedMeasures(cmd.pivot.measures);
57304
+ this.compileCalculatedMeasures(cmd.pivotId, cmd.pivot.measures);
57241
57305
  break;
57242
57306
  }
57243
57307
  }
57244
57308
  }
57245
57309
  adaptRanges(applyChange) {
57246
- for (const sheetId in this.compiledMeasureFormulas) {
57247
- for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
57248
- const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
57310
+ for (const pivotId in this.pivots) {
57311
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
57312
+ if (!definition) {
57313
+ continue;
57314
+ }
57315
+ const newDefinition = pivotRegistry
57316
+ .get(definition.type)
57317
+ ?.adaptRanges?.(this.getters, definition, applyChange);
57318
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
57319
+ this.history.update("pivots", pivotId, "definition", newDefinition);
57320
+ }
57321
+ }
57322
+ for (const pivotId in this.compiledMeasureFormulas) {
57323
+ for (const measureId in this.compiledMeasureFormulas[pivotId]) {
57324
+ const measure = this.pivots[pivotId]?.definition.measures.find((m) => m.id === measureId);
57325
+ if (!measure || !measure.computedBy) {
57326
+ continue;
57327
+ }
57328
+ const sheetId = measure.computedBy.sheetId;
57329
+ const compiledFormula = this.compiledMeasureFormulas[pivotId][measureId].formula;
57249
57330
  const newDependencies = [];
57250
57331
  for (const range of compiledFormula.dependencies) {
57251
57332
  const change = applyChange(range);
@@ -57257,8 +57338,9 @@ class PivotCorePlugin extends CorePlugin {
57257
57338
  }
57258
57339
  }
57259
57340
  const newFormulaString = this.getters.getFormulaString(sheetId, compiledFormula.tokens, newDependencies);
57260
- if (newFormulaString !== formulaString) {
57261
- this.replaceMeasureFormula(sheetId, formulaString, newFormulaString);
57341
+ const oldFormulaString = measure.computedBy.formula;
57342
+ if (newFormulaString !== oldFormulaString) {
57343
+ this.replaceMeasureFormula(pivotId, measure, newFormulaString);
57262
57344
  }
57263
57345
  }
57264
57346
  }
@@ -57296,31 +57378,60 @@ class PivotCorePlugin extends CorePlugin {
57296
57378
  isExistingPivot(pivotId) {
57297
57379
  return pivotId in this.pivots;
57298
57380
  }
57299
- getMeasureCompiledFormula(measure) {
57381
+ getMeasureCompiledFormula(pivotId, measure) {
57382
+ if (!measure.computedBy) {
57383
+ throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
57384
+ }
57385
+ return this.compiledMeasureFormulas[pivotId][measure.id].formula;
57386
+ }
57387
+ getMeasureFullDependencies(pivotId, measure) {
57300
57388
  if (!measure.computedBy) {
57301
57389
  throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
57302
57390
  }
57303
- const sheetId = measure.computedBy.sheetId;
57304
- return this.compiledMeasureFormulas[sheetId][measure.computedBy.formula];
57391
+ return this.compiledMeasureFormulas[pivotId][measure.id].dependencies;
57305
57392
  }
57306
57393
  // -------------------------------------------------------------------------
57307
57394
  // Private
57308
57395
  // -------------------------------------------------------------------------
57309
57396
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
57310
57397
  this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
57311
- this.compileCalculatedMeasures(pivot.measures);
57398
+ this.compileCalculatedMeasures(pivotId, pivot.measures);
57312
57399
  this.history.update("formulaIds", formulaId, pivotId);
57313
57400
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
57314
57401
  }
57315
- compileCalculatedMeasures(measures) {
57402
+ compileCalculatedMeasures(pivotId, measures) {
57316
57403
  for (const measure of measures) {
57317
57404
  if (measure.computedBy) {
57318
- const sheetId = measure.computedBy.sheetId;
57319
57405
  const compiledFormula = this.compileMeasureFormula(measure.computedBy.sheetId, measure.computedBy.formula);
57320
- this.history.update("compiledMeasureFormulas", sheetId, measure.computedBy.formula, compiledFormula);
57406
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "formula", compiledFormula);
57407
+ }
57408
+ }
57409
+ for (const measure of measures) {
57410
+ if (measure.computedBy) {
57411
+ const dependencies = this.computeMeasureFullDependencies(pivotId, measure);
57412
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "dependencies", dependencies);
57321
57413
  }
57322
57414
  }
57323
57415
  }
57416
+ computeMeasureFullDependencies(pivotId, measure, exploredMeasures = new Set()) {
57417
+ const rangeDependencies = [];
57418
+ const definition = this.getPivotCoreDefinition(pivotId);
57419
+ const formula = this.getMeasureCompiledFormula(pivotId, measure);
57420
+ exploredMeasures.add(measure.id);
57421
+ for (const token of formula.tokens) {
57422
+ if (token.type !== "SYMBOL") {
57423
+ continue;
57424
+ }
57425
+ const otherMeasure = definition.measures.find((measureCandidate) => getCanonicalSymbolName(measureCandidate.id) === token.value &&
57426
+ measure.id !== measureCandidate.id);
57427
+ if (!otherMeasure || exploredMeasures.has(otherMeasure.id) || !otherMeasure.computedBy) {
57428
+ continue;
57429
+ }
57430
+ rangeDependencies.push(...this.computeMeasureFullDependencies(pivotId, otherMeasure, exploredMeasures));
57431
+ }
57432
+ rangeDependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
57433
+ return rangeDependencies;
57434
+ }
57324
57435
  insertPivot(position, formulaId, table) {
57325
57436
  this.resizeSheet(position.sheetId, position, table);
57326
57437
  const pivotCells = table.getPivotCells();
@@ -57377,28 +57488,17 @@ class PivotCorePlugin extends CorePlugin {
57377
57488
  dependencies: rangeDependencies,
57378
57489
  };
57379
57490
  }
57380
- replaceMeasureFormula(sheetId, formulaString, newFormulaString) {
57381
- this.history.update("compiledMeasureFormulas", sheetId, formulaString, undefined);
57382
- this.history.update("compiledMeasureFormulas", sheetId, newFormulaString, this.compileMeasureFormula(sheetId, newFormulaString));
57383
- for (const pivotId in this.pivots) {
57384
- const pivot = this.pivots[pivotId];
57385
- if (!pivot) {
57386
- continue;
57387
- }
57388
- const def = deepCopy(pivot.definition);
57389
- for (const measure of def.measures) {
57390
- if (measure.computedBy?.formula === formulaString) {
57391
- const measureIndex = def.measures.indexOf(measure);
57392
- if (measureIndex !== -1) {
57393
- def.measures[measureIndex].computedBy = {
57394
- formula: newFormulaString,
57395
- sheetId,
57396
- };
57397
- }
57398
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
57399
- }
57400
- }
57491
+ replaceMeasureFormula(pivotId, measure, newFormulaString) {
57492
+ const pivot = this.pivots[pivotId];
57493
+ if (!pivot) {
57494
+ return;
57401
57495
  }
57496
+ const measureIndex = pivot.definition.measures.indexOf(measure);
57497
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", {
57498
+ formula: newFormulaString,
57499
+ sheetId: measure.computedBy.sheetId,
57500
+ });
57501
+ this.compileCalculatedMeasures(pivotId, pivot.definition.measures);
57402
57502
  }
57403
57503
  checkDuplicatedMeasureIds(definition) {
57404
57504
  const uniqueIds = new Set(definition.measures.map((m) => m.id));
@@ -57494,20 +57594,6 @@ class SettingsPlugin extends CorePlugin {
57494
57594
  }
57495
57595
  }
57496
57596
 
57497
- function adaptPivotRange(range, applyChange) {
57498
- if (!range) {
57499
- return undefined;
57500
- }
57501
- const change = applyChange(range);
57502
- switch (change.changeType) {
57503
- case "NONE":
57504
- return range;
57505
- case "REMOVE":
57506
- return undefined;
57507
- default:
57508
- return change.range;
57509
- }
57510
- }
57511
57597
  class SpreadsheetPivotCorePlugin extends CorePlugin {
57512
57598
  allowDispatch(cmd) {
57513
57599
  switch (cmd.type) {
@@ -57518,27 +57604,6 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
57518
57604
  }
57519
57605
  return "Success" /* CommandResult.Success */;
57520
57606
  }
57521
- adaptRanges(applyChange) {
57522
- for (const pivotId of this.getters.getPivotIds()) {
57523
- const definition = this.getters.getPivotCoreDefinition(pivotId);
57524
- if (definition.type !== "SPREADSHEET") {
57525
- continue;
57526
- }
57527
- if (definition.dataSet) {
57528
- const { sheetId, zone } = definition.dataSet;
57529
- const range = this.getters.getRangeFromZone(sheetId, zone);
57530
- const adaptedRange = adaptPivotRange(range, applyChange);
57531
- if (adaptedRange === range) {
57532
- return;
57533
- }
57534
- const dataSet = adaptedRange && {
57535
- sheetId: adaptedRange.sheetId,
57536
- zone: adaptedRange.zone,
57537
- };
57538
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
57539
- }
57540
- }
57541
- }
57542
57607
  checkDataSetValidity(definition) {
57543
57608
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
57544
57609
  const { zone, sheetId } = definition.dataSet;
@@ -58896,6 +58961,9 @@ class Evaluator {
58896
58961
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
58897
58962
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
58898
58963
  }
58964
+ isArrayFormulaSpillBlocked(position) {
58965
+ return this.blockedArrayFormulas.has(position);
58966
+ }
58899
58967
  updateDependencies(position) {
58900
58968
  // removing dependencies is slow because it requires
58901
58969
  // to traverse the entire r-tree.
@@ -58907,13 +58975,8 @@ class Evaluator {
58907
58975
  addDependencies(position, dependencies) {
58908
58976
  this.formulaDependencies().addDependencies(position, dependencies);
58909
58977
  for (const range of dependencies) {
58910
- const sheetId = range.sheetId;
58911
- const { left, bottom, right, top } = range.zone;
58912
- for (let col = left; col <= right; col++) {
58913
- for (let row = top; row <= bottom; row++) {
58914
- this.computeAndSave({ sheetId, col, row });
58915
- }
58916
- }
58978
+ // ensure that all ranges are computed
58979
+ this.compilationParams.ensureRange(range);
58917
58980
  }
58918
58981
  }
58919
58982
  updateCompilationParameters() {
@@ -59112,6 +59175,10 @@ class Evaluator {
59112
59175
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
59113
59176
  const nbColumns = formulaReturn.length;
59114
59177
  const nbRows = formulaReturn[0].length;
59178
+ if (nbRows === 0) {
59179
+ // empty matrix
59180
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
59181
+ }
59115
59182
  const resultZone = {
59116
59183
  top: formulaPosition.row,
59117
59184
  bottom: formulaPosition.row + nbRows - 1,
@@ -59384,6 +59451,7 @@ class EvaluationPlugin extends UIPlugin {
59384
59451
  "getEvaluatedCellsPositions",
59385
59452
  "getSpreadZone",
59386
59453
  "getArrayFormulaSpreadingOn",
59454
+ "isArrayFormulaSpillBlocked",
59387
59455
  "isEmpty",
59388
59456
  ];
59389
59457
  shouldRebuildDependenciesGraph = true;
@@ -59496,6 +59564,9 @@ class EvaluationPlugin extends UIPlugin {
59496
59564
  getArrayFormulaSpreadingOn(position) {
59497
59565
  return this.evaluator.getArrayFormulaSpreadingOn(position);
59498
59566
  }
59567
+ isArrayFormulaSpillBlocked(position) {
59568
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
59569
+ }
59499
59570
  /**
59500
59571
  * Check if a zone only contains empty cells
59501
59572
  */
@@ -60719,14 +60790,16 @@ const PERCENT_FORMAT = "0.00%";
60719
60790
  function withPivotPresentationLayer (PivotClass) {
60720
60791
  class PivotPresentationLayer extends PivotClass {
60721
60792
  getters;
60793
+ pivotId;
60722
60794
  cache = {};
60723
60795
  rankAsc = {};
60724
60796
  rankDesc = {};
60725
60797
  runningTotal = {};
60726
60798
  runningTotalInPercent = {};
60727
- constructor(custom, params) {
60799
+ constructor(pivotId, custom, params) {
60728
60800
  super(custom, params);
60729
60801
  this.getters = params.getters;
60802
+ this.pivotId = pivotId;
60730
60803
  }
60731
60804
  markAsDirtyForEvaluation() {
60732
60805
  this.cache = {};
@@ -60776,7 +60849,7 @@ function withPivotPresentationLayer (PivotClass) {
60776
60849
  return handleError(error, measure.aggregator.toUpperCase());
60777
60850
  }
60778
60851
  }
60779
- const formula = this.getters.getMeasureCompiledFormula(measure);
60852
+ const formula = this.getters.getMeasureCompiledFormula(this.pivotId, measure);
60780
60853
  const getSymbolValue = (symbolName) => {
60781
60854
  const { columns, rows } = this.definition;
60782
60855
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
@@ -61494,7 +61567,7 @@ class PivotUIPlugin extends UIPlugin {
61494
61567
  const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
61495
61568
  if (!(pivotId in this.pivots)) {
61496
61569
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
61497
- this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
61570
+ this.pivots[pivotId] = new Pivot(pivotId, this.custom, { definition, getters: this.getters });
61498
61571
  }
61499
61572
  else if (recreate) {
61500
61573
  this.pivots[pivotId].onDefinitionChange(definition);
@@ -74725,6 +74798,6 @@ const constants = {
74725
74798
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
74726
74799
 
74727
74800
 
74728
- __info__.version = "18.0.50";
74729
- __info__.date = "2025-12-02T05:32:00.480Z";
74730
- __info__.hash = "7ed20c4";
74801
+ __info__.version = "18.0.54";
74802
+ __info__.date = "2026-01-14T10:00:02.287Z";
74803
+ __info__.hash = "c0048a0";