@odoo/o-spreadsheet 18.4.19 → 18.4.22

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.4.19
6
- * @date 2025-12-02T05:34:03.902Z
7
- * @hash 95b1252
5
+ * @version 18.4.22
6
+ * @date 2025-12-26T10:19:07.786Z
7
+ * @hash 6ddac00
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -5214,17 +5214,41 @@
5214
5214
  const today = DateTime.now();
5215
5215
  switch (dateValue) {
5216
5216
  case "today":
5217
- return jsDateToNumber(today);
5218
- case "yesterday":
5219
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
5220
- case "tomorrow":
5221
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
5217
+ return Math.floor(jsDateToNumber(today));
5218
+ case "yesterday": {
5219
+ today.setDate(today.getDate() - 1);
5220
+ return Math.floor(jsDateToNumber(today));
5221
+ }
5222
+ case "tomorrow": {
5223
+ today.setDate(today.getDate() + 1);
5224
+ return Math.floor(jsDateToNumber(today));
5225
+ }
5222
5226
  case "lastWeek":
5223
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
5224
- case "lastMonth":
5225
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
5227
+ today.setDate(today.getDate() - 6);
5228
+ return Math.floor(jsDateToNumber(today));
5229
+ case "lastMonth": {
5230
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
5231
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
5232
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
5233
+ today.setDate(1);
5234
+ }
5235
+ else {
5236
+ today.setDate(today.getDate() + 1);
5237
+ today.setMonth(today.getMonth() - 1);
5238
+ }
5239
+ return Math.floor(jsDateToNumber(today));
5240
+ }
5226
5241
  case "lastYear":
5227
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
5242
+ // Handle leap year case
5243
+ if (today.getMonth() === 1 && today.getDate() === 29) {
5244
+ today.setDate(28);
5245
+ today.setFullYear(today.getFullYear() - 1);
5246
+ }
5247
+ else {
5248
+ today.setDate(today.getDate() + 1);
5249
+ today.setFullYear(today.getFullYear() - 1);
5250
+ }
5251
+ return Math.floor(jsDateToNumber(today));
5228
5252
  }
5229
5253
  }
5230
5254
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -29719,7 +29743,7 @@ stores.inject(MyMetaStore, storeInstance);
29719
29743
  return query.replaceAll(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "NAMESPACE" + "$1" + "NAMESPACE" + "$2");
29720
29744
  }
29721
29745
 
29722
- function getChartMenuActions(figureId, onFigureDeleted, env) {
29746
+ function getChartMenuActions(figureId, env) {
29723
29747
  const menuItemSpecs = [
29724
29748
  {
29725
29749
  id: "edit",
@@ -29770,11 +29794,11 @@ stores.inject(MyMetaStore, storeInstance);
29770
29794
  },
29771
29795
  isReadonlyAllowed: true,
29772
29796
  },
29773
- getDeleteMenuItem(figureId, onFigureDeleted, env),
29797
+ getDeleteMenuItem(figureId, env),
29774
29798
  ];
29775
29799
  return createActions(menuItemSpecs).filter((action) => env.model.getters.isReadonly() ? action.isReadonlyAllowed : true);
29776
29800
  }
29777
- function getImageMenuActions(figureId, onFigureDeleted, env) {
29801
+ function getImageMenuActions(figureId, env) {
29778
29802
  const menuItemSpecs = [
29779
29803
  getCopyMenuItem(figureId, env, _t("Image copied to clipboard")),
29780
29804
  getCutMenuItem(figureId, env),
@@ -29819,7 +29843,7 @@ stores.inject(MyMetaStore, storeInstance);
29819
29843
  },
29820
29844
  icon: "o-spreadsheet-Icon.DOWNLOAD",
29821
29845
  },
29822
- getDeleteMenuItem(figureId, onFigureDeleted, env),
29846
+ getDeleteMenuItem(figureId, env),
29823
29847
  ];
29824
29848
  return createActions(menuItemSpecs);
29825
29849
  }
@@ -29855,7 +29879,7 @@ stores.inject(MyMetaStore, storeInstance);
29855
29879
  icon: "o-spreadsheet-Icon.CUT",
29856
29880
  };
29857
29881
  }
