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