@odoo/o-spreadsheet 18.0.13 → 18.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 18.0.13
6
- * @date 2025-01-31T07:59:17.481Z
7
- * @hash f505971
5
+ * @version 18.0.15
6
+ * @date 2025-02-10T08:59:22.993Z
7
+ * @hash 5b19f88
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -765,9 +765,16 @@ function deepEqualsArray(arr1, arr2) {
765
765
  }
766
766
  return true;
767
767
  }
768
- /** Check if the given array contains all the values of the other array. */
768
+ /**
769
+ * Check if the given array contains all the values of the other array.
770
+ * It makes the assumption that both array do not contain duplicates.
771
+ */
769
772
  function includesAll(arr, values) {
770
- return values.every((value) => arr.includes(value));
773
+ if (arr.length < values.length) {
774
+ return false;
775
+ }
776
+ const set = new Set(arr);
777
+ return values.every((value) => set.has(value));
771
778
  }
772
779
  /**
773
780
  * Return an object with all the keys in the object that have a falsy value removed.
@@ -18382,19 +18389,20 @@ const HLOOKUP = {
18382
18389
  description: _t("Horizontal lookup"),
18383
18390
  args: [
18384
18391
  arg("search_key (string, number, boolean)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18385
- arg("range (range)", _t("The range to consider for the search. The first row in the range is searched for the key specified in search_key.")),
18392
+ arg("range (any, range)", _t("The range to consider for the search. The first row in the range is searched for the key specified in search_key.")),
18386
18393
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18387
18394
  arg(`is_sorted (boolean, default=${DEFAULT_IS_SORTED})`, _t("Indicates whether the row to be searched (the first row of the specified range) is sorted, in which case the closest match for search_key will be returned.")),
18388
18395
  ],
18389
18396
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18390
18397
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18391
- assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18398
+ const _range = toMatrix(range);
18399
+ assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18392
18400
  const getValueFromRange = (range, index) => range[index][0].value;
18393
18401
  const _isSorted = toBoolean(isSorted.value);
18394
18402
  const colIndex = _isSorted
18395
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
18396
- : linearSearch(range, searchKey, "wildcard", range.length, getValueFromRange, this.lookupCaches);
18397
- const col = range[colIndex];
18403
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
18404
+ : linearSearch(range, searchKey, "wildcard", _range.length, getValueFromRange, this.lookupCaches);
18405
+ const col = _range[colIndex];
18398
18406
  if (col === undefined) {
18399
18407
  return valueNotAvailable(searchKey);
18400
18408
  }
@@ -18486,35 +18494,37 @@ const LOOKUP = {
18486
18494
  description: _t("Look up a value."),
18487
18495
  args: [
18488
18496
  arg("search_key (string, number, boolean)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18489
- arg("search_array (range)", _t("One method of using this function is to provide a single sorted row or column search_array to look through for the search_key with a second argument result_range. The other way is to combine these two arguments into one search_array where the first row or column is searched and a value is returned from the last row or column in the array. If search_key is not found, a non-exact match may be returned.")),
18490
- arg("result_range (range, optional)", _t("The range from which to return a result. The value returned corresponds to the location where search_key is found in search_range. This range must be only a single row or column and should not be used if using the search_result_array method.")),
18497
+ arg("search_array (any, range)", _t("One method of using this function is to provide a single sorted row or column search_array to look through for the search_key with a second argument result_range. The other way is to combine these two arguments into one search_array where the first row or column is searched and a value is returned from the last row or column in the array. If search_key is not found, a non-exact match may be returned.")),
18498
+ arg("result_range (any, range, optional)", _t("The range from which to return a result. The value returned corresponds to the location where search_key is found in search_range. This range must be only a single row or column and should not be used if using the search_result_array method.")),
18491
18499
  ],
18492
18500
  compute: function (searchKey, searchArray, resultRange) {
18493
- let nbCol = searchArray.length;
18494
- let nbRow = searchArray[0].length;
18501
+ const _searchArray = toMatrix(searchArray);
18502
+ const _resultRange = toMatrix(resultRange);
18503
+ let nbCol = _searchArray.length;
18504
+ let nbRow = _searchArray[0].length;
18495
18505
  const verticalSearch = nbRow >= nbCol;
18496
18506
  const getElement = verticalSearch
18497
18507
  ? (range, index) => range[0][index].value
18498
18508
  : (range, index) => range[index][0].value;
18499
18509
  const rangeLength = verticalSearch ? nbRow : nbCol;
18500
- const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18510
+ const index = dichotomicSearch(_searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18501
18511
  if (index === -1 ||
18502
- (verticalSearch && searchArray[0][index] === undefined) ||
18503
- (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
18512
+ (verticalSearch && _searchArray[0][index] === undefined) ||
18513
+ (!verticalSearch && _searchArray[index][nbRow - 1] === undefined)) {
18504
18514
  return valueNotAvailable(searchKey);
18505
18515
  }
18506
- if (resultRange === undefined) {
18507
- return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
18516
+ if (_resultRange[0].length === 0) {
18517
+ return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
18508
18518
  }
18509
- nbCol = resultRange.length;
18510
- nbRow = resultRange[0].length;
18519
+ nbCol = _resultRange.length;
18520
+ nbRow = _resultRange[0].length;
18511
18521
  assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
18512
18522
  if (nbCol > 1) {
18513
18523
  assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
18514
- return resultRange[index][0];
18524
+ return _resultRange[index][0];
18515
18525
  }
18516
18526
  assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
18517
- return resultRange[0][index];
18527
+ return _resultRange[0][index];
18518
18528
  },
18519
18529
  isExported: true,
18520
18530
  };
@@ -18531,28 +18541,29 @@ const MATCH = {
18531
18541
  ],
18532
18542
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
18533
18543
  let _searchType = toNumber(searchType, this.locale);
18534
- const nbCol = range.length;
18535
- const nbRow = range[0].length;
18544
+ const _range = toMatrix(range);
18545
+ const nbCol = _range.length;
18546
+ const nbRow = _range[0].length;
18536
18547
  assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
18537
18548
  let index = -1;
18538
18549
  const getElement = nbCol === 1
18539
- ? (range, index) => range[0][index].value
18540
- : (range, index) => range[index][0].value;
18541
- const rangeLen = nbCol === 1 ? range[0].length : range.length;
18550
+ ? (_range, index) => _range[0][index].value
18551
+ : (_range, index) => _range[index][0].value;
18552
+ const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
18542
18553
  _searchType = Math.sign(_searchType);
18543
18554
  switch (_searchType) {
18544
18555
  case 1:
18545
- index = dichotomicSearch(range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18556
+ index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18546
18557
  break;
18547
18558
  case 0:
18548
- index = linearSearch(range, searchKey, "wildcard", rangeLen, getElement, this.lookupCaches);
18559
+ index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement, this.lookupCaches);
18549
18560
  break;
18550
18561
  case -1:
18551
- index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18562
+ index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18552
18563
  break;
18553
18564
  }
18554
- if ((nbCol === 1 && range[0][index] === undefined) ||
18555
- (nbCol !== 1 && range[index] === undefined)) {
18565
+ if ((nbCol === 1 && _range[0][index] === undefined) ||
18566
+ (nbCol !== 1 && _range[index] === undefined)) {
18556
18567
  return valueNotAvailable(searchKey);
18557
18568
  }
18558
18569
  return index + 1;
@@ -18607,13 +18618,14 @@ const VLOOKUP = {
18607
18618
  ],
18608
18619
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18609
18620
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18610
- assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18621
+ const _range = toMatrix(range);
18622
+ assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18611
18623
  const getValueFromRange = (range, index) => range[0][index].value;
18612
18624
  const _isSorted = toBoolean(isSorted.value);
18613
18625
  const rowIndex = _isSorted
18614
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
18615
- : linearSearch(range, searchKey, "wildcard", range[0].length, getValueFromRange, this.lookupCaches);
18616
- const value = range[_index - 1][rowIndex];
18626
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
18627
+ : linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange, this.lookupCaches);
18628
+ const value = _range[_index - 1][rowIndex];
18617
18629
  if (value === undefined) {
18618
18630
  return valueNotAvailable(searchKey);
18619
18631
  }
@@ -18650,27 +18662,29 @@ const XLOOKUP = {
18650
18662
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18651
18663
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18652
18664
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
18653
- assert(() => lookupRange.length === 1 || lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18665
+ const _lookupRange = toMatrix(lookupRange);
18666
+ const _returnRange = toMatrix(returnRange);
18667
+ assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18654
18668
  assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("search_mode should be a value in [-1, 1, -2, 2]."));
18655
18669
  assert(() => [-1, 0, 1, 2].includes(_matchMode), _t("match_mode should be a value in [-1, 0, 1, 2]."));
18656
- const lookupDirection = lookupRange.length === 1 ? "col" : "row";
18670
+ const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
18657
18671
  assert(() => !(_matchMode === 2 && [-2, 2].includes(_searchMode)), _t("the search and match mode combination is not supported for XLOOKUP evaluation."));
18658
18672
  assert(() => lookupDirection === "col"
18659
- ? returnRange[0].length === lookupRange[0].length
18660
- : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18673
+ ? _returnRange[0].length === _lookupRange[0].length
18674
+ : _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18661
18675
  const getElement = lookupDirection === "col"
18662
18676
  ? (range, index) => range[0][index].value
18663
18677
  : (range, index) => range[index][0].value;
18664
- const rangeLen = lookupDirection === "col" ? lookupRange[0].length : lookupRange.length;
18678
+ const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
18665
18679
  const mode = MATCH_MODE[_matchMode];
18666
18680
  const reverseSearch = _searchMode === -1;
18667
18681
  const index = _searchMode === 2 || _searchMode === -2
18668
- ? dichotomicSearch(lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18669
- : linearSearch(lookupRange, searchKey, mode, rangeLen, getElement, this.lookupCaches, reverseSearch);
18682
+ ? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18683
+ : linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, this.lookupCaches, reverseSearch);
18670
18684
  if (index !== -1) {
18671
18685
  return lookupDirection === "col"
18672
- ? returnRange.map((col) => [col[index]])
18673
- : [returnRange[index]];
18686
+ ? _returnRange.map((col) => [col[index]])
18687
+ : [_returnRange[index]];
18674
18688
  }
18675
18689
  if (defaultValue === undefined) {
18676
18690
  return valueNotAvailable(searchKey);
@@ -39248,8 +39262,8 @@ function useDragAndDropListItems() {
39248
39262
  document.body.style.cursor = "move";
39249
39263
  state.draggedItemId = args.draggedItemId;
39250
39264
  const container = direction === "horizontal"
39251
- ? new HorizontalContainer(args.containerEl)
39252
- : new VerticalContainer(args.containerEl);
39265
+ ? new HorizontalContainer(args.scrollableContainerEl)
39266
+ : new VerticalContainer(args.scrollableContainerEl);
39253
39267
  dndHelper = new DOMDndHelper({
39254
39268
  ...args,
39255
39269
  container,
@@ -39260,8 +39274,8 @@ function useDragAndDropListItems() {
39260
39274
  const stopListening = startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
39261
39275
  cleanupFns.push(stopListening);
39262
39276
  const onScroll = dndHelper.onScroll.bind(dndHelper);
39263
- args.containerEl.addEventListener("scroll", onScroll);
39264
- cleanupFns.push(() => args.containerEl.removeEventListener("scroll", onScroll));
39277
+ args.scrollableContainerEl.addEventListener("scroll", onScroll);
39278
+ cleanupFns.push(() => args.scrollableContainerEl.removeEventListener("scroll", onScroll));
39265
39279
  cleanupFns.push(dndHelper.destroy.bind(dndHelper));
39266
39280
  };
39267
39281
  onWillUnmount(() => {
@@ -39725,7 +39739,7 @@ class ConditionalFormatPreviewList extends Component {
39725
39739
  draggedItemId: cf.id,
39726
39740
  initialMousePosition: event.clientY,
39727
39741
  items: items,
39728
- containerEl: this.cfListRef.el,
39742
+ scrollableContainerEl: this.cfListRef.el,
39729
39743
  onDragEnd: (cfId, finalIndex) => this.onDragEnd(cfId, finalIndex),
39730
39744
  });
39731
39745
  }
@@ -42709,6 +42723,7 @@ class PivotLayoutConfigurator extends Component {
42709
42723
  unusedGranularities: Object,
42710
42724
  dateGranularities: Array,
42711
42725
  datetimeGranularities: Array,
42726
+ getScrollableContainerEl: { type: Function, optional: true },
42712
42727
  pivotId: String,
42713
42728
  };
42714
42729
  dimensionsRef = useRef("pivot-dimensions");
@@ -42742,7 +42757,7 @@ class PivotLayoutConfigurator extends Component {
42742
42757
  draggedItemId: dimension.nameWithGranularity,
42743
42758
  initialMousePosition: event.clientY,
42744
42759
  items: draggableItems,
42745
- containerEl: this.dimensionsRef.el,
42760
+ scrollableContainerEl: this.props.getScrollableContainerEl?.() || this.dimensionsRef.el,
42746
42761
  onDragEnd: (dimensionName, finalIndex) => {
42747
42762
  const originalIndex = draggableIds.findIndex((id) => id === dimensionName);
42748
42763
  if (originalIndex === finalIndex) {
@@ -42791,7 +42806,7 @@ class PivotLayoutConfigurator extends Component {
42791
42806
  draggedItemId: measure.id,
42792
42807
  initialMousePosition: event.clientY,
42793
42808
  items: draggableItems,
42794
- containerEl: this.dimensionsRef.el,
42809
+ scrollableContainerEl: this.props.getScrollableContainerEl?.() || this.dimensionsRef.el,
42795
42810
  onDragEnd: (measureName, finalIndex) => {
42796
42811
  const originalIndex = draggableIds.findIndex((id) => id === measureName);
42797
42812
  if (originalIndex === finalIndex) {
@@ -44419,6 +44434,7 @@ class PivotSpreadsheetSidePanel extends Component {
44419
44434
  };
44420
44435
  store;
44421
44436
  state;
44437
+ pivotSidePanelRef = useRef("pivotSidePanel");
44422
44438
  setup() {
44423
44439
  this.store = useLocalStore(PivotSidePanelStore, this.props.pivotId);
44424
44440
  this.state = useState({
@@ -44447,6 +44463,9 @@ class PivotSpreadsheetSidePanel extends Component {
44447
44463
  get definition() {
44448
44464
  return this.store.definition;
44449
44465
  }
44466
+ getScrollableContainerEl() {
44467
+ return this.pivotSidePanelRef.el;
44468
+ }
44450
44469
  onSelectionChanged(ranges) {
44451
44470
  this.state.rangeHasChanged = true;
44452
44471
  this.state.range = ranges[0];
@@ -48476,11 +48495,10 @@ class GridRenderer {
48476
48495
  switch (layer) {
48477
48496
  case "Background":
48478
48497
  this.drawGlobalBackground(renderingContext);
48479
- for (const zone of this.getters.getAllActiveViewportsZones()) {
48498
+ for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
48480
48499
  const { ctx } = renderingContext;
48481
48500
  ctx.save();
48482
48501
  ctx.beginPath();
48483
- const rect = this.getters.getVisibleRect(zone);
48484
48502
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
48485
48503
  ctx.clip();
48486
48504
  const boxes = this.getGridBoxes(zone);
@@ -48756,10 +48774,8 @@ class GridRenderer {
48756
48774
  const { ctx, thinLineWidth } = renderingContext;
48757
48775
  const visibleCols = this.getters.getSheetViewVisibleCols();
48758
48776
  const left = visibleCols[0];
48759
- const right = visibleCols[visibleCols.length - 1];
48760
48777
  const visibleRows = this.getters.getSheetViewVisibleRows();
48761
48778
  const top = visibleRows[0];
48762
- const bottom = visibleRows[visibleRows.length - 1];
48763
48779
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
48764
48780
  const selection = this.getters.getSelectedZones();
48765
48781
  const selectedCols = getZonesCols(selection);
@@ -48775,7 +48791,7 @@ class GridRenderer {
48775
48791
  ctx.lineWidth = thinLineWidth;
48776
48792
  ctx.strokeStyle = "#333";
48777
48793
  // Columns headers background
48778
- for (let col = left; col <= right; col++) {
48794
+ for (const col of visibleCols) {
48779
48795
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
48780
48796
  const { x, width } = this.getters.getVisibleRect(colZone);
48781
48797
  const isColActive = activeCols.has(col);
@@ -48792,7 +48808,7 @@ class GridRenderer {
48792
48808
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
48793
48809
  }
48794
48810
  // Rows headers background
48795
- for (let row = top; row <= bottom; row++) {
48811
+ for (const row of visibleRows) {
48796
48812
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
48797
48813
  const { y, height } = this.getters.getVisibleRect(rowZone);
48798
48814
  const isRowActive = activeRows.has(row);
@@ -48818,21 +48834,21 @@ class GridRenderer {
48818
48834
  ctx.stroke();
48819
48835
  ctx.beginPath();
48820
48836
  // column text + separator
48821
- for (const i of visibleCols) {
48822
- const colSize = this.getters.getColSize(sheetId, i);
48823
- const colName = numberToLetters(i);
48824
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
48825
- let colStart = this.getHeaderOffset("COL", left, i);
48837
+ for (const col of visibleCols) {
48838
+ const colSize = this.getters.getColSize(sheetId, col);
48839
+ const colName = numberToLetters(col);
48840
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
48841
+ let colStart = this.getHeaderOffset("COL", left, col);
48826
48842
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
48827
48843
  ctx.moveTo(colStart + colSize, 0);
48828
48844
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
48829
48845
  }
48830
48846
  // row text + separator
48831
- for (const i of visibleRows) {
48832
- const rowSize = this.getters.getRowSize(sheetId, i);
48833
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
48834
- let rowStart = this.getHeaderOffset("ROW", top, i);
48835
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
48847
+ for (const row of visibleRows) {
48848
+ const rowSize = this.getters.getRowSize(sheetId, row);
48849
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
48850
+ let rowStart = this.getHeaderOffset("ROW", top, row);
48851
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
48836
48852
  ctx.moveTo(0, rowStart + rowSize);
48837
48853
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
48838
48854
  }
@@ -49132,6 +49148,9 @@ function useGridDrawing(refName, model, canvasSize) {
49132
49148
  canvas.width = width * dpr;
49133
49149
  canvas.height = height * dpr;
49134
49150
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
49151
+ if (width === 0 || height === 0) {
49152
+ return;
49153
+ }
49135
49154
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
49136
49155
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
49137
49156
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -50703,7 +50722,7 @@ class BordersPlugin extends CorePlugin {
50703
50722
  getCommonSides(border1, border2) {
50704
50723
  const commonBorder = {};
50705
50724
  for (let side of ["top", "bottom", "left", "right"]) {
50706
- if (border1[side] && border1[side] === border2[side]) {
50725
+ if (border1[side] && deepEquals(border1[side], border2[side])) {
50707
50726
  commonBorder[side] = border1[side];
50708
50727
  }
50709
50728
  }
@@ -64973,8 +64992,17 @@ class InternalViewport {
64973
64992
  this.getters = getters;
64974
64993
  this.sheetId = sheetId;
64975
64994
  this.boundaries = boundaries;
64976
- this.viewportWidth = sizeInGrid.width;
64977
- this.viewportHeight = sizeInGrid.height;
64995
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
64996
+ throw new Error("Viewport size cannot be negative");
64997
+ }
64998
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
64999
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
65000
+ this.top = boundaries.top;
65001
+ this.bottom = boundaries.bottom;
65002
+ this.left = boundaries.left;
65003
+ this.right = boundaries.right;
65004
+ this.offsetX = offsets.x;
65005
+ this.offsetY = offsets.y;
64978
65006
  this.offsetScrollbarX = offsets.x;
64979
65007
  this.offsetScrollbarY = offsets.y;
64980
65008
  this.canScrollVertically = options.canScrollVertically;
@@ -65017,9 +65045,9 @@ class InternalViewport {
65017
65045
  Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
65018
65046
  );
65019
65047
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
65020
- }
65021
- if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
65022
- height += FOOTER_HEIGHT;
65048
+ if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
65049
+ height += FOOTER_HEIGHT;
65050
+ }
65023
65051
  }
65024
65052
  return { width, height };
65025
65053
  }
@@ -65160,6 +65188,9 @@ class InternalViewport {
65160
65188
  !this.getters.isRowHidden(this.sheetId, row));
65161
65189
  }
65162
65190
  searchHeaderIndex(dimension, position, startIndex = 0) {
65191
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
65192
+ return -1;
65193
+ }
65163
65194
  const sheetId = this.sheetId;
65164
65195
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
65165
65196
  // using a binary search:
@@ -65196,7 +65227,7 @@ class InternalViewport {
65196
65227
  this.adjustViewportZoneY();
65197
65228
  }
65198
65229
  /** Corrects the viewport's horizontal offset based on the current structure
65199
- * To make sure that at least on column is visible inside the viewport.
65230
+ * To make sure that at least one column is visible inside the viewport.
65200
65231
  */
