@odoo/o-spreadsheet 18.4.13 → 18.4.16

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.13
6
- * @date 2025-10-07T10:00:55.413Z
7
- * @hash d4df70e
5
+ * @version 18.4.16
6
+ * @date 2025-11-03T12:31:57.153Z
7
+ * @hash 1ba569f
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -3193,7 +3193,17 @@
3193
3193
  return toMatrix(data).map((row) => {
3194
3194
  return row.map((cell) => {
3195
3195
  if (typeof cell.value !== "number") {
3196
- throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects number values for %s, but got a %s.", argName, typeof cell.value));
3196
+ let message = "";
3197
+ if (typeof cell === "object") {
3198
+ message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got an empty value.", argName);
3199
+ }
3200
+ else if (typeof cell === "string") {
3201
+ message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got a string.", argName);
3202
+ }
3203
+ else if (typeof cell === "boolean") {
3204
+ message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got a boolean.", argName);
3205
+ }
3206
+ throw new EvaluationError(message);
3197
3207
  }
3198
3208
  return cell.value;
3199
3209
  });
@@ -9081,7 +9091,7 @@
9081
9091
  pasteCell(origin, target, clipboardOption) {
9082
9092
  const { sheetId, col, row } = target;
9083
9093
  const targetCell = this.getters.getEvaluatedCell(target);
9084
- const originFormat = origin?.format ?? origin.evaluatedCell.format;
9094
+ const originFormat = origin?.format || origin.evaluatedCell.format;
9085
9095
  if (clipboardOption?.pasteOption === "asValue") {
9086
9096
  this.dispatch("UPDATE_CELL", {
9087
9097
  ...target,
@@ -13178,7 +13188,7 @@ stores.inject(MyMetaStore, storeInstance);
13178
13188
  if (knownDataY.length === 0 || knownDataY[0].length === 0) {
13179
13189
  return new EvaluationError(emptyDataErrorMessage("known_data_y"));
13180
13190
  }
13181
- return expM(predictLinearValues(logM(toNumberMatrix(knownDataY, "the first argument (known_data_y)")), toNumberMatrix(knownDataX, "the second argument (known_data_x)"), toNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b)));
13191
+ return expM(predictLinearValues(logM(toNumberMatrix(knownDataY, "known_data_y")), toNumberMatrix(knownDataX, "known_data_x"), toNumberMatrix(newDataX, "new_data_y"), toBoolean(b)));
13182
13192
  },
13183
13193
  };
13184
13194
  // -----------------------------------------------------------------------------
@@ -13251,7 +13261,7 @@ stores.inject(MyMetaStore, storeInstance);
13251
13261
  if (dataY.length === 0 || dataY[0].length === 0) {
13252
13262
  return new EvaluationError(emptyDataErrorMessage("data_y"));
13253
13263
  }
13254
- return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13264
+ return fullLinearRegression(toNumberMatrix(dataX, "data_x"), toNumberMatrix(dataY, "data_y"), toBoolean(calculateB), toBoolean(verbose));
13255
13265
  },
13256
13266
  isExported: true,
13257
13267
  };
@@ -13270,7 +13280,7 @@ stores.inject(MyMetaStore, storeInstance);
13270
13280
  if (dataY.length === 0 || dataY[0].length === 0) {
13271
13281
  return new EvaluationError(emptyDataErrorMessage("data_y"));
13272
13282
  }
13273
- const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13283
+ const coeffs = fullLinearRegression(toNumberMatrix(dataX, "data_x"), logM(toNumberMatrix(dataY, "data_y")), toBoolean(calculateB), toBoolean(verbose));
13274
13284
  for (let i = 0; i < coeffs.length; i++) {
13275
13285
  coeffs[i][0] = Math.exp(coeffs[i][0]);
13276
13286
  }
@@ -13884,7 +13894,7 @@ stores.inject(MyMetaStore, storeInstance);
13884
13894
  if (knownDataY.length === 0 || knownDataY[0].length === 0) {
13885
13895
  return new EvaluationError(emptyDataErrorMessage("known_data_y"));
13886
13896
  }
13887
- return predictLinearValues(toNumberMatrix(knownDataY, "the first argument (known_data_y)"), toNumberMatrix(knownDataX, "the second argument (known_data_x)"), toNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b));
13897
+ return predictLinearValues(toNumberMatrix(knownDataY, "known_data_y"), toNumberMatrix(knownDataX, "known_data_x"), toNumberMatrix(newDataX, "new_data_y"), toBoolean(b));
13888
13898
  },
