@odoo/o-spreadsheet 18.0.19 → 18.0.21

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.0.19
6
- * @date 2025-03-12T15:33:28.300Z
7
- * @hash d8dea1b
5
+ * @version 18.0.21
6
+ * @date 2025-03-26T12:49:46.872Z
7
+ * @hash c687e1c
8
8
  */
9
9
 
10
10
  'use strict';
@@ -1113,7 +1113,10 @@ function rgbaStringToHex(color) {
1113
1113
  }
1114
1114
  else if (stringVals.length === 4) {
1115
1115
  const alpha = parseFloat(stringVals.pop() || "1");
1116
- alphaHex = Math.round((alpha || 1) * 255);
1116
+ if (isNaN(alpha)) {
1117
+ throw new Error("invalid alpha value");
1118
+ }
1119
+ alphaHex = Math.round(alpha * 255);
1117
1120
  }
1118
1121
  const vals = stringVals.map((val) => parseInt(val, 10));
1119
1122
  if (alphaHex !== 255) {
@@ -6109,11 +6112,13 @@ function getDefaultCellHeight(ctx, cell, colSize) {
6109
6112
  if (!cell || (!cell.isFormula && !cell.content)) {
6110
6113
  return DEFAULT_CELL_HEIGHT;
6111
6114
  }
6112
- const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
6113
- const numberOfLines = cell.isFormula
6114
- ? 1
6115
- : splitTextToWidth(ctx, cell.content, cell.style, maxWidth).length;
6116
- const fontSize = computeTextFontSizeInPixels(cell.style);
6115
+ const content = cell.isFormula ? "" : cell.content;
6116
+ return getCellContentHeight(ctx, content, cell.style, colSize);
6117
+ }
6118
+ function getCellContentHeight(ctx, content, style, colSize) {
6119
+ const maxWidth = style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
6120
+ const numberOfLines = splitTextToWidth(ctx, content, style, maxWidth).length;
6121
+ const fontSize = computeTextFontSizeInPixels(style);
6117
6122
  return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
6118
6123
  }
6119
6124
  function getDefaultContextFont(fontSize, bold = false, italic = false) {
@@ -6835,7 +6840,7 @@ function isValidLocale(locale) {
6835
6840
  */
6836
6841
  function canonicalizeNumberContent(content, locale) {
6837
6842
  return content.startsWith("=")
6838
- ? canonicalizeFormula$1(content, locale)
6843
+ ? canonicalizeFormula(content, locale)
6839
6844
  : canonicalizeNumberLiteral(content, locale);
6840
6845
  }
6841
6846
  /**
@@ -6850,7 +6855,7 @@ function canonicalizeNumberContent(content, locale) {
6850
6855
  */
6851
6856
  function canonicalizeContent(content, locale) {
6852
6857
  return content.startsWith("=")
6853
- ? canonicalizeFormula$1(content, locale)
6858
+ ? canonicalizeFormula(content, locale)
6854
6859
  : canonicalizeLiteral(content, locale);
6855
6860
  }
6856
6861
  /**
@@ -6866,15 +6871,21 @@ function localizeContent(content, locale) {
6866
6871
  ? localizeFormula(content, locale)
6867
6872
  : localizeLiteral(content, locale);
6868
6873
  }
6874
+ /** Change a number string to its canonical form (en_US locale) */
6875
+ function canonicalizeNumberValue(content, locale) {
6876
+ return content.startsWith("=")
6877
+ ? canonicalizeFormula(content, locale)
6878
+ : canonicalizeNumberLiteral(content, locale);
6879
+ }
6869
6880
  /** Change a formula to its canonical form (en_US locale) */
6870
- function canonicalizeFormula$1(formula, locale) {
6871
- return _localizeFormula$1(formula, locale, DEFAULT_LOCALE);
6881
+ function canonicalizeFormula(formula, locale) {
6882
+ return _localizeFormula(formula, locale, DEFAULT_LOCALE);
6872
6883
  }
6873
6884
  /** Change a formula from the canonical form to the given locale */
6874
6885
  function localizeFormula(formula, locale) {
6875
- return _localizeFormula$1(formula, DEFAULT_LOCALE, locale);
6886
+ return _localizeFormula(formula, DEFAULT_LOCALE, locale);
6876
6887
  }
6877
- function _localizeFormula$1(formula, fromLocale, toLocale) {
6888
+ function _localizeFormula(formula, fromLocale, toLocale) {
6878
6889
  if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
6879
6890
  fromLocale.decimalSeparator === toLocale.decimalSeparator) {
6880
6891
  return formula;
@@ -7030,37 +7041,6 @@ function getDateTimeFormat(locale) {
7030
7041
  return locale.dateFormat + " " + locale.timeFormat;
7031
7042
  }
7032
7043
 
7033
- /** Change a number string to its canonical form (en_US locale) */
7034
- function canonicalizeNumberValue(content, locale) {
7035
- return content.startsWith("=")
7036
- ? canonicalizeFormula(content, locale)
7037
- : canonicalizeNumberLiteral(content, locale);
7038
- }
7039
- /** Change a formula to its canonical form (en_US locale) */
7040
- function canonicalizeFormula(formula, locale) {
7041
- return _localizeFormula(formula, locale, DEFAULT_LOCALE);
7042
- }
7043
- function _localizeFormula(formula, fromLocale, toLocale) {
7044
- if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
7045
- fromLocale.decimalSeparator === toLocale.decimalSeparator) {
7046
- return formula;
7047
- }
7048
- const tokens = tokenize(formula, fromLocale);
7049
- let localizedFormula = "";
7050
- for (const token of tokens) {
7051
- if (token.type === "NUMBER") {
7052
- localizedFormula += token.value.replace(fromLocale.decimalSeparator, toLocale.decimalSeparator);
7053
- }
7054
- else if (token.type === "ARG_SEPARATOR") {
7055
- localizedFormula += toLocale.formulaArgSeparator;
7056
- }
7057
- else {
7058
- localizedFormula += token.value;
7059
- }
7060
- }
7061
- return localizedFormula;
7062
- }
7063
-
7064
7044
  function boolAnd(args) {
7065
7045
  let foundBoolean = false;
7066
7046
  let acc = true;
@@ -8276,13 +8256,6 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8276
8256
  this.clearClippedZones(content);
8277
8257
  const selection = target[0];
8278
8258
  this.pasteZone(sheetId, selection.left, selection.top, content.cells, options);
8279
- this.dispatch("MOVE_RANGES", {
8280
- target: content.zones,
8281
- sheetId: content.sheetId,
8282
- targetSheetId: sheetId,
8283
- col: selection.left,
8284
- row: selection.top,
8285
- });
8286
8259
  }
8287
8260
  /**
8288
8261
  * Clear the clipped zones: remove the cells and clear the formatting
@@ -8791,14 +8764,15 @@ class MergeClipboardHandler extends AbstractCellClipboardHandler {
8791
8764
  }
8792
8765
  merges.push(mergesInRow);
8793
8766
  }
8794
- return { merges };
8767
+ return { merges, sheetId };
8795
8768
  }
8796
8769
  /**
8797
8770
  * Paste the clipboard content in the given target
8798
8771
  */
8799
8772
  paste(target, content, options) {
8800
8773
  if (options.isCutOperation) {
8801
- return;
8774
+ const copiedMerges = content.merges.flat().filter(isDefined);
8775
+ this.dispatch("REMOVE_MERGE", { sheetId: content.sheetId, target: copiedMerges });
8802
8776
  }
8803
8777
  this.pasteFromCopy(target.sheetId, target.zones, content.merges, options);
8804
8778
  }
@@ -8833,6 +8807,27 @@ class MergeClipboardHandler extends AbstractCellClipboardHandler {
8833
8807
  }
8834
8808
  }
8835
8809
 
8810
+ class ReferenceClipboardHandler extends AbstractCellClipboardHandler {
8811
+ copy(data) {
8812
+ return {
8813
+ zones: data.clippedZones,
8814
+ sheetId: data.sheetId,
8815
+ };
8816
+ }
8817
+ paste(target, content, options) {
8818
+ if (options.isCutOperation) {
8819
+ const selection = target.zones[0];
8820
+ this.dispatch("MOVE_RANGES", {
8821
+ target: content.zones,
8822
+ sheetId: content.sheetId,
8823
+ targetSheetId: target.sheetId,
8824
+ col: selection.left,
8825
+ row: selection.top,
8826
+ });
8827
+ }
8828
+ }
8829
+ }
8830
+
8836
8831
  class SheetClipboardHandler extends AbstractCellClipboardHandler {
8837
8832
  isPasteAllowed(sheetId, target, content, options) {
8838
8833
  if (!("cells" in content)) {
@@ -9000,7 +8995,8 @@ clipboardHandlersRegistries.cellHandlers
9000
8995
  .add("merge", MergeClipboardHandler)
9001
8996
  .add("border", BorderClipboardHandler)
9002
8997
  .add("table", TableClipboardHandler)
9003
- .add("conditionalFormat", ConditionalFormatClipboardHandler);
8998
+ .add("conditionalFormat", ConditionalFormatClipboardHandler)
8999
+ .add("references", ReferenceClipboardHandler);
9004
9000
 
9005
9001
  function transformZone(zone, executed) {
9006
9002
  if (executed.type === "REMOVE_COLUMNS_ROWS") {
@@ -10055,9 +10051,9 @@ const XLSX_CHART_TYPES = [
10055
10051
  /** In XLSX color format (no #) */
10056
10052
  const AUTO_COLOR = "000000";
10057
10053
  const XLSX_ICONSET_MAP = {
10058
- arrow: "3Arrows",
10054
+ arrows: "3Arrows",
10059
10055
  smiley: "3Symbols",
10060
- dot: "3TrafficLights1",
10056
+ dots: "3TrafficLights1",
10061
10057
  };
10062
10058
  const NAMESPACE = {
10063
10059
  styleSheet: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
@@ -10729,6 +10725,7 @@ const ICON_SET_CONVERSION_MAP = {
10729
10725
  };
10730
10726
  /** Map between legend position in XLSX file and human readable position */
10731
10727
  const DRAWING_LEGEND_POSITION_CONVERSION_MAP = {
10728
+ none: "none",
10732
10729
  b: "bottom",
10733
10730
  t: "top",
10734
10731
  l: "left",
@@ -13485,7 +13482,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
13485
13482
  default: "ffffff",
13486
13483
  }).asString(),
13487
13484
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
13488
- default: "b",
13485
+ default: "none",
13489
13486
  }).asString()],
13490
13487
  stacked: barChartGrouping === "stacked",
13491
13488
  fontColor: "000000",
@@ -13519,7 +13516,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
13519
13516
  default: "ffffff",
13520
13517
  }).asString(),
13521
13518
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(chartElement, "c:legendPos", "val", {
13522
- default: "b",
13519
+ default: "none",
13523
13520
  }).asString()],
13524
13521
  stacked: barChartGrouping === "stacked",
13525
13522
  fontColor: "000000",
@@ -16711,7 +16708,8 @@ function getChartLabelValues(getters, dataSets, labelRange) {
16711
16708
  }
16712
16709
  }
16713
16710
  else if (dataSets.length === 1) {
16714
- for (let i = 0; i < getData(getters, dataSets[0]).length; i++) {
16711
+ const dataLength = getData(getters, dataSets[0]).length;
16712
+ for (let i = 0; i < dataLength; i++) {
16715
16713
  labels.formattedValues.push("");
16716
16714
  labels.values.push("");
16717
16715
  }
@@ -25957,11 +25955,26 @@ const SEARCH = {
25957
25955
  const _searchFor = toString(searchFor).toLowerCase();
25958
25956
  const _textToSearch = toString(textToSearch).toLowerCase();
25959
25957
  const _startingAt = toNumber(startingAt, this.locale);
25960
- assert(() => _textToSearch !== "", _t("The text_to_search must be non-empty."));
25961
- assert(() => _startingAt >= 1, _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt.toString()));
25958
+ if (_textToSearch === "") {
25959
+ return {
25960
+ value: CellErrorType.GenericError,
25961
+ message: _t("The text_to_search must be non-empty."),
25962
+ };
25963
+ }
25964
+ if (_startingAt < 1) {
25965
+ return {
25966
+ value: CellErrorType.GenericError,
25967
+ message: _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt),
25968
+ };
25969
+ }
25962
25970
  const result = _textToSearch.indexOf(_searchFor, _startingAt - 1);
25963
- assert(() => result >= 0, _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch));
25964
- return result + 1;
25971
+ if (result === -1) {
25972
+ return {
25973
+ value: CellErrorType.GenericError,
25974
+ message: _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch),
25975
+ };
25976
+ }
25977
+ return { value: result + 1 };
25965
25978
  },
25966
25979
  isExported: true,
25967
25980
  };
