@odoo/o-spreadsheet 18.3.28 → 18.3.31

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.3.28
6
- * @date 2025-12-02T05:34:06.602Z
7
- * @hash a205f91
5
+ * @version 18.3.31
6
+ * @date 2025-12-26T10:18:10.765Z
7
+ * @hash 1e143e1
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -6044,17 +6044,41 @@
6044
6044
  const today = DateTime.now();
6045
6045
  switch (dateValue) {
6046
6046
  case "today":
6047
- return jsDateToNumber(today);
6048
- case "yesterday":
6049
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
6050
- case "tomorrow":
6051
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
6047
+ return Math.floor(jsDateToNumber(today));
6048
+ case "yesterday": {
6049
+ today.setDate(today.getDate() - 1);
6050
+ return Math.floor(jsDateToNumber(today));
6051
+ }
6052
+ case "tomorrow": {
6053
+ today.setDate(today.getDate() + 1);
6054
+ return Math.floor(jsDateToNumber(today));
6055
+ }
6052
6056
  case "lastWeek":
6053
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
6054
- case "lastMonth":
6055
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
6057
+ today.setDate(today.getDate() - 6);
6058
+ return Math.floor(jsDateToNumber(today));
6059
+ case "lastMonth": {
6060
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
6061
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
6062
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
6063
+ today.setDate(1);
6064
+ }
6065
+ else {
6066
+ today.setDate(today.getDate() + 1);
6067
+ today.setMonth(today.getMonth() - 1);
6068
+ }
6069
+ return Math.floor(jsDateToNumber(today));
6070
+ }
6056
6071
  case "lastYear":
6057
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
6072
+ // Handle leap year case
6073
+ if (today.getMonth() === 1 && today.getDate() === 29) {
6074
+ today.setDate(28);
6075
+ today.setFullYear(today.getFullYear() - 1);
6076
+ }
6077
+ else {
6078
+ today.setDate(today.getDate() + 1);
6079
+ today.setFullYear(today.getFullYear() - 1);
6080
+ }
6081
+ return Math.floor(jsDateToNumber(today));
6058
6082
  }
6059
6083
  }
6060
6084
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -29439,7 +29463,6 @@ stores.inject(MyMetaStore, storeInstance);
29439
29463
  static template = "o-spreadsheet-ChartFigure";
29440
29464
  static props = {
29441
29465
  figureUI: Object,
29442
- onFigureDeleted: Function,
29443
29466
  };
29444
29467
  static components = {};
29445
29468
  onDoubleClick() {
@@ -29463,7 +29486,6 @@ stores.inject(MyMetaStore, storeInstance);
29463
29486
  static template = "o-spreadsheet-ImageFigure";
29464
29487
  static props = {
29465
29488
  figureUI: Object,
29466
- onFigureDeleted: Function,
29467
29489
  };
29468
29490
  static components = {};
29469
29491
  // ---------------------------------------------------------------------------
@@ -30131,7 +30153,7 @@ stores.inject(MyMetaStore, storeInstance);
30131
30153
  borderWidth: 0,
30132
30154
  menuBuilder: getImageMenuRegistry,
30133
30155
  });
30134
- function getChartMenu(figureId, onFigureDeleted, env) {
30156
+ function getChartMenu(figureId, env) {
30135
30157
  const menuItemSpecs = [
30136
30158
  {
30137
30159
  id: "edit",
@@ -30183,11 +30205,11 @@ stores.inject(MyMetaStore, storeInstance);
30183
30205
  downloadFile(url, "chart");
30184
30206
  },
30185
30207
  },
30186
- getDeleteMenuItem(figureId, onFigureDeleted, env),
30208
+ getDeleteMenuItem(figureId, env),
30187
30209
  ];
30188
30210
  return createActions(menuItemSpecs);
30189
30211
  }
30190
- function getImageMenuRegistry(figureId, onFigureDeleted, env) {
30212
+ function getImageMenuRegistry(figureId, env) {
30191
30213
  const menuItemSpecs = [
30192
30214
  getCopyMenuItem(figureId, env),
30193
30215
  getCutMenuItem(figureId, env),
@@ -30232,7 +30254,7 @@ stores.inject(MyMetaStore, storeInstance);
30232
30254
  },
30233
30255
  icon: "o-spreadsheet-Icon.DOWNLOAD",
30234
30256
  },
30235
- getDeleteMenuItem(figureId, onFigureDeleted, env),
30257
+ getDeleteMenuItem(figureId, env),
30236
30258
  ];
