@odoo/o-spreadsheet 17.0.15 → 17.0.17

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 17.0.15
6
- * @date 2024-03-15T11:00:59.958Z
7
- * @hash e02add9
5
+ * @version 17.0.17
6
+ * @date 2024-04-05T13:59:37.139Z
7
+ * @hash 33f09d7
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -557,7 +557,7 @@ function getItemId(item, itemsDic) {
557
557
  }
558
558
  // Generate new Id if the item didn't exist in the dictionary
559
559
  const ids = Object.keys(itemsDic);
560
- const maxId = ids.length === 0 ? 0 : Math.max(...ids.map((id) => parseInt(id, 10)));
560
+ const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
561
561
  itemsDic[maxId + 1] = item;
562
562
  return maxId + 1;
563
563
  }
@@ -774,6 +774,34 @@ function isNumberBetween(value, min, max) {
774
774
  }
775
775
  return value >= min && value <= max;
776
776
  }
777
+ /**
778
+ * Alternative to Math.max that works with large arrays.
779
+ * Typically useful for arrays bigger than 100k elements.
780
+ */
781
+ function largeMax(array) {
782
+ let len = array.length;
783
+ if (len < 100000)
784
+ return Math.max(...array);
785
+ let max = -Infinity;
786
+ while (len--) {
787
+ max = array[len] > max ? array[len] : max;
788
+ }
789
+ return max;
790
+ }
791
+ /**
792
+ * Alternative to Math.min that works with large arrays.
793
+ * Typically useful for arrays bigger than 100k elements.
794
+ */
795
+ function largeMin(array) {
796
+ let len = array.length;
797
+ if (len < 100000)
798
+ return Math.min(...array);
799
+ let min = +Infinity;
800
+ while (len--) {
801
+ min = array[len] < min ? array[len] : min;
802
+ }
803
+ return min;
804
+ }
777
805
 
778
806
  const RBA_REGEX = /rgba?\(|\s+|\)/gi;
779
807
  const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
@@ -4420,8 +4448,9 @@ function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
4420
4448
  * Get the default height of the cell given its style.
4421
4449
  */
4422
4450
  function getDefaultCellHeight(ctx, cell, colSize) {
4423
- if (!cell || !cell.content)
4451
+ if (!cell || (!cell.isFormula && !cell.content)) {
4424
4452
  return DEFAULT_CELL_HEIGHT;
4453
+ }
4425
4454
  const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
4426
4455
  const numberOfLines = cell.isFormula
4427
4456
  ? 1
@@ -8324,10 +8353,10 @@ function aggregateDataForLabels(labels, datasets) {
8324
8353
  }
8325
8354
  }
8326
8355
  return {
8327
- labels: Object.keys(labelMap),
8356
+ labels: Array.from(labelSet),
8328
8357
  dataSetsValues: datasets.map((dataset, indexOfDataset) => ({
8329
8358
  ...dataset,
8330
- data: Object.values(labelMap).map((dataOfLabel) => dataOfLabel[indexOfDataset]),
8359
+ data: Array.from(labelSet).map((label) => labelMap[label][indexOfDataset]),
8331
8360
  })),
8332
8361
  };
8333
8362
  }
@@ -8378,7 +8407,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale })
8378
8407
  const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
8379
8408
  // tooltipItem.parsed.y can be an object or a number for pie charts
8380
8409
  const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
8381
- const toolTipFormat = !format && yLabel > 1000 ? "#,##" : format;
8410
+ const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
8382
8411
  const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
8383
8412
  return xLabel ? `${xLabel}: ${yLabelStr}` : yLabelStr;
8384
8413
  },
@@ -8664,7 +8693,10 @@ function getBarConfiguration(chart, labels, localeFormat) {
8664
8693
  if (isNaN(value))
8665
8694
  return value;
8666
8695
  const { locale, format } = localeFormat;
8667
- return formatValue(value, { locale, format: !format && value > 1000 ? "#,##" : format });
8696
+ return formatValue(value, {
8697
+ locale,
8698
+ format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
8699
+ });
8668
8700
  },
8669
8701
  },
8670
8702
  },
@@ -9078,7 +9110,7 @@ function getBestTimeUnitForScale(labels, format, locale) {
9078
9110
  return undefined;
9079
9111
  }
