@odoo/o-spreadsheet 17.2.18 → 17.2.20

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.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.2.18
7
- * @date 2024-07-24T10:28:05.353Z
8
- * @hash 6c65743
6
+ * @version 17.2.20
7
+ * @date 2024-08-09T12:24:12.002Z
8
+ * @hash d667a15
9
9
  */
10
10
 
11
11
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw } from '@odoo/owl';
@@ -485,7 +485,7 @@ function debounce(func, wait, immediate) {
485
485
  let timeout = undefined;
486
486
  const debounced = function () {
487
487
  const context = this;
488
- const args = arguments;
488
+ const args = Array.from(arguments);
489
489
  function later() {
490
490
  timeout = undefined;
491
491
  if (!immediate) {
@@ -713,7 +713,7 @@ function getSearchRegex(searchStr, searchOptions) {
713
713
  */
714
714
  function largeMax(array) {
715
715
  let len = array.length;
716
- if (len < 100000)
716
+ if (len < 100_000)
717
717
  return Math.max(...array);
718
718
  let max = -Infinity;
719
719
  while (len--) {
@@ -727,7 +727,7 @@ function largeMax(array) {
727
727
  */
728
728
  function largeMin(array) {
729
729
  let len = array.length;
730
- if (len < 100000)
730
+ if (len < 100_000)
731
731
  return Math.min(...array);
732
732
  let min = +Infinity;
733
733
  while (len--) {
@@ -2668,13 +2668,16 @@ const wildcardToRegExp = memoize(function wildcardToRegExp(operand) {
2668
2668
  }
2669
2669
  return new RegExp("^" + exp + "$", "i");
2670
2670
  });
2671
- function evaluatePredicate(value = "", criterion) {
2671
+ function evaluatePredicate(value = "", criterion, locale) {
2672
2672
  const { operator, operand } = criterion;
2673
2673
  if (operand === undefined || value === null || operand === null) {
2674
2674
  return false;
2675
2675
  }
2676
2676
  if (typeof operand === "number" && operator === "=") {
2677
- return value.toString() === operand.toString();
2677
+ if (typeof value === "string" && (isNumber(value, locale) || isDateTime(value, locale))) {
2678
+ return toNumber(value, locale) === operand;
2679
+ }
2680
+ return value === operand;
2678
2681
  }
2679
2682
  if (operator === "<>" || operator === "=") {
2680
2683
  let result;
@@ -2756,7 +2759,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2756
2759
  for (let k = 0; k < countArg - 1; k += 2) {
2757
2760
  const criteriaValue = toMatrix(args[k])[i][j].value;
2758
2761
  const criterion = predicates[k / 2];
2759
- validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2762
+ validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion, locale);
2760
2763
  if (!validatedPredicates) {
2761
2764
  break;
2762
2765
  }
@@ -7180,7 +7183,7 @@ function textCell(value, format, formattedValue) {
7180
7183
  }
7181
7184
  function numberCell(value, format, formattedValue) {
7182
7185
  return {
7183
- value: value || 0,
7186
+ value: value || 0, // necessary to avoid "-0" and NaN values,
7184
7187
  format,
7185
7188
  formattedValue,
7186
7189
  type: CellValueType.number,
@@ -19628,8 +19631,8 @@ function truncateLabel(label) {
19628
19631
  function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, truncateLabels = true }) {
19629
19632
  const options = {
19630
19633
  // https://www.chartjs.org/docs/latest/general/responsive.html
19631
- responsive: true,
19632
- maintainAspectRatio: false,
19634
+ responsive: true, // will resize when its container is resized
19635
+ maintainAspectRatio: false, // doesn't maintain the aspect ration (width/height =2 by default) so the user has the choice of the exact layout
19633
19636
  layout: {
19634
19637
  padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
19635
19638
  },
@@ -19675,7 +19678,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
19675
19678
  labels: truncateLabels ? labels.map(truncateLabel) : labels,
19676
19679
  datasets: [],
19677
19680
  },
19678
- platform: undefined,
19681
+ platform: undefined, // This key is optional and will be set by chart.js
19679
19682
  plugins: [],
19680
19683
  };
19681
19684
  }
@@ -19952,7 +19955,7 @@ function getBarConfiguration(chart, labels, localeFormat) {
19952
19955
  },
19953
19956
  y: {
19954
19957
  position: chart.verticalAxisPosition,
19955
- beginAtZero: true,
19958
+ beginAtZero: true, // the origin of the y axis is always zero
19956
19959
  ticks: {
19957
19960
  color: fontColor,
19958
19961
  callback: (value) => {
@@ -20476,7 +20479,7 @@ function getLineOrScatterConfiguration(chart, labels, options) {
20476
20479
  },
20477
20480
  y: {
20478
20481
  position: chart.verticalAxisPosition,
20479
- beginAtZero: true,
20482
+ beginAtZero: true, // the origin of the y axis is always zero
20480
20483
  ticks: {
20481
20484
  color: fontColor,
20482
20485
  callback: (value) => {
@@ -20566,7 +20569,7 @@ function createLineOrScatterChartRuntime(chart, getters) {
20566
20569
  const dataset = {
20567
20570
  label,
20568
20571
  data,
20569
- tension: 0,
20572
+ tension: 0, // 0 -> render straight lines, which is much faster
20570
20573
  borderColor: color,
20571
20574
  backgroundColor,
20572
20575
  pointBackgroundColor: color,
@@ -20788,7 +20791,7 @@ class PieChart extends AbstractChart {
20788
20791
  ...this.getDefinition(),
20789
20792
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
20790
20793
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
20791
- verticalAxisPosition: "left",
20794
+ verticalAxisPosition: "left", //TODO ExcelChartDefinition should be adapted, but can be done later
20792
20795
  dataSets,
20793
20796
  labelRange,
20794
20797
  };
@@ -23355,7 +23358,7 @@ const lightTemplateWithHeader = (colorSet) => ({
23355
23358
  style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
23356
23359
  border: { bottom: { color: colorSet.highlight, style: "thin" } },
23357
23360
  },
23358
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
23361
+ totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
23359
23362
  firstRowStripe: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
23360
23363
  secondRowStripe: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
23361
23364
  });
@@ -23373,7 +23376,7 @@ const lightTemplateAllBorders = (colorSet) => ({
23373
23376
  },
23374
23377
  },
23375
23378
  headerRow: { border: { bottom: { color: colorSet.highlight, style: "medium" } } },
23376
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
23379
+ totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
23377
23380
  firstRowStripe: { style: { fillColor: colorSet.light } },
23378
23381
  firstColumnStripe: { style: { fillColor: colorSet.light } },
23379
23382
  });
@@ -23392,7 +23395,7 @@ const mediumTemplateBandedBorders = (colorSet) => ({
23392
23395
  headerRow: {
23393
23396
  style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
23394
23397
  },
23395
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
23398
+ totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
23396
23399
  firstRowStripe: { style: { fillColor: colorSet.light } },
23397
23400
  firstColumnStripe: { style: { fillColor: colorSet.light } },
23398
23401
  });
@@ -23428,7 +23431,7 @@ const mediumTemplateMinimalBorders = (colorSet) => ({
23428
23431
  bottom: { color: "#000000", style: "medium" },
23429
23432
  },
23430
23433
  },
23431
- totalRow: { border: { top: { color: "#000000", style: "medium" } } },
23434
+ totalRow: { border: { top: { color: "#000000", style: "medium" } } }, // @compatibility: should be double line
23432
23435
  headerRow: {
23433
23436
  style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
23434
23437
  border: { bottom: { color: "#000000", style: "medium" } },
@@ -23452,7 +23455,7 @@ const mediumTemplateAllBorders = (colorSet) => ({
23452
23455
  },
23453
23456
  style: { fillColor: colorSet.light },
23454
23457
  },
23455
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
23458
+ totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
23456
23459
  firstRowStripe: { style: { fillColor: colorSet.medium } },
23457
23460
  firstColumnStripe: { style: { fillColor: colorSet.medium } },
23458
23461
  });
@@ -23483,7 +23486,7 @@ const darkTemplateNoBorders = (colorSet) => ({
23483
23486
  category: "dark",
23484
23487
  colorName: colorSet.name,
23485
23488
  wholeTable: { style: { fillColor: colorSet.light } },
23486
- totalRow: { border: { top: { color: "#000000", style: "medium" } } },
23489
+ totalRow: { border: { top: { color: "#000000", style: "medium" } } }, // @compatibility: should be double line
23487
23490
  headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
23488
23491
  firstRowStripe: { style: { fillColor: colorSet.medium } },
23489
23492
  firstColumnStripe: { style: { fillColor: colorSet.medium } },
@@ -32255,7 +32258,9 @@ class Composer extends Component {
32255
32258
  argToFocus: 0,
32256
32259
  });
32257
32260
  compositionActive = false;
32261
+ spreadsheetRect = useSpreadsheetRect();
32258
32262
  get assistantStyle() {
32263
+ const composerRect = this.composerRef.el.getBoundingClientRect();
32259
32264
  const assistantStyle = {};
32260
32265
  assistantStyle["min-width"] = `${this.props.rect?.width || ASSISTANT_WIDTH}px`;
32261
32266
  const proposals = this.autoCompleteState.provider?.proposals;
@@ -32282,6 +32287,9 @@ class Composer extends Component {
32282
32287
  }
32283
32288
  else if (this.props.delimitation) {
32284
32289
  assistantStyle["max-height"] = `${this.props.delimitation.height}px`;
32290
+ if (composerRect.left + ASSISTANT_WIDTH > this.spreadsheetRect.width) {
32291
+ assistantStyle.right = `0px`;
32292
+ }
32285
32293
  }
32286
32294
  return cssPropertiesToCss(assistantStyle);
32287
32295
  }
@@ -35681,7 +35689,7 @@ class VerticalScrollBar extends Component {
35681
35689
  onScroll(offset) {
35682
35690
  const { scrollX } = this.env.model.getters.getActiveSheetDOMScrollInfo();
35683
35691
  this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
35684
- offsetX: scrollX,
35692
+ offsetX: scrollX, // offsetX is the same
35685
35693
  offsetY: offset,
35686
35694
  });
35687
35695
  }
@@ -35970,8 +35978,8 @@ class Grid extends Component {
35970
35978
  "Ctrl+Shift+L": () => this.setHorizontalAlign("left"),
35971
35979
  "Ctrl+Shift+R": () => this.setHorizontalAlign("right"),
35972
35980
  "Ctrl+Shift+V": () => PASTE_AS_VALUE_ACTION(this.env),
35973
- "Ctrl+Shift+<": () => this.clearFormatting(),
35974
- "Ctrl+<": () => this.clearFormatting(),
35981
+ "Ctrl+Shift+<": () => this.clearFormatting(), // for qwerty
35982
+ "Ctrl+<": () => this.clearFormatting(), // for azerty
35975
35983
  "Ctrl+Shift+ ": () => {
35976
35984
  this.env.model.selection.selectAll();
35977
35985
  },
@@ -36772,10 +36780,10 @@ function convertCFCellIsOperator(xlsxCfOperator) {
36772
36780
  const CF_TYPE_CONVERSION_MAP = {
36773
36781
  aboveAverage: undefined,
36774
36782
  expression: undefined,
36775
- cellIs: undefined,
36776
- colorScale: undefined,
36783
+ cellIs: undefined, // exist but isn't an operator in o_spreadsheet
36784
+ colorScale: undefined, // exist but isn't an operator in o_spreadsheet
36777
36785
  dataBar: undefined,
36778
- iconSet: undefined,
36786
+ iconSet: undefined, // exist but isn't an operator in o_spreadsheet
36779
36787
  top10: undefined,
36780
36788
  uniqueValues: undefined,
36781
36789
  duplicateValues: undefined,
@@ -37010,7 +37018,7 @@ const XLSX_INDEXED_COLORS = {
37010
37018
  61: "993366",
37011
37019
  62: "333399",
37012
37020
  63: "333333",
37013
- 64: "000000",
37021
+ 64: "000000", // system foreground
37014
37022
  65: "FFFFFF", // system background
37015
37023
  };
37016
37024
  const IMAGE_MIMETYPE_TO_EXTENSION_MAPPING = {
@@ -40653,12 +40661,13 @@ class BordersPlugin extends CorePlugin {
40653
40661
  this.clearBorders(cmd.sheetId, cmd.target);
40654
40662
  break;
40655
40663
  case "REMOVE_COLUMNS_ROWS":
40656
- for (let el of [...cmd.elements].sort((a, b) => b - a)) {
40664
+ const elements = [...cmd.elements].sort((a, b) => b - a);
40665
+ for (const group of groupConsecutive(elements)) {
40657
40666
  if (cmd.dimension === "COL") {
40658
- this.shiftBordersHorizontally(cmd.sheetId, el + 1, -1);
40667
+ this.shiftBordersHorizontally(cmd.sheetId, group[group.length - 1] + 1, -group.length);
40659
40668
  }
40660
40669
  else {
40661
- this.shiftBordersVertically(cmd.sheetId, el + 1, -1);
40670
+ this.shiftBordersVertically(cmd.sheetId, group[group.length - 1] + 1, -group.length);
40662
40671
  }
40663
40672
  }
40664
40673
  break;
@@ -44129,7 +44138,7 @@ class RangeAdapter {
44129
44138
  * @param sheetXC the string description of a range, in the form SheetName!XC:XC
44130
44139
  */
44131
44140
  getRangeFromSheetXC(defaultSheetId, sheetXC) {
44132
- if (!rangeReference.test(sheetXC)) {
44141
+ if (!rangeReference.test(sheetXC) || !this.getters.tryGetSheet(defaultSheetId)) {
44133
44142
  return new RangeImpl({
44134
44143
  sheetId: "",
44135
44144
  zone: { left: -1, top: -1, right: -1, bottom: -1 },
@@ -45023,12 +45032,7 @@ class SheetPlugin extends CorePlugin {
45023
45032
  });
45024
45033
  }
45025
45034
  if (colIndex > deletedColumn) {
45026
- this.dispatch("UPDATE_CELL_POSITION", {
45027
- sheetId: sheet.id,
45028
- cellId: cellId,
45029
- col: colIndex - 1,
45030
- row: rowIndex,
45031
- });
45035
+ this.setNewPosition(cellId, sheet.id, colIndex - 1, rowIndex);
45032
45036
  }
45033
45037
  }
45034
45038
  }
@@ -45038,7 +45042,7 @@ class SheetPlugin extends CorePlugin {
45038
45042
  * Move the cells after a column or rows insertion
45039
45043
  */
45040
45044
  moveCellsOnAddition(sheet, addedElement, quantity, dimension) {
45041
- const commands = [];
45045
+ const updates = [];
45042
45046
  for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
45043
45047
  const row = sheet.rows[rowIndex];
45044
45048
  if (dimension !== "rows" || rowIndex >= addedElement) {
@@ -45047,20 +45051,20 @@ class SheetPlugin extends CorePlugin {
45047
45051
  const cellId = row.cells[i];
45048
45052
  if (cellId) {
45049
45053
  if (dimension === "rows" || colIndex >= addedElement) {
45050
- commands.push({
45051
- type: "UPDATE_CELL_POSITION",
45054
+ updates.push({
45052
45055
  sheetId: sheet.id,
45053
45056
  cellId: cellId,
45054
45057
  col: colIndex + (dimension === "columns" ? quantity : 0),
45055
45058
  row: rowIndex + (dimension === "rows" ? quantity : 0),
45059
+ type: "UPDATE_CELL_POSITION",
45056
45060
  });
45057
45061
  }
45058
45062
  }
45059
45063
  }
45060
45064
  }
45061
45065
  }
45062
- for (let cmd of commands.reverse()) {
45063
- this.dispatch(cmd.type, cmd);
45066
+ for (let update of updates.reverse()) {
45067
+ this.updateCellPosition(update);
45064
45068
  }
45065
45069
  }
45066
45070
  /**
@@ -45093,12 +45097,7 @@ class SheetPlugin extends CorePlugin {
45093
45097
  const colIndex = Number(i);
45094
45098
  const cellId = row.cells[i];
45095
45099
  if (cellId) {
45096
- this.dispatch("UPDATE_CELL_POSITION", {
45097
- sheetId: sheet.id,
45098
- cellId: cellId,
45099
- col: colIndex,
45100
- row: rowIndex - numberRows,
45101
- });
45100
+ this.setNewPosition(cellId, sheet.id, colIndex, rowIndex - numberRows);
45102
45101
  }
45103
45102
  }
45104
45103
  }
@@ -47728,18 +47727,23 @@ class Evaluator {
47728
47727
  this.evaluatedCells = new PositionMap();
47729
47728
  this.evaluate(this.getAllCells());
47730
47729
  }
47731
- evaluateFormula(sheetId, formulaString) {
47732
- const compiledFormula = compile(formulaString);
47733
- const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
47734
- this.updateCompilationParameters();
47735
- const result = updateEvalContextAndExecute({ ...compiledFormula, dependencies: ranges }, this.compilationParams, sheetId);
47736
- if (isMatrix(result)) {
47737
- return matrixMap(result, (cell) => cell.value);
47730
+ evaluateFormulaResult(sheetId, formulaString) {
47731
+ try {
47732
+ const compiledFormula = compile(formulaString);
47733
+ const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
47734
+ this.updateCompilationParameters();
47735
+ const result = updateEvalContextAndExecute({ ...compiledFormula, dependencies: ranges }, this.compilationParams, sheetId);
47736
+ if (isMatrix(result)) {
47737
+ return result;
47738
+ }
47739
+ if (result.value === null) {
47740
+ return { value: 0, format: result.format };
47741
+ }
47742
+ return result;
47738
47743
  }
47739
- if (result.value === null) {
47740
- return 0;
47744
+ catch (error) {
47745
+ return handleError(error, "");
47741
47746
  }
47742
- return result.value;
47743
47747
  }
47744
47748
  getAllCells() {
47745
47749
  const positions = this.createEmptyPositionSet();
@@ -48083,6 +48087,7 @@ function updateEvalContextAndExecute(compiledFormula, compilationParams, sheetId
48083
48087
  class EvaluationPlugin extends UIPlugin {
48084
48088
  static getters = [
48085
48089
  "evaluateFormula",
48090
+ "evaluateFormulaResult",
48086
48091
  "getCorrespondingFormulaCell",
48087
48092
  "getRangeFormattedValues",
48088
48093
  "getRangeValues",
@@ -48145,12 +48150,14 @@ class EvaluationPlugin extends UIPlugin {
48145
48150
  // Getters
48146
48151
  // ---------------------------------------------------------------------------
48147
48152
  evaluateFormula(sheetId, formulaString) {
48148
- try {
48149
- return this.evaluator.evaluateFormula(sheetId, formulaString);
48150
- }
48151
- catch (error) {
48152
- return error.value || CellErrorType.GenericError;
48153
+ const result = this.evaluateFormulaResult(sheetId, formulaString);
48154
+ if (isMatrix(result)) {
48155
+ return matrixMap(result, (cell) => cell.value);
48153
48156
  }
48157
+ return result.value;
48158
+ }
48159
+ evaluateFormulaResult(sheetId, formulaString) {
48160
+ return this.evaluator.evaluateFormulaResult(sheetId, formulaString);
48154
48161
  }
48155
48162
  /**
48156
48163
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -48291,17 +48298,17 @@ function isBadExpression(tokens) {
48291
48298
  */
48292
48299
  function sortWithClusters(colorsToSort) {
48293
48300
  const clusters = [
48294
- { leadColor: rgba(255, 0, 0), colors: [] },
48295
- { leadColor: rgba(255, 128, 0), colors: [] },
48296
- { leadColor: rgba(128, 128, 0), colors: [] },
48297
- { leadColor: rgba(128, 255, 0), colors: [] },
48298
- { leadColor: rgba(0, 255, 0), colors: [] },
48299
- { leadColor: rgba(0, 255, 128), colors: [] },
48300
- { leadColor: rgba(0, 255, 255), colors: [] },
48301
- { leadColor: rgba(0, 127, 255), colors: [] },
48302
- { leadColor: rgba(0, 0, 255), colors: [] },
48303
- { leadColor: rgba(127, 0, 255), colors: [] },
48304
- { leadColor: rgba(128, 0, 128), colors: [] },
48301
+ { leadColor: rgba(255, 0, 0), colors: [] }, // red
48302
+ { leadColor: rgba(255, 128, 0), colors: [] }, // orange
48303
+ { leadColor: rgba(128, 128, 0), colors: [] }, // yellow
48304
+ { leadColor: rgba(128, 255, 0), colors: [] }, // chartreuse
48305
+ { leadColor: rgba(0, 255, 0), colors: [] }, // green
48306
+ { leadColor: rgba(0, 255, 128), colors: [] }, // spring green
48307
+ { leadColor: rgba(0, 255, 255), colors: [] }, // cyan
48308
+ { leadColor: rgba(0, 127, 255), colors: [] }, // azure
48309
+ { leadColor: rgba(0, 0, 255), colors: [] }, // blue
48310
+ { leadColor: rgba(127, 0, 255), colors: [] }, // violet
48311
+ { leadColor: rgba(128, 0, 128), colors: [] }, // magenta
48305
48312
  { leadColor: rgba(255, 0, 128), colors: [] }, // rose
48306
48313
  ];
48307
48314
  for (const color of colorsToSort.map(colorToRGBA)) {
@@ -51009,6 +51016,7 @@ class FormatPlugin extends UIPlugin {
51009
51016
  * evaluated and updated with the number type.
51010
51017
  */
51011
51018
  setDecimal(sheetId, zones, step) {
51019
+ const positionsByFormat = {};
51012
51020
  // Find the each cell with a number value and get the format
51013
51021
  for (const zone of zones) {
51014
51022
  for (const position of positions(zone)) {
@@ -51018,15 +51026,20 @@ class FormatPlugin extends UIPlugin {
51018
51026
  // of the format
51019
51027
  this.getters.getLocale();
51020
51028
  const newFormat = changeDecimalPlaces(numberFormat, step);
51021
- // Apply the new format on the whole zone
51022
- this.dispatch("SET_FORMATTING", {
51023
- sheetId,
51024
- target: [positionToZone(position)],
51025
- format: newFormat,
51026
- });
51029
+ positionsByFormat[newFormat] = positionsByFormat[newFormat] || [];
51030
+ positionsByFormat[newFormat].push(position);
51027
51031
  }
51028
51032
  }
51029
51033
  }
51034
+ // consolidate all positions with the same format in bigger zones
51035
+ for (const newFormat in positionsByFormat) {
51036
+ const zones = futureRecomputeZones(positionsByFormat[newFormat].map((position) => positionToZone(position)));
51037
+ this.dispatch("SET_FORMATTING", {
51038
+ sheetId,
51039
+ format: newFormat,
51040
+ target: zones,
51041
+ });
51042
+ }
51030
51043
  }
51031
51044
  /**
51032
51045
  * Take a range of cells and return the format of the first cell containing a
@@ -55422,7 +55435,7 @@ class BottomBar extends Component {
55422
55435
  .map((sheetEl) => sheetEl.getBoundingClientRect())
55423
55436
  .map((rect) => ({
55424
55437
  x: rect.x,
55425
- width: rect.width - 1,
55438
+ width: rect.width - 1, // -1 to compensate negative margin
55426
55439
  y: rect.y,
55427
55440
  height: rect.height,
55428
55441
  }));
@@ -55644,7 +55657,7 @@ class RowGroup extends AbstractHeaderGroup {
55644
55657
  }
55645
55658
  return cssPropertiesToCss({
55646
55659
  top: `${groupBox.headerRect.height / 2}px`,
55647
- left: `calc(50% - 1px)`,
55660
+ left: `calc(50% - 1px)`, // -1px: we want the border to be on the center
55648
55661
  width: `30%`,
55649
55662
  height: `calc(100% - ${groupBox.headerRect.height / 2}px)`,
55650
55663
  "border-left": `1px solid ${HEADER_GROUPING_BORDER_COLOR}`,
@@ -55696,7 +55709,7 @@ class ColGroup extends AbstractHeaderGroup {
55696
55709
  return "";
55697
55710
  }
55698
55711
  return cssPropertiesToCss({
55699
- top: `calc(50% - 1px)`,
55712
+ top: `calc(50% - 1px)`, // -1px: we want the border to be on the center
55700
55713
  left: `${groupBox.headerRect.width / 2}px`,
55701
55714
  width: `calc(100% - ${groupBox.headerRect.width / 2}px)`,
55702
55715
  height: `30%`,
@@ -57114,7 +57127,7 @@ class Spreadsheet extends Component {
57114
57127
  const gridColSize = GROUP_LAYER_WIDTH * this.rowLayers.length;
57115
57128
  const gridRowSize = GROUP_LAYER_WIDTH * this.colLayers.length;
57116
57129
  return cssPropertiesToCss({
57117
- "grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`,
57130
+ "grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`, // +2: margins
57118
57131
  "grid-template-rows": `${gridRowSize ? gridRowSize + 2 : 0}px auto`,
57119
57132
  });
57120
57133
  }
@@ -58564,7 +58577,7 @@ class SelectionStreamProcessorImpl {
58564
58577
  }
58565
58578
 
58566
58579
  class StateObserver {
58567
- changes = [];
58580
+ changes;
58568
58581
  commands = [];
58569
58582
  /**
58570
58583
  * Record the changes which could happen in the given callback, save them in a
@@ -58596,7 +58609,7 @@ class StateObserver {
58596
58609
  if (value[key] === val) {
58597
58610
  return;
58598
58611
  }
58599
- this.changes.push({
58612
+ this.changes?.push({
58600
58613
  path: args,
58601
58614
  before: value[key],
58602
58615
  after: val,
@@ -59727,7 +59740,7 @@ function addTableColumns(table, sheetData) {
59727
59740
  const colHeaderXc = toXC(tableZone.left + i, tableZone.top);
59728
59741
  const colName = sheetData.cells[colHeaderXc]?.content || `col${i}`;
59729
59742
  const colAttributes = [
59730
- ["id", i + 1],
59743
+ ["id", i + 1], // id cannot be 0
59731
59744
  ["name", colName],
59732
59745
  ];
59733
59746
  columns.push(escapeXml /*xml*/ `<tableColumn ${formatAttributes(colAttributes)}/>`);
@@ -60843,6 +60856,6 @@ const constants = {
60843
60856
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
60844
60857
 
60845
60858
 
60846
- __info__.version = "17.2.18";
60847
- __info__.date = "2024-07-24T10:28:05.353Z";
60848
- __info__.hash = "6c65743";
60859
+ __info__.version = "17.2.20";
60860
+ __info__.date = "2024-08-09T12:24:12.002Z";
60861
+ __info__.hash = "d667a15";