30237
30259
  return createActions(menuItemSpecs);
30238
30260
  }
@@ -30265,7 +30287,7 @@ stores.inject(MyMetaStore, storeInstance);
30265
30287
  icon: "o-spreadsheet-Icon.CUT",
30266
30288
  };
30267
30289
  }
30268
- function getDeleteMenuItem(figureId, onFigureDeleted, env) {
30290
+ function getDeleteMenuItem(figureId, env) {
30269
30291
  return {
30270
30292
  id: "delete",
30271
30293
  name: _t("Delete"),
@@ -30275,7 +30297,6 @@ stores.inject(MyMetaStore, storeInstance);
30275
30297
  sheetId: env.model.getters.getActiveSheetId(),
30276
30298
  figureId,
30277
30299
  });
30278
- onFigureDeleted();
30279
30300
  },
30280
30301
  icon: "o-spreadsheet-Icon.TRASH",
30281
30302
  };
@@ -45377,7 +45398,7 @@ stores.inject(MyMetaStore, storeInstance);
45377
45398
  }
45378
45399
 
45379
45400
  css /* scss */ `
45380
- .o-cf-preview {
45401
+ .o-spreadsheet .o-cf-preview {
45381
45402
  &.o-cf-cursor-ptr {
45382
45403
  cursor: pointer;
45383
45404
  }
@@ -45385,6 +45406,7 @@ stores.inject(MyMetaStore, storeInstance);
45385
45406
  border-bottom: 1px solid ${GRAY_300};
45386
45407
  height: 80px;
45387
45408
  padding: 10px;
45409
+ box-sizing: border-box;
45388
45410
  position: relative;
45389
45411
  cursor: pointer;
45390
45412
  &:hover,
@@ -45398,7 +45420,6 @@ stores.inject(MyMetaStore, storeInstance);
45398
45420
  .o-cf-preview-icon {
45399
45421
  border: 1px solid ${GRAY_300};
45400
45422
  background-color: #fff;
45401
- position: absolute;
45402
45423
  height: 50px;
45403
45424
  width: 50px;
45404
45425
  .o-icon {
@@ -45407,12 +45428,6 @@ stores.inject(MyMetaStore, storeInstance);
45407
45428
  }
45408
45429
  }
45409
45430
  .o-cf-preview-description {
45410
- left: 65px;
45411
- margin-bottom: auto;
45412
- margin-right: 8px;
45413
- margin-top: auto;
45414
- position: relative;
45415
- width: 142px;
45416
45431
  .o-cf-preview-description-rule {
45417
45432
  margin-bottom: 4px;
45418
45433
  max-height: 2.8em;
@@ -45422,16 +45437,11 @@ stores.inject(MyMetaStore, storeInstance);
45422
45437
  font-size: 12px;
45423
45438
  }
45424
45439
  }
45425
- .o-cf-delete {
45426
- left: 90%;
45427
- top: 39%;
45428
- position: absolute;
45429
- }
45430
45440
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
45431
45441
  display: none !important;
45432
45442
  }
45433
45443
  .o-cf-drag-handle {
45434
- left: -8px;
45444
+ left: 2px;
45435
45445
  cursor: move;
45436
45446
  .o-icon {
45437
45447
  width: 6px;
@@ -46420,7 +46430,7 @@ stores.inject(MyMetaStore, storeInstance);
46420
46430
  return false;
46421
46431
  }
46422
46432
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
46423
- const today = jsDateToRoundNumber(DateTime.now());
46433
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
46424
46434
  return isDateBetween(dateValue, today, criterionValue);
46425
46435
  }
46426
46436
  return areDatesSameDay(dateValue, criterionValue);
@@ -50277,7 +50287,37 @@ stores.inject(MyMetaStore, storeInstance);
50277
50287
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
50278
50288
  isMeasureCandidate: (field) => field.type !== "boolean",
50279
50289
  isGroupable: () => true,
50290
+ adaptRanges: (getters, definition, applyChange) => {
50291
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
50292
+ return definition;
50293
+ }
50294
+ const { sheetId, zone } = definition.dataSet;
50295
+ const range = getters.getRangeFromZone(sheetId, zone);
50296
+ const adaptedRange = adaptPivotRange(range, applyChange);
50297
+ if (adaptedRange === range) {
50298
+ return definition;
50299
+ }
50300
+ const dataSet = adaptedRange && {
50301
+ sheetId: adaptedRange.sheetId,
50302
+ zone: adaptedRange.zone,
50303
+ };
50304
+ return { ...definition, dataSet };
50305
+ },
50280
50306
  });
50307
+ function adaptPivotRange(range, applyChange) {
50308
+ if (!range) {
50309
+ return undefined;
50310
+ }
50311
+ const change = applyChange(range);
50312
+ switch (change.changeType) {
50313
+ case "NONE":
50314
+ return range;
50315
+ case "REMOVE":
50316
+ return undefined;
50317
+ default:
50318
+ return change.range;
50319
+ }
50320
+ }
50281
50321
 
50282
50322
  class PivotSidePanelStore extends SpreadsheetStore {
50283
50323
  pivotId;
@@ -51917,13 +51957,11 @@ stores.inject(MyMetaStore, storeInstance);
51917
51957
  static props = {
51918
51958
  figureUI: Object,
51919
51959
  style: { type: String, optional: true },
51920
- onFigureDeleted: { type: Function, optional: true },
51921
51960
  onMouseDown: { type: Function, optional: true },
51922
51961
  onClickAnchor: { type: Function, optional: true },
51923
51962
  };
51924
51963
  static components = { Menu };
51925
51964
  static defaultProps = {
51926
- onFigureDeleted: () => { },
51927
51965
  onMouseDown: () => { },
51928
51966
  onClickAnchor: () => { },
51929
51967
  };
@@ -52001,9 +52039,6 @@ stores.inject(MyMetaStore, storeInstance);
52001
52039
  this.props.figureUI.id,
52002
52040
  this.figureRef.el,
52003
52041
  ]);
52004
- owl.onWillUnmount(() => {
52005
- this.props.onFigureDeleted();
52006
- });
52007
52042
  }
52008
52043
  clickAnchor(dirX, dirY, ev) {
52009
52044
  this.props.onClickAnchor(dirX, dirY, ev);
@@ -52020,7 +52055,6 @@ stores.inject(MyMetaStore, storeInstance);
52020
52055
  sheetId: this.env.model.getters.getActiveSheetId(),
52021
52056
  figureId: this.props.figureUI.id,
52022
52057
  });
52023
- this.props.onFigureDeleted();
52024
52058
  ev.preventDefault();
52025
52059
  ev.stopPropagation();
52026
52060
  break;
@@ -52113,7 +52147,7 @@ stores.inject(MyMetaStore, storeInstance);
52113
52147
  this.menuState.anchorRect = anchorRect;
52114
52148
  this.menuState.menuItems = figureRegistry
52115
52149
  .get(this.props.figureUI.tag)
52116
- .menuBuilder(this.props.figureUI.id, this.props.onFigureDeleted, this.env);
52150
+ .menuBuilder(this.props.figureUI.id, this.env);
52117
52151
  }
52118
52152
  }
52119
52153
 
@@ -52226,21 +52260,20 @@ stores.inject(MyMetaStore, storeInstance);
52226
52260
  this.highlightStore.register(this);
52227
52261
  }
52228
52262
  get highlights() {
52229
- let zone;
52230
52263
  const position = this.model.getters.getActivePosition();
52231
- const cell = this.getters.getEvaluatedCell(position);
52232
52264
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
52233
- zone = spreader
52265
+ const zone = spreader
52234
52266
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
52235
52267
  : this.model.getters.getSpreadZone(position, { ignoreSpillError: true });
52236
52268
  if (!zone) {
52237
52269
  return [];
52238
52270
  }
52271
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
52239
52272
  return [
52240
52273
  {
52241
52274
  sheetId: position.sheetId,
52242
52275
  zone,
52243
- dashed: cell.value === CellErrorType.SpilledBlocked,
52276
+ dashed: isArrayFormulaBlocked,
52244
52277
  color: "#17A2B8",
52245
52278
  noFill: true,
52246
52279
  thinLine: true,
@@ -53408,9 +53441,7 @@ stores.inject(MyMetaStore, storeInstance);
53408
53441
  */
53409
53442
  class FiguresContainer extends owl.Component {
53410
53443
  static template = "o-spreadsheet-FiguresContainer";
53411
- static props = {
53412
- onFigureDeleted: Function,
53413
- };
53444
+ static props = {};
53414
53445
  static components = { FigureComponent };
53415
53446
  dnd = owl.useState({
53416
53447
  draggedFigure: undefined,
@@ -53801,16 +53832,16 @@ stores.inject(MyMetaStore, storeInstance);
53801
53832
  `;