9080
9112
  const labelsTimestamps = labelDates.map((date) => date.getTime());
9081
- const period = Math.max(...labelsTimestamps) - Math.min(...labelsTimestamps);
9113
+ const period = largeMax(labelsTimestamps) - largeMin(labelsTimestamps);
9082
9114
  const minUnit = getFormatMinDisplayUnit(format);
9083
9115
  if (UNIT_LENGTH.second >= UNIT_LENGTH[minUnit] && Milliseconds.inSeconds(period) < 180) {
9084
9116
  return "second";
@@ -9315,7 +9347,10 @@ function getLineConfiguration(chart, labels, localeFormat) {
9315
9347
  if (isNaN(value))
9316
9348
  return value;
9317
9349
  const { locale, format } = localeFormat;
9318
- return formatValue(value, { locale, format: !format && value > 1000 ? "#,##" : format });
9350
+ return formatValue(value, {
9351
+ locale,
9352
+ format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
9353
+ });
9319
9354
  },
9320
9355
  },
9321
9356
  },
@@ -9542,7 +9577,7 @@ function getPieConfiguration(chart, labels, localeFormat) {
9542
9577
  const percentage = calculatePercentage(data, dataIndex);
9543
9578
  const xLabel = tooltipItem.label || tooltipItem.dataset.label;
9544
9579
  const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
9545
- const toolTipFormat = !format && yLabel > 1000 ? "#,##" : format;
9580
+ const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
9546
9581
  const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
9547
9582
  return xLabel ? `${xLabel}: ${yLabelStr} (${percentage}%)` : `${yLabelStr} (${percentage}%)`;
9548
9583
  };
@@ -9550,7 +9585,7 @@ function getPieConfiguration(chart, labels, localeFormat) {
9550
9585
  }
