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