53802
53833
  class GridAddRowsFooter extends owl.Component {
53803
53834
  static template = "o-spreadsheet-GridAddRowsFooter";
53804
- static props = {
53805
- focusGrid: Function,
53806
- };
53835
+ static props = {};
53807
53836
  static components = { ValidationMessages };
53837
+ DOMFocusableElementStore;
53808
53838
  inputRef = owl.useRef("inputRef");
53809
53839
  state = owl.useState({
53810
53840
  inputValue: "100",
53811
53841
  errorFlag: false,
53812
53842
  });
53813
53843
  setup() {
53844
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
53814
53845
  owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
53815
53846
  }
53816
53847
  get addRowsPosition() {
@@ -53828,7 +53859,7 @@ stores.inject(MyMetaStore, storeInstance);
53828
53859
  }
53829
53860
  onKeydown(ev) {
53830
53861
  if (ev.key.toUpperCase() === "ESCAPE") {
53831
- this.props.focusGrid();
53862
+ this.focusDefaultElement();
53832
53863
  }
53833
53864
  else if (ev.key.toUpperCase() === "ENTER") {
53834
53865
  this.onConfirm();
@@ -53855,7 +53886,7 @@ stores.inject(MyMetaStore, storeInstance);
53855
53886
  quantity,
53856
53887
  dimension: "ROW",
53857
53888
  });
53858
- this.props.focusGrid();
53889
+ this.focusDefaultElement();
53859
53890
  // After adding new rows, scroll down to the new last row
53860
53891
  const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
53861
53892
  const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
@@ -53868,7 +53899,12 @@ stores.inject(MyMetaStore, storeInstance);
53868
53899
  if (this.inputRef.el !== document.activeElement || ev.target === this.inputRef.el) {
53869
53900
  return;
53870
53901
  }
53871
- this.props.focusGrid();
53902
+ this.focusDefaultElement();
53903
+ }
53904
+ focusDefaultElement() {
53905
+ if (document.activeElement === this.inputRef.el) {
53906
+ this.DOMFocusableElementStore.focus();
53907
+ }
53872
53908
  }