9551
9586
  function getPieColors(colors, dataSetsValues) {
9552
9587
  const pieColors = [];
9553
- const maxLength = Math.max(...dataSetsValues.map((ds) => ds.data.length));
9588
+ const maxLength = largeMax(dataSetsValues.map((ds) => ds.data.length));
9554
9589
  for (let i = 0; i <= maxLength; i++) {
9555
9590
  pieColors.push(colors.next());
9556
9591
  }
@@ -10452,8 +10487,8 @@ const DELETE_CONTENT_ROWS_NAME = (env) => {
10452
10487
  let last;
10453
10488
  const activesRows = env.model.getters.getActiveRows();
10454
10489
  if (activesRows.size !== 0) {
10455
- first = Math.min(...activesRows);
10456
- last = Math.max(...activesRows);
10490
+ first = largeMin([...activesRows]);
10491
+ last = largeMax([...activesRows]);
10457
10492
  }
10458
10493
  else {
10459
10494
  const zone = env.model.getters.getSelectedZones()[0];
@@ -10481,8 +10516,8 @@ const DELETE_CONTENT_COLUMNS_NAME = (env) => {
10481
10516
  let last;
10482
10517
  const activeCols = env.model.getters.getActiveCols();
10483
10518
  if (activeCols.size !== 0) {
10484
- first = Math.min(...activeCols);
10485
- last = Math.max(...activeCols);
10519
+ first = largeMin([...activeCols]);
10520
+ last = largeMax([...activeCols]);
10486
10521
  }
10487
10522
  else {
10488
10523
  const zone = env.model.getters.getSelectedZones()[0];
@@ -10510,8 +10545,8 @@ const REMOVE_ROWS_NAME = (env) => {
10510
10545
  let last;
10511
10546
  const activesRows = env.model.getters.getActiveRows();
10512
10547
  if (activesRows.size !== 0) {
10513
- first = Math.min(...activesRows);
10514
- last = Math.max(...activesRows);
10548
+ first = largeMin([...activesRows]);
10549
+ last = largeMax([...activesRows]);
10515
10550
  }
10516
10551
  else {
10517
10552
  const zone = env.model.getters.getSelectedZones()[0];
@@ -10552,8 +10587,8 @@ const REMOVE_COLUMNS_NAME = (env) => {
10552
10587
  let last;
10553
10588
  const activeCols = env.model.getters.getActiveCols();
10554
10589
  if (activeCols.size !== 0) {
10555
- first = Math.min(...activeCols);
10556
- last = Math.max(...activeCols);
10590
+ first = largeMin([...activeCols]);
10591
+ last = largeMax([...activeCols]);
10557
10592
  }
10558
10593
  else {
10559
10594
  const zone = env.model.getters.getSelectedZones()[0];
@@ -10594,7 +10629,7 @@ const INSERT_ROWS_BEFORE_ACTION = (env) => {
10594
10629
  let row;
10595
10630
  let quantity;
10596
10631
  if (activeRows.size) {
10597
- row = Math.min(...activeRows);
10632
+ row = largeMin([...activeRows]);
10598
10633
  quantity = activeRows.size;
10599
10634
  }
10600
10635
  else {
@@ -10615,7 +10650,7 @@ const INSERT_ROWS_AFTER_ACTION = (env) => {
10615
10650
  let row;
10616
10651
  let quantity;
10617
10652
  if (activeRows.size) {
10618
- row = Math.max(...activeRows);
10653
+ row = largeMax([...activeRows]);
10619
10654
  quantity = activeRows.size;
10620
10655
  }
10621
10656
  else {
@@ -10636,7 +10671,7 @@ const INSERT_COLUMNS_BEFORE_ACTION = (env) => {
10636
10671
  let column;
10637
10672
  let quantity;
10638
10673
  if (activeCols.size) {
10639
- column = Math.min(...activeCols);
10674
+ column = largeMin([...activeCols]);
10640
10675
  quantity = activeCols.size;
10641
10676
  }
10642
10677
  else {
@@ -10657,7 +10692,7 @@ const INSERT_COLUMNS_AFTER_ACTION = (env) => {
10657
10692
  let column;
10658
10693
  let quantity;
10659
10694
  if (activeCols.size) {
10660
- column = Math.max(...activeCols);
10695
+ column = largeMax([...activeCols]);
10661
10696
  quantity = activeCols.size;
10662
10697
  }
10663
10698
  else {
@@ -11055,6 +11090,9 @@ function makeArg(str, description) {
11055
11090
  result.default = true;
11056
11091
  result.defaultValue = defaultValue;
11057
11092
  }
11093
+ if (types.some((t) => t.startsWith("RANGE"))) {
11094
+ result.acceptMatrix = true;
11095
+ }
11058
11096
  return result;
11059
11097
  }
11060
11098
  /**
@@ -19420,11 +19458,27 @@ class FunctionRegistry extends Registry {
19420
19458
  }
19421
19459
  const descr = addMetaInfoFromArg(addDescr);
19422
19460
  validateArguments(descr.args);
19423
- this.mapping[name] = createComputeFunctionFromDescription(descr);
19461
+ this.mapping[name] = addInputHandling(descr, createComputeFunctionFromDescription(descr));
19424
19462
  super.add(name, descr);
19425
19463
  return this;
19426
19464
  }
19427
19465
  }
19466
+ function addInputHandling(descr, computeFunction) {
19467
+ function computeWithInputHandling(...args) {
19468
+ for (let i = 0; i < args.length; i++) {
19469
+ const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
19470
+ const arg = args[i];
19471
+ if (isMatrix(arg) && !argDefinition.acceptMatrix) {
19472
+ if (arg.length !== 1 || arg[0].length !== 1) {
19473
+ throw new EvaluationError(CellErrorType.GenericError, _t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be a single value or a single cell reference, not a range.", argDefinition.name));
19474
+ }
19475
+ args[i] = arg[0][0];
19476
+ }
19477
+ }
19478
+ return computeFunction.apply(this, args);
19479
+ }
19480
+ return computeWithInputHandling;
19481
+ }
19428
19482
  function createComputeFunctionFromDescription(descr) {
19429
19483
  const computeValueAndFormat = "computeValueAndFormat" in descr;
19430
19484
  const computeValue = "compute" in descr;
@@ -19675,14 +19729,19 @@ const categorieFunctionAll = {
19675
19729
  children: [allFunctionListMenuBuilder],
19676
19730
  };
19677
19731
  function allFunctionListMenuBuilder() {
19678
- const fnNames = functionRegistry.getKeys();
19732
+ const fnNames = functionRegistry.getKeys().filter((key) => !functionRegistry.get(key).hidden);
19679
19733
  return createFormulaFunctions(fnNames);
19680
19734
  }
19681
19735
  const categoriesFunctionListMenuBuilder = () => {
19682
19736
  const functions = functionRegistry.content;
19683
- const categories = [...new Set(functionRegistry.getAll().map((fn) => fn.category))].filter(isDefined$1);
19737
+ const categories = [
19738
+ ...new Set(functionRegistry
19739
+ .getAll()
19740
+ .filter((fn) => !fn.hidden)
19741
+ .map((fn) => fn.category)),
19742
+ ].filter(isDefined$1);
19684
19743
  return categories.sort().map((category, i) => {
19685
- const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category);
19744
+ const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category && !functions[key].hidden);
19686
19745
  return {
19687
19746
  name: category,
19688
19747
  children: createFormulaFunctions(functionsInCategory),
@@ -23335,11 +23394,9 @@ css /* scss */ `
23335
23394
  }
23336
23395
  .o-cell-is-operator {
23337
23396
  margin-bottom: 5px;
23338
- width: 96%;
23339
23397
  }
23340
23398
  .o-cell-is-value {
23341
23399
  margin-bottom: 5px;
23342
- width: 96%;
23343
23400
  }
23344
23401
  .o-color-picker-widget .o-color-picker-button {
23345
23402
  pointer-events: all;
@@ -25705,6 +25762,9 @@ class FigureComponent extends Component {
25705
25762
  el?.focus({ preventScroll: true });
25706
25763
  }
25707
25764
  }, () => [this.env.model.getters.getSelectedFigureId(), this.props.figure.id, this.figureRef.el]);
25765
+ onWillUnmount(() => {
25766
+ this.props.onFigureDeleted();
25767
+ });
25708
25768
  }
25709
25769
  clickAnchor(dirX, dirY, ev) {
25710
25770
  this.props.onClickAnchor(dirX, dirY, ev);
@@ -25723,6 +25783,7 @@ class FigureComponent extends Component {
25723
25783
  this.props.onFigureDeleted();
25724
25784
  ev.stopPropagation();
25725
25785
  ev.preventDefault();
25786
+ ev.stopPropagation();
25726
25787
  break;
25727
25788
  case "ArrowDown":
25728
25789
  case "ArrowLeft":
@@ -25743,6 +25804,7 @@ class FigureComponent extends Component {
25743
25804
  });
25744
25805
  ev.stopPropagation();
25745
25806
  ev.preventDefault();
25807
+ ev.stopPropagation();
25746
25808
  break;
25747
25809
  }
25748
25810
  }
@@ -26424,6 +26486,7 @@ function compareContentToSpanElement(content, node) {
26424
26486
  // -----------------------------------------------------------------------------
26425
26487
  css /* scss */ `
26426
26488
  .o-formula-assistant {
26489
+ background: #ffffff;
26427
26490
  .o-formula-assistant-head {
26428
26491
  background-color: #f2f2f2;
26429
26492
  padding: 10px;
@@ -26474,6 +26537,9 @@ class FunctionDescriptionProvider extends Component {
26474
26537
  this.assistantState.allowCellSelectionBehind = false;
26475
26538
  }, 2000);
26476
26539
  }
26540
+ get formulaArgSeparator() {
26541
+ return this.env.model.getters.getLocale().formulaArgSeparator + " ";
26542
+ }
26477
26543
  }
26478
26544
  FunctionDescriptionProvider.props = {
26479
26545
  functionName: String,
@@ -26625,6 +26691,12 @@ class Composer extends Component {
26625
26691
  useEffect(() => {
26626
26692
  this.processContent();
26627
26693
  });
26694
+ onPatched(() => {
26695
+ // Required because typing '=SUM' and double-clicking another cell leaves ShowProvider/ShowDescription true
26696
+ if (this.env.model.getters.getEditionMode() === "inactive") {
26697
+ this.processTokenAtCursor();
26698
+ }
26699
+ });
26628
26700
  }
26629
26701
  // ---------------------------------------------------------------------------
26630
26702
  // Handlers
@@ -31817,7 +31889,7 @@ function convertHyperlink(link, cellValue, warningManager) {
31817
31889
  function getSheetDims(sheet) {
31818
31890
  const dims = [0, 0];
31819
31891
  for (let row of sheet.rows) {
31820
- dims[0] = Math.max(dims[0], ...row.cells.map((cell) => toCartesian(cell.xc).col));
31892
+ dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
31821
31893
  dims[1] = Math.max(dims[1], row.index);
31822
31894
  }
31823
31895
  dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
@@ -36707,6 +36779,9 @@ class DataValidationPlugin extends CorePlugin {
36707
36779
  if (newRule.criterion.type === "isBoolean") {
36708
36780
  this.setCenterStyleToBooleanCells(newRule);
36709
36781
  }
36782
+ else if (newRule.criterion.type === "isValueInList") {
36783
+ newRule.criterion.values = Array.from(new Set(newRule.criterion.values));
36784
+ }
36710
36785
  const adaptedRules = this.removeRangesFromRules(sheetId, newRule.ranges, rules);
36711
36786
  const ruleIndex = adaptedRules.findIndex((rule) => rule.id === newRule.id);
36712
36787
  if (ruleIndex !== -1) {
@@ -37433,7 +37508,7 @@ class HeaderVisibilityPlugin extends CorePlugin {
37433
37508
  if (hiddenElements.size >= elements) {
37434
37509
  return "TooManyHiddenElements" /* CommandResult.TooManyHiddenElements */;
37435
37510
  }
37436
- else if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
37511
+ else if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
37437
37512
  return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
37438
37513
  }
37439
37514
  else {
@@ -38248,8 +38323,8 @@ class RangeAdapter {
38248
38323
  let newRange = range;
38249
38324
  let changeType = "NONE";
38250
38325
  for (let group of groups) {
38251
- const min = Math.min(...group);
38252
- const max = Math.max(...group);
38326
+ const min = largeMin(group);
38327
+ const max = largeMax(group);
38253
38328
  if (range.zone[start] <= min && min <= range.zone[end]) {
38254
38329
  const toRemove = Math.min(range.zone[end], max) - min + 1;
38255
38330
  changeType = "RESIZE";
@@ -38672,8 +38747,8 @@ class SheetPlugin extends CorePlugin {
38672
38747
  }
38673
38748
  return "Success" /* CommandResult.Success */;
38674
38749
  case "REMOVE_COLUMNS_ROWS": {
38675
- const min = Math.min(...cmd.elements);
38676
- const max = Math.max(...cmd.elements);
38750
+ const min = largeMin(cmd.elements);
38751
+ const max = largeMax(cmd.elements);
38677
38752
  if (min < 0 || !this.doesHeaderExist(cmd.sheetId, cmd.dimension, max)) {
38678
38753
  return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
38679
38754
  }
@@ -41585,7 +41660,7 @@ class EvaluationPlugin extends UIPlugin {
41585
41660
  ? getItemId(newFormat, data.formats)
41586
41661
  : exportedCellData.format;
41587
41662
  let content;
41588
- if (formulaCell instanceof FormulaCellWithDependencies) {
41663
+ if (isFormula && formulaCell instanceof FormulaCellWithDependencies) {
41589
41664
  content = this.getters.getFormulaCellContent(exportedSheetData.id, formulaCell.compiledFormula, formulaCell.compiledFormula.dependencies, true);
41590
41665
  }
41591
41666
  else {
@@ -42005,13 +42080,13 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
42005
42080
  .map((cell) => cell.value);
42006
42081
  switch (threshold.type) {
42007
42082
  case "value":
42008
- const result = functionName === "max" ? Math.max(...rangeValues) : Math.min(...rangeValues);
42083
+ const result = functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
42009
42084
  return result;
42010
42085
  case "number":
42011
42086
  return Number(threshold.value);
42012
42087
  case "percentage":
42013
- const min = Math.min(...rangeValues);
42014
- const max = Math.max(...rangeValues);
42088
+ const min = largeMin(rangeValues);
42089
+ const max = largeMax(rangeValues);
42015
42090
  const delta = max - min;
42016
42091
  return min + (delta * Number(threshold.value)) / 100;
42017
42092
  case "percentile":
@@ -43063,13 +43138,13 @@ class AutomaticSumPlugin extends UIPlugin {
43063
43138
  const cells = this.getters.getEvaluatedCellsInZone(sheet.id, zone);
43064
43139
  const cellPositions = range(end, -1, -1);
43065
43140
  const invalidCells = cellPositions.filter((position) => cells[position] && !cells[position].isAutoSummable);
43066
- const maxValidPosition = Math.max(...invalidCells);
43141
+ const maxValidPosition = largeMax(invalidCells);
43067
43142
  const numberSequences = groupConsecutive(cellPositions.filter((position) => this.isNumber(cells[position])));
43068
43143
  const firstSequence = numberSequences[0] || [];
43069
- if (Math.max(...firstSequence) < maxValidPosition) {
43144
+ if (largeMax(firstSequence) < maxValidPosition) {
43070
43145
  return Infinity;
43071
43146
  }
43072
- return Math.min(...firstSequence);
43147
+ return largeMin(firstSequence);
43073
43148
  }
43074
43149
  shouldFindData(sheetId, zone) {
43075
43150
  return this.getters.isEmpty(sheetId, zone) || this.getters.isSingleCellOrMerge(sheetId, zone);
@@ -45473,7 +45548,7 @@ class RendererPlugin extends UIPlugin {
45473
45548
  * column of the current viewport
45474
45549
  */
45475
45550
  getColDimensionsInViewport(sheetId, col) {
45476
- const left = Math.min(...this.getters.getSheetViewVisibleCols());
45551
+ const left = largeMin(this.getters.getSheetViewVisibleCols());
45477
45552
  const start = this.getters.getColRowOffsetInViewport("COL", left, col);
45478
45553
  const size = this.getters.getColSize(sheetId, col);
45479
45554
  const isColHidden = this.getters.isColHidden(sheetId, col);
@@ -45488,7 +45563,7 @@ class RendererPlugin extends UIPlugin {
45488
45563
  * of the current viewport
45489
45564
  */
45490
45565
  getRowDimensionsInViewport(sheetId, row) {
45491
- const top = Math.min(...this.getters.getSheetViewVisibleRows());
45566
+ const top = largeMin(this.getters.getSheetViewVisibleRows());
45492
45567
  const start = this.getters.getColRowOffsetInViewport("ROW", top, row);
45493
45568
  const size = this.getters.getRowSize(sheetId, row);
45494
45569
  const isRowHidden = this.getters.isRowHidden(sheetId, row);
@@ -46952,7 +47027,7 @@ class SheetUIPlugin extends UIPlugin {
46952
47027
  getColMaxWidth(sheetId, index) {
46953
47028
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
46954
47029
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
46955
- return Math.max(0, ...sizes);
47030
+ return Math.max(0, largeMax(sizes));
46956
47031
  }
46957
47032
  /**
46958
47033
  * Check that any "sheetId" in the command matches an existing
@@ -47717,7 +47792,7 @@ class ClipboardOsState extends ClipboardCellsAbstractState {
47717
47792
  }
47718
47793
  getPasteZone(target) {
47719
47794
  const height = this.values.length;
47720
- const width = Math.max(...this.values.map((a) => a.length));
47795
+ const width = largeMax(this.values.map((a) => a.length));
47721
47796
  const { left: activeCol, top: activeRow } = target[0];
47722
47797
  return {
47723
47798
  top: activeRow,
@@ -48754,11 +48829,11 @@ class EditionPlugin extends UIPlugin {
48754
48829
  }
48755
48830
  else {
48756
48831
  const range = this.getters.getRangeFromSheetXC(this.sheetId, rule.criterion.values[0]);
48757
- values = this.getters
48832
+ values = Array.from(new Set(this.getters
48758
48833
  .getRangeValues(range)
48759
48834
  .filter(isNotNull)
48760
48835
  .map((value) => value.toString())
48761
- .filter((val) => val !== "");
48836
+ .filter((val) => val !== "")));
48762
48837
  }
48763
48838
  const composerContent = this.getCurrentContent();
48764
48839
  if (composerContent && composerContent !== this.getInitialComposerContent()) {
@@ -49295,6 +49370,7 @@ class GridSelectionPlugin extends UIPlugin {
49295
49370
  this.gridSelection.zones = this.gridSelection.zones.map((z) => this.getters.expandZone(sheetId, z));
49296
49371
  this.gridSelection.anchor.zone = this.getters.expandZone(sheetId, this.gridSelection.anchor.zone);
49297
49372
  this.setSelectionMixin(this.gridSelection.anchor, this.gridSelection.zones);
49373
+ this.selectedFigureId = null;
49298
49374
  break;
49299
49375
  }
49300
49376
  /** Any change to the selection has to be reflected in the selection processor. */
@@ -51214,12 +51290,14 @@ class BottomBarSheet extends Component {
51214
51290
  this.editionState = "initializing";
51215
51291
  }
51216
51292
  stopEdition() {
51217
- if (!this.state.isEditing)
51293
+ const input = this.sheetNameRef.el;
51294
+ if (!this.state.isEditing || !input)
51218
51295
  return;
51219
51296
  this.state.isEditing = false;
51220
51297
  this.editionState = "initializing";
51221
- this.sheetNameRef.el?.blur();
51298
+ input.blur();
51222
51299
  const inputValue = this.getInputContent() || "";
51300
+ input.innerText = inputValue;
51223
51301
  interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
51224
51302
  }
51225
51303
  cancelEdition() {
@@ -51513,7 +51591,7 @@ class BottomBar extends Component {
51513
51591
  this.sheetListRef.el.scrollTo({ top: 0, left: scroll, behavior: "smooth" });
51514
51592
  }
51515
51593
  onSheetMouseDown(sheetId, event) {
51516
- if (event.button !== 0)
51594
+ if (event.button !== 0 || this.env.model.getters.isReadonly())
51517
51595
  return;
51518
51596
  this.closeMenu();
51519
51597
  const visibleSheets = this.getVisibleSheets();
@@ -52872,9 +52950,6 @@ css /* scss */ `
52872
52950
  .text-muted {
52873
52951
  color: grey !important;
52874
52952
  }
52875
- button {
52876
- color: #333;
52877
- }
52878
52953
  .o-disabled {
52879
52954
  opacity: 0.4;
52880
52955
  pointer: default;
@@ -52995,17 +53070,17 @@ css /* scss */ `
52995
53070
  }
52996
53071
 
52997
53072
  .o-button {
52998
- border: 1px solid lightgrey;
53073
+ border: 1px solid;
52999
53074
  padding: 0px 20px 0px 20px;
53000
53075
  border-radius: 4px;
53001
53076
  font-weight: 500;
53002
53077
  font-size: 14px;
53003
53078
  height: 30px;
53004
53079
  line-height: 16px;
53005
- background: white;
53006
53080
  margin-right: 8px;
53007
- &:hover:enabled {
53008
- background-color: rgba(0, 0, 0, 0.08);
53081
+
53082
+ &:not(:hover) {
53083
+ background-color: transparent;
53009
53084
  }
53010
53085
 
53011
53086
  &:enabled {
@@ -53019,6 +53094,15 @@ css /* scss */ `
53019
53094
  &:last-child {
53020
53095
  margin-right: 0px;
53021
53096
  }
53097
+
53098
+ &.o-button-grey {
53099
+ border-color: lightgrey;
53100
+ background: #ffffff;
53101
+ color: #333;
53102
+ &:hover:enabled {
53103
+ background-color: rgba(0, 0, 0, 0.08);
53104
+ }
53105
+ }
53022
53106
  }
53023
53107
 
53024
53108
  .o-input {
@@ -55012,7 +55096,7 @@ function addLineChart(chart) {
55012
55096
  }
55013
55097
  function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
55014
55098
  const colors = new ChartColors();
55015
- const maxLength = Math.max(...chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
55099
+ const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
55016
55100
  const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
55017
55101
  const dataSetsNodes = [];
55018
55102
  for (const [dsIndex, dataset] of Object.entries(chart.dataSets).reverse()) {
@@ -56931,6 +57015,6 @@ const constants = {
56931
57015
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
56932
57016
 
56933
57017
 
56934
- __info__.version = "17.0.15";
56935
- __info__.date = "2024-03-15T11:00:59.958Z";
56936
- __info__.hash = "e02add9";
57018
+ __info__.version = "17.0.17";
57019
+ __info__.date = "2024-04-05T13:59:37.139Z";
57020
+ __info__.hash = "33f09d7";