@odoo/o-spreadsheet 17.1.4 → 17.1.7

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.1.4
6
- * @date 2024-02-09T13:09:13.430Z
7
- * @hash 16d3ece
5
+ * @version 17.1.7
6
+ * @date 2024-03-12T07:56:10.783Z
7
+ * @hash 3a9f334
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';
@@ -451,8 +451,8 @@ function isObjectEmptyRecursive(argument) {
451
451
  * If the given item does not exist in the dictionary, it creates one with a new id.
452
452
  */
453
453
  function getItemId(item, itemsDic) {
454
- for (let [key, value] of Object.entries(itemsDic)) {
455
- if (deepEquals(value, item)) {
454
+ for (const key in itemsDic) {
455
+ if (deepEquals(itemsDic[key], item)) {
456
456
  return parseInt(key, 10);
457
457
  }
458
458
  }
@@ -551,11 +551,13 @@ function deepEquals(o1, o2) {
551
551
  if (typeof o1 !== "object")
552
552
  return o1 === o2;
553
553
  // Objects can have different keys if the values are undefined
554
- const keys = new Set();
555
- Object.keys(o1).forEach((key) => keys.add(key));
556
- Object.keys(o2).forEach((key) => keys.add(key));
557
- for (let key of keys) {
558
- if (typeof o1[key] !== typeof o1[key])
554
+ for (const key in o2) {
555
+ if (!(key in o1) && o2[key] !== undefined) {
556
+ return false;
557
+ }
558
+ }
559
+ for (const key in o1) {
560
+ if (typeof o1[key] !== typeof o2[key])
559
561
  return false;
560
562
  if (typeof o1[key] === "object") {
561
563
  if (!deepEquals(o1[key], o2[key]))
@@ -625,18 +627,18 @@ function isConsecutive(iterable) {
625
627
  return true;
626
628
  }
627
629
  class JetSet extends Set {
628
- add(...iterable) {
630
+ addMany(iterable) {
629
631
  for (const element of iterable) {
630
632
  super.add(element);
631
633
  }
632
634
  return this;
633
635
  }
634
- delete(...iterable) {
635
- let deleted = false;
636
+ deleteMany(iterable) {
637
+ let wasDeleted = false;
636
638
  for (const element of iterable) {
637
- deleted ||= super.delete(element);
639
+ wasDeleted ||= super.delete(element);
638
640
  }
639
- return deleted;
641
+ return wasDeleted;
640
642
  }
641
643
  }
642
644
  /**
@@ -1934,7 +1936,7 @@ class DispatchResult {
1934
1936
  * Static helper which returns a successful DispatchResult
1935
1937
  */
1936
1938
  static get Success() {
1937
- return new DispatchResult();
1939
+ return SUCCESS;
1938
1940
  }
1939
1941
  get isSuccessful() {
1940
1942
  return this.reasons.length === 0;
@@ -1947,6 +1949,7 @@ class DispatchResult {
1947
1949
  return this.reasons.includes(reason);
1948
1950
  }
1949
1951
  }
1952
+ const SUCCESS = new DispatchResult();
1950
1953
  var CommandResult;
1951
1954
  (function (CommandResult) {
1952
1955
  CommandResult["Success"] = "Success";
@@ -6095,8 +6098,10 @@ function getGroup(cell, cells, filter) {
6095
6098
  if (x === cell) {
6096
6099
  found = true;
6097
6100
  }
6098
- const cellValue = evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
6099
- if (filter(cellValue)) {
6101
+ const cellValue = x?.isFormula
6102
+ ? undefined
6103
+ : evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
6104
+ if (cellValue && filter(cellValue)) {
6100
6105
  group.push(cellValue);
6101
6106
  }
6102
6107
  else {
@@ -6320,11 +6325,14 @@ function cellTextStyleToCss(style) {
6320
6325
  * Transform CSS properties into a CSS string.
6321
6326
  */
6322
6327
  function cssPropertiesToCss(attributes) {
6323
- const str = Object.entries(attributes)
6324
- .filter(([attName, attValue]) => attValue !== undefined)
6325
- .map(([attName, attValue]) => `${attName}:${attValue};`)
6326
- .join(" ");
6327
- return str;
6328
+ let styleStr = "";
6329
+ for (const attName in attributes) {
6330
+ if (!attributes[attName]) {
6331
+ continue;
6332
+ }
6333
+ styleStr += `${attName}:${attributes[attName]}; `;
6334
+ }
6335
+ return styleStr;
6328
6336
  }
6329
6337
  function getElementMargins(el) {
6330
6338
  const style = window.getComputedStyle(el);
@@ -7653,6 +7661,9 @@ function isValidLocale(locale) {
7653
7661
  if (locale.formulaArgSeparator === locale.decimalSeparator) {
7654
7662
  return false;
7655
7663
  }
7664
+ if (locale.thousandsSeparator === locale.decimalSeparator) {
7665
+ return false;
7666
+ }
7656
7667
  try {
7657
7668
  formatValue(1, { locale, format: "#,##0.00" });
7658
7669
  formatValue(1, { locale, format: locale.dateFormat });
@@ -7743,7 +7754,7 @@ function canonicalizeNumberLiteral(content, locale) {
7743
7754
  if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
7744
7755
  return content;
7745
7756
  }
7746
- return content.replace(locale.decimalSeparator, ".");
7757
+ return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
7747
7758
  }
7748
7759
  /**
7749
7760
  * Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
@@ -10838,6 +10849,12 @@ const INSERT_LINK = (env) => {
10838
10849
  let { col, row } = env.model.getters.getActivePosition();
10839
10850
  env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
10840
10851
  };
10852
+ const INSERT_LINK_NAME = (env) => {
10853
+ const sheetId = env.model.getters.getActiveSheetId();
10854
+ const { col, row } = env.model.getters.getActivePosition();
10855
+ const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
10856
+ return cell && cell.link ? _t("Edit link") : _t("Insert link");
10857
+ };
10841
10858
  //------------------------------------------------------------------------------
10842
10859
  // Filters action
10843
10860
  //------------------------------------------------------------------------------
@@ -13039,6 +13056,18 @@ const TRUNC = {
13039
13056
  },
13040
13057
  isExported: true,
13041
13058
  };
13059
+ // -----------------------------------------------------------------------------
13060
+ // INT
13061
+ // -----------------------------------------------------------------------------
13062
+ const INT = {
13063
+ description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
13064
+ args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
13065
+ returns: ["NUMBER"],
13066
+ compute: function (value) {
13067
+ return Math.floor(toNumber(value, this.locale));
13068
+ },
13069
+ isExported: true,
13070
+ };
13042
13071
 
13043
13072
  var math = /*#__PURE__*/Object.freeze({
13044
13073
  __proto__: null,
@@ -13072,6 +13101,7 @@ var math = /*#__PURE__*/Object.freeze({
13072
13101
  FLOOR: FLOOR,
13073
13102
  FLOOR_MATH: FLOOR_MATH,
13074
13103
  FLOOR_PRECISE: FLOOR_PRECISE,
13104
+ INT: INT,
13075
13105
  ISEVEN: ISEVEN,
13076
13106
  ISODD: ISODD,
13077
13107
  ISO_CEILING: ISO_CEILING,
@@ -18598,10 +18628,11 @@ const DEFAULT_IS_SORTED = true;
18598
18628
  const DEFAULT_MATCH_MODE = 0;
18599
18629
  const DEFAULT_SEARCH_MODE = 1;
18600
18630
  const DEFAULT_ABSOLUTE_RELATIVE_MODE = 1;
18601
- function assertAvailable(variable, searchKey) {
18602
- if (variable === undefined) {
18603
- throw new NotAvailableError(_t("Did not find value '%s' in [[FUNCTION_NAME]] evaluation.", toString(searchKey)));
18604
- }
18631
+ function valueNotAvailable(searchKey) {
18632
+ return {
18633
+ value: CellErrorType.NotAvailable,
18634
+ message: _t("Did not find value '%s' in [[FUNCTION_NAME]] evaluation.", toString(searchKey)),
18635
+ };
18605
18636
  }
18606
18637
  // -----------------------------------------------------------------------------
18607
18638
  // ADDRESS
@@ -18698,7 +18729,9 @@ const HLOOKUP = {
18698
18729
  ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
18699
18730
  : linearSearch(range, searchKey, "strict", range.length, getValueFromRange);
18700
18731
  const col = range[colIndex];
18701
- assertAvailable(col, searchKey?.value);
18732
+ if (col === undefined) {
18733
+ return valueNotAvailable(searchKey);
18734
+ }
18702
18735
  return col[_index - 1];
18703
18736
  },
18704
18737
  isExported: true,
@@ -18755,11 +18788,11 @@ const LOOKUP = {
18755
18788
  : (range, index) => range[index][0].value;
18756
18789
  const rangeLength = verticalSearch ? nbRow : nbCol;
18757
18790
  const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18758
- if (index === -1)
18759
- assertAvailable(undefined, searchKey?.value);
18760
- verticalSearch
18761
- ? assertAvailable(searchArray[0][index], searchKey?.value)
18762
- : assertAvailable(searchArray[index][nbRow - 1], searchKey?.value);
18791
+ if (index === -1 ||
18792
+ (verticalSearch && searchArray[0][index] === undefined) ||
18793
+ (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
18794
+ return valueNotAvailable(searchKey);
18795
+ }
18763
18796
  if (resultRange === undefined) {
18764
18797
  return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
18765
18798
  }
@@ -18809,7 +18842,10 @@ const MATCH = {
18809
18842
  index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18810
18843
  break;
18811
18844
  }
18812
- assertAvailable(nbCol === 1 ? range[0][index] : range[index], searchKey);
18845
+ if ((nbCol === 1 && range[0][index] === undefined) ||
18846
+ (nbCol !== 1 && range[index] === undefined)) {
18847
+ return valueNotAvailable(searchKey);
18848
+ }
18813
18849
  return index + 1;
18814
18850
  },
18815
18851
  isExported: true,
@@ -18868,7 +18904,9 @@ const VLOOKUP = {
18868
18904
  ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
18869
18905
  : linearSearch(range, searchKey, "strict", range[0].length, getValueFromRange);
18870
18906
  const value = range[_index - 1][rowIndex];
18871
- assertAvailable(value, searchKey);
18907
+ if (value === undefined) {
18908
+ return valueNotAvailable(searchKey);
18909
+ }
18872
18910
  return value;
18873
18911
  },
18874
18912
  isExported: true,
@@ -18918,7 +18956,9 @@ const XLOOKUP = {
18918
18956
  ? returnRange.map((col) => [col[index]])
18919
18957
  : [returnRange[index]];
18920
18958
  }
18921
- assertAvailable(defaultValue, searchKey);
18959
+ if (defaultValue === undefined) {
18960
+ return valueNotAvailable(searchKey);
18961
+ }
18922
18962
  return [[defaultValue]];
18923
18963
  },
18924
18964
  isExported: true,
@@ -19690,8 +19730,7 @@ class FunctionRegistry extends Registry {
19690
19730
  function addErrorHandling(compute, functionName) {
19691
19731
  return function (...args) {
19692
19732
  try {
19693
- const computeFormula = compute.bind(this);
19694
- return computeFormula(...args);
19733
+ return compute.apply(this, args);
19695
19734
  }
19696
19735
  catch (e) {
19697
19736
  return handleError(e, functionName);
@@ -19725,8 +19764,7 @@ function hasStringMessage(obj) {
19725
19764
  }
19726
19765
  function addResultHandling(compute) {
19727
19766
  return function (...args) {
19728
- const computeResult = compute.bind(this);
19729
- const result = computeResult(...args);
19767
+ const result = compute.apply(this, args);
19730
19768
  if (!isMatrix(result)) {
19731
19769
  if (typeof result === "object" && result !== null && "value" in result) {
19732
19770
  return result;
@@ -20082,7 +20120,7 @@ cellMenuRegistry
20082
20120
  })
20083
20121
  .add("insert_link", {
20084
20122
  ...insertLink,
20085
- name: _t("Insert link"),
20123
+ name: INSERT_LINK_NAME,
20086
20124
  sequence: 150,
20087
20125
  separator: true,
20088
20126
  });
@@ -21693,7 +21731,7 @@ class SelectionInput extends Component {
21693
21731
  ? existingSelectionRanges
21694
21732
  : this.props.ranges().map((xc, id) => ({
21695
21733
  xc,
21696
- id,
21734
+ id: id + 1,
21697
21735
  isFocused: false,
21698
21736
  }));
21699
21737
  return ranges.map((range) => ({
@@ -26525,6 +26563,17 @@ class TextValueProvider extends Component {
26525
26563
  onValueSelected: Function,
26526
26564
  onValueHovered: Function,
26527
26565
  };
26566
+ autoCompleteListRef = useRef("autoCompleteList");
26567
+ setup() {
26568
+ useEffect(() => {
26569
+ const selectedIndex = this.props.selectedIndex;
26570
+ if (selectedIndex === undefined) {
26571
+ return;
26572
+ }
26573
+ const selectedElement = this.autoCompleteListRef.el?.children[selectedIndex];
26574
+ selectedElement?.scrollIntoView?.({ block: "nearest" });
26575
+ }, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
26576
+ }
26528
26577
  }
26529
26578
 
26530
26579
  class ContentEditableHelper {
@@ -26969,6 +27018,7 @@ css /* scss */ `
26969
27018
  position: absolute;
26970
27019
  margin: 1px 4px;
26971
27020
  pointer-events: none;
27021
+ overflow: auto;
26972
27022
 
26973
27023
  .o-semi-bold {
26974
27024
  /** FIXME: to remove in favor of Bootstrap
@@ -27026,7 +27076,10 @@ class Composer extends Component {
27026
27076
  if (this.props.delimitation && this.props.rect) {
27027
27077
  const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
27028
27078
  const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
27079
+ assistantStyle["max-height"] = `${remainingHeight}px`;
27029
27080
  if (cellY > remainingHeight) {
27081
+ const availableSpaceAbove = cellY;
27082
+ assistantStyle["max-height"] = `${availableSpaceAbove}px`;
27030
27083
  // render top
27031
27084
  // We compensate 2 px of margin on the assistant style + 1px for design reasons
27032
27085
  assistantStyle.top = `-3px`;
@@ -27718,7 +27771,11 @@ class GridComposer extends Component {
27718
27771
  }
27719
27772
  }
27720
27773
  updateCellReferenceVisibility() {
27721
- if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
27774
+ if (this.env.model.getters.getEditionMode() === "inactive") {
27775
+ this.isCellReferenceVisible = false;
27776
+ return;
27777
+ }
27778
+ if (this.isCellReferenceVisible) {
27722
27779
  return;
27723
27780
  }
27724
27781
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -27747,19 +27804,21 @@ class GridCellIcon extends Component {
27747
27804
  slots: Object,
27748
27805
  };
27749
27806
  get iconStyle() {
27750
- const x = this.getIconHorizontalPosition();
27751
- const y = this.getIconVerticalPosition();
27807
+ const cellPosition = this.props.cellPosition;
27808
+ const merge = this.env.model.getters.getMerge(cellPosition);
27809
+ const zone = merge || positionToZone(cellPosition);
27810
+ const rect = this.env.model.getters.getVisibleRectWithoutHeaders(zone);
27811
+ const x = this.getIconHorizontalPosition(rect, cellPosition);
27812
+ const y = this.getIconVerticalPosition(rect, cellPosition);
27752
27813
  return cssPropertiesToCss({
27753
27814
  top: `${y + (this.props.offset?.y || 0)}px`,
27754
27815
  left: `${x + (this.props.offset?.x || 0)}px`,
27755
27816
  });
27756
27817
  }
27757
- getIconVerticalPosition() {
27758
- const { sheetId, row } = this.props.cellPosition;
27759
- const merge = this.env.model.getters.getMerge(this.props.cellPosition);
27760
- const start = this.env.model.getters.getRowDimensionsInViewport(sheetId, row).start;
27761
- const end = this.env.model.getters.getRowDimensionsInViewport(sheetId, merge ? merge.bottom : row).end;
27762
- const cell = this.env.model.getters.getCell(this.props.cellPosition);
27818
+ getIconVerticalPosition(rect, cellPosition) {
27819
+ const start = rect.y;
27820
+ const end = rect.y + rect.height;
27821
+ const cell = this.env.model.getters.getCell(cellPosition);
27763
27822
  const align = this.props.verticalAlign || cell?.style?.verticalAlign || DEFAULT_VERTICAL_ALIGN;
27764
27823
  switch (align) {
27765
27824
  case "bottom":
@@ -27771,13 +27830,11 @@ class GridCellIcon extends Component {
27771
27830
  return end - GRID_ICON_EDGE_LENGTH - centeringOffset;
27772
27831
  }
27773
27832
  }
27774
- getIconHorizontalPosition() {
27775
- const { sheetId, col } = this.props.cellPosition;
27776
- const merge = this.env.model.getters.getMerge(this.props.cellPosition);
27777
- const start = this.env.model.getters.getColDimensionsInViewport(sheetId, col).start;
27778
- const end = this.env.model.getters.getColDimensionsInViewport(sheetId, merge ? merge.right : col).end;
27779
- const cell = this.env.model.getters.getCell(this.props.cellPosition);
27780
- const evaluatedCell = this.env.model.getters.getEvaluatedCell(this.props.cellPosition);
27833
+ getIconHorizontalPosition(rect, cellPosition) {
27834
+ const start = rect.x;
27835
+ const end = rect.x + rect.width;
27836
+ const cell = this.env.model.getters.getCell(cellPosition);
27837
+ const evaluatedCell = this.env.model.getters.getEvaluatedCell(cellPosition);
27781
27838
  const align = this.props.horizontalAlign || cell?.style?.align || evaluatedCell.defaultAlign;
27782
27839
  switch (align) {
27783
27840
  case "right":
@@ -27861,6 +27918,8 @@ css /* scss */ `
27861
27918
  height: ${CHECKBOX_WIDTH}px;
27862
27919
  accent-color: #808080;
27863
27920
  margin: ${MARGIN}px;
27921
+ /** required to prevent the checkbox position to be sensible to the font-size (affects Firefox) */
27922
+ position: absolute;
27864
27923
  }
27865
27924
  `;
27866
27925
  class DataValidationCheckbox extends Component {
@@ -27879,7 +27938,7 @@ class DataValidationCheckbox extends Component {
27879
27938
  }
27880
27939
  get isDisabled() {
27881
27940
  const cell = this.env.model.getters.getCell(this.props.cellPosition);
27882
- return !!cell?.isFormula;
27941
+ return this.env.model.getters.isReadonly() || !!cell?.isFormula;
27883
27942
  }
27884
27943
  }
27885
27944
 
@@ -27919,12 +27978,17 @@ class DataValidationOverlay extends Component {
27919
27978
  static props = {};
27920
27979
  static components = { GridCellIcon, DataValidationCheckbox, DataValidationListIcon };
27921
27980
  get checkBoxCellPositions() {
27922
- return this.env.model.getters.getDataValidationCheckBoxCellPositions();
27981
+ return this.env.model.getters
27982
+ .getVisibleCellPositions()
27983
+ .filter(this.env.model.getters.isCellValidCheckbox);
27923
27984
  }
27924
27985
  get listIconsCellPositions() {
27925
- return this.env.model.getters.isReadonly()
27926
- ? []
27927
- : this.env.model.getters.getDataValidationListCellsPositions();
27986
+ if (this.env.model.getters.isReadonly()) {
27987
+ return [];
27988
+ }
27989
+ return this.env.model.getters
27990
+ .getVisibleCellPositions()
27991
+ .filter(this.env.model.getters.cellHasListDataValidationIcon);
27928
27992
  }
27929
27993
  }
27930
27994
 
@@ -34286,29 +34350,12 @@ const MIGRATIONS = [
34286
34350
  from: 12,
34287
34351
  to: 12.5,
34288
34352
  applyMigration(data) {
34289
- for (let sheet of data.sheets || []) {
34290
- let knownDataFilterZones = [];
34291
- for (let filterTable of sheet.filterTables || []) {
34292
- const zone = toZone(filterTable.range);
34293
- // See commit message for the details
34294
- const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
34295
- if (intersectZoneIndex !== -1) {
34296
- knownDataFilterZones[intersectZoneIndex] = zone;
34297
- }
34298
- else {
34299
- knownDataFilterZones.push(zone);
34300
- }
34301
- }
34302
- sheet.filterTables = knownDataFilterZones.map((zone) => ({
34303
- range: zoneToXc(zone),
34304
- }));
34305
- }
34306
- return data;
34353
+ return fixOverlappingFilters(data);
34307
34354
  },
34308
34355
  },
34309
34356
  {
34310
34357
  description: "Change Border description structure",
34311
- from: 12,
34358
+ from: 12.5,
34312
34359
  to: 13,
34313
34360
  applyMigration(data) {
34314
34361
  for (const borderId in data.borders) {
@@ -34339,6 +34386,14 @@ const MIGRATIONS = [
34339
34386
  return data;
34340
34387
  },
34341
34388
  },
34389
+ {
34390
+ description: "Fix datafilter duplication (post saas-16.4)",
34391
+ from: 14,
34392
+ to: 14.5,
34393
+ applyMigration(data) {
34394
+ return fixOverlappingFilters(data);
34395
+ },
34396
+ },
34342
34397
  ];
34343
34398
  /**
34344
34399
  * This function is used to repair faulty data independently of the migration.
@@ -34496,6 +34551,26 @@ function fixChartDefinitions(data, initialMessages) {
34496
34551
  }
34497
34552
  return messages;
34498
34553
  }
34554
+ function fixOverlappingFilters(data) {
34555
+ for (let sheet of data.sheets || []) {
34556
+ let knownDataFilterZones = [];
34557
+ for (let filterTable of sheet.filterTables || []) {
34558
+ const zone = toZone(filterTable.range);
34559
+ // See commit message of https://github.com/odoo/o-spreadsheet/pull/3632 of more details
34560
+ const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
34561
+ if (intersectZoneIndex !== -1) {
34562
+ knownDataFilterZones[intersectZoneIndex] = zone;
34563
+ }
34564
+ else {
34565
+ knownDataFilterZones.push(zone);
34566
+ }
34567
+ }
34568
+ sheet.filterTables = knownDataFilterZones.map((zone) => ({
34569
+ range: zoneToXc(zone),
34570
+ }));
34571
+ }
34572
+ return data;
34573
+ }
34499
34574
  // -----------------------------------------------------------------------------
34500
34575
  // Helpers
34501
34576
  // -----------------------------------------------------------------------------
@@ -35145,22 +35220,7 @@ class BordersPlugin extends CorePlugin {
35145
35220
  }
35146
35221
  }
35147
35222
  export(data) {
35148
- // Borders
35149
- let borderId = 0;
35150
35223
  const borders = {};
35151
- /**
35152
- * Get the id of the given border. If the border does not exist, it creates
35153
- * one.
35154
- */
35155
- function getBorderId(border) {
35156
- for (let [key, value] of Object.entries(borders)) {
35157
- if (deepEquals(value, border)) {
35158
- return parseInt(key, 10);
35159
- }
35160
- }
35161
- borders[++borderId] = border;
35162
- return borderId;
35163
- }
35164
35224
  for (let sheet of data.sheets) {
35165
35225
  for (let col = 0; col < sheet.colNumber; col++) {
35166
35226
  for (let row = 0; row < sheet.rowNumber; row++) {
@@ -35168,7 +35228,7 @@ class BordersPlugin extends CorePlugin {
35168
35228
  if (border) {
35169
35229
  const xc = toXC(col, row);
35170
35230
  const cell = sheet.cells[xc];
35171
- const borderId = getBorderId(border);
35231
+ const borderId = getItemId(border, borders);
35172
35232
  if (cell) {
35173
35233
  cell.border = borderId;
35174
35234
  }
@@ -35957,9 +36017,9 @@ class CellPlugin extends CorePlugin {
35957
36017
  allowDispatch(cmd) {
35958
36018
  switch (cmd.type) {
35959
36019
  case "UPDATE_CELL":
35960
- return this.checkCellOutOfSheet(cmd);
36020
+ return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
35961
36021
  case "CLEAR_CELL":
35962
- return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
36022
+ return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
35963
36023
  default:
35964
36024
  return "Success" /* CommandResult.Success */;
35965
36025
  }
@@ -36109,8 +36169,8 @@ class CellPlugin extends CorePlugin {
36109
36169
  }
36110
36170
  removeDefaultStyleValues(style) {
36111
36171
  const cleanedStyle = { ...style };
36112
- for (const [property, defaultValue] of Object.entries(DEFAULT_STYLE)) {
36113
- if (cleanedStyle[property] === defaultValue) {
36172
+ for (const property in DEFAULT_STYLE) {
36173
+ if (cleanedStyle[property] === DEFAULT_STYLE[property]) {
36114
36174
  delete cleanedStyle[property];
36115
36175
  }
36116
36176
  }
@@ -36266,10 +36326,7 @@ class CellPlugin extends CorePlugin {
36266
36326
  else {
36267
36327
  style = before ? before.style : undefined;
36268
36328
  }
36269
- const locale = this.getters.getLocale();
36270
- let format = ("format" in after ? after.format : before && before.format) ||
36271
- detectDateFormat(afterContent, locale) ||
36272
- detectNumberFormat(afterContent);
36329
+ const format = "format" in after ? after.format : before && before.format;
36273
36330
  /* Read the following IF as:
36274
36331
  * we need to remove the cell if it is completely empty, but we can know if it completely empty if:
36275
36332
  * - the command says the new content is empty and has no border/format/style
@@ -36310,6 +36367,7 @@ class CellPlugin extends CorePlugin {
36310
36367
  }
36311
36368
  createLiteralCell(id, content, format, style) {
36312
36369
  const locale = this.getters.getLocale();
36370
+ format = format || detectDateFormat(content, locale) || detectNumberFormat(content);
36313
36371
  if (format !== PLAIN_TEXT_FORMAT && !isEvaluationError(content)) {
36314
36372
  content = toString(parseLiteral(content, locale));
36315
36373
  }
@@ -36382,6 +36440,18 @@ class CellPlugin extends CorePlugin {
36382
36440
  }
36383
36441
  return "Success" /* CommandResult.Success */;
36384
36442
  }
36443
+ checkUselessUpdateCell(cmd) {
36444
+ const cell = this.getters.getCell(cmd);
36445
+ const hasContent = "content" in cmd || "formula" in cmd;
36446
+ const hasStyle = "style" in cmd;
36447
+ const hasFormat = "format" in cmd;
36448
+ if ((!hasContent || cell?.content === cmd.content) &&
36449
+ (!hasStyle || deepEquals(cell?.style, cmd.style)) &&
36450
+ (!hasFormat || cell?.format === cmd.format)) {
36451
+ return "NoChanges" /* CommandResult.NoChanges */;
36452
+ }
36453
+ return "Success" /* CommandResult.Success */;
36454
+ }
36385
36455
  }
36386
36456
  class FormulaCellWithDependencies {
36387
36457
  id;
@@ -39022,7 +39092,6 @@ class SheetPlugin extends CorePlugin {
39022
39092
  "getNumberHeaders",
39023
39093
  "getGridLinesVisibility",
39024
39094
  "getNextSheetName",
39025
- "isEmpty",
39026
39095
  "getSheetSize",
39027
39096
  "getSheetZone",
39028
39097
  "getPaneDivisions",
@@ -39397,14 +39466,6 @@ class SheetPlugin extends CorePlugin {
39397
39466
  // ---------------------------------------------------------------------------
39398
39467
  // Row/Col manipulation
39399
39468
  // ---------------------------------------------------------------------------
39400
- /**
39401
- * Check if a zone only contains empty cells
39402
- */
39403
- isEmpty(sheetId, zone) {
39404
- return positions(zone)
39405
- .map(({ col, row }) => this.getCell({ sheetId, col, row }))
39406
- .every((cell) => !cell || cell.content === "");
39407
- }
39408
39469
  getCommandZones(cmd) {
39409
39470
  const zones = [];
39410
39471
  if ("zone" in cmd) {
@@ -41166,7 +41227,15 @@ class SpreadsheetRTree {
41166
41227
  if (!this.rTrees[sheetId]) {
41167
41228
  return;
41168
41229
  }
41169
- this.rTrees[sheetId].remove(item, deepEquals);
41230
+ this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
41231
+ }
41232
+ rtreeItemComparer(left, right) {
41233
+ return (left.data == right.data &&
41234
+ left.boundingBox.sheetId === right.boundingBox.sheetId &&
41235
+ left.boundingBox?.zone.left === right.boundingBox.zone.left &&
41236
+ left.boundingBox?.zone.top === right.boundingBox.zone.top &&
41237
+ left.boundingBox?.zone.right === right.boundingBox.zone.right &&
41238
+ left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
41170
41239
  }
41171
41240
  }
41172
41241
  /**
@@ -41244,7 +41313,7 @@ class FormulaDependencyGraph {
41244
41313
  const queue = Array.from(ranges).reverse();
41245
41314
  while (queue.length > 0) {
41246
41315
  const range = queue.pop();
41247
- visited.add(...this.encoder.encodeBoundingBox(range));
41316
+ visited.addMany(this.encoder.encodeBoundingBox(range));
41248
41317
  const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
41249
41318
  for (const positionId of impactedPositionIds) {
41250
41319
  if (!visited.has(positionId)) {
@@ -41252,7 +41321,7 @@ class FormulaDependencyGraph {
41252
41321
  }
41253
41322
  }
41254
41323
  }
41255
- visited.delete(...ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
41324
+ visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
41256
41325
  return visited;
41257
41326
  }
41258
41327
  }
@@ -41392,9 +41461,9 @@ class Evaluator {
41392
41461
  const cells = positions.map((p) => this.encoder.encode(p));
41393
41462
  const cellsToCompute = new JetSet(cells);
41394
41463
  const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
41395
- cellsToCompute.add(...this.getCellsDependingOn(cells));
41396
- cellsToCompute.add(...arrayFormulasPositionIds);
41397
- cellsToCompute.add(...this.getCellsDependingOn(arrayFormulasPositionIds));
41464
+ cellsToCompute.addMany(this.getCellsDependingOn(cells));
41465
+ cellsToCompute.addMany(arrayFormulasPositionIds);
41466
+ cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
41398
41467
  this.evaluate(cellsToCompute);
41399
41468
  }
41400
41469
  getArrayFormulasImpactedByChangesOf(positionIds) {
@@ -41408,7 +41477,7 @@ class Evaluator {
41408
41477
  }
41409
41478
  if (!content) {
41410
41479
  // The previous content could have blocked some array formulas
41411
- impactedPositionIds.add(...this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
41480
+ impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
41412
41481
  }
41413
41482
  }
41414
41483
  return impactedPositionIds;
@@ -41460,7 +41529,7 @@ class Evaluator {
41460
41529
  }
41461
41530
  const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
41462
41531
  const cells = new JetSet(arrayFormulas);
41463
- cells.add(...this.getCellsDependingOn(arrayFormulas));
41532
+ cells.addMany(this.getCellsDependingOn(arrayFormulas));
41464
41533
  return cells;
41465
41534
  }
41466
41535
  nextPositionsToUpdate = new JetSet();
@@ -41511,7 +41580,7 @@ class Evaluator {
41511
41580
  : evaluateLiteral(cell.content, localeFormat);
41512
41581
  }
41513
41582
  catch (e) {
41514
- return createEvaluatedCell(e.value, localeFormat, e.message);
41583
+ return createEvaluatedCell(e?.value || CellErrorType.GenericError, localeFormat, e?.message || implementationErrorMessage);
41515
41584
  }
41516
41585
  finally {
41517
41586
  this.cellsBeingComputed.delete(cellId);
@@ -41598,7 +41667,7 @@ class Evaluator {
41598
41667
  this.setEvaluatedCell(positionId, evaluatedCell);
41599
41668
  // check if formula dependencies present in the spread zone
41600
41669
  // if so, they need to be recomputed
41601
- this.nextPositionsToUpdate.add(...this.getCellsDependingOn([positionId]));
41670
+ this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
41602
41671
  };
41603
41672
  }
41604
41673
  invalidateSpreading(positionId) {
@@ -41613,8 +41682,8 @@ class Evaluator {
41613
41682
  continue;
41614
41683
  }
41615
41684
  this.evaluatedCells.delete(child);
41616
- this.nextPositionsToUpdate.add(...this.getCellsDependingOn([child]));
41617
- this.nextPositionsToUpdate.add(...this.getArrayFormulasBlockedByOrSpreadingOn(child));
41685
+ this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
41686
+ this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
41618
41687
  }
41619
41688
  this.spreadingRelations.removeNode(positionId);
41620
41689
  }
@@ -41845,6 +41914,7 @@ class EvaluationPlugin extends UIPlugin {
41845
41914
  "getEvaluatedCellsInZone",
41846
41915
  "getSpreadPositionsOf",
41847
41916
  "getArrayFormulaSpreadingOn",
41917
+ "isEmpty",
41848
41918
  ];
41849
41919
  shouldRebuildDependenciesGraph = true;
41850
41920
  evaluator;
@@ -41950,6 +42020,14 @@ class EvaluationPlugin extends UIPlugin {
41950
42020
  getArrayFormulaSpreadingOn(position) {
41951
42021
  return this.evaluator.getArrayFormulaSpreadingOn(position);
41952
42022
  }
42023
+ /**
42024
+ * Check if a zone only contains empty cells
42025
+ */
42026
+ isEmpty(sheetId, zone) {
42027
+ return positions(zone)
42028
+ .map(({ col, row }) => this.getEvaluatedCell({ sheetId, col, row }))
42029
+ .every((cell) => cell.type === CellValueType.empty);
42030
+ }
41953
42031
  // ---------------------------------------------------------------------------
41954
42032
  // Export
41955
42033
  // ---------------------------------------------------------------------------
@@ -42597,8 +42675,6 @@ const VALID_RESULT = { isValid: true };
42597
42675
  class EvaluationDataValidationPlugin extends UIPlugin {
42598
42676
  static getters = [
42599
42677
  "getDataValidationInvalidCriterionValueMessage",
42600
- "getDataValidationCheckBoxCellPositions",
42601
- "getDataValidationListCellsPositions",
42602
42678
  "getInvalidDataValidationMessage",
42603
42679
  "getValidationResultForCellValue",
42604
42680
  "isCellValidCheckbox",
@@ -42662,19 +42738,6 @@ class EvaluationDataValidationPlugin extends UIPlugin {
42662
42738
  const error = this.getRuleErrorForCellValue(cellValue, cellPosition, rule);
42663
42739
  return error ? { error, rule, isValid: false } : VALID_RESULT;
42664
42740
  }
42665
- getDataValidationCheckBoxCellPositions() {
42666
- const rules = this.getters
42667
- .getDataValidationRules(this.getters.getActiveSheetId())
42668
- .filter((rule) => rule.criterion.type === "isBoolean");
42669
- return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat()).filter((position) => this.isCellValidCheckbox(position));
42670
- }
42671
- getDataValidationListCellsPositions() {
42672
- const rules = this.getters
42673
- .getDataValidationRules(this.getters.getActiveSheetId())
42674
- .filter((rule) => (rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") &&
42675
- rule.criterion.displayStyle === "arrow");
42676
- return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat());
42677
- }
42678
42741
  getValidationResultForCell(cellPosition) {
42679
42742
  const { col, row, sheetId } = cellPosition;
42680
42743
  if (!this.validationResults[sheetId]) {
@@ -45483,7 +45546,7 @@ class FindAndReplacePlugin extends UIPlugin {
45483
45546
  }
45484
45547
  finalize() {
45485
45548
  if (this.isSearchDirty) {
45486
- this.refreshSearch();
45549
+ this.refreshSearch(false);
45487
45550
  this.isSearchDirty = false;
45488
45551
  }
45489
45552
  }
@@ -45527,10 +45590,10 @@ class FindAndReplacePlugin extends UIPlugin {
45527
45590
  /**
45528
45591
  * refresh the matches according to the current search options
45529
45592
  */
45530
- refreshSearch() {
45593
+ refreshSearch(jumpToMatchSheet = true) {
45531
45594
  this.selectedMatchIndex = null;
45532
45595
  this.findMatches();
45533
- this.selectNextCell(Direction.current);
45596
+ this.selectNextCell(Direction.current, jumpToMatchSheet);
45534
45597
  }
45535
45598
  /**
45536
45599
  * Updates the regex based on the current searchOptions and
@@ -45612,7 +45675,7 @@ class FindAndReplacePlugin extends UIPlugin {
45612
45675
  * It is also used to keep coherence between the selected searchMatch
45613
45676
  * and selectedMatchIndex.
45614
45677
  */
45615
- selectNextCell(indexChange) {
45678
+ selectNextCell(indexChange, jumpToMatchSheet = true) {
45616
45679
  const matches = this.searchMatches;
45617
45680
  if (!matches.length) {
45618
45681
  this.selectedMatchIndex = null;
@@ -45638,11 +45701,13 @@ class FindAndReplacePlugin extends UIPlugin {
45638
45701
  this.selectedMatchIndex = nextIndex;
45639
45702
  const selectedMatch = matches[nextIndex];
45640
45703
  // Switch to the sheet where the match is located
45641
- if (this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
45704
+ if (jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
45642
45705
  this.dispatch("ACTIVATE_SHEET", {
45643
45706
  sheetIdFrom: this.getters.getActiveSheetId(),
45644
45707
  sheetIdTo: selectedMatch.sheetId,
45645
45708
  });
45709
+ // We do not want to reset the selection at finalize in this case
45710
+ this.isSearchDirty = false;
45646
45711
  }
45647
45712
  // we want grid selection to capture the selection stream
45648
45713
  this.selection.getBackToDefault();
@@ -46944,19 +47009,17 @@ class SelectionInputsManagerPlugin extends UIPlugin {
46944
47009
  break;
46945
47010
  case "FOCUS_RANGE":
46946
47011
  case "CHANGE_RANGE":
46947
- if (cmd.id !== this.focusedInputId) {
46948
- const input = this.inputs[cmd.id];
46949
- const range = input.ranges.find((range) => range.id === cmd.rangeId);
46950
- if (this.isRangeValid(range?.xc || "A1")) {
46951
- const sheetId = this.getters.getActiveSheetId();
46952
- const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
46953
- this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
46954
- handleEvent: input.handleEvent.bind(input),
46955
- release: () => (this.focusedInputId = null),
46956
- });
46957
- }
46958
- this.focusedInputId = cmd.id;
47012
+ const input = this.inputs[cmd.id];
47013
+ const range = input.ranges.find((range) => range.id === cmd.rangeId);
47014
+ if (range) {
47015
+ const sheetId = this.getters.getActiveSheetId();
47016
+ const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
47017
+ this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
47018
+ handleEvent: input.handleEvent.bind(input),
47019
+ release: () => (this.focusedInputId = null),
47020
+ });
46959
47021
  }
47022
+ this.focusedInputId = cmd.id;
46960
47023
  break;
46961
47024
  }
46962
47025
  this.currentInput?.handle(cmd);
@@ -47210,7 +47273,7 @@ class SheetUIPlugin extends UIPlugin {
47210
47273
  "getCellText",
47211
47274
  "getCellMultiLineText",
47212
47275
  "getContiguousZone",
47213
- "isCellEmpty",
47276
+ "isEvaluatedCellEmpty",
47214
47277
  ];
47215
47278
  ctx = document.createElement("canvas").getContext("2d");
47216
47279
  // ---------------------------------------------------------------------------
@@ -47338,14 +47401,23 @@ class SheetUIPlugin extends UIPlugin {
47338
47401
  return zone;
47339
47402
  }
47340
47403
  /**
47341
- * Check if a cell is empty. If the cell is part of a merge,
47342
- * check if the merge containing the cell is empty.
47404
+ * Checks if a cell evaluated value is empty. If the cell is part of a merge,
47405
+ * the check applies to the main cell of the merge.
47343
47406
  */
47344
- isCellEmpty(position) {
47407
+ isEvaluatedCellEmpty(position) {
47345
47408
  const mainPosition = this.getters.getMainCellPosition(position);
47346
47409
  const cell = this.getters.getEvaluatedCell(mainPosition);
47347
47410
  return cell.type === CellValueType.empty;
47348
47411
  }
47412
+ /**
47413
+ * Checks if a cell is empty (i.e. does not have a content or a formula does not spread over it).
47414
+ * If the cell is part of a merge, the check applies to the main cell of the merge.
47415
+ */
47416
+ isCellEmpty(position) {
47417
+ const mainPosition = this.getters.getMainCellPosition(position);
47418
+ return !(this.getters.getCorrespondingFormulaCell(mainPosition) ||
47419
+ this.getters.getCell(mainPosition)?.content);
47420
+ }
47349
47421
  getColMaxWidth(sheetId, index) {
47350
47422
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
47351
47423
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
@@ -50366,6 +50438,8 @@ class SheetViewPlugin extends UIPlugin {
50366
50438
  "getEdgeScrollRow",
50367
50439
  "getVisibleFigures",
50368
50440
  "getVisibleRect",
50441
+ "getVisibleRectWithoutHeaders",
50442
+ "getVisibleCellPositions",
50369
50443
  "getColRowOffsetInViewport",
50370
50444
  "getMainViewportCoordinates",
50371
50445
  "getActiveSheetScrollInfo",
@@ -50609,6 +50683,26 @@ class SheetViewPlugin extends UIPlugin {
50609
50683
  const viewports = this.getSubViewports(sheetId);
50610
50684
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
50611
50685
  }
50686
+ /**
50687
+ * Get the positions of all the cells that are visible in the viewport, taking merges into account.
50688
+ */
50689
+ getVisibleCellPositions() {
50690
+ const visibleCols = this.getSheetViewVisibleCols();
50691
+ const visibleRows = this.getSheetViewVisibleRows();
50692
+ const sheetId = this.getters.getActiveSheetId();
50693
+ const positions = [];
50694
+ for (const col of visibleCols) {
50695
+ for (const row of visibleRows) {
50696
+ const position = { sheetId, col, row };
50697
+ const mainPosition = this.getters.getMainCellPosition(position);
50698
+ if (mainPosition.row !== row || mainPosition.col !== col) {
50699
+ continue;
50700
+ }
50701
+ positions.push(position);
50702
+ }
50703
+ }
50704
+ return positions;
50705
+ }
50612
50706
  /**
50613
50707
  * Return the main viewport maximum size relative to the client size.
50614
50708
  */
@@ -50728,6 +50822,13 @@ class SheetViewPlugin extends UIPlugin {
50728
50822
  * Computes the coordinates and size to draw the zone on the canvas
50729
50823
  */
50730
50824
  getVisibleRect(zone) {
50825
+ const rect = this.getVisibleRectWithoutHeaders(zone);
50826
+ return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
50827
+ }
50828
+ /**
50829
+ * Computes the coordinates and size to draw the zone without taking the grid offset into account
50830
+ */
50831
+ getVisibleRectWithoutHeaders(zone) {
50731
50832
  const sheetId = this.getters.getActiveSheetId();
50732
50833
  const viewportRects = this.getSubViewports(sheetId)
50733
50834
  .map((viewport) => viewport.getRect(zone))
@@ -50739,12 +50840,7 @@ class SheetViewPlugin extends UIPlugin {
50739
50840
  const y = Math.min(...viewportRects.map((rect) => rect.y));
50740
50841
  const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
50741
50842
  const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
50742
- return {
50743
- x: x + this.gridOffsetX,
50744
- y: y + this.gridOffsetY,
50745
- width,
50746
- height,
50747
- };
50843
+ return { x, y, width, height };
50748
50844
  }
50749
50845
  /**
50750
50846
  * Returns the position of the MainViewport relatively to the start of the grid (without headers)
@@ -50968,13 +51064,8 @@ class HeaderPositionsUIPlugin extends UIPlugin {
50968
51064
  }
50969
51065
  break;
50970
51066
  case "UPDATE_CELL":
50971
- if ("content" in cmd || "format" in cmd) {
50972
- this.headerPositions = {};
50973
- this.isDirty = true;
50974
- }
50975
- else {
50976
- this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
50977
- }
51067
+ this.headerPositions = {};
51068
+ this.isDirty = true;
50978
51069
  break;
50979
51070
  case "UPDATE_FILTER":
50980
51071
  case "REMOVE_FILTER_TABLE":
@@ -54887,8 +54978,8 @@ class SelectionStreamProcessorImpl {
54887
54978
  let currentPosition = startPosition;
54888
54979
  // If both the current cell and the next cell are not empty, we want to go to the end of the cluster
54889
54980
  const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
54890
- let mode = !this.getters.isCellEmpty({ ...currentPosition, sheetId }) &&
54891
- !this.getters.isCellEmpty({ ...nextCellPosition, sheetId })
54981
+ let mode = !this.getters.isEvaluatedCellEmpty({ ...currentPosition, sheetId }) &&
54982
+ !this.getters.isEvaluatedCellEmpty({ ...nextCellPosition, sheetId })
54892
54983
  ? "endOfCluster"
54893
54984
  : "nextCluster";
54894
54985
  while (true) {
@@ -54898,7 +54989,7 @@ class SelectionStreamProcessorImpl {
54898
54989
  currentPosition.row === nextCellPosition.row) {
54899
54990
  break;
54900
54991
  }
54901
- const isNextCellEmpty = this.getters.isCellEmpty({ ...nextCellPosition, sheetId });
54992
+ const isNextCellEmpty = this.getters.isEvaluatedCellEmpty({ ...nextCellPosition, sheetId });
54902
54993
  if (mode === "endOfCluster" && isNextCellEmpty) {
54903
54994
  break;
54904
54995
  }
@@ -57147,6 +57238,6 @@ const constants = {
57147
57238
  export { AbstractChart, CellErrorType, 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 };
57148
57239
 
57149
57240
 
57150
- __info__.version = "17.1.4";
57151
- __info__.date = "2024-02-09T13:09:13.430Z";
57152
- __info__.hash = "16d3ece";
57241
+ __info__.version = "17.1.7";
57242
+ __info__.date = "2024-03-12T07:56:10.783Z";
57243
+ __info__.hash = "3a9f334";