@@ -27811,11 +27824,14 @@ function compileTokens(tokens) {
27811
27824
  }
27812
27825
  }
27813
27826
  function compileTokensOrThrow(tokens) {
27814
- const { dependencies, constantValues, symbols } = formulaArguments(tokens);
27815
- const cacheKey = compilationCacheKey(tokens, dependencies, constantValues);
27827
+ const { dependencies, literalValues, symbols } = formulaArguments(tokens);
27828
+ const cacheKey = compilationCacheKey(tokens);
27816
27829
  if (!functionCache[cacheKey]) {
27817
27830
  const ast = parseTokens([...tokens]);
27818
27831
  const scope = new Scope();
27832
+ let stringCount = 0;
27833
+ let numberCount = 0;
27834
+ let dependencyCount = 0;
27819
27835
  if (ast.type === "BIN_OPERATION" && ast.value === ":") {
27820
27836
  throw new BadExpressionError(_t("Invalid formula"));
27821
27837
  }
@@ -27888,16 +27904,15 @@ function compileTokensOrThrow(tokens) {
27888
27904
  case "BOOLEAN":
27889
27905
  return code.return(`{ value: ${ast.value} }`);
27890
27906
  case "NUMBER":
27891
- return code.return(`{ value: this.constantValues.numbers[${constantValues.numbers.indexOf(ast.value)}] }`);
27907
+ return code.return(`this.literalValues.numbers[${numberCount++}]`);
27892
27908
  case "STRING":
27893
- return code.return(`{ value: this.constantValues.strings[${constantValues.strings.indexOf(ast.value)}] }`);
27909
+ return code.return(`this.literalValues.strings[${stringCount++}]`);
27894
27910
  case "REFERENCE":
27895
- const referenceIndex = dependencies.indexOf(ast.value);
27896
27911
  if ((!isMeta && ast.value.includes(":")) || hasRange) {
27897
- return code.return(`range(deps[${referenceIndex}])`);
27912
+ return code.return(`range(deps[${dependencyCount++}])`);
27898
27913
  }
27899
27914
  else {
27900
- return code.return(`ref(deps[${referenceIndex}], ${isMeta ? "true" : "false"})`);
27915
+ return code.return(`ref(deps[${dependencyCount++}], ${isMeta ? "true" : "false"})`);
27901
27916
  }
27902
27917
  case "FUNCALL":
27903
27918
  const args = compileFunctionArgs(ast).map((arg) => arg.assignResultToVariable());
@@ -27929,7 +27944,7 @@ function compileTokensOrThrow(tokens) {
27929
27944
  const compiledFormula = {
27930
27945
  execute: functionCache[cacheKey],
27931
27946
  dependencies,
27932
- constantValues,
27947
+ literalValues,
27933
27948
  symbols,
27934
27949
  tokens,
27935
27950
  isBadExpression: false,
@@ -27941,33 +27956,31 @@ function compileTokensOrThrow(tokens) {
27941
27956
  * References, numbers and strings are replaced with placeholders because
27942
27957
  * the compiled formula does not depend on their actual value.
27943
27958
  * Both `=A1+1+"2"` and `=A2+2+"3"` are compiled to the exact same function.
27944
- *
27945
27959
  * Spaces are also ignored to compute the cache key.
27946
27960
  *
27947
- * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|0|+|1|+SUM(|N0|,|N0|,|S0|)`
27961
+ * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|C|+|C|+SUM(|N|,|N|,|S|)`
27948
27962
  */
27949
- function compilationCacheKey(tokens, dependencies, constantValues, symbols) {
27963
+ function compilationCacheKey(tokens) {
27950
27964
  let cacheKey = "";
27951
27965
  for (const token of tokens) {
27952
27966
  switch (token.type) {
27953
27967
  case "STRING":
27954
- const value = removeStringQuotes(token.value);
27955
- cacheKey += `|S${constantValues.strings.indexOf(value)}|`;
27968
+ cacheKey += "|S|";
27956
27969
  break;
27957
27970
  case "NUMBER":
27958
- cacheKey += `|N${constantValues.numbers.indexOf(parseNumber(token.value, DEFAULT_LOCALE))}|`;
27971
+ cacheKey += "|N|";
27959
27972
  break;
27960
27973
  case "REFERENCE":
27961
27974
  case "INVALID_REFERENCE":
27962
27975
  if (token.value.includes(":")) {
27963
- cacheKey += `R|${dependencies.indexOf(token.value)}|`;
27976
+ cacheKey += "|R|";
27964
27977
  }
27965
27978
  else {
27966
- cacheKey += `C|${dependencies.indexOf(token.value)}|`;
27979
+ cacheKey += "|C|";
27967
27980
  }
27968
27981
  break;
27969
27982
  case "SPACE":
27970
- cacheKey += "";
27983
+ // ignore spaces
27971
27984
  break;
27972
27985
  default:
27973
27986
  cacheKey += token.value;
@@ -27980,7 +27993,7 @@ function compilationCacheKey(tokens, dependencies, constantValues, symbols) {
27980
27993
  * Return formula arguments which are references, strings and numbers.
27981
27994
  */
27982
27995
  function formulaArguments(tokens) {
27983
- const constantValues = {
27996
+ const literalValues = {
27984
27997
  numbers: [],
27985
27998
  strings: [],
27986
27999
  };
@@ -27994,15 +28007,11 @@ function formulaArguments(tokens) {
27994
28007
  break;
27995
28008
  case "STRING":
27996
28009
  const value = removeStringQuotes(token.value);
27997
- if (!constantValues.strings.includes(value)) {
27998
- constantValues.strings.push(value);
27999
- }
28010
+ literalValues.strings.push({ value });
28000
28011
  break;
28001
28012
  case "NUMBER": {
28002
28013
  const value = parseNumber(token.value, DEFAULT_LOCALE);
28003
- if (!constantValues.numbers.includes(value)) {
28004
- constantValues.numbers.push(value);
28005
- }
28014
+ literalValues.numbers.push({ value });
28006
28015
  break;
28007
28016
  }
28008
28017
  case "SYMBOL": {
@@ -28013,7 +28022,7 @@ function formulaArguments(tokens) {
28013
28022
  }
28014
28023
  return {
28015
28024
  dependencies,
28016
- constantValues,
28025
+ literalValues,
28017
28026
  symbols,
28018
28027
  };
28019
28028
  }
@@ -28437,7 +28446,7 @@ autoCompleteProviders.add("pivot_group_values", {
28437
28446
  text,
28438
28447
  description: usedLabel,
28439
28448
  htmlContent: [{ value: text, color }],
28440
- fuzzySearchKey: value + usedLabel,
28449
+ fuzzySearchKey: text + usedLabel,
28441
28450
  };
28442
28451
  });
28443
28452
  },
@@ -38840,8 +38849,8 @@ class AbstractComposerStore extends SpreadsheetStore {
38840
38849
  this.updateRangeColor();
38841
38850
  }
38842
38851
  cancelEdition() {
38843
- this.cancelEditionAndActivateSheet();
38844
38852
  this.resetContent();
38853
+ this.cancelEditionAndActivateSheet();
38845
38854
  }
38846
38855
  setCurrentContent(content, selection) {
38847
38856
  if (selection && !this.isSelectionValid(content.length, selection.start, selection.end)) {
@@ -38857,8 +38866,8 @@ class AbstractComposerStore extends SpreadsheetStore {
38857
38866
  switch (cmd.type) {
38858
38867
  case "SELECT_FIGURE":
38859
38868
  if (cmd.id) {
38860
- this.cancelEditionAndActivateSheet();
38861
38869
  this.resetContent();
38870
+ this.cancelEditionAndActivateSheet();
38862
38871
  }
38863
38872
  break;
38864
38873
  case "START_CHANGE_HIGHLIGHT":
@@ -44753,6 +44762,7 @@ class RemoveDuplicatesPanel extends owl.Component {
44753
44762
  columns: {},
44754
44763
  });
44755
44764
  setup() {
44765
+ this.updateColumns();
44756
44766
  owl.onWillUpdateProps(() => this.updateColumns());
44757
44767
  }
44758
44768
  toggleHasHeader() {
@@ -46541,8 +46551,8 @@ class CellComposerStore extends AbstractComposerStore {
46541
46551
  const sheetIdExists = !!this.getters.tryGetSheet(this.sheetId);
46542
46552
  if (!sheetIdExists && this.editionMode !== "inactive") {
46543
46553
  this.sheetId = this.getters.getActiveSheetId();
46544
- this.cancelEditionAndActivateSheet();
46545
46554
  this.resetContent();
46555
+ this.cancelEditionAndActivateSheet();
46546
46556
  this.notificationStore.raiseError(CELL_DELETED_MESSAGE);
46547
46557
  }
46548
46558
  break;
@@ -62898,12 +62908,7 @@ class SheetUIPlugin extends UIPlugin {
62898
62908
  }
62899
62909
  break;
62900
62910
  case "AUTORESIZE_ROWS":
62901
- this.dispatch("RESIZE_COLUMNS_ROWS", {
62902
- elements: cmd.rows,
62903
- dimension: "ROW",
62904
- size: null,
62905
- sheetId: cmd.sheetId,
62906
- });
62911
+ this.autoResizeRows(cmd.sheetId, cmd.rows);
62907
62912
  break;
62908
62913
  }
62909
62914
  }
@@ -63068,6 +63073,48 @@ class SheetUIPlugin extends UIPlugin {
63068
63073
  }
63069
63074
  return "Success" /* CommandResult.Success */;
63070
63075
  }
63076
+ autoResizeRows(sheetId, rows) {
63077
+ const rowSizes = [];
63078
+ for (const row of rows) {
63079
+ let evaluatedRowSize = 0;
63080
+ for (const cellId of this.getters.getRowCells(sheetId, row)) {
63081
+ const cell = this.getters.getCellById(cellId);
63082
+ if (!cell) {
63083
+ continue;
63084
+ }
63085
+ const position = this.getters.getCellPosition(cell.id);
63086
+ const colSize = this.getters.getColSize(sheetId, position.col);
63087
+ if (cell.isFormula) {
63088
+ const content = this.getters.getEvaluatedCell(position).formattedValue;
63089
+ const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
63090
+ if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
63091
+ evaluatedRowSize = evaluatedSize;
63092
+ }
63093
+ }
63094
+ else {
63095
+ const content = cell.content;
63096
+ const dynamicRowSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
63097
+ // Only keep the size of evaluated cells if it's bigger than the dynamic row size
63098
+ if (dynamicRowSize >= evaluatedRowSize && dynamicRowSize > DEFAULT_CELL_HEIGHT) {
63099
+ evaluatedRowSize = 0;
63100
+ }
63101
+ }
63102
+ }
63103
+ rowSizes.push(evaluatedRowSize || null);
63104
+ }
63105
+ const groupedSizes = new Map(rowSizes.map((size) => [size, []]));
63106
+ for (let i = 0; i < rowSizes.length; i++) {
63107
+ groupedSizes.get(rowSizes[i])?.push(rows[i]);
63108
+ }
63109
+ for (const [size, rows] of groupedSizes) {
63110
+ this.dispatch("RESIZE_COLUMNS_ROWS", {
63111
+ elements: rows,
63112
+ dimension: "ROW",
63113
+ size,
63114
+ sheetId,
63115
+ });
63116
+ }
63117
+ }
63071
63118
  }
63072
63119
 
63073
63120
  class TableComputedStylePlugin extends UIPlugin {
@@ -68243,7 +68290,9 @@ css /* scss */ `
68243
68290
  border: 1px solid;
68244
68291
  font-family: ${DEFAULT_FONT};
68245
68292
 
68246
- .o-composer:empty:not(:focus):not(.active)::before {
68293
+ /* In readonly we always show the fx icon if the composer is empty, not matter the focus */
68294
+ .o-composer:empty:not(:focus):not(.active)::before,
68295
+ &.o-topbar-composer-readonly .o-composer:empty::before {
68247
68296
  content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
68248
68297
  position: relative;
68249
68298
  top: 20%;
@@ -71604,10 +71653,14 @@ function addIconSetRule(cf, rule) {
71604
71653
  continue;
71605
71654
  }
71606
71655
  const cfValueObjectNodes = cfValueObject.map((attrs) => escapeXml /*xml*/ `<cfvo ${formatAttributes(attrs)} />`);
71656
+ const iconSetAttrs = [["iconSet", getIconSet(rule.icons)]];
71657
+ if (isIconSetReversed(rule.icons)) {
71658
+ iconSetAttrs.push(["reverse", "1"]);
71659
+ }
71607
71660
  conditionalFormats.push(escapeXml /*xml*/ `
71608
71661
  <conditionalFormatting sqref="${range}">
71609
71662
  <cfRule ${formatAttributes(ruleAttributes)}>
71610
- <iconSet iconSet="${getIconSet(rule.icons)}">
71663
+ <iconSet ${formatAttributes(iconSetAttrs)}>
71611
71664
  ${joinXmlNodes(cfValueObjectNodes)}
71612
71665
  </iconSet>
71613
71666
  </cfRule>
@@ -71625,9 +71678,21 @@ function commonCfAttributes(cf) {
71625
71678
  ["stopIfTrue", cf.stopIfTrue ? 1 : 0],
71626
71679
  ];
71627
71680
  }
71681
+ function isIconSetReversed(iconSet) {
71682
+ const defaultIconSet = ICON_SETS[detectIconsType(iconSet)];
71683
+ return iconSet.upper === defaultIconSet.bad && iconSet.lower === defaultIconSet.good;
71684
+ }
71628
71685
  function getIconSet(iconSet) {
71629
- return XLSX_ICONSET_MAP[Object.keys(XLSX_ICONSET_MAP).find((key) => iconSet.upper.toLowerCase().startsWith(key)) ||
71630
- "dots"];
71686
+ return XLSX_ICONSET_MAP[detectIconsType(iconSet)];
71687
+ }
71688
+ /**
71689
+ * Partial detection based on "upper" point only.
71690
+ * We support any arbitrary icon in the set, while excel doesn't allow
71691
+ * mixing icons from different types.
71692
+ */
71693
+ function detectIconsType(iconSet) {
71694
+ const type = Object.keys(ICON_SETS).find((type) => Object.values(ICON_SETS[type]).includes(iconSet.upper)) || "dots";
71695
+ return type;
71631
71696
  }
71632
71697
  function thresholdAttributes(threshold, position) {
71633
71698
  const type = getExcelThresholdType(threshold.type, position);
@@ -73551,6 +73616,6 @@ exports.tokenColors = tokenColors;
73551
73616
  exports.tokenize = tokenize;
73552
73617
 
73553
73618
 
73554
- __info__.version = "18.0.19";
73555
- __info__.date = "2025-03-12T15:33:28.300Z";
73556
- __info__.hash = "d8dea1b";
73619
+ __info__.version = "18.0.21";
73620
+ __info__.date = "2025-03-26T12:49:46.872Z";
73621
+ __info__.hash = "c687e1c";
@@ -5276,6 +5276,7 @@ declare class SheetUIPlugin extends UIPlugin {
5276
5276
  * not outside the sheet.
5277
5277
  */
5278
5278
  private checkZonesAreInSheet;
5279
+ private autoResizeRows;
5279
5280
  }
5280
5281
 
5281
5282
  declare class HeaderPositionsUIPlugin extends UIPlugin {