@odoo/o-spreadsheet 18.2.36 → 18.2.40

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.2.36
6
- * @date 2025-12-02T05:31:10.558Z
7
- * @hash d385099
5
+ * @version 18.2.40
6
+ * @date 2026-01-14T09:59:34.210Z
7
+ * @hash 755a787
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -6016,17 +6016,41 @@ function toCriterionDateNumber(dateValue) {
6016
6016
  const today = DateTime.now();
6017
6017
  switch (dateValue) {
6018
6018
  case "today":
6019
- return jsDateToNumber(today);
6020
- case "yesterday":
6021
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
6022
- case "tomorrow":
6023
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
6019
+ return Math.floor(jsDateToNumber(today));
6020
+ case "yesterday": {
6021
+ today.setDate(today.getDate() - 1);
6022
+ return Math.floor(jsDateToNumber(today));
6023
+ }
6024
+ case "tomorrow": {
6025
+ today.setDate(today.getDate() + 1);
6026
+ return Math.floor(jsDateToNumber(today));
6027
+ }
6024
6028
  case "lastWeek":
6025
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
6026
- case "lastMonth":
6027
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
6029
+ today.setDate(today.getDate() - 6);
6030
+ return Math.floor(jsDateToNumber(today));
6031
+ case "lastMonth": {
6032
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
6033
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
6034
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
6035
+ today.setDate(1);
6036
+ }
6037
+ else {
6038
+ today.setDate(today.getDate() + 1);
6039
+ today.setMonth(today.getMonth() - 1);
6040
+ }
6041
+ return Math.floor(jsDateToNumber(today));
6042
+ }
6028
6043
  case "lastYear":
6029
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
6044
+ // Handle leap year case
6045
+ if (today.getMonth() === 1 && today.getDate() === 29) {
6046
+ today.setDate(28);
6047
+ today.setFullYear(today.getFullYear() - 1);
6048
+ }
6049
+ else {
6050
+ today.setDate(today.getDate() + 1);
6051
+ today.setFullYear(today.getFullYear() - 1);
6052
+ }
6053
+ return Math.floor(jsDateToNumber(today));
6030
6054
  }
6031
6055
  }
6032
6056
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -19093,9 +19117,10 @@ function assertDomainLength(domain) {
19093
19117
  throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
19094
19118
  }
19095
19119
  }
19096
- function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
19120
+ function addPivotDependencies(evalContext, pivotId, forMeasures) {
19097
19121
  //TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
19098
19122
  const dependencies = [];
19123
+ const coreDefinition = evalContext.getters.getPivotCoreDefinition(pivotId);
19099
19124
  if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
19100
19125
  const { sheetId, zone } = coreDefinition.dataSet;
19101
19126
  const xc = zoneToXc(zone);
@@ -19112,8 +19137,7 @@ function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
19112
19137
  }
19113
19138
  for (const measure of forMeasures) {
19114
19139
  if (measure.computedBy) {
19115
- const formula = evalContext.getters.getMeasureCompiledFormula(measure);
19116
- dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
19140
+ dependencies.push(...evalContext.getters.getMeasureFullDependencies(pivotId, measure));
19117
19141
  }
19118
19142
  }
19119
19143
  const originPosition = evalContext.__originCellPosition;