29858
- function getDeleteMenuItem(figureId, onFigureDeleted, env) {
29882
+ function getDeleteMenuItem(figureId, env) {
29859
29883
  return {
29860
29884
  id: "delete",
29861
29885
  name: _t("Delete"),
@@ -29865,7 +29889,6 @@ stores.inject(MyMetaStore, storeInstance);
29865
29889
  sheetId: env.model.getters.getActiveSheetId(),
29866
29890
  figureId,
29867
29891
  });
29868
- onFigureDeleted();
29869
29892
  },
29870
29893
  icon: "o-spreadsheet-Icon.TRASH",
29871
29894
  };
@@ -30710,7 +30733,7 @@ stores.inject(MyMetaStore, storeInstance);
30710
30733
  openContextMenu(ev) {
30711
30734
  this.menuState.isOpen = true;
30712
30735
  this.menuState.anchorRect = getBoundingRectAsPOJO(ev.currentTarget);
30713
- this.menuState.menuItems = getChartMenuActions(this.props.figureUI.id, () => { }, this.env);
30736
+ this.menuState.menuItems = getChartMenuActions(this.props.figureUI.id, this.env);
30714
30737
  }
30715
30738
  get fullScreenMenuItem() {
30716
30739
  const definition = this.env.model.getters.getChartDefinition(this.props.figureUI.id);
@@ -30752,7 +30775,6 @@ stores.inject(MyMetaStore, storeInstance);
30752
30775
  static template = "o-spreadsheet-ChartFigure";
30753
30776
  static props = {
30754
30777
  figureUI: Object,
30755
- onFigureDeleted: Function,
30756
30778
  };
30757
30779
  static components = { ChartDashboardMenu };
30758
30780
  onDoubleClick() {
@@ -30776,7 +30798,6 @@ stores.inject(MyMetaStore, storeInstance);
30776
30798
  static template = "o-spreadsheet-ImageFigure";
30777
30799
  static props = {
30778
30800
  figureUI: Object,
30779
- onFigureDeleted: Function,
30780
30801
  };
30781
30802
  static components = {};
30782
30803
  // ---------------------------------------------------------------------------
@@ -30887,13 +30908,11 @@ stores.inject(MyMetaStore, storeInstance);
30887
30908
  static props = {
30888
30909
  figureUI: Object,
30889
30910
  style: { type: String, optional: true },
30890
- onFigureDeleted: { type: Function, optional: true },
30891
30911
  onMouseDown: { type: Function, optional: true },
30892
30912
  onClickAnchor: { type: Function, optional: true },
30893
30913
  };
30894
30914
  static components = { MenuPopover };
30895
30915
  static defaultProps = {
30896
- onFigureDeleted: () => { },
30897
30916
  onMouseDown: () => { },
30898
30917
  onClickAnchor: () => { },
30899
30918
  };
@@ -30970,9 +30989,6 @@ stores.inject(MyMetaStore, storeInstance);
30970
30989
  this.props.figureUI.id,
30971
30990
  this.figureRef.el,
30972
30991
  ]);
30973
- owl.onWillUnmount(() => {
30974
- this.props.onFigureDeleted();
30975
- });
30976
30992
  }
30977
30993
  clickAnchor(dirX, dirY, ev) {
30978
30994
  this.props.onClickAnchor(dirX, dirY, ev);
@@ -30996,7 +31012,6 @@ stores.inject(MyMetaStore, storeInstance);
30996
31012
  sheetId: this.env.model.getters.getActiveSheetId(),
30997
31013
  figureId: this.props.figureUI.id,
30998
31014
  });
30999
- this.props.onFigureDeleted();
31000
31015
  ev.preventDefault();
31001
31016
  ev.stopPropagation();
31002
31017
  break;
@@ -31089,7 +31104,7 @@ stores.inject(MyMetaStore, storeInstance);
31089
31104
  this.menuState.anchorRect = anchorRect;
31090
31105
  this.menuState.menuItems = figureRegistry
31091
31106
  .get(this.props.figureUI.tag)
31092
- .menuBuilder(this.props.figureUI.id, this.props.onFigureDeleted, this.env);
31107
+ .menuBuilder(this.props.figureUI.id, this.env);
31093
31108
  }
31094
31109
  }
31095
31110
 
@@ -31454,7 +31469,7 @@ stores.inject(MyMetaStore, storeInstance);
31454
31469
  return false;
31455
31470
  }
31456
31471
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
31457
- const today = jsDateToRoundNumber(DateTime.now());
31472
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
31458
31473
  return isDateBetween(dateValue, today, criterionValue);
