@odoo/o-spreadsheet 18.4.13 → 18.4.14

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.14
6
+ * @date 2025-10-16T06:39:40.249Z
7
+ * @hash bc55c40
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, useExternalListener, onWillUpdateProps, onWillStart, onWillPatch, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -3192,7 +3192,17 @@ function toNumberMatrix(data, argName) {
3192
3192
  return toMatrix(data).map((row) => {
3193
3193
  return row.map((cell) => {
3194
3194
  if (typeof cell.value !== "number") {
3195
- throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects number values for %s, but got a %s.", argName, typeof cell.value));
3195
+ let message = "";
3196
+ if (typeof cell === "object") {
3197
+ message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got an empty value.", argName);
3198
+ }
3199
+ else if (typeof cell === "string") {
3200
+ message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got a string.", argName);
3201
+ }
3202
+ else if (typeof cell === "boolean") {
3203
+ message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got a boolean.", argName);
3204
+ }
3205
+ throw new EvaluationError(message);
3196
3206
  }
3197
3207
  return cell.value;
3198
3208
  });
@@ -9080,7 +9090,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
9080
9090
  pasteCell(origin, target, clipboardOption) {
9081
9091
  const { sheetId, col, row } = target;
9082
9092
  const targetCell = this.getters.getEvaluatedCell(target);
9083
- const originFormat = origin?.format ?? origin.evaluatedCell.format;
9093
+ const originFormat = origin?.format || origin.evaluatedCell.format;
9084
9094
  if (clipboardOption?.pasteOption === "asValue") {
9085
9095
  this.dispatch("UPDATE_CELL", {
9086
9096
  ...target,
@@ -13177,7 +13187,7 @@ const GROWTH = {
13177
13187
  if (knownDataY.length === 0 || knownDataY[0].length === 0) {
13178
13188
  return new EvaluationError(emptyDataErrorMessage("known_data_y"));
13179
13189
  }
13180
- 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)));
13190
+ return expM(predictLinearValues(logM(toNumberMatrix(knownDataY, "known_data_y")), toNumberMatrix(knownDataX, "known_data_x"), toNumberMatrix(newDataX, "new_data_y"), toBoolean(b)));
13181
13191
  },
13182
13192
  };
13183
13193
  // -----------------------------------------------------------------------------
@@ -13250,7 +13260,7 @@ const LINEST = {
13250
13260
  if (dataY.length === 0 || dataY[0].length === 0) {
13251
13261
  return new EvaluationError(emptyDataErrorMessage("data_y"));
13252
13262
  }
13253
- return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13263
+ return fullLinearRegression(toNumberMatrix(dataX, "data_x"), toNumberMatrix(dataY, "data_y"), toBoolean(calculateB), toBoolean(verbose));
13254
13264
  },
13255
13265
  isExported: true,
13256
13266
  };
@@ -13269,7 +13279,7 @@ const LOGEST = {
13269
13279
  if (dataY.length === 0 || dataY[0].length === 0) {
13270
13280
  return new EvaluationError(emptyDataErrorMessage("data_y"));
13271
13281
  }
13272
- const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13282
+ const coeffs = fullLinearRegression(toNumberMatrix(dataX, "data_x"), logM(toNumberMatrix(dataY, "data_y")), toBoolean(calculateB), toBoolean(verbose));
13273
13283
  for (let i = 0; i < coeffs.length; i++) {
13274
13284
  coeffs[i][0] = Math.exp(coeffs[i][0]);
13275
13285
  }
@@ -13883,7 +13893,7 @@ const TREND = {
13883
13893
  if (knownDataY.length === 0 || knownDataY[0].length === 0) {
13884
13894
  return new EvaluationError(emptyDataErrorMessage("known_data_y"));
13885
13895
  }
13886
- 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));
13896
+ return predictLinearValues(toNumberMatrix(knownDataY, "known_data_y"), toNumberMatrix(knownDataX, "known_data_x"), toNumberMatrix(newDataX, "new_data_y"), toBoolean(b));
13887
13897
  },
13888
13898
  };
13889
13899
  // -----------------------------------------------------------------------------
@@ -21877,6 +21887,10 @@ const chartShowValuesPlugin = {
21877
21887
  }
21878
21888
  const ctx = chart.ctx;
21879
21889
  ctx.save();
21890
+ const { left, top, height, width } = chart.chartArea;
21891
+ ctx.beginPath();
21892
+ ctx.rect(left, top, width, height);
21893
+ ctx.clip();
21880
21894
  ctx.textAlign = "center";