53873
53909
  }
53874
53910
 
@@ -54113,7 +54149,6 @@ stores.inject(MyMetaStore, storeInstance);
54113
54149
  onCellClicked: { type: Function, optional: true },
54114
54150
  onCellRightClicked: { type: Function, optional: true },
54115
54151
  onGridResized: { type: Function, optional: true },
54116
- onFigureDeleted: { type: Function, optional: true },
54117
54152
  onGridMoved: Function,
54118
54153
  gridOverlayDimensions: String,
54119
54154
  slots: { type: Object, optional: true },
@@ -54129,7 +54164,6 @@ stores.inject(MyMetaStore, storeInstance);
54129
54164
  onCellClicked: () => { },
54130
54165
  onCellRightClicked: () => { },
54131
54166
  onGridResized: () => { },
54132
- onFigureDeleted: () => { },
54133
54167
  };
54134
54168
  gridOverlay = owl.useRef("gridOverlay");
54135
54169
  gridOverlayRect = useAbsoluteBoundingRect(this.gridOverlay);
@@ -60698,6 +60732,7 @@ stores.inject(MyMetaStore, storeInstance);
60698
60732
  class RangeAdapter {
60699
60733
  getters;
60700
60734
  providers = [];
60735
+ isAdaptingRanges = false;
60701
60736
  constructor(getters) {
60702
60737
  this.getters = getters;
60703
60738
  }
@@ -60729,6 +60764,9 @@ stores.inject(MyMetaStore, storeInstance);
60729
60764
  }