13889
13899
  };
13890
13900
  // -----------------------------------------------------------------------------
@@ -21878,6 +21888,10 @@ stores.inject(MyMetaStore, storeInstance);
21878
21888
  }
21879
21889
  const ctx = chart.ctx;
21880
21890
  ctx.save();
21891
+ const { left, top, height, width } = chart.chartArea;
21892
+ ctx.beginPath();
21893
+ ctx.rect(left, top, width, height);
21894
+ ctx.clip();
21881
21895
  ctx.textAlign = "center";
21882
21896
  ctx.textBaseline = "middle";
21883
21897
  ctx.miterLimit = 1; // Avoid sharp artifacts on strokeText
@@ -22913,7 +22927,18 @@ stores.inject(MyMetaStore, storeInstance);
22913
22927
  this.chart.update();
22914
22928
  }
22915
22929
  hasChartDataChanged() {
22916
- return !deepEquals(this.currentRuntime.chartJsConfig.data, this.chartRuntime.chartJsConfig.data);
22930
+ return !deepEquals(this.getChartDataInRuntime(this.currentRuntime), this.getChartDataInRuntime(this.chartRuntime));
22931
+ }
22932
+ getChartDataInRuntime(runtime) {
22933
+ const data = runtime.chartJsConfig.data;
22934
+ return {
22935
+ labels: data.labels,
22936
+ dataset: data.datasets.map((dataset) => ({
22937
+ data: dataset.data,
22938
+ label: dataset.label,
22939
+ tree: dataset.tree,
22940
+ })),
22941
+ };
22917
22942
  }
22918
22943
  enableAnimationInChartData(chartData) {
22919
22944
  return {
@@ -24535,6 +24560,7 @@ stores.inject(MyMetaStore, storeInstance);
24535
24560
  parser: luxonFormat,
24536
24561
  displayFormats,
24537
24562
  unit: timeUnit ?? false,
24563
+ tooltipFormat: luxonFormat,
24538
24564
  };
24539
24565
  }