21881
21895
  ctx.textBaseline = "middle";
21882
21896
  ctx.miterLimit = 1; // Avoid sharp artifacts on strokeText
@@ -22912,7 +22926,18 @@ class ChartJsComponent extends Component {
22912
22926
  this.chart.update();
22913
22927
  }
22914
22928
  hasChartDataChanged() {
22915
- return !deepEquals(this.currentRuntime.chartJsConfig.data, this.chartRuntime.chartJsConfig.data);
22929
+ return !deepEquals(this.getChartDataInRuntime(this.currentRuntime), this.getChartDataInRuntime(this.chartRuntime));
22930
+ }
22931
+ getChartDataInRuntime(runtime) {
22932
+ const data = runtime.chartJsConfig.data;
22933
+ return {
22934
+ labels: data.labels,
22935
+ dataset: data.datasets.map((dataset) => ({
22936
+ data: dataset.data,
22937
+ label: dataset.label,
22938
+ tree: dataset.tree,
22939
+ })),
22940
+ };
22916
22941
  }
22917
22942
  enableAnimationInChartData(chartData) {
22918
22943
  return {
@@ -24534,6 +24559,7 @@ function getChartTimeOptions(labels, labelFormat, locale) {
24534
24559
  parser: luxonFormat,
24535
24560
  displayFormats,
24536
24561
  unit: timeUnit ?? false,
24562
+ tooltipFormat: luxonFormat,
24537
24563
  };
24538
24564
  }
24539
24565
  /**
@@ -25614,6 +25640,7 @@ function getLineChartScales(definition, args) {
25614
25640
  };
25615
25641
  Object.assign(scales.x, axis);
25616
25642
  scales.x.ticks.maxTicksLimit = 15;
25643
+ delete scales?.x?.ticks?.callback;
25617
25644
  }
25618
25645
  else if (axisType === "linear") {
25619
25646
  scales.x.type = "linear";
@@ -30662,7 +30689,7 @@ class ChartDashboardMenu extends Component {
30662
30689
  }
30663
30690
  openContextMenu(ev) {
30664
30691
  this.menuState.isOpen = true;
30665
- this.menuState.anchorRect = { x: ev.clientX, y: ev.clientY, width: 0, height: 0 };
30692
+ this.menuState.anchorRect = getBoundingRectAsPOJO(ev.currentTarget);
30666
30693
  this.menuState.menuItems = getChartMenuActions(this.props.figureUI.id, () => { }, this.env);
30667
30694
  }
30668
30695
  get fullScreenMenuItem() {
@@ -37464,6 +37491,74 @@ function getPath2D(svgPath) {
37464
37491
  return path2D;
37465
37492
  }
37466
37493
 
37494
+ /**
37495
+ * Get the relative path between two files
37496
+ *
37497
+ * Eg.:
37498
+ * from "folder1/file1.txt" to "folder2/file2.txt" => "../folder2/file2.txt"
37499
+ */
37500
+ function getRelativePath(from, to) {
37501
+ const fromPathParts = from.split("/");
37502
+ const toPathParts = to.split("/");
37503
+ let relPath = "";
37504
+ let startIndex = 0;
37505
+ for (let i = 0; i < fromPathParts.length - 1; i++) {
37506
+ if (fromPathParts[i] === toPathParts[i]) {
37507
+ startIndex++;
37508
+ }
37509
+ else {
37510
+ relPath += "../";
37511
+ }
37512
+ }
37513
+ relPath += toPathParts.slice(startIndex).join("/");
37514
+ return relPath;
37515
+ }
37516
+ /**
37517
+ * Convert an array of element into an object where the objects keys were the elements position in the array.
37518
+ * Can give an offset as argument, and all the array indexes will we shifted by this offset in the returned object.
37519
+ *
37520
+ * eg. : ["a", "b"] => {0:"a", 1:"b"}
37521
+ */
37522
+ function arrayToObject(array, indexOffset = 0) {
37523
+ const obj = {};
37524
+ for (let i = 0; i < array.length; i++) {
37525
+ if (array[i]) {
37526
+ obj[i + indexOffset] = array[i];
37527
+ }
37528
+ }
37529
+ return obj;
37530
+ }
37531
+ /**
37532
+ * In xlsx we can have string with unicode characters with the format _x00fa_.
37533
+ * Replace with characters understandable by JS
37534
+ */
37535
+ function fixXlsxUnicode(str) {
37536
+ return str.replace(/_x([0-9a-zA-Z]{4})_/g, (match, code) => {
37537
+ return String.fromCharCode(parseInt(code, 16));
37538
+ });
37539
+ }
37540
+ /** Get a header in the SheetData. Create the header if it doesn't exist in the SheetData */
37541
+ function getSheetDataHeader(sheetData, dimension, index) {
37542
+ if (dimension === "COL") {
37543
+ if (!sheetData.cols[index]) {
37544
+ sheetData.cols[index] = {};
37545
+ }
37546
+ return sheetData.cols[index];
37547
+ }
37548
+ if (!sheetData.rows[index]) {
37549
+ sheetData.rows[index] = {};
37550
+ }
37551
+ return sheetData.rows[index];
37552
+ }
37553
+ /** Prefix the string by "=" if the string looks like a formula */
37554
+ function prefixFormulaWithEqual(formula) {
37555
+ if (formula[0] === "=") {
37556
+ return formula;
37557
+ }
37558
+ const tokens = tokenize(formula);
37559
+ return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
37560
+ }
37561
+
37467
37562
  /**
37468
37563
  * Map of the different types of conversions warnings and their name in error messages
37469
37564
  */
@@ -37986,66 +38081,6 @@ function hexaToInt(hex) {
37986
38081
  */
37987
38082
  const DEFAULT_SYSTEM_COLOR = "FF000000";
37988
38083
 
37989
- /**
37990
- * Get the relative path between two files
37991
- *
37992
- * Eg.:
37993
- * from "folder1/file1.txt" to "folder2/file2.txt" => "../folder2/file2.txt"
37994
- */
37995
- function getRelativePath(from, to) {
37996
- const fromPathParts = from.split("/");
37997
- const toPathParts = to.split("/");
37998
- let relPath = "";
37999
- let startIndex = 0;
38000
- for (let i = 0; i < fromPathParts.length - 1; i++) {
38001
- if (fromPathParts[i] === toPathParts[i]) {
38002
- startIndex++;
38003
- }
38004
- else {
38005
- relPath += "../";
38006
- }
38007
- }
38008
- relPath += toPathParts.slice(startIndex).join("/");
38009
- return relPath;
38010
- }
38011
- /**
38012
- * Convert an array of element into an object where the objects keys were the elements position in the array.
38013
- * Can give an offset as argument, and all the array indexes will we shifted by this offset in the returned object.
38014
- *
38015
- * eg. : ["a", "b"] => {0:"a", 1:"b"}
38016
- */
38017
- function arrayToObject(array, indexOffset = 0) {
38018
- const obj = {};
38019
- for (let i = 0; i < array.length; i++) {
38020
- if (array[i]) {
38021
- obj[i + indexOffset] = array[i];
38022
- }
38023
- }
38024
- return obj;
38025
- }
38026
- /**
38027
- * In xlsx we can have string with unicode characters with the format _x00fa_.
38028
- * Replace with characters understandable by JS
38029
- */
38030
- function fixXlsxUnicode(str) {
38031
- return str.replace(/_x([0-9a-zA-Z]{4})_/g, (match, code) => {
38032
- return String.fromCharCode(parseInt(code, 16));
38033
- });
38034
- }
38035
- /** Get a header in the SheetData. Create the header if it doesn't exist in the SheetData */
38036
- function getSheetDataHeader(sheetData, dimension, index) {
38037
- if (dimension === "COL") {
38038
- if (!sheetData.cols[index]) {
38039
- sheetData.cols[index] = {};
38040
- }
38041
- return sheetData.cols[index];
38042
- }
38043
- if (!sheetData.rows[index]) {
38044
- sheetData.rows[index] = {};
38045
- }
38046
- return sheetData.rows[index];
38047
- }
38048
-
38049
38084
  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;
38050
38085
  /**
38051
38086
  * Convert excel format to o_spreadsheet format
@@ -38255,9 +38290,9 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
38255
38290
  if (!rule.operator || !rule.formula || rule.formula.length === 0)
38256
38291
  continue;
38257
38292
  operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.operator];
38258
- values.push(prefixFormula(rule.formula[0]));
38293
+ values.push(prefixFormulaWithEqual(rule.formula[0]));
38259
38294
  if (rule.formula.length === 2) {
38260
- values.push(prefixFormula(rule.formula[1]));
38295
+ values.push(prefixFormulaWithEqual(rule.formula[1]));
38261
38296
  }
38262
38297
  break;
38263
38298
  }
@@ -38415,11 +38450,6 @@ function convertIcons(xlsxIconSet, index) {
38415
38450
  ? ICON_SETS[iconSet].neutral
38416
38451
  : ICON_SETS[iconSet].good;
38417
38452
  }
38418
- /** Prefix the string by "=" if the string looks like a formula */
38419
- function prefixFormula(formula) {
38420
- const tokens = tokenize(formula);
38421
- return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
38422
- }
38423
38453
  // ---------------------------------------------------------------------------
38424
38454
  // Warnings
38425
38455
  // ---------------------------------------------------------------------------
@@ -38891,7 +38921,7 @@ function convertDataValidationRules(xlsxDataValidations, warningManager) {
38891
38921
  dvRules.push(decimalRule);
38892
38922
  break;
38893
38923
  case "list":
38894
- const listRule = convertListrule(dvId++, dv);
38924
+ const listRule = convertListRule(dvId++, dv);
38895
38925
  dvRules.push(listRule);
38896
38926
  break;
38897
38927
  case "date":
@@ -38911,9 +38941,9 @@ function convertDataValidationRules(xlsxDataValidations, warningManager) {
38911
38941
  return dvRules;
38912
38942
  }
38913
38943
  function convertDecimalRule(id, dv) {
38914
- const values = [dv.formula1.toString()];
38944
+ const values = [prefixFormulaWithEqual(dv.formula1.toString())];
38915
38945
  if (dv.formula2) {
38916
- values.push(dv.formula2.toString());
38946
+ values.push(prefixFormulaWithEqual(dv.formula2.toString()));
38917
38947
  }
38918
38948
  return {
38919
38949
  id: id.toString(),
@@ -38925,7 +38955,7 @@ function convertDecimalRule(id, dv) {
38925
38955
  },
38926
38956
  };
38927
38957
  }
38928
- function convertListrule(id, dv) {
38958
+ function convertListRule(id, dv) {
38929
38959
  const formula1 = dv.formula1.toString();
38930
38960
  const isRangeRule = rangeReference.test(formula1);
38931
38961
  return {
@@ -38941,9 +38971,9 @@ function convertListrule(id, dv) {
38941
38971
  }
38942
38972
  function convertDateRule(id, dv) {
38943
38973
  let criterion;
38944
- const values = [dv.formula1.toString()];
38974
+ const values = [prefixFormulaWithEqual(dv.formula1.toString())];
38945
38975
  if (dv.formula2) {
38946
- values.push(dv.formula2.toString());
38976
+ values.push(prefixFormulaWithEqual(dv.formula2.toString()));
38947
38977
  criterion = {
38948
38978
  type: XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[dv.operator],
38949
38979
  values: getDateCriterionFormattedValues(values, DEFAULT_LOCALE),
@@ -38970,7 +39000,7 @@ function convertCustomRule(id, dv) {
38970
39000
  isBlocking: dv.errorStyle !== "warning",
38971
39001
  criterion: {
38972
39002
  type: "customFormula",
38973
- values: [`=${dv.formula1.toString()}`],
39003
+ values: [prefixFormulaWithEqual(dv.formula1.toString())],
38974
39004
  },
38975
39005
  };
38976
39006
  }
@@ -52861,12 +52891,13 @@ class DataValidationEditor extends Component {
52861
52891
  onCloseSidePanel: { type: Function, optional: true },
52862
52892
  };
52863
52893
  state = useState({ rule: this.defaultDataValidationRule, errors: [] });
52894
+ editingSheetId;
52864
52895
  setup() {
52896
+ this.editingSheetId = this.env.model.getters.getActiveSheetId();
52865
52897
  if (this.props.rule) {
52866
- const sheetId = this.env.model.getters.getActiveSheetId();
52867
52898
  this.state.rule = {
52868
52899
  ...this.props.rule,
52869
- ranges: this.props.rule.ranges.map((range) => this.env.model.getters.getRangeString(range, sheetId)),
52900
+ ranges: this.props.rule.ranges.map((range) => this.env.model.getters.getRangeString(range, this.editingSheetId)),
52870
52901
  };
52871
52902
  this.state.rule.criterion.type = this.props.rule.criterion.type;
52872
52903
  }
@@ -52900,7 +52931,6 @@ class DataValidationEditor extends Component {
52900
52931
  const locale = this.env.model.getters.getLocale();
52901
52932
  const criterion = rule.criterion;
52902
52933
  const criterionEvaluator = criterionEvaluatorRegistry.get(criterion.type);
52903
- const sheetId = this.env.model.getters.getActiveSheetId();
52904
52934
  const values = criterion.values
52905
52935
  .slice(0, criterionEvaluator.numberOfValues(criterion))
52906
52936
  .map((value) => value?.trim())
@@ -52908,8 +52938,8 @@ class DataValidationEditor extends Component {
52908
52938
  .map((value) => canonicalizeContent(value, locale));
52909
52939
  rule.criterion = { ...criterion, values };
52910
52940
  return {
52911
- sheetId,
52912
- ranges: this.state.rule.ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(sheetId, xc)),
52941
+ sheetId: this.editingSheetId,
52942
+ ranges: this.state.rule.ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(this.editingSheetId, xc)),
52913
52943
  rule,
52914
52944
  };
52915
52945
  }
@@ -53436,6 +53466,7 @@ css /* scss */ `
53436
53466
  .o-button {
53437
53467
  height: 19px;
53438
53468
  width: 19px;
53469
+ box-sizing: content-box;
53439
53470
  .o-icon {
53440
53471
  height: 14px;
53441
53472
  width: 14px;
@@ -65526,7 +65557,7 @@ class FormulaDependencyGraph {
65526
65557
  * in the correct order they should be evaluated.
65527
65558
  * This is called a topological ordering (excluding cycles)
65528
65559
  */
65529
- getCellsDependingOn(ranges) {
65560
+ getCellsDependingOn(ranges, ignore) {
65530
65561
  const visited = this.createEmptyPositionSet();
65531
65562
  const queue = Array.from(ranges).reverse();
65532
65563
  while (queue.length > 0) {
@@ -65541,7 +65572,7 @@ class FormulaDependencyGraph {
65541
65572
  const impactedPositions = this.rTree.search(range).map((dep) => dep.data);
65542
65573
  const nextInQueue = {};
65543
65574
  for (const position of impactedPositions) {
65544
- if (!visited.has(position)) {
65575
+ if (!visited.has(position) && !ignore.has(position)) {
65545
65576
  if (!nextInQueue[position.sheetId]) {
65546
65577
  nextInQueue[position.sheetId] = [];
65547
65578
  }
@@ -66098,7 +66129,7 @@ class Evaluator {
66098
66129
  }
66099
66130
  invalidatePositionsDependingOnSpread(sheetId, resultZone) {
66100
66131
  // the result matrix is split in 2 zones to exclude the array formula position
66101
- const invalidatedPositions = this.formulaDependencies().getCellsDependingOn(excludeTopLeft(resultZone).map((zone) => ({ sheetId, zone })));
66132
+ const invalidatedPositions = this.formulaDependencies().getCellsDependingOn(excludeTopLeft(resultZone).map((zone) => ({ sheetId, zone })), this.nextPositionsToUpdate);
66102
66133
  invalidatedPositions.delete({ sheetId, col: resultZone.left, row: resultZone.top });
66103
66134
  this.nextPositionsToUpdate.addMany(invalidatedPositions);
66104
66135
  }
@@ -66216,7 +66247,7 @@ class Evaluator {
66216
66247
  for (const sheetId in zonesBySheetIds) {
66217
66248
  ranges.push(...zonesBySheetIds[sheetId].map((zone) => ({ sheetId, zone })));
66218
66249
  }
66219
- return this.formulaDependencies().getCellsDependingOn(ranges);
66250
+ return this.formulaDependencies().getCellsDependingOn(ranges, this.nextPositionsToUpdate);
66220
66251
  }
66221
66252
  }
66222
66253
  function forEachSpreadPositionInMatrix(nbColumns, nbRows, callback) {
@@ -67689,7 +67720,8 @@ class DynamicTablesPlugin extends CoreViewPlugin {
67689
67720
  const topLeft = { col: unionZone.left, row: unionZone.top, sheetId };
67690
67721
  const parentSpreadingCell = this.getters.getArrayFormulaSpreadingOn(topLeft);
67691
67722
  if (!parentSpreadingCell) {
67692
- return false;
67723
+ const evaluatedCell = this.getters.getEvaluatedCell(topLeft);
67724
+ return (evaluatedCell.value === CellErrorType.SpilledBlocked && !evaluatedCell.errorOriginPosition);
67693
67725
  }
67694
67726
  else if (deepEquals(parentSpreadingCell, topLeft) && getZoneArea(unionZone) === 1) {
67695
67727
  return true;
@@ -78590,6 +78622,7 @@ class RibbonMenu extends Component {
78590
78622
  static components = { Menu };
78591
78623
  rootItems = topbarMenuRegistry.getMenuItems();
78592
78624
  menuRef = useRef("menu");
78625
+ containerRef = useRef("container");
78593
78626
  state = useState({
78594
78627
  menuItems: this.rootItems,
78595
78628
  title: _t("Menu Bar"),
@@ -78597,6 +78630,7 @@ class RibbonMenu extends Component {
78597
78630
  });
78598
78631
  setup() {
78599
78632
  useExternalListener(window, "click", this.onExternalClick, { capture: true });
78633
+ onMounted(this.updateShadows);
78600
78634
  }
78601
78635
  onExternalClick(ev) {
78602
78636
  if (!this.menuRef.el?.contains(ev.target)) {
@@ -78609,6 +78643,7 @@ class RibbonMenu extends Component {
78609
78643
  this.state.parentState = { ...this.state };
78610
78644
  this.state.menuItems = children;
78611
78645
  this.state.title = menu.name(this.env);
78646
+ this.containerRef.el?.scrollTo({ top: 0 });
78612
78647
  }
78613
78648
  else {
78614
78649
  this.state.menuItems = this.rootItems;
@@ -78630,6 +78665,19 @@ class RibbonMenu extends Component {
78630
78665
  height: `${this.props.height}px`,
78631
78666
  });
78632
78667
  }
78668
+ updateShadows() {
78669
+ if (!this.containerRef.el) {
78670
+ return;
78671
+ }
78672
+ this.containerRef.el.classList.remove("scroll-top", "scroll-bottom");
78673
+ const maxScroll = this.containerRef.el.scrollHeight - this.containerRef.el.clientHeight || 0;
78674
+ if (this.containerRef.el.scrollTop < maxScroll - 1) {
78675
+ this.containerRef.el.classList.add("scroll-bottom");
78676
+ }
78677
+ if (this.containerRef.el.scrollTop > 0) {
78678
+ this.containerRef.el.classList.add("scroll-top");
78679
+ }
78680
+ }
78633
78681
  onClickBack() {
78634
78682
  if (!this.state.parentState) {
78635
78683
  this.props.onClose();
@@ -78638,6 +78686,7 @@ class RibbonMenu extends Component {
78638
78686
  this.state.menuItems = this.state.parentState.menuItems;
78639
78687
  this.state.title = this.state.parentState.title;
78640
78688
  this.state.parentState = this.state.parentState.parentState;
78689
+ this.containerRef.el?.scrollTo({ top: 0 });
78641
78690
  }
78642
78691
  get backTitle() {
78643
78692
  return this.state.parentState ? _t("Go to previous menu") : _t("Close menu bar");
@@ -78694,7 +78743,9 @@ class SmallBottomBar extends Component {
78694
78743
  : "inactive";
78695
78744
  }
78696
78745
  get showFxIcon() {
78697
- return this.focus === "inactive" && !this.composerStore.currentContent;
78746
+ return (this.focus === "inactive" &&
78747
+ !this.composerStore.currentContent &&
78748
+ !this.composerStore.placeholder);
78698
78749
  }
78699
78750
  get rect() {
78700
78751
  return this.composerRef.el
@@ -78720,6 +78771,7 @@ class SmallBottomBar extends Component {
78720
78771
  "max-height": `130px`,
78721
78772
  }),
78722
78773
  showAssistant: !isIOS(), // Hide assistant on iOS as it breaks visually
78774
+ placeholder: this.composerStore.placeholder,
78723
78775
  };
78724
78776
  }
78725
78777
  get symbols() {
@@ -78782,7 +78834,9 @@ class TopBarComposer extends Component {
78782
78834
  : "inactive";
78783
78835
  }
78784
78836
  get showFxIcon() {
78785
- return this.focus === "inactive" && !this.composerStore.currentContent;
78837
+ return (this.focus === "inactive" &&
78838
+ !this.composerStore.currentContent &&
78839
+ !this.composerStore.placeholder);
78786
78840
  }
78787
78841
  get composerStyle() {
78788
78842
  const style = {
@@ -84801,6 +84855,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
84801
84855
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
84802
84856
 
84803
84857
 
84804
- __info__.version = "18.4.13";
84805
- __info__.date = "2025-10-07T10:00:55.413Z";
84806
- __info__.hash = "d4df70e";
84858
+ __info__.version = "18.4.14";
84859
+ __info__.date = "2025-10-16T06:39:40.249Z";
84860
+ __info__.hash = "bc55c40";