65201
65232
  adjustViewportOffsetX() {
65202
65233
  if (this.canScrollHorizontally) {
@@ -65208,7 +65239,7 @@ class InternalViewport {
65208
65239
  this.adjustViewportZoneX();
65209
65240
  }
65210
65241
  /** Corrects the viewport's vertical offset based on the current structure
65211
- * To make sure that at least on row is visible inside the viewport.
65242
+ * To make sure that at least one row is visible inside the viewport.
65212
65243
  */
65213
65244
  adjustViewportOffsetY() {
65214
65245
  if (this.canScrollVertically) {
@@ -65225,11 +65256,14 @@ class InternalViewport {
65225
65256
  const sheetId = this.sheetId;
65226
65257
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
65227
65258
  this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
65259
+ if (!this.viewportWidth) {
65260
+ return;
65261
+ }
65228
65262
  if (this.left === -1) {
65229
65263
  this.left = this.boundaries.left;
65230
65264
  }
65231
65265
  if (this.right === -1) {
65232
- this.right = this.getters.getNumberCols(sheetId) - 1;
65266
+ this.right = this.boundaries.right;
65233
65267
  }
65234
65268
  this.offsetX =
65235
65269
  this.getters.getColDimensions(sheetId, this.left).start -
@@ -65241,11 +65275,14 @@ class InternalViewport {
65241
65275
  const sheetId = this.sheetId;
65242
65276
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
65243
65277
  this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
65278
+ if (!this.viewportHeight) {
65279
+ return;
65280
+ }
65244
65281
  if (this.top === -1) {
65245
65282
  this.top = this.boundaries.top;
65246
65283
  }
65247
65284
  if (this.bottom === -1) {
65248
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
65285
+ this.bottom = this.boundaries.bottom;
65249
65286
  }
65250
65287
  this.offsetY =
65251
65288
  this.getters.getRowDimensions(sheetId, this.top).start -
@@ -65319,7 +65356,7 @@ class SheetViewPlugin extends UIPlugin {
65319
65356
  "isPositionVisible",
65320
65357
  "getColDimensionsInViewport",
65321
65358
  "getRowDimensionsInViewport",
65322
- "getAllActiveViewportsZones",
65359
+ "getAllActiveViewportsZonesAndRect",
65323
65360
  "getRect",
65324
65361
  ];
65325
65362
  viewports = {};
@@ -65552,12 +65589,12 @@ class SheetViewPlugin extends UIPlugin {
65552
65589
  const sheetId = this.getters.getActiveSheetId();
65553
65590
  const viewports = this.getSubViewports(sheetId);
65554
65591
  //TODO ake another commit to eimprove this
65555
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
65592
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
65556
65593
  }
65557
65594
  getSheetViewVisibleRows() {
65558
65595
  const sheetId = this.getters.getActiveSheetId();
65559
65596
  const viewports = this.getSubViewports(sheetId);
65560
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
65597
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
65561
65598
  }
65562
65599
  /**
65563
65600
  * Get the positions of all the cells that are visible in the viewport, taking merges into account.
@@ -65600,19 +65637,19 @@ class SheetViewPlugin extends UIPlugin {
65600
65637
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
65601
65638
  };
65602
65639
  }
65603
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
65604
- const sheetId = this.getters.getActiveSheetId();
65605
- const visibleCols = this.getters.getSheetViewVisibleCols();
65606
- const visibleRows = this.getters.getSheetViewVisibleRows();
65607
- if (index < referenceIndex) {
65608
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
65640
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
65641
+ if (targetHeaderIndex < referenceHeaderIndex) {
65642
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
65609
65643
  }
65644
+ const sheetId = this.getters.getActiveSheetId();
65645
+ const visibleHeaders = dimension === "COL"
65646
+ ? this.getters.getSheetViewVisibleCols()
65647
+ : this.getters.getSheetViewVisibleRows();
65648
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
65649
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
65650
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
65610
65651
  let offset = 0;
65611
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
65612
- for (let i = referenceIndex; i < index; i++) {
65613
- if (!visibleIndexes.includes(i)) {
65614
- continue;
65615
- }
65652
+ for (const i of relevantIndexes) {
65616
65653
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
65617
65654
  }
65618
65655
  return offset;
@@ -65659,7 +65696,7 @@ class SheetViewPlugin extends UIPlugin {
65659
65696
  }
65660
65697
  return { canEdgeScroll, direction, delay };
65661
65698
  }
65662
- getEdgeScrollRow(y, previousY, tartingY) {
65699
+ getEdgeScrollRow(y, previousY, startingY) {
65663
65700
  let canEdgeScroll = false;
65664
65701
  let direction = 0;
65665
65702
  let delay = 0;
@@ -65680,7 +65717,7 @@ class SheetViewPlugin extends UIPlugin {
65680
65717
  delay = scrollDelay(y - height);
65681
65718
  direction = 1;
65682
65719
  }
65683
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
65720
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
65684
65721
  // 2
65685
65722
  canEdgeScroll = true;
65686
65723
  delay = scrollDelay(offsetCorrectionY - y);
@@ -65706,13 +65743,7 @@ class SheetViewPlugin extends UIPlugin {
65706
65743
  */
65707
65744
  getVisibleRectWithoutHeaders(zone) {
65708
65745
  const sheetId = this.getters.getActiveSheetId();
65709
- const viewportRects = this.getSubViewports(sheetId)
65710
- .map((viewport) => viewport.getVisibleRect(zone))
65711
- .filter(isDefined);
65712
- if (viewportRects.length === 0) {
65713
- return { x: 0, y: 0, width: 0, height: 0 };
65714
- }
65715
- return this.recomposeRect(viewportRects);
65746
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
65716
65747
  }
65717
65748
  /**
65718
65749
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -65720,13 +65751,7 @@ class SheetViewPlugin extends UIPlugin {
65720
65751
  */
65721
65752
  getRect(zone) {
65722
65753
  const sheetId = this.getters.getActiveSheetId();
65723
- const viewportRects = this.getSubViewports(sheetId)
65724
- .map((viewport) => viewport.getFullRect(zone))
65725
- .filter(isDefined);
65726
- if (viewportRects.length === 0) {
65727
- return { x: 0, y: 0, width: 0, height: 0 };
65728
- }
65729
- const rect = this.recomposeRect(viewportRects);
65754
+ const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
65730
65755
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
65731
65756
  }
65732
65757
  /**
@@ -65771,9 +65796,18 @@ class SheetViewPlugin extends UIPlugin {
65771
65796
  end: start + (isRowHidden ? 0 : size),
65772
65797
  };
65773
65798
  }
65774
- getAllActiveViewportsZones() {
65799
+ getAllActiveViewportsZonesAndRect() {
65775
65800
  const sheetId = this.getters.getActiveSheetId();
65776
- return this.getSubViewports(sheetId);
65801
+ return this.getSubViewports(sheetId).map((viewport) => {
65802
+ return {
65803
+ zone: viewport,
65804
+ rect: {
65805
+ x: viewport.offsetCorrectionX + this.gridOffsetX,
65806
+ y: viewport.offsetCorrectionY + this.gridOffsetY,
65807
+ ...viewport.getMaxSize(),
65808
+ },
65809
+ };
65810
+ });
65777
65811
  }
65778
65812
  // ---------------------------------------------------------------------------
65779
65813
  // Private
@@ -65832,12 +65866,11 @@ class SheetViewPlugin extends UIPlugin {
65832
65866
  }
65833
65867
  /** gets rid of deprecated sheetIds */
65834
65868
  cleanViewports() {
65835
- const sheetIds = this.getters.getSheetIds();
65836
- for (let sheetId of Object.keys(this.viewports)) {
65837
- if (!sheetIds.includes(sheetId)) {
65838
- delete this.viewports[sheetId];
65839
- }
65869
+ const newViewport = {};
65870
+ for (const sheetId of this.getters.getSheetIds()) {
65871
+ newViewport[sheetId] = this.viewports[sheetId];
65840
65872
  }
65873
+ this.viewports = newViewport;
65841
65874
  }
65842
65875
  resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
65843
65876
  this.sheetViewHeight = height;
@@ -65847,7 +65880,7 @@ class SheetViewPlugin extends UIPlugin {
65847
65880
  this.recomputeViewports();
65848
65881
  }
65849
65882
  recomputeViewports() {
65850
- for (let sheetId of Object.keys(this.viewports)) {
65883
+ for (const sheetId of this.getters.getSheetIds()) {
65851
65884
  this.resetViewports(sheetId);
65852
65885
  }
65853
65886
  }
@@ -65869,8 +65902,10 @@ class SheetViewPlugin extends UIPlugin {
65869
65902
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
65870
65903
  const nCols = this.getters.getNumberCols(sheetId);
65871
65904
  const nRows = this.getters.getNumberRows(sheetId);
65872
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
65873
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
65905
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
65906
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
65907
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
65908
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
65874
65909
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
65875
65910
  const canScrollHorizontally = xRatio < 1.0;
65876
65911
  const canScrollVertically = yRatio < 1.0;
@@ -65881,14 +65916,14 @@ class SheetViewPlugin extends UIPlugin {
65881
65916
  new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: 0, bottom: ySplit - 1 }, { width: colOffset, height: rowOffset }, { canScrollHorizontally: false, canScrollVertically: false }, { x: 0, y: 0 })) ||
65882
65917
  undefined,
65883
65918
  topRight: (ySplit &&
65884
- new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: 0, bottom: ySplit - 1 }, { width: this.sheetViewWidth - colOffset, height: rowOffset }, { canScrollHorizontally, canScrollVertically: false }, { x: canScrollHorizontally ? previousOffset.x : 0, y: 0 })) ||
65919
+ new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: 0, bottom: ySplit - 1 }, { width: unfrozenWidth, height: rowOffset }, { canScrollHorizontally, canScrollVertically: false }, { x: canScrollHorizontally ? previousOffset.x : 0, y: 0 })) ||
65885
65920
  undefined,
65886
65921
  bottomLeft: (xSplit &&
65887
- new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: ySplit, bottom: nRows - 1 }, { width: colOffset, height: this.sheetViewHeight - rowOffset }, { canScrollHorizontally: false, canScrollVertically }, { x: 0, y: canScrollVertically ? previousOffset.y : 0 })) ||
65922
+ new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: ySplit, bottom: nRows - 1 }, { width: colOffset, height: unfrozenHeight }, { canScrollHorizontally: false, canScrollVertically }, { x: 0, y: canScrollVertically ? previousOffset.y : 0 })) ||
65888
65923
  undefined,