@@ -19554,7 +19578,7 @@ const PIVOT_VALUE = {
19554
19578
  assertDomainLength(domainArgs);
19555
19579
  const pivot = this.getters.getPivot(pivotId);
19556
19580
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
19557
- addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
19581
+ addPivotDependencies(this, pivotId, coreDefinition.measures.filter((m) => m.id === _measure));
19558
19582
  pivot.init({ reload: pivot.needsReevaluation });
19559
19583
  const error = pivot.assertIsValid({ throwOnError: false });
19560
19584
  if (error) {
@@ -19587,8 +19611,7 @@ const PIVOT_HEADER = {
19587
19611
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
19588
19612
  assertDomainLength(domainArgs);
19589
19613
  const pivot = this.getters.getPivot(_pivotId);
19590
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
19591
- addPivotDependencies(this, coreDefinition, []);
19614
+ addPivotDependencies(this, _pivotId, []);
19592
19615
  pivot.init({ reload: pivot.needsReevaluation });
19593
19616
  const error = pivot.assertIsValid({ throwOnError: false });
19594
19617
  if (error) {
@@ -19642,7 +19665,7 @@ const PIVOT = {
19642
19665
  const pivotId = getPivotId(_pivotFormulaId, this.getters);
19643
19666
  const pivot = this.getters.getPivot(pivotId);
19644
19667
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
19645
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
19668
+ addPivotDependencies(this, pivotId, coreDefinition.measures);
19646
19669
  pivot.init({ reload: pivot.needsReevaluation });
19647
19670
  const error = pivot.assertIsValid({ throwOnError: false });
19648
19671
  if (error) {
@@ -21299,7 +21322,7 @@ class AbstractComposerStore extends SpreadsheetStore {
21299
21322
  }
21300
21323
  captureSelection(zone, col, row) {
21301
21324
  this.model.selection.capture(this, {
21302
- cell: { col: col ?? zone.left, row: row ?? zone.right },
21325
+ cell: { col: col ?? zone.left, row: row ?? zone.top },
21303
21326
  zone,
21304
21327
  }, {
21305
21328
  handleEvent: this.handleEvent.bind(this),
@@ -32660,7 +32683,6 @@ class ChartFigure extends Component {
32660
32683
  static template = "o-spreadsheet-ChartFigure";
32661
32684
  static props = {
32662
32685
  figure: Object,
32663
- onFigureDeleted: Function,
32664
32686
  };
32665
32687
  static components = {};
32666
32688
  onDoubleClick() {
@@ -32684,7 +32706,6 @@ class ImageFigure extends Component {
32684
32706
  static template = "o-spreadsheet-ImageFigure";
32685
32707
  static props = {
32686
32708
  figure: Object,
32687
- onFigureDeleted: Function,
32688
32709
  };
32689
32710
  static components = {};
32690
32711
  // ---------------------------------------------------------------------------
@@ -32741,7 +32762,7 @@ figureRegistry.add("image", {
32741
32762
  borderWidth: 0,
32742
32763
  menuBuilder: getImageMenuRegistry,
32743
32764
  });
32744
- function getChartMenu(figureId, onFigureDeleted, env) {
32765
+ function getChartMenu(figureId, env) {
32745
32766
  const menuItemSpecs = [
32746
32767
  {
32747
32768
  id: "edit",
@@ -32755,11 +32776,11 @@ function getChartMenu(figureId, onFigureDeleted, env) {
32755
32776
  },
32756
32777
  getCopyMenuItem(figureId, env),
32757
32778
  getCutMenuItem(figureId, env),
32758
- getDeleteMenuItem(figureId, onFigureDeleted, env),
32779
+ getDeleteMenuItem(figureId, env),
32759
32780
  ];
32760
32781
  return createActions(menuItemSpecs);
32761
32782
  }
32762
- function getImageMenuRegistry(figureId, onFigureDeleted, env) {
32783
+ function getImageMenuRegistry(figureId, env) {
32763
32784
  const menuItemSpecs = [
32764
32785
  getCopyMenuItem(figureId, env),
32765
32786
  getCutMenuItem(figureId, env),
@@ -32785,7 +32806,7 @@ function getImageMenuRegistry(figureId, onFigureDeleted, env) {
32785
32806
  },
32786
32807
  icon: "o-spreadsheet-Icon.REFRESH",
32787
32808
  },
32788
- getDeleteMenuItem(figureId, onFigureDeleted, env),
32809
+ getDeleteMenuItem(figureId, env),
32789
32810
  ];
32790
32811
  return createActions(menuItemSpecs);
32791
32812
  }
@@ -32817,7 +32838,7 @@ function getCutMenuItem(figureId, env) {
32817
32838
  icon: "o-spreadsheet-Icon.CUT",
32818
32839
  };
32819
32840
  }
32820
- function getDeleteMenuItem(figureId, onFigureDeleted, env) {
32841
+ function getDeleteMenuItem(figureId, env) {
32821
32842
  return {
32822
32843
  id: "delete",
32823
32844
  name: _t("Delete"),
@@ -32827,7 +32848,6 @@ function getDeleteMenuItem(figureId, onFigureDeleted, env) {
32827
32848
  sheetId: env.model.getters.getActiveSheetId(),
32828
32849
  id: figureId,
32829
32850
  });
32830
- onFigureDeleted();
32831
32851
  },
32832
32852
  icon: "o-spreadsheet-Icon.TRASH",
32833
32853
  };
@@ -42621,7 +42641,7 @@ function useHighlights(highlightProvider) {
42621
42641
  }
42622
42642
 
42623
42643
  css /* scss */ `
42624
- .o-cf-preview {
42644
+ .o-spreadsheet .o-cf-preview {
42625
42645
  &.o-cf-cursor-ptr {
42626
42646
  cursor: pointer;
42627
42647
  }
@@ -42629,6 +42649,7 @@ css /* scss */ `
42629
42649
  border-bottom: 1px solid ${GRAY_300};
42630
42650
  height: 80px;
42631
42651
  padding: 10px;
42652
+ box-sizing: border-box;
42632
42653
  position: relative;
42633
42654
  cursor: pointer;
42634
42655
  &:hover,
@@ -42642,7 +42663,6 @@ css /* scss */ `
42642
42663
  .o-cf-preview-icon {
42643
42664
  border: 1px solid ${GRAY_300};
42644
42665
  background-color: #fff;
42645
- position: absolute;
42646
42666
  height: 50px;
42647
42667
  width: 50px;
42648
42668
  .o-icon {
@@ -42651,12 +42671,6 @@ css /* scss */ `
42651
42671
  }
42652
42672
  }
42653
42673
  .o-cf-preview-description {
42654
- left: 65px;
42655
- margin-bottom: auto;
42656
- margin-right: 8px;
42657
- margin-top: auto;
42658
- position: relative;
42659
- width: 142px;
42660
42674
  .o-cf-preview-description-rule {
42661
42675
  margin-bottom: 4px;
42662
42676
  max-height: 2.8em;
@@ -42666,16 +42680,11 @@ css /* scss */ `
42666
42680
  font-size: 12px;
42667
42681
  }
42668
42682
  }
42669
- .o-cf-delete {
42670
- left: 90%;
42671
- top: 39%;
42672
- position: absolute;
42673
- }
42674
42683
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
42675
42684
  display: none !important;
42676
42685
  }
42677
42686
  .o-cf-drag-handle {
42678
- left: -8px;
42687
+ left: 2px;
42679
42688
  cursor: move;
42680
42689
  .o-icon {
42681
42690
  width: 6px;
@@ -43664,7 +43673,7 @@ dataValidationEvaluatorRegistry.add("dateIs", {
43664
43673
  return false;
43665
43674
  }
43666
43675
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
43667
- const today = jsDateToRoundNumber(DateTime.now());
43676
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
43668
43677
  return isDateBetween(dateValue, today, criterionValue);
43669
43678
  }
43670
43679
  return areDatesSameDay(dateValue, criterionValue);
@@ -44854,6 +44863,11 @@ class FindAndReplaceStore extends SpreadsheetStore {
44854
44863
  case "ACTIVATE_SHEET":
44855
44864
  this.isSearchDirty = true;
44856
44865
  this.shouldFinalizeUpdateSelection = true;
44866
+ if (this.searchOptions.specificRange) {
44867
+ this.searchOptions.specificRange = this.searchOptions.specificRange.clone({
44868
+ sheetId: this.getters.getActiveSheetId(),
44869
+ });
44870
+ }
44857
44871
  break;
44858
44872
  case "REPLACE_SEARCH":
44859
44873
  for (const match of cmd.matches) {
@@ -45275,9 +45289,20 @@ class FindAndReplacePanel extends Component {
45275
45289
  const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
45276
45290
  this.store.updateSearchOptions({ specificRange });
45277
45291
  }
45292
+ get specificRange() {
45293
+ const range = this.store.searchOptions.specificRange;
45294
+ return range ? this.env.model.getters.getRangeString(range, "forceSheetReference") : "";
45295
+ }
45278
45296
  get pendingSearch() {
45279
45297
  return this.updateSearchContent.isDebouncePending();
45280
45298
  }
45299
+ get selectionInputKey() {
45300
+ // Selections input are made to work with objects linked to a sheet id. They store the active sheet id at their creation,
45301
+ // and have specific behaviour linked to it (eg. go back to the initial sheet after confirmation).
45302
+ // We don't want all those behaviors here, so we force the recreation of the component when the active sheet changes.
45303
+ // The only drawback is that the input loses focus when changing sheet.
45304
+ return this.env.model.getters.getActiveSheetId();
45305
+ }
45281
45306
  }
45282
45307
 
45283
45308
  css /* scss */ `
@@ -47518,7 +47543,37 @@ pivotRegistry.add("SPREADSHEET", {
47518
47543
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
47519
47544
  isMeasureCandidate: (field) => field.type !== "boolean",
47520
47545
  isGroupable: () => true,
47546
+ adaptRanges: (getters, definition, applyChange) => {
47547
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
47548
+ return definition;
47549
+ }
47550
+ const { sheetId, zone } = definition.dataSet;
47551
+ const range = getters.getRangeFromZone(sheetId, zone);
47552
+ const adaptedRange = adaptPivotRange(range, applyChange);
47553
+ if (adaptedRange === range) {
47554
+ return definition;
47555
+ }
47556
+ const dataSet = adaptedRange && {
47557
+ sheetId: adaptedRange.sheetId,
47558
+ zone: adaptedRange.zone,
47559
+ };
47560
+ return { ...definition, dataSet };
47561
+ },
47521
47562
  });
47563
+ function adaptPivotRange(range, applyChange) {
47564
+ if (!range) {
47565
+ return undefined;
47566
+ }
47567
+ const change = applyChange(range);
47568
+ switch (change.changeType) {
47569
+ case "NONE":
47570
+ return range;
47571
+ case "REMOVE":
47572
+ return undefined;
47573
+ default:
47574
+ return change.range;
47575
+ }
47576
+ }
47522
47577
 
47523
47578
  class PivotSidePanelStore extends SpreadsheetStore {
47524
47579
  pivotId;
@@ -49159,13 +49214,11 @@ class FigureComponent extends Component {
49159
49214
  static props = {
49160
49215
  figure: Object,
49161
49216
  style: { type: String, optional: true },
49162
- onFigureDeleted: { type: Function, optional: true },
49163
49217
  onMouseDown: { type: Function, optional: true },
49164
49218
  onClickAnchor: { type: Function, optional: true },
49165
49219
  };
49166
49220
  static components = { Menu };
49167
49221
  static defaultProps = {
49168
- onFigureDeleted: () => { },
49169
49222
  onMouseDown: () => { },
49170
49223
  onClickAnchor: () => { },
49171
49224
  };
@@ -49239,9 +49292,6 @@ class FigureComponent extends Component {
49239
49292
  el?.focus({ preventScroll: true });
49240
49293
  }
49241
49294
  }, () => [this.env.model.getters.getSelectedFigureId(), this.props.figure.id, this.figureRef.el]);
49242
- onWillUnmount(() => {
49243
- this.props.onFigureDeleted();
49244
- });
49245
49295
  }
49246
49296
  clickAnchor(dirX, dirY, ev) {
49247
49297
  this.props.onClickAnchor(dirX, dirY, ev);
@@ -49259,7 +49309,6 @@ class FigureComponent extends Component {
49259
49309
  sheetId: this.env.model.getters.getActiveSheetId(),
49260
49310
  id: figure.id,
49261
49311
  });
49262
- this.props.onFigureDeleted();
49263
49312
  ev.preventDefault();
49264
49313
  ev.stopPropagation();
49265
49314
  break;
@@ -49323,7 +49372,7 @@ class FigureComponent extends Component {
49323
49372
  this.menuState.position = position;
49324
49373
  this.menuState.menuItems = figureRegistry
49325
49374
  .get(this.props.figure.tag)
49326
- .menuBuilder(this.props.figure.id, this.props.onFigureDeleted, this.env);
49375
+ .menuBuilder(this.props.figure.id, this.env);
49327
49376
  }
49328
49377
  }
49329
49378
 
@@ -49436,21 +49485,20 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
49436
49485
  this.highlightStore.register(this);
49437
49486
  }
49438
49487
  get highlights() {
49439
- let zone;
49440
49488
  const position = this.model.getters.getActivePosition();
49441
- const cell = this.getters.getEvaluatedCell(position);
49442
49489
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
49443
- zone = spreader
49490
+ const zone = spreader
49444
49491
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
49445
49492
  : this.model.getters.getSpreadZone(position, { ignoreSpillError: true });
49446
49493
  if (!zone) {
49447
49494
  return [];
49448
49495
  }
49496
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
49449
49497
  return [
49450
49498
  {
49451
49499
  sheetId: position.sheetId,
49452
49500
  zone,
49453
- dashed: cell.value === CellErrorType.SpilledBlocked,
49501
+ dashed: isArrayFormulaBlocked,
49454
49502
  color: "#17A2B8",
49455
49503
  noFill: true,
49456
49504
  thinLine: true,
@@ -50518,9 +50566,7 @@ css /*SCSS*/ `
50518
50566
  */
50519
50567
  class FiguresContainer extends Component {
50520
50568
  static template = "o-spreadsheet-FiguresContainer";
50521
- static props = {
50522
- onFigureDeleted: Function,
50523
- };
50569
+ static props = {};
50524
50570
  static components = { FigureComponent };
50525
50571
  dnd = useState({
50526
50572
  draggedFigure: undefined,
@@ -50876,16 +50922,16 @@ css /* scss */ `
50876
50922
  `;
50877
50923
  class GridAddRowsFooter extends Component {
50878
50924
  static template = "o-spreadsheet-GridAddRowsFooter";
50879
- static props = {
50880
- focusGrid: Function,
50881
- };
50925
+ static props = {};
50882
50926
  static components = { ValidationMessages };
50927
+ DOMFocusableElementStore;
50883
50928
  inputRef = useRef("inputRef");
50884
50929
  state = useState({
50885
50930
  inputValue: "100",
50886
50931
  errorFlag: false,
50887
50932
  });
50888
50933
  setup() {
50934
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
50889
50935
  useExternalListener(window, "click", this.onExternalClick, { capture: true });
50890
50936
  }
50891
50937
  get addRowsPosition() {
@@ -50903,7 +50949,7 @@ class GridAddRowsFooter extends Component {
50903
50949
  }
50904
50950
  onKeydown(ev) {
50905
50951
  if (ev.key.toUpperCase() === "ESCAPE") {
50906
- this.props.focusGrid();
50952
+ this.focusDefaultElement();
50907
50953
  }
50908
50954
  else if (ev.key.toUpperCase() === "ENTER") {
50909
50955
  this.onConfirm();
@@ -50929,7 +50975,7 @@ class GridAddRowsFooter extends Component {
50929
50975
  quantity,
50930
50976
  dimension: "ROW",
50931
50977
  });
50932
- this.props.focusGrid();
50978
+ this.focusDefaultElement();
50933
50979
  // After adding new rows, scroll down to the new last row
50934
50980
  const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
50935
50981
  const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
@@ -50942,7 +50988,12 @@ class GridAddRowsFooter extends Component {
50942
50988
  if (this.inputRef.el !== document.activeElement || ev.target === this.inputRef.el) {
50943
50989
  return;
50944
50990
  }
50945
- this.props.focusGrid();
50991
+ this.focusDefaultElement();
50992
+ }
50993
+ focusDefaultElement() {
50994
+ if (document.activeElement === this.inputRef.el) {
50995
+ this.DOMFocusableElementStore.focus();
50996
+ }
50946
50997
  }
50947
50998
  }
50948
50999
 
@@ -51131,7 +51182,6 @@ class GridOverlay extends Component {
51131
51182
  onCellClicked: { type: Function, optional: true },
51132
51183
  onCellRightClicked: { type: Function, optional: true },
51133
51184
  onGridResized: { type: Function, optional: true },
51134
- onFigureDeleted: { type: Function, optional: true },
51135
51185
  onGridMoved: Function,
51136
51186
  gridOverlayDimensions: String,
51137
51187
  };
@@ -51147,7 +51197,6 @@ class GridOverlay extends Component {
51147
51197
  onCellClicked: () => { },
51148
51198
  onCellRightClicked: () => { },
51149
51199
  onGridResized: () => { },
51150
- onFigureDeleted: () => { },
51151
51200
  };
51152
51201
  gridOverlay = useRef("gridOverlay");
51153
51202
  gridOverlayRect = useAbsoluteBoundingRect(this.gridOverlay);
@@ -57554,6 +57603,7 @@ function rangeToMerge(mergeId, range) {
57554
57603
  class RangeAdapter {
57555
57604
  getters;
57556
57605
  providers = [];
57606
+ isAdaptingRanges = false;
57557
57607
  constructor(getters) {
57558
57608
  this.getters = getters;
57559
57609
  }
@@ -57584,6 +57634,9 @@ class RangeAdapter {
57584
57634
  }
57585
57635
  beforeHandle(command) { }
57586
57636
  handle(cmd) {
57637
+ if (this.isAdaptingRanges) {
57638
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
57639
+ }
57587
57640
  switch (cmd.type) {
57588
57641
  case "REMOVE_COLUMNS_ROWS": {
57589
57642
  let start = cmd.dimension === "COL" ? "left" : "top";
@@ -57739,10 +57792,12 @@ class RangeAdapter {
57739
57792
  return adaptedRange;
57740
57793
  }
57741
57794
  executeOnAllRanges(adaptRange, sheetId) {
57795
+ this.isAdaptingRanges = true;
57742
57796
  const func = this.verifyRangeRemoved(adaptRange);
57743
57797
  for (const provider of this.providers) {
57744
57798
  provider(func, sheetId);
57745
57799
  }
57800
+ this.isAdaptingRanges = false;
57746
57801
  }
57747
57802
  /**
57748
57803
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -59778,6 +59833,7 @@ class PivotCorePlugin extends CorePlugin {
59778
59833
  "getMeasureCompiledFormula",
59779
59834
  "getPivotName",
59780
59835
  "isExistingPivot",
59836
+ "getMeasureFullDependencies",
59781
59837
  ];
59782
59838
  nextFormulaId = 1;
59783
59839
  pivots = {};
@@ -59860,15 +59916,32 @@ class PivotCorePlugin extends CorePlugin {
59860
59916
  }
59861
59917
  case "UPDATE_PIVOT": {
59862
59918
  this.history.update("pivots", cmd.pivotId, "definition", this.repairSortedColumn(deepCopy(cmd.pivot)));
59863
- this.compileCalculatedMeasures(cmd.pivot.measures);
59919
+ this.compileCalculatedMeasures(cmd.pivotId, cmd.pivot.measures);
59864
59920
  break;
59865
59921
  }
59866
59922
  }
59867
59923
  }
59868
59924
  adaptRanges(applyChange) {
59869
- for (const sheetId in this.compiledMeasureFormulas) {
59870
- for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
59871
- const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
59925
+ for (const pivotId in this.pivots) {
59926
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
59927
+ if (!definition) {
59928
+ continue;
59929
+ }
59930
+ const newDefinition = pivotRegistry
59931
+ .get(definition.type)
59932
+ ?.adaptRanges?.(this.getters, definition, applyChange);
59933
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
59934
+ this.history.update("pivots", pivotId, "definition", newDefinition);
59935
+ }
59936
+ }
59937
+ for (const pivotId in this.compiledMeasureFormulas) {
59938
+ for (const measureId in this.compiledMeasureFormulas[pivotId]) {
59939
+ const measure = this.pivots[pivotId]?.definition.measures.find((m) => m.id === measureId);
59940
+ if (!measure || !measure.computedBy) {
59941
+ continue;
59942
+ }
59943
+ const sheetId = measure.computedBy.sheetId;
59944
+ const compiledFormula = this.compiledMeasureFormulas[pivotId][measureId].formula;
59872
59945
  const newDependencies = [];
59873
59946
  for (const range of compiledFormula.dependencies) {
59874
59947
  const change = applyChange(range);
@@ -59880,8 +59953,9 @@ class PivotCorePlugin extends CorePlugin {
59880
59953
  }
59881
59954
  }
59882
59955
  const newFormulaString = this.getters.getFormulaString(sheetId, compiledFormula.tokens, newDependencies);
59883
- if (newFormulaString !== formulaString) {
59884
- this.replaceMeasureFormula(sheetId, formulaString, newFormulaString);
59956
+ const oldFormulaString = measure.computedBy.formula;
59957
+ if (newFormulaString !== oldFormulaString) {
59958
+ this.replaceMeasureFormula(pivotId, measure, newFormulaString);
59885
59959
  }
59886
59960
  }
59887
59961
  }
@@ -59919,12 +59993,17 @@ class PivotCorePlugin extends CorePlugin {
59919
59993
  isExistingPivot(pivotId) {
59920
59994
  return pivotId in this.pivots;
59921
59995
  }
59922
- getMeasureCompiledFormula(measure) {
59996
+ getMeasureCompiledFormula(pivotId, measure) {
59997
+ if (!measure.computedBy) {
59998
+ throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
59999
+ }
60000
+ return this.compiledMeasureFormulas[pivotId][measure.id].formula;
60001
+ }
60002
+ getMeasureFullDependencies(pivotId, measure) {
59923
60003
  if (!measure.computedBy) {
59924
60004
  throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
59925
60005
  }
59926
- const sheetId = measure.computedBy.sheetId;
59927
- return this.compiledMeasureFormulas[sheetId][measure.computedBy.formula];
60006
+ return this.compiledMeasureFormulas[pivotId][measure.id].dependencies;
59928
60007
  }
59929
60008
  // -------------------------------------------------------------------------
59930
60009
  // Private
@@ -59934,18 +60013,42 @@ class PivotCorePlugin extends CorePlugin {
59934
60013
  definition: this.repairSortedColumn(deepCopy(pivot)),
59935
60014
  formulaId,
59936
60015
  });
59937
- this.compileCalculatedMeasures(pivot.measures);
60016
+ this.compileCalculatedMeasures(pivotId, pivot.measures);
59938
60017
  this.history.update("formulaIds", formulaId, pivotId);
59939
60018
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
59940
60019
  }
59941
- compileCalculatedMeasures(measures) {
60020
+ compileCalculatedMeasures(pivotId, measures) {
59942
60021
  for (const measure of measures) {
59943
60022
  if (measure.computedBy) {
59944
- const sheetId = measure.computedBy.sheetId;
59945
60023
  const compiledFormula = this.compileMeasureFormula(measure.computedBy.sheetId, measure.computedBy.formula);
59946
- this.history.update("compiledMeasureFormulas", sheetId, measure.computedBy.formula, compiledFormula);
60024
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "formula", compiledFormula);
60025
+ }
60026
+ }
60027
+ for (const measure of measures) {
60028
+ if (measure.computedBy) {
60029
+ const dependencies = this.computeMeasureFullDependencies(pivotId, measure);
60030
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "dependencies", dependencies);
60031
+ }
60032
+ }
60033
+ }
60034
+ computeMeasureFullDependencies(pivotId, measure, exploredMeasures = new Set()) {
60035
+ const rangeDependencies = [];
60036
+ const definition = this.getPivotCoreDefinition(pivotId);
60037
+ const formula = this.getMeasureCompiledFormula(pivotId, measure);
60038
+ exploredMeasures.add(measure.id);
60039
+ for (const token of formula.tokens) {
60040
+ if (token.type !== "SYMBOL") {
60041
+ continue;
60042
+ }
60043
+ const otherMeasure = definition.measures.find((measureCandidate) => getCanonicalSymbolName(measureCandidate.id) === token.value &&
60044
+ measure.id !== measureCandidate.id);
60045
+ if (!otherMeasure || exploredMeasures.has(otherMeasure.id) || !otherMeasure.computedBy) {
60046
+ continue;
59947
60047
  }
60048
+ rangeDependencies.push(...this.computeMeasureFullDependencies(pivotId, otherMeasure, exploredMeasures));
59948
60049
  }
60050
+ rangeDependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
60051
+ return rangeDependencies;
59949
60052
  }
59950
60053
  insertPivot(position, formulaId, table) {
59951
60054
  this.resizeSheet(position.sheetId, position, table);
@@ -60003,28 +60106,17 @@ class PivotCorePlugin extends CorePlugin {
60003
60106
  dependencies: rangeDependencies,
60004
60107
  };
60005
60108
  }
60006
- replaceMeasureFormula(sheetId, formulaString, newFormulaString) {
60007
- this.history.update("compiledMeasureFormulas", sheetId, formulaString, undefined);
60008
- this.history.update("compiledMeasureFormulas", sheetId, newFormulaString, this.compileMeasureFormula(sheetId, newFormulaString));
60009
- for (const pivotId in this.pivots) {
60010
- const pivot = this.pivots[pivotId];
60011
- if (!pivot) {
60012
- continue;
60013
- }
60014
- const def = deepCopy(pivot.definition);
60015
- for (const measure of def.measures) {
60016
- if (measure.computedBy?.formula === formulaString) {
60017
- const measureIndex = def.measures.indexOf(measure);
60018
- if (measureIndex !== -1) {
60019
- def.measures[measureIndex].computedBy = {
60020
- formula: newFormulaString,
60021
- sheetId,
60022
- };
60023
- }
60024
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
60025
- }
60026
- }
60109
+ replaceMeasureFormula(pivotId, measure, newFormulaString) {
60110
+ const pivot = this.pivots[pivotId];
60111
+ if (!pivot) {
60112
+ return;
60027
60113
  }
60114
+ const measureIndex = pivot.definition.measures.indexOf(measure);
60115
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", {
60116
+ formula: newFormulaString,
60117
+ sheetId: measure.computedBy.sheetId,
60118
+ });
60119
+ this.compileCalculatedMeasures(pivotId, pivot.definition.measures);
60028
60120
  }
60029
60121
  checkDuplicatedMeasureIds(definition) {
60030
60122
  const uniqueIds = new Set(definition.measures.map((m) => m.id));
@@ -60140,20 +60232,6 @@ class SettingsPlugin extends CorePlugin {
60140
60232
  }
60141
60233
  }
60142
60234
 
60143
- function adaptPivotRange(range, applyChange) {
60144
- if (!range) {
60145
- return undefined;
60146
- }
60147
- const change = applyChange(range);
60148
- switch (change.changeType) {
60149
- case "NONE":
60150
- return range;
60151
- case "REMOVE":
60152
- return undefined;
60153
- default:
60154
- return change.range;
60155
- }
60156
- }
60157
60235
  class SpreadsheetPivotCorePlugin extends CorePlugin {
60158
60236
  allowDispatch(cmd) {
60159
60237
  switch (cmd.type) {
@@ -60164,27 +60242,6 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
60164
60242
  }
60165
60243
  return "Success" /* CommandResult.Success */;
60166
60244
  }
60167
- adaptRanges(applyChange) {
60168
- for (const pivotId of this.getters.getPivotIds()) {
60169
- const definition = this.getters.getPivotCoreDefinition(pivotId);
60170
- if (definition.type !== "SPREADSHEET") {
60171
- continue;
60172
- }
60173
- if (definition.dataSet) {
60174
- const { sheetId, zone } = definition.dataSet;
60175
- const range = this.getters.getRangeFromZone(sheetId, zone);
60176
- const adaptedRange = adaptPivotRange(range, applyChange);
60177
- if (adaptedRange === range) {
60178
- return;
60179
- }
60180
- const dataSet = adaptedRange && {
60181
- sheetId: adaptedRange.sheetId,
60182
- zone: adaptedRange.zone,
60183
- };
60184
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
60185
- }
60186
- }
60187
- }
60188
60245
  checkDataSetValidity(definition) {
60189
60246
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
60190
60247
  const { zone, sheetId } = definition.dataSet;
@@ -61526,6 +61583,9 @@ class Evaluator {
61526
61583
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
61527
61584
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
61528
61585
  }
61586
+ isArrayFormulaSpillBlocked(position) {
61587
+ return this.blockedArrayFormulas.has(position);
61588
+ }
61529
61589
  updateDependencies(position) {
61530
61590
  // removing dependencies is slow because it requires
61531
61591
  // to traverse the entire r-tree.
@@ -61537,13 +61597,8 @@ class Evaluator {
61537
61597
  addDependencies(position, dependencies) {
61538
61598
  this.formulaDependencies().addDependencies(position, dependencies);
61539
61599
  for (const range of dependencies) {
61540
- const sheetId = range.sheetId;
61541
- const { left, bottom, right, top } = range.zone;
61542
- for (let col = left; col <= right; col++) {
61543
- for (let row = top; row <= bottom; row++) {
61544
- this.computeAndSave({ sheetId, col, row });
61545
- }
61546
- }
61600
+ // ensure that all ranges are computed
61601
+ this.compilationParams.ensureRange(range);
61547
61602
  }
61548
61603
  }
61549
61604
  updateCompilationParameters() {
@@ -61746,6 +61801,10 @@ class Evaluator {
61746
61801
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
61747
61802
  const nbColumns = formulaReturn.length;
61748
61803
  const nbRows = formulaReturn[0].length;
61804
+ if (nbRows === 0) {
61805
+ // empty matrix
61806
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
61807
+ }
61749
61808
  const resultZone = {
61750
61809
  top: formulaPosition.row,
61751
61810
  bottom: formulaPosition.row + nbRows - 1,
@@ -62021,6 +62080,7 @@ class EvaluationPlugin extends CoreViewPlugin {
62021
62080
  "getEvaluatedCellsPositions",
62022
62081
  "getSpreadZone",
62023
62082
  "getArrayFormulaSpreadingOn",
62083
+ "isArrayFormulaSpillBlocked",
62024
62084
  "isEmpty",
62025
62085
  ];
62026
62086
  shouldRebuildDependenciesGraph = true;
@@ -62133,6 +62193,9 @@ class EvaluationPlugin extends CoreViewPlugin {
62133
62193
  getArrayFormulaSpreadingOn(position) {
62134
62194
  return this.evaluator.getArrayFormulaSpreadingOn(position);
62135
62195
  }
62196
+ isArrayFormulaSpillBlocked(position) {
62197
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
62198
+ }
62136
62199
  /**
62137
62200
  * Check if a zone only contains empty cells
62138
62201
  */
@@ -63318,14 +63381,16 @@ const PERCENT_FORMAT = "0.00%";
63318
63381
  function withPivotPresentationLayer (PivotClass) {
63319
63382
  class PivotPresentationLayer extends PivotClass {
63320
63383
  getters;
63384
+ pivotId;
63321
63385
  cache = {};
63322
63386
  rankAsc = {};
63323
63387
  rankDesc = {};
63324
63388
  runningTotal = {};
63325
63389
  runningTotalInPercent = {};
63326
- constructor(custom, params) {
63390
+ constructor(pivotId, custom, params) {
63327
63391
  super(custom, params);
63328
63392
  this.getters = params.getters;
63393
+ this.pivotId = pivotId;
63329
63394
  }
63330
63395
  markAsDirtyForEvaluation() {
63331
63396
  this.cache = {};
@@ -63375,7 +63440,7 @@ function withPivotPresentationLayer (PivotClass) {
63375
63440
  return handleError(error, measure.aggregator.toUpperCase());
63376
63441
  }
63377
63442
  }
63378
- const formula = this.getters.getMeasureCompiledFormula(measure);
63443
+ const formula = this.getters.getMeasureCompiledFormula(this.pivotId, measure);
63379
63444
  const getSymbolValue = (symbolName) => {
63380
63445
  const { columns, rows } = this.definition;
63381
63446
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
@@ -64103,7 +64168,7 @@ class PivotUIPlugin extends CoreViewPlugin {
64103
64168
  const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
64104
64169
  if (!(pivotId in this.pivots)) {
64105
64170
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
64106
- this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
64171
+ this.pivots[pivotId] = new Pivot(pivotId, this.custom, { definition, getters: this.getters });
64107
64172
  }
64108
64173
  else if (recreate) {
64109
64174
  this.pivots[pivotId].onDefinitionChange(definition);
@@ -72838,7 +72903,7 @@ class Spreadsheet extends Component {
72838
72903
  document.activeElement?.contains(this.spreadsheetRef.el)) {
72839
72904
  this.focusGrid();
72840
72905
  }
72841
- }, () => [this.env.model.getters.getActiveSheetId()]);
72906
+ });
72842
72907
  useExternalListener(window, "resize", () => this.render(true));
72843
72908
  // For some reason, the wheel event is not properly registered inside templates
72844
72909
  // in Chromium-based browsers based on chromium 125
@@ -77358,6 +77423,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
77358
77423
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, 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 };
77359
77424
 
77360
77425
 
77361
- __info__.version = "18.2.36";
77362
- __info__.date = "2025-12-02T05:31:10.558Z";
77363
- __info__.hash = "d385099";
77426
+ __info__.version = "18.2.40";
77427
+ __info__.date = "2026-01-14T09:59:34.210Z";
77428
+ __info__.hash = "755a787";