60730
60765
  beforeHandle(command) { }
60731
60766
  handle(cmd) {
60767
+ if (this.isAdaptingRanges) {
60768
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
60769
+ }
60732
60770
  const rangeAdapter = getRangeAdapter(cmd);
60733
60771
  if (rangeAdapter?.applyChange) {
60734
60772
  this.executeOnAllRanges(rangeAdapter.applyChange, rangeAdapter.sheetId, rangeAdapter.sheetName);
@@ -60751,10 +60789,12 @@ stores.inject(MyMetaStore, storeInstance);
60751
60789
  };
60752
60790
  }
60753
60791
  executeOnAllRanges(adaptRange, sheetId, sheetName) {
60792
+ this.isAdaptingRanges = true;
60754
60793
  const func = this.verifyRangeRemoved(adaptRange);
60755
60794
  for (const provider of this.providers) {
60756
60795
  provider(func, sheetId, sheetName);
60757
60796
  }
60797
+ this.isAdaptingRanges = false;
60758
60798
  }
60759
60799
  /**
60760
60800
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -62790,6 +62830,18 @@ stores.inject(MyMetaStore, storeInstance);
62790
62830
  }
62791
62831
  }
62792
62832
  adaptRanges(applyChange) {
62833
+ for (const pivotId in this.pivots) {
62834
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
62835
+ if (!definition) {
62836
+ continue;
62837
+ }
62838
+ const newDefinition = pivotRegistry
62839
+ .get(definition.type)
62840
+ ?.adaptRanges?.(this.getters, definition, applyChange);
62841
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
62842
+ this.history.update("pivots", pivotId, "definition", newDefinition);
62843
+ }
62844
+ }
62793
62845
  for (const sheetId in this.compiledMeasureFormulas) {
62794
62846
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
62795
62847
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -62937,17 +62989,10 @@ stores.inject(MyMetaStore, storeInstance);
62937
62989
  if (!pivot) {
62938
62990
  continue;
62939
62991
  }
62940
- const def = deepCopy(pivot.definition);
62941
- for (const measure of def.measures) {
62992
+ for (const measure of pivot.definition.measures) {
62942
62993
  if (measure.computedBy?.formula === formulaString) {
62943
- const measureIndex = def.measures.indexOf(measure);
62944
- if (measureIndex !== -1) {
62945
- def.measures[measureIndex].computedBy = {
62946
- formula: newFormulaString,
62947
- sheetId,
62948
- };
62949
- }
62950
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
62994
+ const measureIndex = pivot.definition.measures.indexOf(measure);
62995
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
62951
62996
  }
62952
62997
  }
62953
62998
  }
@@ -63074,20 +63119,6 @@ stores.inject(MyMetaStore, storeInstance);
63074
63119
  }
63075
63120
  }
63076
63121
 
63077
- function adaptPivotRange(range, applyChange) {
63078
- if (!range) {
63079
- return undefined;
63080
- }
63081
- const change = applyChange(range);
63082
- switch (change.changeType) {
63083
- case "NONE":
63084
- return range;
63085
- case "REMOVE":
63086
- return undefined;
63087
- default:
63088
- return change.range;
63089
- }
63090
- }
63091
63122
  class SpreadsheetPivotCorePlugin extends CorePlugin {
63092
63123
  allowDispatch(cmd) {
63093
63124
  switch (cmd.type) {
@@ -63098,27 +63129,6 @@ stores.inject(MyMetaStore, storeInstance);
63098
63129
  }
63099
63130
  return "Success" /* CommandResult.Success */;
63100
63131
  }