65889
65924
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
65890
- width: this.sheetViewWidth - colOffset,
65891
- height: this.sheetViewHeight - rowOffset,
65925
+ width: unfrozenWidth,
65926
+ height: unfrozenHeight,
65892
65927
  }, { canScrollHorizontally, canScrollVertically }, {
65893
65928
  x: canScrollHorizontally ? previousOffset.x : 0,
65894
65929
  y: canScrollVertically ? previousOffset.y : 0,
@@ -65965,12 +66000,26 @@ class SheetViewPlugin extends UIPlugin {
65965
66000
  const height = this.sheetViewHeight + this.gridOffsetY;
65966
66001
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
65967
66002
  }
65968
- recomposeRect(viewportRects) {
65969
- const x = Math.min(...viewportRects.map((rect) => rect.x));
65970
- const y = Math.min(...viewportRects.map((rect) => rect.y));
65971
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
65972
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
65973
- return { x, y, width, height };
66003
+ mapViewportsToRect(sheetId, rectCallBack) {
66004
+ let x = Infinity;
66005
+ let y = Infinity;
66006
+ let width = 0;
66007
+ let height = 0;
66008
+ let hasViewports = false;
66009
+ for (const viewport of this.getSubViewports(sheetId)) {
66010
+ const rect = rectCallBack(viewport);
66011
+ if (rect) {
66012
+ hasViewports = true;
66013
+ x = Math.min(x, rect.x);
66014
+ y = Math.min(y, rect.y);
66015
+ width = Math.max(width, rect.x + rect.width);
66016
+ height = Math.max(height, rect.y + rect.height);
66017
+ }
66018
+ }
66019
+ if (!hasViewports) {
66020
+ return { x: 0, y: 0, width: 0, height: 0 };
66021
+ }
66022
+ return { x, y, width: width - x, height: height - y };
65974
66023
  }
65975
66024
  }
65976
66025
 
@@ -66966,7 +67015,7 @@ class BottomBar extends Component {
66966
67015
  draggedItemId: sheetId,
66967
67016
  initialMousePosition: event.clientX,
66968
67017
  items: sheets,
66969
- containerEl: this.sheetListRef.el,
67018
+ scrollableContainerEl: this.sheetListRef.el,
66970
67019
  onDragEnd: (sheetId, finalIndex) => this.onDragEnd(sheetId, finalIndex),
66971
67020
  });
66972
67021
  }
@@ -73088,6 +73137,6 @@ const constants = {
73088
73137
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, 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 };
73089
73138
 
73090
73139
 
73091
- __info__.version = "18.0.13";
73092
- __info__.date = "2025-01-31T07:59:17.481Z";
73093
- __info__.hash = "f505971";
73140
+ __info__.version = "18.0.15";
73141
+ __info__.date = "2025-02-10T08:59:22.993Z";
73142
+ __info__.hash = "5b19f88";