24540
24566
  /**
@@ -25615,6 +25641,7 @@ stores.inject(MyMetaStore, storeInstance);
25615
25641
  };
25616
25642
  Object.assign(scales.x, axis);
25617
25643
  scales.x.ticks.maxTicksLimit = 15;
25644
+ delete scales?.x?.ticks?.callback;
25618
25645
  }
25619
25646
  else if (axisType === "linear") {
25620
25647
  scales.x.type = "linear";
@@ -30663,7 +30690,7 @@ stores.inject(MyMetaStore, storeInstance);
30663
30690
  }
30664
30691
  openContextMenu(ev) {
30665
30692
  this.menuState.isOpen = true;
30666
- this.menuState.anchorRect = { x: ev.clientX, y: ev.clientY, width: 0, height: 0 };
30693
+ this.menuState.anchorRect = getBoundingRectAsPOJO(ev.currentTarget);
30667
30694
  this.menuState.menuItems = getChartMenuActions(this.props.figureUI.id, () => { }, this.env);
30668
30695
  }
30669
30696
  get fullScreenMenuItem() {
@@ -32207,7 +32234,7 @@ stores.inject(MyMetaStore, storeInstance);
32207
32234
  else {
32208
32235
  text += NEWLINE;
32209
32236
  }
32210
- emptyParagraph = ["<br>", "<span><br></span>"].includes(current.value.innerHTML);
32237
+ emptyParagraph = isEmptyParagraph(current.value);
32211
32238
  continue;
32212
32239
  }
32213
32240
  if (!current.value.hasChildNodes()) {
@@ -32228,6 +32255,21 @@ stores.inject(MyMetaStore, storeInstance);
32228
32255
  const sameContent = node.innerText === content.value;
32229
32256
  return sameColor && sameClass && sameContent;
32230
32257
  }
32258
+ const doc = new DOMParser();
32259
+ const brNode = doc.parseFromString("<br>", "text/html").body.firstChild;
32260
+ const spanBrNode = doc.parseFromString("<span><br></span>", "text/html").body.firstChild;
32261
+ function isEmptyParagraph(node) {
32262
+ if (node.childNodes.length > 1)
32263
+ return false;
32264
+ const node2 = node.firstChild?.cloneNode(true);
32265
+ if (!node2)
32266
+ return true;
32267
+ if (!(node2 instanceof Element))
32268
+ return false;
32269
+ node2.removeAttribute("class");
32270
+ node2.removeAttribute("style");
32271
+ return node2.isEqualNode(brNode) || node2.isEqualNode(spanBrNode) || false;
32272
+ }
32231
32273
 
32232
32274
  // -----------------------------------------------------------------------------
32233
32275
  // Formula Assistant component
@@ -37465,6 +37507,74 @@ stores.inject(MyMetaStore, storeInstance);
37465
37507
  return path2D;
37466
37508
  }
37467
37509
 
37510
+ /**
37511
+ * Get the relative path between two files
37512
+ *
37513
+ * Eg.:
37514
+ * from "folder1/file1.txt" to "folder2/file2.txt" => "../folder2/file2.txt"
37515
+ */
37516
+ function getRelativePath(from, to) {
37517
+ const fromPathParts = from.split("/");
37518
+ const toPathParts = to.split("/");
37519
+ let relPath = "";
37520
+ let startIndex = 0;
37521
+ for (let i = 0; i < fromPathParts.length - 1; i++) {
37522
+ if (fromPathParts[i] === toPathParts[i]) {
37523
+ startIndex++;
37524
+ }
37525
+ else {
37526
+ relPath += "../";
37527
+ }
37528
+ }
37529
+ relPath += toPathParts.slice(startIndex).join("/");
37530
+ return relPath;
37531
+ }
37532
+ /**
37533
+ * Convert an array of element into an object where the objects keys were the elements position in the array.
37534
+ * Can give an offset as argument, and all the array indexes will we shifted by this offset in the returned object.
37535
+ *
37536
+ * eg. : ["a", "b"] => {0:"a", 1:"b"}
37537
+ */
37538
+ function arrayToObject(array, indexOffset = 0) {
37539
+ const obj = {};
37540
+ for (let i = 0; i < array.length; i++) {
37541
+ if (array[i]) {
37542
+ obj[i + indexOffset] = array[i];
37543
+ }
37544
+ }
37545
+ return obj;
37546
+ }
37547
+ /**
37548
+ * In xlsx we can have string with unicode characters with the format _x00fa_.
37549
+ * Replace with characters understandable by JS
37550
+ */
37551
+ function fixXlsxUnicode(str) {
37552
+ return str.replace(/_x([0-9a-zA-Z]{4})_/g, (match, code) => {
37553
+ return String.fromCharCode(parseInt(code, 16));
37554
+ });
37555
+ }
37556
+ /** Get a header in the SheetData. Create the header if it doesn't exist in the SheetData */
37557
+ function getSheetDataHeader(sheetData, dimension, index) {
37558
+ if (dimension === "COL") {
37559
+ if (!sheetData.cols[index]) {
37560
+ sheetData.cols[index] = {};
37561
+ }
37562
+ return sheetData.cols[index];
37563
+ }
37564
+ if (!sheetData.rows[index]) {
37565
+ sheetData.rows[index] = {};
37566
+ }
37567
+ return sheetData.rows[index];
37568
+ }
37569
+ /** Prefix the string by "=" if the string looks like a formula */
37570
+ function prefixFormulaWithEqual(formula) {
37571
+ if (formula[0] === "=") {
37572
+ return formula;
37573
+ }
37574
+ const tokens = tokenize(formula);
37575
+ return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
37576
+ }
37577
+
37468
37578
  /**
37469
37579
  * Map of the different types of conversions warnings and their name in error messages
37470
37580
  */
@@ -37987,66 +38097,6 @@ stores.inject(MyMetaStore, storeInstance);
37987
38097
  */
37988
38098
  const DEFAULT_SYSTEM_COLOR = "FF000000";
37989
38099
 