31459
31474
  }
31460
31475
  return areDatesSameDay(dateValue, criterionValue);
@@ -45256,7 +45271,6 @@ stores.inject(MyMetaStore, storeInstance);
45256
45271
  }
45257
45272
  get highlights() {
45258
45273
  const position = this.model.getters.getActivePosition();
45259
- const cell = this.getters.getEvaluatedCell(position);
45260
45274
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
45261
45275
  const zone = spreader
45262
45276
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
@@ -45264,10 +45278,11 @@ stores.inject(MyMetaStore, storeInstance);
45264
45278
  if (!zone) {
45265
45279
  return [];
45266
45280
  }
45281
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
45267
45282
  return [
45268
45283
  {
45269
45284
  range: this.model.getters.getRangeFromZone(position.sheetId, zone),
45270
- dashed: cell.value === CellErrorType.SpilledBlocked,
45285
+ dashed: isArrayFormulaBlocked,
45271
45286
  color: "#17A2B8",
45272
45287
  noFill: true,
45273
45288
  thinLine: true,
@@ -46365,9 +46380,7 @@ stores.inject(MyMetaStore, storeInstance);
46365
46380
  */
46366
46381
  class FiguresContainer extends owl.Component {
46367
46382
  static template = "o-spreadsheet-FiguresContainer";
46368
- static props = {
46369
- onFigureDeleted: Function,
46370
- };
46383
+ static props = {};
46371
46384
  static components = { FigureComponent };
46372
46385
  dnd = owl.useState({
46373
46386
  draggedFigure: undefined,
@@ -46742,16 +46755,16 @@ stores.inject(MyMetaStore, storeInstance);
46742
46755
  `;
46743
46756
  class GridAddRowsFooter extends owl.Component {
46744
46757
  static template = "o-spreadsheet-GridAddRowsFooter";
46745
- static props = {
46746
- focusGrid: Function,
46747
- };
46758
+ static props = {};
46748
46759
  static components = { ValidationMessages };
46760
+ DOMFocusableElementStore;
46749
46761
  inputRef = owl.useRef("inputRef");
46750
46762
  state = owl.useState({
46751
46763
  inputValue: "100",
46752
46764
  errorFlag: false,
46753
46765
  });
46754
46766
  setup() {
46767
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
46755
46768
  owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
46756
46769
  }
46757
46770
  get addRowsPosition() {
@@ -46769,7 +46782,7 @@ stores.inject(MyMetaStore, storeInstance);
46769
46782
  }
46770
46783
  onKeydown(ev) {
46771
46784
  if (ev.key.toUpperCase() === "ESCAPE") {
46772
- this.props.focusGrid();
46785
+ this.focusDefaultElement();
46773
46786
  }
46774
46787
  else if (ev.key.toUpperCase() === "ENTER") {
46775
46788
  this.onConfirm();
@@ -46796,7 +46809,7 @@ stores.inject(MyMetaStore, storeInstance);
46796
46809
  quantity,
46797
46810
  dimension: "ROW",
46798
46811
  });
46799
- this.props.focusGrid();
46812
+ this.focusDefaultElement();
46800
46813
  // After adding new rows, scroll down to the new last row
46801
46814
  const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
46802
46815
  const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
@@ -46809,7 +46822,12 @@ stores.inject(MyMetaStore, storeInstance);
46809
46822
  if (this.inputRef.el !== document.activeElement || ev.target === this.inputRef.el) {
46810
46823
  return;
46811
46824
  }
46812
- this.props.focusGrid();
46825
+ this.focusDefaultElement();
46826
+ }
46827
+ focusDefaultElement() {
46828
+ if (document.activeElement === this.inputRef.el) {
46829
+ this.DOMFocusableElementStore.focus();
46830
+ }
46813
46831
  }
46814
46832
  }
46815
46833
 
@@ -47084,7 +47102,6 @@ stores.inject(MyMetaStore, storeInstance);
47084
47102
  onCellClicked: { type: Function, optional: true },
47085
47103
  onCellRightClicked: { type: Function, optional: true },
47086
47104
  onGridResized: { type: Function, optional: true },
47087
- onFigureDeleted: { type: Function, optional: true },
47088
47105
  onGridMoved: Function,
47089
47106
  gridOverlayDimensions: String,
47090
47107
  slots: { type: Object, optional: true },
@@ -47099,7 +47116,6 @@ stores.inject(MyMetaStore, storeInstance);
47099
47116
  onCellClicked: () => { },
47100
47117
  onCellRightClicked: () => { },
47101
47118
  onGridResized: () => { },
47102
- onFigureDeleted: () => { },
47103
47119
  };
47104
47120
  gridOverlay = owl.useRef("gridOverlay");
47105
47121
  cellPopovers;
@@ -51958,7 +51974,7 @@ stores.inject(MyMetaStore, storeInstance);
51958
51974
  }
51959
51975
 
51960
51976
  css /* scss */ `
51961
- .o-cf-preview {
51977
+ .o-spreadsheet .o-cf-preview {
51962
51978
  &.o-cf-cursor-ptr {
51963
51979
  cursor: pointer;
51964
51980
  }
@@ -51966,6 +51982,7 @@ stores.inject(MyMetaStore, storeInstance);
51966
51982
  border-bottom: 1px solid ${GRAY_300};
51967
51983
  height: 80px;
51968
51984
  padding: 10px;
51985
+ box-sizing: border-box;
51969
51986
  position: relative;
51970
51987
  cursor: pointer;
51971
51988
  &:hover,
@@ -51979,7 +51996,6 @@ stores.inject(MyMetaStore, storeInstance);
51979
51996
  .o-cf-preview-icon {
51980
51997
  border: 1px solid ${GRAY_300};
51981
51998
  background-color: #fff;
51982
- position: absolute;
51983
51999
  height: 50px;
51984
52000
  width: 50px;
51985
52001
  .o-icon {
@@ -51988,12 +52004,6 @@ stores.inject(MyMetaStore, storeInstance);
51988
52004
  }
51989
52005
  }
51990
52006
  .o-cf-preview-description {
51991
- left: 65px;
51992
- margin-bottom: auto;
51993
- margin-right: 8px;
51994
- margin-top: auto;
51995
- position: relative;
51996
- width: 142px;
51997
52007
  .o-cf-preview-description-rule {
51998
52008
  margin-bottom: 4px;
51999
52009
  max-height: 2.8em;
@@ -52003,16 +52013,11 @@ stores.inject(MyMetaStore, storeInstance);
52003
52013
  font-size: 12px;
52004
52014
  }
52005
52015
  }
52006
- .o-cf-delete {
52007
- left: 90%;
52008
- top: 39%;
52009
- position: absolute;
52010
- }
52011
52016
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
52012
52017
  display: none !important;
52013
52018
  }
52014
52019
  .o-cf-drag-handle {
52015
- left: -8px;
52020
+ left: 2px;
52016
52021
  cursor: move;
52017
52022
  .o-icon {
52018
52023
  width: 6px;
@@ -56061,7 +56066,37 @@ stores.inject(MyMetaStore, storeInstance);
56061
56066
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
56062
56067
  isMeasureCandidate: (field) => field.type !== "boolean",
56063
56068
  isGroupable: () => true,
56069
+ adaptRanges: (getters, definition, applyChange) => {
56070
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
56071
+ return definition;
56072
+ }
56073
+ const { sheetId, zone } = definition.dataSet;
56074
+ const range = getters.getRangeFromZone(sheetId, zone);
56075
+ const adaptedRange = adaptPivotRange(range, applyChange);
56076
+ if (adaptedRange === range) {
56077
+ return definition;
56078
+ }
56079
+ const dataSet = adaptedRange && {
56080
+ sheetId: adaptedRange.sheetId,
56081
+ zone: adaptedRange.zone,
56082
+ };
56083
+ return { ...definition, dataSet };
56084
+ },
56064
56085
  });
56086
+ function adaptPivotRange(range, applyChange) {
56087
+ if (!range) {
56088
+ return undefined;
56089
+ }
56090
+ const change = applyChange(range);
56091
+ switch (change.changeType) {
56092
+ case "NONE":
56093
+ return range;
56094
+ case "REMOVE":
56095
+ return undefined;
56096
+ default:
56097
+ return change.range;
56098
+ }
56099
+ }
56065
56100
 
56066
56101
  class PivotSidePanelStore extends SpreadsheetStore {
56067
56102
  pivotId;
@@ -62214,6 +62249,7 @@ stores.inject(MyMetaStore, storeInstance);
62214
62249
  class RangeAdapter {
62215
62250
  getters;
62216
62251
  providers = [];
62252
+ isAdaptingRanges = false;
62217
62253
  constructor(getters) {
62218
62254
  this.getters = getters;
62219
62255
  }
@@ -62245,6 +62281,9 @@ stores.inject(MyMetaStore, storeInstance);
62245
62281
  }
62246
62282
  beforeHandle(command) { }
62247
62283
  handle(cmd) {
62284
+ if (this.isAdaptingRanges) {
62285
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
62286
+ }
62248
62287
  const rangeAdapter = getRangeAdapter(cmd);
62249
62288
  if (rangeAdapter?.applyChange) {
62250
62289
  this.executeOnAllRanges(rangeAdapter.applyChange, rangeAdapter.sheetId, rangeAdapter.sheetName);
@@ -62267,10 +62306,12 @@ stores.inject(MyMetaStore, storeInstance);
62267
62306
  };
62268
62307
  }
62269
62308
  executeOnAllRanges(adaptRange, sheetId, sheetName) {
62309
+ this.isAdaptingRanges = true;
62270
62310
  const func = this.verifyRangeRemoved(adaptRange);
62271
62311
  for (const provider of this.providers) {
62272
62312
  provider(func, sheetId, sheetName);
62273
62313
  }
62314
+ this.isAdaptingRanges = false;
62274
62315
  }
62275
62316
  /**
62276
62317
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -64306,6 +64347,18 @@ stores.inject(MyMetaStore, storeInstance);
64306
64347
  }
64307
64348
  }
64308
64349
  adaptRanges(applyChange) {
64350
+ for (const pivotId in this.pivots) {
64351
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
64352
+ if (!definition) {
64353
+ continue;
64354
+ }
64355
+ const newDefinition = pivotRegistry
64356
+ .get(definition.type)
64357
+ ?.adaptRanges?.(this.getters, definition, applyChange);
64358
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
64359
+ this.history.update("pivots", pivotId, "definition", newDefinition);
64360
+ }
64361
+ }
64309
64362
  for (const sheetId in this.compiledMeasureFormulas) {
64310
64363
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
64311
64364
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -64450,17 +64503,10 @@ stores.inject(MyMetaStore, storeInstance);
64450
64503
  if (!pivot) {
64451
64504
  continue;
64452
64505
  }
64453
- const def = deepCopy(pivot.definition);
64454
- for (const measure of def.measures) {
64506
+ for (const measure of pivot.definition.measures) {
64455
64507
  if (measure.computedBy?.formula === formulaString) {
64456
- const measureIndex = def.measures.indexOf(measure);
64457
- if (measureIndex !== -1) {
64458
- def.measures[measureIndex].computedBy = {
64459
- formula: newFormulaString,
64460
- sheetId,
64461
- };
64462
- }
64463
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
64508
+ const measureIndex = pivot.definition.measures.indexOf(measure);
64509
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
64464
64510
  }
64465
64511
  }
64466
64512
  }
@@ -64564,20 +64610,6 @@ stores.inject(MyMetaStore, storeInstance);
64564
64610
  }
64565
64611
  }
64566
64612
 
64567
- function adaptPivotRange(range, applyChange) {
64568
- if (!range) {
64569
- return undefined;
64570
- }
64571
- const change = applyChange(range);
64572
- switch (change.changeType) {
64573
- case "NONE":
64574
- return range;
64575
- case "REMOVE":
64576
- return undefined;
64577
- default:
64578
- return change.range;
64579
- }
64580
- }
64581
64613
  class SpreadsheetPivotCorePlugin extends CorePlugin {
64582
64614
  allowDispatch(cmd) {
64583
64615
  switch (cmd.type) {
@@ -64588,27 +64620,6 @@ stores.inject(MyMetaStore, storeInstance);
64588
64620
  }
64589
64621
  return "Success" /* CommandResult.Success */;
64590
64622
  }
64591
- adaptRanges(applyChange) {
64592
- for (const pivotId of this.getters.getPivotIds()) {
64593
- const definition = this.getters.getPivotCoreDefinition(pivotId);
64594
- if (definition.type !== "SPREADSHEET") {
64595
- continue;
64596
- }
64597
- if (definition.dataSet) {
64598
- const { sheetId, zone } = definition.dataSet;
64599
- const range = this.getters.getRangeFromZone(sheetId, zone);
64600
- const adaptedRange = adaptPivotRange(range, applyChange);
64601
- if (adaptedRange === range) {
64602
- return;
64603
- }
64604
- const dataSet = adaptedRange && {
64605
- sheetId: adaptedRange.sheetId,
64606
- zone: adaptedRange.zone,
64607
- };
64608
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
64609
- }
64610
- }
64611
- }
64612
64623
  checkDataSetValidity(definition) {
64613
64624
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
64614
64625
  const { zone, sheetId } = definition.dataSet;
@@ -65950,6 +65961,9 @@ stores.inject(MyMetaStore, storeInstance);
65950
65961
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
65951
65962
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
65952
65963
  }
65964
+ isArrayFormulaSpillBlocked(position) {
65965
+ return this.blockedArrayFormulas.has(position);
65966
+ }
65953
65967
  updateDependencies(position) {
65954
65968
  // removing dependencies is slow because it requires
65955
65969
  // to traverse the entire r-tree.
@@ -65961,13 +65975,8 @@ stores.inject(MyMetaStore, storeInstance);
65961
65975
  addDependencies(position, dependencies) {
65962
65976
  this.formulaDependencies().addDependencies(position, dependencies);
65963
65977
  for (const range of dependencies) {
65964
- const sheetId = range.sheetId;
65965
- const { left, bottom, right, top } = range.zone;
65966
- for (let col = left; col <= right; col++) {
65967
- for (let row = top; row <= bottom; row++) {
65968
- this.computeAndSave({ sheetId, col, row });
65969
- }
65970
- }
65978
+ // ensure that all ranges are computed
65979
+ this.compilationParams.ensureRange(range);
65971
65980
  }
65972
65981
  }
65973
65982
  updateCompilationParameters() {
@@ -66170,6 +66179,10 @@ stores.inject(MyMetaStore, storeInstance);
66170
66179
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
66171
66180
  const nbColumns = formulaReturn.length;
66172
66181
  const nbRows = formulaReturn[0].length;
66182
+ if (nbRows === 0) {
66183
+ // empty matrix
66184
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
66185
+ }
66173
66186
  const resultZone = {
66174
66187
  top: formulaPosition.row,
66175
66188
  bottom: formulaPosition.row + nbRows - 1,
@@ -66445,6 +66458,7 @@ stores.inject(MyMetaStore, storeInstance);
66445
66458
  "getEvaluatedCellsPositions",
66446
66459
  "getSpreadZone",
66447
66460
  "getArrayFormulaSpreadingOn",
66461
+ "isArrayFormulaSpillBlocked",
66448
66462
  "isEmpty",
66449
66463
  ];
66450
66464
  shouldRebuildDependenciesGraph = true;
@@ -66557,6 +66571,9 @@ stores.inject(MyMetaStore, storeInstance);
66557
66571
  getArrayFormulaSpreadingOn(position) {
66558
66572
  return this.evaluator.getArrayFormulaSpreadingOn(position);
66559
66573
  }
66574
+ isArrayFormulaSpillBlocked(position) {
66575
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
66576
+ }
66560
66577
  /**
66561
66578
  * Check if a zone only contains empty cells
66562
66579
  */
@@ -80359,7 +80376,7 @@ stores.inject(MyMetaStore, storeInstance);
80359
80376
  document.activeElement?.contains(this.spreadsheetRef.el)) {
80360
80377
  this.focusGrid();
80361
80378
  }
80362
- }, () => [this.env.model.getters.getActiveSheetId()]);
80379
+ });
80363
80380
  owl.useExternalListener(window, "resize", () => this.render(true));
80364
80381
  // For some reason, the wheel event is not properly registered inside templates
80365
80382
  // in Chromium-based browsers based on chromium 125
@@ -85000,9 +85017,9 @@ stores.inject(MyMetaStore, storeInstance);
85000
85017
  exports.tokenize = tokenize;
85001
85018
 
85002
85019
 
85003
- __info__.version = "18.4.19";
85004
- __info__.date = "2025-12-02T05:34:03.902Z";
85005
- __info__.hash = "95b1252";
85020
+ __info__.version = "18.4.22";
85021
+ __info__.date = "2025-12-26T10:19:07.786Z";
85022
+ __info__.hash = "6ddac00";
85006
85023
 
85007
85024
 
85008
85025
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);