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