37990
- /**
37991
- * Get the relative path between two files
37992
- *
37993
- * Eg.:
37994
- * from "folder1/file1.txt" to "folder2/file2.txt" => "../folder2/file2.txt"
37995
- */
37996
- function getRelativePath(from, to) {
37997
- const fromPathParts = from.split("/");
37998
- const toPathParts = to.split("/");
37999
- let relPath = "";
38000
- let startIndex = 0;
38001
- for (let i = 0; i < fromPathParts.length - 1; i++) {
38002
- if (fromPathParts[i] === toPathParts[i]) {
38003
- startIndex++;
38004
- }
38005
- else {
38006
- relPath += "../";
38007
- }
38008
- }
38009
- relPath += toPathParts.slice(startIndex).join("/");
38010
- return relPath;
38011
- }
38012
- /**
38013
- * Convert an array of element into an object where the objects keys were the elements position in the array.
38014
- * Can give an offset as argument, and all the array indexes will we shifted by this offset in the returned object.
38015
- *
38016
- * eg. : ["a", "b"] => {0:"a", 1:"b"}
38017
- */
38018
- function arrayToObject(array, indexOffset = 0) {
38019
- const obj = {};
38020
- for (let i = 0; i < array.length; i++) {
38021
- if (array[i]) {
38022
- obj[i + indexOffset] = array[i];
38023
- }
38024
- }
38025
- return obj;
38026
- }
38027
- /**
38028
- * In xlsx we can have string with unicode characters with the format _x00fa_.
38029
- * Replace with characters understandable by JS
38030
- */
38031
- function fixXlsxUnicode(str) {
38032
- return str.replace(/_x([0-9a-zA-Z]{4})_/g, (match, code) => {
38033
- return String.fromCharCode(parseInt(code, 16));
38034
- });
38035
- }
38036
- /** Get a header in the SheetData. Create the header if it doesn't exist in the SheetData */
38037
- function getSheetDataHeader(sheetData, dimension, index) {
38038
- if (dimension === "COL") {
38039
- if (!sheetData.cols[index]) {
38040
- sheetData.cols[index] = {};
38041
- }
38042
- return sheetData.cols[index];
38043
- }
38044
- if (!sheetData.rows[index]) {
38045
- sheetData.rows[index] = {};
38046
- }
38047
- return sheetData.rows[index];
38048
- }
38049
-
38050
38100
  const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
38051
38101
  /**
38052
38102
  * Convert excel format to o_spreadsheet format
@@ -38256,9 +38306,9 @@ stores.inject(MyMetaStore, storeInstance);
38256
38306
  if (!rule.operator || !rule.formula || rule.formula.length === 0)
38257
38307
  continue;
38258
38308
  operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.operator];
38259
- values.push(prefixFormula(rule.formula[0]));
38309
+ values.push(prefixFormulaWithEqual(rule.formula[0]));
38260
38310
  if (rule.formula.length === 2) {
38261
- values.push(prefixFormula(rule.formula[1]));
38311
+ values.push(prefixFormulaWithEqual(rule.formula[1]));
38262
38312
  }
38263
38313
  break;
38264
38314
  }
@@ -38416,11 +38466,6 @@ stores.inject(MyMetaStore, storeInstance);
38416
38466
  ? ICON_SETS[iconSet].neutral
38417
38467
  : ICON_SETS[iconSet].good;
38418
38468
  }
38419
- /** Prefix the string by "=" if the string looks like a formula */
38420
- function prefixFormula(formula) {
38421
- const tokens = tokenize(formula);
38422
- return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
38423
- }
38424
38469
  // ---------------------------------------------------------------------------
38425
38470
  // Warnings
38426
38471
  // ---------------------------------------------------------------------------
@@ -38892,7 +38937,7 @@ stores.inject(MyMetaStore, storeInstance);
38892
38937
  dvRules.push(decimalRule);
38893
38938
  break;
38894
38939
  case "list":
38895
- const listRule = convertListrule(dvId++, dv);
38940
+ const listRule = convertListRule(dvId++, dv);
38896
38941
  dvRules.push(listRule);
38897
38942
  break;
38898
38943
  case "date":
@@ -38912,9 +38957,9 @@ stores.inject(MyMetaStore, storeInstance);
38912
38957
  return dvRules;
38913
38958
  }
38914
38959
  function convertDecimalRule(id, dv) {
38915
- const values = [dv.formula1.toString()];
38960
+ const values = [prefixFormulaWithEqual(dv.formula1.toString())];
38916
38961
  if (dv.formula2) {
38917
- values.push(dv.formula2.toString());
38962
+ values.push(prefixFormulaWithEqual(dv.formula2.toString()));
38918
38963
  }
38919
38964
  return {
38920
38965
  id: id.toString(),
@@ -38926,7 +38971,7 @@ stores.inject(MyMetaStore, storeInstance);
38926
38971
  },
38927
38972
  };