63101
- adaptRanges(applyChange) {
63102
- for (const pivotId of this.getters.getPivotIds()) {
63103
- const definition = this.getters.getPivotCoreDefinition(pivotId);
63104
- if (definition.type !== "SPREADSHEET") {
63105
- continue;
63106
- }
63107
- if (definition.dataSet) {
63108
- const { sheetId, zone } = definition.dataSet;
63109
- const range = this.getters.getRangeFromZone(sheetId, zone);
63110
- const adaptedRange = adaptPivotRange(range, applyChange);
63111
- if (adaptedRange === range) {
63112
- return;
63113
- }
63114
- const dataSet = adaptedRange && {
63115
- sheetId: adaptedRange.sheetId,
63116
- zone: adaptedRange.zone,
63117
- };
63118
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
63119
- }
63120
- }
63121
- }
63122
63132
  checkDataSetValidity(definition) {
63123
63133
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
63124
63134
  const { zone, sheetId } = definition.dataSet;
@@ -64460,6 +64470,9 @@ stores.inject(MyMetaStore, storeInstance);
64460
64470
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
64461
64471
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
64462
64472
  }
64473
+ isArrayFormulaSpillBlocked(position) {
64474
+ return this.blockedArrayFormulas.has(position);
64475
+ }
64463
64476
  updateDependencies(position) {
64464
64477
  // removing dependencies is slow because it requires
64465
64478
  // to traverse the entire r-tree.
@@ -64471,13 +64484,8 @@ stores.inject(MyMetaStore, storeInstance);
64471
64484
  addDependencies(position, dependencies) {
64472
64485
  this.formulaDependencies().addDependencies(position, dependencies);
64473
64486
  for (const range of dependencies) {
64474
- const sheetId = range.sheetId;
64475
- const { left, bottom, right, top } = range.zone;
64476
- for (let col = left; col <= right; col++) {
64477
- for (let row = top; row <= bottom; row++) {
64478
- this.computeAndSave({ sheetId, col, row });
64479
- }
64480
- }
64487
+ // ensure that all ranges are computed
64488
+ this.compilationParams.ensureRange(range);
64481
64489
  }
64482
64490
  }
64483
64491
  updateCompilationParameters() {
@@ -64680,6 +64688,10 @@ stores.inject(MyMetaStore, storeInstance);
64680
64688
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
64681
64689
  const nbColumns = formulaReturn.length;
64682
64690
  const nbRows = formulaReturn[0].length;
64691
+ if (nbRows === 0) {
64692
+ // empty matrix
64693
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
64694
+ }
64683
64695
  const resultZone = {
64684
64696
  top: formulaPosition.row,
64685
64697
  bottom: formulaPosition.row + nbRows - 1,
@@ -64955,6 +64967,7 @@ stores.inject(MyMetaStore, storeInstance);
64955
64967
  "getEvaluatedCellsPositions",
64956
64968
  "getSpreadZone",
64957
64969
  "getArrayFormulaSpreadingOn",
64970
+ "isArrayFormulaSpillBlocked",
64958
64971
  "isEmpty",
64959
64972
  ];
64960
64973
  shouldRebuildDependenciesGraph = true;
@@ -65067,6 +65080,9 @@ stores.inject(MyMetaStore, storeInstance);
65067
65080
  getArrayFormulaSpreadingOn(position) {
65068
65081
  return this.evaluator.getArrayFormulaSpreadingOn(position);
65069
65082
  }
65083
+ isArrayFormulaSpillBlocked(position) {
65084
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
65085
+ }
65070
65086
  /**
65071
65087
  * Check if a zone only contains empty cells
65072
65088
  */
@@ -76520,7 +76536,7 @@ stores.inject(MyMetaStore, storeInstance);
76520
76536
  document.activeElement?.contains(this.spreadsheetRef.el)) {
76521
76537
  this.focusGrid();
76522
76538
  }
76523
- }, () => [this.env.model.getters.getActiveSheetId()]);
76539
+ });
76524
76540
  owl.useExternalListener(window, "resize", () => this.render(true));
76525
76541
  // For some reason, the wheel event is not properly registered inside templates
76526
76542
  // in Chromium-based browsers based on chromium 125
@@ -81097,9 +81113,9 @@ stores.inject(MyMetaStore, storeInstance);
81097
81113
  exports.tokenize = tokenize;
81098
81114
 
81099
81115
 
81100
- __info__.version = "18.3.28";
81101
- __info__.date = "2025-12-02T05:34:06.602Z";
81102
- __info__.hash = "a205f91";
81116
+ __info__.version = "18.3.31";
81117
+ __info__.date = "2025-12-26T10:18:10.765Z";
81118
+ __info__.hash = "1e143e1";
81103
81119
 
81104
81120
 
81105
81121
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);