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