38928
38973
  }
38929
- function convertListrule(id, dv) {
38974
+ function convertListRule(id, dv) {
38930
38975
  const formula1 = dv.formula1.toString();
38931
38976
  const isRangeRule = rangeReference.test(formula1);
38932
38977
  return {
@@ -38942,9 +38987,9 @@ stores.inject(MyMetaStore, storeInstance);
38942
38987
  }
38943
38988
  function convertDateRule(id, dv) {
38944
38989
  let criterion;
38945
- const values = [dv.formula1.toString()];
38990
+ const values = [prefixFormulaWithEqual(dv.formula1.toString())];
38946
38991
  if (dv.formula2) {
38947
- values.push(dv.formula2.toString());
38992
+ values.push(prefixFormulaWithEqual(dv.formula2.toString()));
38948
38993
  criterion = {
38949
38994
  type: XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[dv.operator],
38950
38995
  values: getDateCriterionFormattedValues(values, DEFAULT_LOCALE),
@@ -38971,7 +39016,7 @@ stores.inject(MyMetaStore, storeInstance);
38971
39016
  isBlocking: dv.errorStyle !== "warning",
38972
39017
  criterion: {
38973
39018
  type: "customFormula",
38974
- values: [`=${dv.formula1.toString()}`],
39019
+ values: [prefixFormulaWithEqual(dv.formula1.toString())],
38975
39020
  },
38976
39021
  };
38977
39022
  }
@@ -41784,8 +41829,10 @@ stores.inject(MyMetaStore, storeInstance);
41784
41829
  17: "17.4",
41785
41830
  16: "17.3",
41786
41831
  15: "17.2",
41832
+ "14.5": "16.4.1",
41787
41833
  14: "16.4",
41788
41834
  13: "16.3",
41835
+ "12.5": "15.4.1",
41789
41836
  12: "15.4",
41790
41837
  // not accurate starting at this point
41791
41838
  11: "0.10",
@@ -52862,12 +52909,13 @@ stores.inject(MyMetaStore, storeInstance);
52862
52909
  onCloseSidePanel: { type: Function, optional: true },
52863
52910
  };
52864
52911
  state = owl.useState({ rule: this.defaultDataValidationRule, errors: [] });
52912
+ editingSheetId;
52865
52913
  setup() {
52914
+ this.editingSheetId = this.env.model.getters.getActiveSheetId();
52866
52915
  if (this.props.rule) {
52867
- const sheetId = this.env.model.getters.getActiveSheetId();
52868
52916
  this.state.rule = {
52869
52917
  ...this.props.rule,
52870
- ranges: this.props.rule.ranges.map((range) => this.env.model.getters.getRangeString(range, sheetId)),
52918
+ ranges: this.props.rule.ranges.map((range) => this.env.model.getters.getRangeString(range, this.editingSheetId)),
52871
52919
  };
52872
52920
  this.state.rule.criterion.type = this.props.rule.criterion.type;
52873
52921
  }
@@ -52901,7 +52949,6 @@ stores.inject(MyMetaStore, storeInstance);
52901
52949
  const locale = this.env.model.getters.getLocale();
52902
52950
  const criterion = rule.criterion;
52903
52951
  const criterionEvaluator = criterionEvaluatorRegistry.get(criterion.type);
52904
- const sheetId = this.env.model.getters.getActiveSheetId();
52905
52952
  const values = criterion.values
52906
52953
  .slice(0, criterionEvaluator.numberOfValues(criterion))
52907
52954
  .map((value) => value?.trim())
@@ -52909,8 +52956,8 @@ stores.inject(MyMetaStore, storeInstance);
52909
52956
  .map((value) => canonicalizeContent(value, locale));
52910
52957
  rule.criterion = { ...criterion, values };
52911
52958
  return {
52912
- sheetId,
52913
- ranges: this.state.rule.ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(sheetId, xc)),
52959
+ sheetId: this.editingSheetId,
52960
+ ranges: this.state.rule.ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(this.editingSheetId, xc)),
52914
52961
  rule,
52915
52962
  };
52916
52963
  }
@@ -53437,6 +53484,7 @@ stores.inject(MyMetaStore, storeInstance);
53437
53484
  .o-button {
53438
53485
  height: 19px;
53439
53486
  width: 19px;
53487
+ box-sizing: content-box;
53440
53488
  .o-icon {
53441
53489
  height: 14px;
53442
53490
  width: 14px;
@@ -65527,7 +65575,7 @@ stores.inject(MyMetaStore, storeInstance);
65527
65575
  * in the correct order they should be evaluated.
65528
65576
  * This is called a topological ordering (excluding cycles)
65529
65577
  */
65530
- getCellsDependingOn(ranges) {
65578
+ getCellsDependingOn(ranges, ignore) {
65531
65579
  const visited = this.createEmptyPositionSet();
65532
65580
  const queue = Array.from(ranges).reverse();
65533
65581
  while (queue.length > 0) {
@@ -65542,7 +65590,7 @@ stores.inject(MyMetaStore, storeInstance);
65542
65590
  const impactedPositions = this.rTree.search(range).map((dep) => dep.data);
65543
65591
  const nextInQueue = {};
65544
65592
  for (const position of impactedPositions) {
65545
- if (!visited.has(position)) {
65593
+ if (!visited.has(position) && !ignore.has(position)) {
65546
65594
  if (!nextInQueue[position.sheetId]) {
65547
65595
  nextInQueue[position.sheetId] = [];
65548
65596
  }
@@ -66099,7 +66147,7 @@ stores.inject(MyMetaStore, storeInstance);
66099
66147
  }
66100
66148
  invalidatePositionsDependingOnSpread(sheetId, resultZone) {
66101
66149
  // the result matrix is split in 2 zones to exclude the array formula position
66102
- const invalidatedPositions = this.formulaDependencies().getCellsDependingOn(excludeTopLeft(resultZone).map((zone) => ({ sheetId, zone })));
66150
+ const invalidatedPositions = this.formulaDependencies().getCellsDependingOn(excludeTopLeft(resultZone).map((zone) => ({ sheetId, zone })), this.nextPositionsToUpdate);
66103
66151
  invalidatedPositions.delete({ sheetId, col: resultZone.left, row: resultZone.top });
66104
66152
  this.nextPositionsToUpdate.addMany(invalidatedPositions);
66105
66153
  }
@@ -66217,7 +66265,7 @@ stores.inject(MyMetaStore, storeInstance);
66217
66265
  for (const sheetId in zonesBySheetIds) {
66218
66266
  ranges.push(...zonesBySheetIds[sheetId].map((zone) => ({ sheetId, zone })));
66219
66267
  }
66220
- return this.formulaDependencies().getCellsDependingOn(ranges);
66268
+ return this.formulaDependencies().getCellsDependingOn(ranges, this.nextPositionsToUpdate);
66221
66269
  }
66222
66270
  }
66223
66271
  function forEachSpreadPositionInMatrix(nbColumns, nbRows, callback) {
@@ -67690,7 +67738,8 @@ stores.inject(MyMetaStore, storeInstance);
67690
67738
  const topLeft = { col: unionZone.left, row: unionZone.top, sheetId };
67691
67739
  const parentSpreadingCell = this.getters.getArrayFormulaSpreadingOn(topLeft);
67692
67740
  if (!parentSpreadingCell) {
67693
- return false;
67741
+ const evaluatedCell = this.getters.getEvaluatedCell(topLeft);
67742
+ return (evaluatedCell.value === CellErrorType.SpilledBlocked && !evaluatedCell.errorOriginPosition);
67694
67743
  }
67695
67744
  else if (deepEquals(parentSpreadingCell, topLeft) && getZoneArea(unionZone) === 1) {
67696
67745
  return true;
@@ -78591,6 +78640,7 @@ stores.inject(MyMetaStore, storeInstance);
78591
78640
  static components = { Menu };
78592
78641
  rootItems = topbarMenuRegistry.getMenuItems();
78593
78642
  menuRef = owl.useRef("menu");
78643
+ containerRef = owl.useRef("container");
78594
78644
  state = owl.useState({
78595
78645
  menuItems: this.rootItems,
78596
78646
  title: _t("Menu Bar"),
@@ -78598,6 +78648,7 @@ stores.inject(MyMetaStore, storeInstance);
78598
78648
  });
78599
78649
  setup() {
78600
78650
  owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
78651
+ owl.onMounted(this.updateShadows);
78601
78652
  }
78602
78653
  onExternalClick(ev) {
78603
78654
  if (!this.menuRef.el?.contains(ev.target)) {
@@ -78610,6 +78661,7 @@ stores.inject(MyMetaStore, storeInstance);
78610
78661
  this.state.parentState = { ...this.state };
78611
78662
  this.state.menuItems = children;
78612
78663
  this.state.title = menu.name(this.env);
78664
+ this.containerRef.el?.scrollTo({ top: 0 });
78613
78665
  }
78614
78666
  else {
78615
78667
  this.state.menuItems = this.rootItems;
@@ -78631,6 +78683,19 @@ stores.inject(MyMetaStore, storeInstance);
78631
78683
  height: `${this.props.height}px`,
78632
78684
  });
78633
78685
  }
78686
+ updateShadows() {
78687
+ if (!this.containerRef.el) {
78688
+ return;
78689
+ }
78690
+ this.containerRef.el.classList.remove("scroll-top", "scroll-bottom");
78691
+ const maxScroll = this.containerRef.el.scrollHeight - this.containerRef.el.clientHeight || 0;
78692
+ if (this.containerRef.el.scrollTop < maxScroll - 1) {
78693
+ this.containerRef.el.classList.add("scroll-bottom");
78694
+ }
78695
+ if (this.containerRef.el.scrollTop > 0) {
78696
+ this.containerRef.el.classList.add("scroll-top");
78697
+ }
78698
+ }
78634
78699
  onClickBack() {
78635
78700
  if (!this.state.parentState) {
78636
78701
  this.props.onClose();
@@ -78639,6 +78704,7 @@ stores.inject(MyMetaStore, storeInstance);
78639
78704
  this.state.menuItems = this.state.parentState.menuItems;
78640
78705
  this.state.title = this.state.parentState.title;
78641
78706
  this.state.parentState = this.state.parentState.parentState;
78707
+ this.containerRef.el?.scrollTo({ top: 0 });
78642
78708
  }
78643
78709
  get backTitle() {
78644
78710
  return this.state.parentState ? _t("Go to previous menu") : _t("Close menu bar");
@@ -78695,7 +78761,9 @@ stores.inject(MyMetaStore, storeInstance);
78695
78761
  : "inactive";
78696
78762
  }
78697
78763
  get showFxIcon() {
78698
- return this.focus === "inactive" && !this.composerStore.currentContent;
78764
+ return (this.focus === "inactive" &&
78765
+ !this.composerStore.currentContent &&
78766
+ !this.composerStore.placeholder);
78699
78767
  }
78700
78768
  get rect() {
78701
78769
  return this.composerRef.el
@@ -78721,6 +78789,7 @@ stores.inject(MyMetaStore, storeInstance);
78721
78789
  "max-height": `130px`,
78722
78790
  }),
78723
78791
  showAssistant: !isIOS(), // Hide assistant on iOS as it breaks visually
78792
+ placeholder: this.composerStore.placeholder,
78724
78793
  };
78725
78794
  }
78726
78795
  get symbols() {
@@ -78783,7 +78852,9 @@ stores.inject(MyMetaStore, storeInstance);
78783
78852
  : "inactive";
78784
78853
  }
78785
78854
  get showFxIcon() {
78786
- return this.focus === "inactive" && !this.composerStore.currentContent;
78855
+ return (this.focus === "inactive" &&
78856
+ !this.composerStore.currentContent &&
78857
+ !this.composerStore.placeholder);
78787
78858
  }
78788
78859
  get composerStyle() {
78789
78860
  const style = {
@@ -84850,9 +84921,9 @@ stores.inject(MyMetaStore, storeInstance);
84850
84921
  exports.tokenize = tokenize;
84851
84922
 
84852
84923
 
84853
- __info__.version = "18.4.13";
84854
- __info__.date = "2025-10-07T10:00:55.413Z";
84855
- __info__.hash = "d4df70e";
84924
+ __info__.version = "18.4.16";
84925
+ __info__.date = "2025-11-03T12:31:57.153Z";
84926
+ __info__.hash = "1ba569f";
84856
84927
 
84857
84928
 
84858
84929
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);