@odoo/o-spreadsheet 18.2.2 → 18.2.4

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.2.2
6
- * @date 2025-03-07T10:41:04.411Z
7
- * @hash f567932
5
+ * @version 18.2.4
6
+ * @date 2025-03-19T08:20:57.717Z
7
+ * @hash 958936a
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -423,7 +423,6 @@ function escapeRegExp(str) {
423
423
  * Sparse arrays remain sparse.
424
424
  */
425
425
  function deepCopy(obj) {
426
- const result = Array.isArray(obj) ? [] : {};
427
426
  switch (typeof obj) {
428
427
  case "object": {
429
428
  if (obj === null) {
@@ -435,8 +434,18 @@ function deepCopy(obj) {
435
434
  else if (!(isPlainObject(obj) || obj instanceof Array)) {
436
435
  throw new Error("Unsupported type: only objects and arrays are supported");
437
436
  }
438
- for (const key in obj) {
439
- result[key] = deepCopy(obj[key]);
437
+ const result = Array.isArray(obj) ? new Array(obj.length) : {};
438
+ if (Array.isArray(obj)) {
439
+ for (let i = 0, len = obj.length; i < len; i++) {
440
+ if (i in obj) {
441
+ result[i] = deepCopy(obj[i]);
442
+ }
443
+ }
444
+ }
445
+ else {
446
+ for (const key in obj) {
447
+ result[key] = deepCopy(obj[key]);
448
+ }
440
449
  }
441
450
  return result;
442
451
  }
@@ -2699,21 +2708,30 @@ function mergeContiguousZones(zones) {
2699
2708
  return mergedZones;
2700
2709
  }
2701
2710
 
2711
+ const globalReverseLookup$1 = new WeakMap();
2712
+ const globalIdCounter = new WeakMap();
2702
2713
  /**
2703
2714
  * Get the id of the given item (its key in the given dictionary).
2704
2715
  * If the given item does not exist in the dictionary, it creates one with a new id.
2705
2716
  */
2706
2717
  function getItemId(item, itemsDic) {
2707
- for (const key in itemsDic) {
2708
- if (deepEquals(itemsDic[key], item)) {
2709
- return parseInt(key, 10);
2710
- }
2718
+ if (!globalReverseLookup$1.has(itemsDic)) {
2719
+ globalReverseLookup$1.set(itemsDic, new Map());
2720
+ globalIdCounter.set(itemsDic, 0);
2721
+ }
2722
+ const reverseLookup = globalReverseLookup$1.get(itemsDic);
2723
+ const canonical = getCanonicalRepresentation(item);
2724
+ if (reverseLookup.has(canonical)) {
2725
+ const id = reverseLookup.get(canonical);
2726
+ itemsDic[id] = item;
2727
+ return id;
2711
2728
  }
2712
2729
  // Generate new Id if the item didn't exist in the dictionary
2713
- const ids = Object.keys(itemsDic);
2714
- const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
2715
- itemsDic[maxId + 1] = item;
2716
- return maxId + 1;
2730
+ const newId = globalIdCounter.get(itemsDic) + 1;
2731
+ reverseLookup.set(canonical, newId);
2732
+ globalIdCounter.set(itemsDic, newId);
2733
+ itemsDic[newId] = item;
2734
+ return newId;
2717
2735
  }
2718
2736
  function groupItemIdsByZones(positionsByItemId) {
2719
2737
  const result = {};
@@ -2737,6 +2755,33 @@ function* iterateItemIdsPositions(sheetId, itemIdsByZones) {
2737
2755
  }
2738
2756
  }
2739
2757
  }
2758
+ function getCanonicalRepresentation(item) {
2759
+ if (item === null)
2760
+ return "null";
2761
+ if (item === undefined)
2762
+ return "undefined";
2763
+ if (typeof item !== "object")
2764
+ return String(item);
2765
+ if (Array.isArray(item)) {
2766
+ const len = item.length;
2767
+ let result = "[";
2768
+ for (let i = 0; i < len; i++) {
2769
+ if (i > 0)
2770
+ result += ",";
2771
+ result += getCanonicalRepresentation(item[i]);
2772
+ }
2773
+ return result + "]";
2774
+ }
2775
+ const keys = Object.keys(item).sort();
2776
+ let repr = "{";
2777
+ for (const key of keys) {
2778
+ if (item[key] !== undefined) {
2779
+ repr += `"${key}":${getCanonicalRepresentation(item[key])},`;
2780
+ }
2781
+ }
2782
+ repr += "}";
2783
+ return repr;
2784
+ }
2740
2785
 
2741
2786
  // -----------------------------------------------------------------------------
2742
2787
  // Date Type
@@ -6240,11 +6285,13 @@ function getDefaultCellHeight(ctx, cell, colSize) {
6240
6285
  if (!cell || (!cell.isFormula && !cell.content)) {
6241
6286
  return DEFAULT_CELL_HEIGHT;
6242
6287
  }
6243
- const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
6244
- const numberOfLines = cell.isFormula
6245
- ? 1
6246
- : splitTextToWidth(ctx, cell.content, cell.style, maxWidth).length;
6247
- const fontSize = computeTextFontSizeInPixels(cell.style);
6288
+ const content = cell.isFormula ? "" : cell.content;
6289
+ return getCellContentHeight(ctx, content, cell.style, colSize);
6290
+ }
6291
+ function getCellContentHeight(ctx, content, style, colSize) {
6292
+ const maxWidth = style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
6293
+ const numberOfLines = splitTextToWidth(ctx, content, style, maxWidth).length;
6294
+ const fontSize = computeTextFontSizeInPixels(style);
6248
6295
  return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
6249
6296
  }
6250
6297
  function getDefaultContextFont(fontSize, bold = false, italic = false) {
@@ -8289,7 +8336,8 @@ function isSortedColumnValid(sortedColumn, pivot) {
8289
8336
  const possibleValues = pivot
8290
8337
  .getPossibleFieldValues(columns[i])
8291
8338
  .map((v) => v.value);
8292
- if (!possibleValues.includes(sortedColumn.domain[i].value)) {
8339
+ if (!possibleValues.includes(sortedColumn.domain[i].value) &&
8340
+ !(sortedColumn.domain[i].value === null && possibleValues.includes(""))) {
8293
8341
  return false;
8294
8342
  }
8295
8343
  }
@@ -8440,13 +8488,6 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8440
8488
  this.clearClippedZones(content);
8441
8489
  const selection = target[0];
8442
8490
  this.pasteZone(sheetId, selection.left, selection.top, content.cells, options);
8443
- this.dispatch("MOVE_RANGES", {
8444
- target: content.zones,
8445
- sheetId: content.sheetId,
8446
- targetSheetId: sheetId,
8447
- col: selection.left,
8448
- row: selection.top,
8449
- });
8450
8491
  }
8451
8492
  /**
8452
8493
  * Clear the clipped zones: remove the cells and clear the formatting
@@ -8955,14 +8996,15 @@ class MergeClipboardHandler extends AbstractCellClipboardHandler {
8955
8996
  }
8956
8997
  merges.push(mergesInRow);
8957
8998
  }
8958
- return { merges };
8999
+ return { merges, sheetId };
8959
9000
  }
8960
9001
  /**
8961
9002
  * Paste the clipboard content in the given target
8962
9003
  */
8963
9004
  paste(target, content, options) {
8964
9005
  if (options.isCutOperation) {
8965
- return;
9006
+ const copiedMerges = content.merges.flat().filter(isDefined);
9007
+ this.dispatch("REMOVE_MERGE", { sheetId: content.sheetId, target: copiedMerges });
8966
9008
  }
8967
9009
  this.pasteFromCopy(target.sheetId, target.zones, content.merges, options);
8968
9010
  }
@@ -8997,6 +9039,27 @@ class MergeClipboardHandler extends AbstractCellClipboardHandler {
8997
9039
  }
8998
9040
  }
8999
9041
 
9042
+ class ReferenceClipboardHandler extends AbstractCellClipboardHandler {
9043
+ copy(data) {
9044
+ return {
9045
+ zones: data.clippedZones,
9046
+ sheetId: data.sheetId,
9047
+ };
9048
+ }
9049
+ paste(target, content, options) {
9050
+ if (options.isCutOperation) {
9051
+ const selection = target.zones[0];
9052
+ this.dispatch("MOVE_RANGES", {
9053
+ target: content.zones,
9054
+ sheetId: content.sheetId,
9055
+ targetSheetId: target.sheetId,
9056
+ col: selection.left,
9057
+ row: selection.top,
9058
+ });
9059
+ }
9060
+ }
9061
+ }
9062
+
9000
9063
  class SheetClipboardHandler extends AbstractCellClipboardHandler {
9001
9064
  isPasteAllowed(sheetId, target, content, options) {
9002
9065
  if (!("cells" in content)) {
@@ -9160,7 +9223,8 @@ clipboardHandlersRegistries.cellHandlers
9160
9223
  .add("merge", MergeClipboardHandler)
9161
9224
  .add("border", BorderClipboardHandler)
9162
9225
  .add("table", TableClipboardHandler)
9163
- .add("conditionalFormat", ConditionalFormatClipboardHandler);
9226
+ .add("conditionalFormat", ConditionalFormatClipboardHandler)
9227
+ .add("references", ReferenceClipboardHandler);
9164
9228
 
9165
9229
  function transformZone(zone, executed) {
9166
9230
  if (executed.type === "REMOVE_COLUMNS_ROWS") {
@@ -11318,6 +11382,7 @@ class ScorecardChart extends Component {
11318
11382
  const autoCompleteProviders = new Registry();
11319
11383
 
11320
11384
  autoCompleteProviders.add("dataValidation", {
11385
+ displayAllOnInitialContent: true,
11321
11386
  getProposals(tokenAtCursor, content) {
11322
11387
  if (content.startsWith("=")) {
11323
11388
  return [];
@@ -21110,8 +21175,8 @@ class AbstractComposerStore extends SpreadsheetStore {
21110
21175
  this.computeParenthesisRelatedToCursor();
21111
21176
  }
21112
21177
  cancelEdition() {
21113
- this.cancelEditionAndActivateSheet();
21114
21178
  this.resetContent();
21179
+ this.cancelEditionAndActivateSheet();
21115
21180
  }
21116
21181
  setCurrentContent(content, selection) {
21117
21182
  if (selection && !this.isSelectionValid(content.length, selection.start, selection.end)) {
@@ -21129,8 +21194,8 @@ class AbstractComposerStore extends SpreadsheetStore {
21129
21194
  switch (cmd.type) {
21130
21195
  case "SELECT_FIGURE":
21131
21196
  if (cmd.id) {
21132
- this.cancelEditionAndActivateSheet();
21133
21197
  this.resetContent();
21198
+ this.cancelEditionAndActivateSheet();
21134
21199
  }
21135
21200
  break;
21136
21201
  case "START_CHANGE_HIGHLIGHT":
@@ -21614,6 +21679,15 @@ class AbstractComposerStore extends SpreadsheetStore {
21614
21679
  const exactMatch = proposals?.find((p) => p.text === tokenAtCursor.value);
21615
21680
  // remove tokens that are likely to be other parts of the formula that slipped in the token if it's a string
21616
21681
  const searchTerm = tokenAtCursor.value.replace(/[ ,\(\)]/g, "");
21682
+ if (this._currentContent === this.initialContent &&
21683
+ provider.displayAllOnInitialContent &&
21684
+ proposals?.length) {
21685
+ return {
21686
+ proposals,
21687
+ selectProposal: provider.selectProposal,
21688
+ autoSelectFirstProposal: provider.autoSelectFirstProposal ?? false,
21689
+ };
21690
+ }
21617
21691
  if (exactMatch && this._currentContent !== this.initialContent) {
21618
21692
  // this means the user has chosen a proposal
21619
21693
  return;
@@ -22437,7 +22511,7 @@ autoCompleteProviders.add("pivot_group_values", {
22437
22511
  text,
22438
22512
  description: usedLabel,
22439
22513
  htmlContent: [{ value: text, color }],
22440
- fuzzySearchKey: value + usedLabel,
22514
+ fuzzySearchKey: text + usedLabel,
22441
22515
  };
22442
22516
  });
22443
22517
  },
@@ -24359,16 +24433,25 @@ function addRelsToFile(relsFiles, path, rel) {
24359
24433
  }
24360
24434
  return id;
24361
24435
  }
24436
+ const globalReverseLookup = new WeakMap();
24362
24437
  function pushElement(property, propertyList) {
24363
- let len = propertyList.length;
24364
- const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
24365
- for (let i = 0; i < len; i++) {
24366
- if (operator(property, propertyList[i])) {
24367
- return i;
24438
+ let reverseLookup = globalReverseLookup.get(propertyList);
24439
+ if (!reverseLookup) {
24440
+ reverseLookup = new Map();
24441
+ for (let i = 0; i < propertyList.length; i++) {
24442
+ const canonical = getCanonicalRepresentation(propertyList[i]);
24443
+ reverseLookup.set(canonical, i);
24368
24444
  }
24445
+ globalReverseLookup.set(propertyList, reverseLookup);
24369
24446
  }
24370
- propertyList[propertyList.length] = property;
24371
- return propertyList.length - 1;
24447
+ const canonical = getCanonicalRepresentation(property);
24448
+ if (reverseLookup.has(canonical)) {
24449
+ return reverseLookup.get(canonical);
24450
+ }
24451
+ const maxId = propertyList.length;
24452
+ propertyList.push(property);
24453
+ reverseLookup.set(canonical, maxId);
24454
+ return maxId;
24372
24455
  }
24373
24456
  const chartIds = [];
24374
24457
  /**
@@ -26215,7 +26298,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
26215
26298
  title: { text: chartTitle },
26216
26299
  type: CHART_TYPE_CONVERSION_MAP[chartType],
26217
26300
  dataSets: this.extractChartDatasets(this.querySelectorAll(rootChartElement, `c:${chartType}`), chartType),
26218
- labelRange: this.extractChildTextContent(rootChartElement, `c:ser ${chartType === "scatterChart" ? "c:numRef" : "c:cat"} c:f`),
26301
+ labelRange: this.extractLabelRange(chartType, rootChartElement),
26219
26302
  backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
26220
26303
  default: "ffffff",
26221
26304
  }).asString(),
@@ -26227,6 +26310,13 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
26227
26310
  };
26228
26311
  })[0];
26229
26312
  }
26313
+ extractLabelRange(chartType, rootChartElement) {
26314
+ if (chartType === "scatterChart") {
26315
+ return (this.extractChildTextContent(rootChartElement, `c:ser c:strRef c:f`) ||
26316
+ this.extractChildTextContent(rootChartElement, `c:ser c:numRef c:f`));
26317
+ }
26318
+ return this.extractChildTextContent(rootChartElement, `c:ser c:cat c:f`);
26319
+ }
26230
26320
  extractComboChart(chartElement) {
26231
26321
  // Title can be separated into multiple xml elements (for styling and such), we only import the text
26232
26322
  const chartTitle = this.mapOnElements({ parent: chartElement, query: "c:title a:t" }, (textElement) => {
@@ -36399,6 +36489,7 @@ const irregularityMap = {
36399
36489
  fingerprintStore.enable();
36400
36490
  }
36401
36491
  },
36492
+ isReadonlyAllowed: true,
36402
36493
  icon: "o-spreadsheet-Icon.IRREGULARITY_MAP",
36403
36494
  };
36404
36495
  const viewFormulas = {
@@ -47097,6 +47188,7 @@ class RemoveDuplicatesPanel extends Component {
47097
47188
  columns: {},
47098
47189
  });
47099
47190
  setup() {
47191
+ this.updateColumns();
47100
47192
  onWillUpdateProps(() => this.updateColumns());
47101
47193
  }
47102
47194
  toggleHasHeader() {
@@ -48880,8 +48972,8 @@ class CellComposerStore extends AbstractComposerStore {
48880
48972
  const sheetIdExists = !!this.getters.tryGetSheet(this.sheetId);
48881
48973
  if (!sheetIdExists && this.editionMode !== "inactive") {
48882
48974
  this.sheetId = this.getters.getActiveSheetId();
48883
- this.cancelEditionAndActivateSheet();
48884
48975
  this.resetContent();
48976
+ this.cancelEditionAndActivateSheet();
48885
48977
  this.notificationStore.raiseError(CELL_DELETED_MESSAGE);
48886
48978
  }
48887
48979
  break;
@@ -50460,6 +50552,71 @@ class GridPopover extends Component {
50460
50552
  }
50461
50553
  }
50462
50554
 
50555
+ class UnhideRowHeaders extends Component {
50556
+ static template = "o-spreadsheet-UnhideRowHeaders";
50557
+ static props = {
50558
+ headersGroups: Array,
50559
+ headerRange: Object,
50560
+ offset: { type: Number, optional: true },
50561
+ };
50562
+ static defaultProps = { offset: 0 };
50563
+ get sheetId() {
50564
+ return this.env.model.getters.getActiveSheetId();
50565
+ }
50566
+ getUnhidePreviousButtonStyle(hiddenIndex) {
50567
+ const rect = this.env.model.getters.getRect(positionToZone({ col: 0, row: hiddenIndex }));
50568
+ const y = rect.y + rect.height - HEADER_HEIGHT;
50569
+ return cssPropertiesToCss({ top: y - this.props.offset + "px", "margin-right": "1px" });
50570
+ }
50571
+ getUnhideNextButtonStyle(hiddenIndex) {
50572
+ const rect = this.env.model.getters.getRect(positionToZone({ col: 0, row: hiddenIndex }));
50573
+ const y = rect.y - HEADER_HEIGHT;
50574
+ return cssPropertiesToCss({ top: y - this.props.offset + "px", "margin-right": "1px" });
50575
+ }
50576
+ unhide(hiddenElements) {
50577
+ this.env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
50578
+ sheetId: this.sheetId,
50579
+ dimension: "ROW",
50580
+ elements: hiddenElements,
50581
+ });
50582
+ }
50583
+ isVisible(header) {
50584
+ return header >= this.props.headerRange.start && header <= this.props.headerRange.end;
50585
+ }
50586
+ }
50587
+ class UnhideColumnHeaders extends Component {
50588
+ static template = "o-spreadsheet-UnhideColumnHeaders";
50589
+ static props = {
50590
+ headersGroups: Array,
50591
+ headerRange: Object,
50592
+ offset: { type: Number, optional: true },
50593
+ };
50594
+ static defaultProps = { offset: 0 };
50595
+ get sheetId() {
50596
+ return this.env.model.getters.getActiveSheetId();
50597
+ }
50598
+ getUnhidePreviousButtonStyle(hiddenIndex) {
50599
+ const rect = this.env.model.getters.getRect(positionToZone({ col: hiddenIndex, row: 0 }));
50600
+ const x = rect.x + rect.width - HEADER_WIDTH;
50601
+ return cssPropertiesToCss({ left: x - this.props.offset + "px" });
50602
+ }
50603
+ getUnhideNextButtonStyle(hiddenIndex) {
50604
+ const rect = this.env.model.getters.getRect(positionToZone({ col: hiddenIndex, row: 0 }));
50605
+ const x = rect.x - HEADER_WIDTH;
50606
+ return cssPropertiesToCss({ left: x - this.props.offset + "px" });
50607
+ }
50608
+ unhide(hiddenElements) {
50609
+ this.env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
50610
+ sheetId: this.sheetId,
50611
+ dimension: "COL",
50612
+ elements: hiddenElements,
50613
+ });
50614
+ }
50615
+ isVisible(header) {
50616
+ return header >= this.props.headerRange.start && header <= this.props.headerRange.end;
50617
+ }
50618
+ }
50619
+
50463
50620
  class AbstractResizer extends Component {
50464
50621
  static props = {
50465
50622
  onOpenContextMenu: Function,
@@ -50678,6 +50835,7 @@ css /* scss */ `
50678
50835
  left: ${HEADER_WIDTH}px;
50679
50836
  right: 0;
50680
50837
  height: ${HEADER_HEIGHT}px;
50838
+ width: calc(100% - ${HEADER_WIDTH + SCROLLBAR_WIDTH}px);
50681
50839
  &.o-dragging {
50682
50840
  cursor: grabbing;
50683
50841
  }
@@ -50727,6 +50885,7 @@ class ColResizer extends AbstractResizer {
50727
50885
  onOpenContextMenu: Function,
50728
50886
  };
50729
50887
  static template = "o-spreadsheet-ColResizer";
50888
+ static components = { UnhideColumnHeaders };
50730
50889
  colResizerRef;
50731
50890
  setup() {
50732
50891
  super.setup();
@@ -50735,6 +50894,9 @@ class ColResizer extends AbstractResizer {
50735
50894
  this.MAX_SIZE_MARGIN = 90;
50736
50895
  this.MIN_ELEMENT_SIZE = MIN_COL_WIDTH;
50737
50896
  }
50897
+ get sheetId() {
50898
+ return this.env.model.getters.getActiveSheetId();
50899
+ }
50738
50900
  _getEvOffset(ev) {
50739
50901
  return ev.offsetX;
50740
50902
  }
@@ -50757,10 +50919,10 @@ class ColResizer extends AbstractResizer {
50757
50919
  return this.env.model.getters.getEdgeScrollCol(position, position, position);
50758
50920
  }
50759
50921
  _getDimensionsInViewport(index) {
50760
- return this.env.model.getters.getColDimensionsInViewport(this.env.model.getters.getActiveSheetId(), index);
50922
+ return this.env.model.getters.getColDimensionsInViewport(this.sheetId, index);
50761
50923
  }
50762
50924
  _getElementSize(index) {
50763
- return this.env.model.getters.getColSize(this.env.model.getters.getActiveSheetId(), index);
50925
+ return this.env.model.getters.getColSize(this.sheetId, index);
50764
50926
  }
50765
50927
  _getMaxSize() {
50766
50928
  return this.colResizerRef.el.clientWidth;
@@ -50771,7 +50933,7 @@ class ColResizer extends AbstractResizer {
50771
50933
  const cols = this.env.model.getters.getActiveCols();
50772
50934
  this.env.model.dispatch("RESIZE_COLUMNS_ROWS", {
50773
50935
  dimension: "COL",
50774
- sheetId: this.env.model.getters.getActiveSheetId(),
50936
+ sheetId: this.sheetId,
50775
50937
  elements: cols.has(index) ? [...cols] : [index],
50776
50938
  size,
50777
50939
  });
@@ -50784,7 +50946,7 @@ class ColResizer extends AbstractResizer {
50784
50946
  elements.push(colIndex);
50785
50947
  }
50786
50948
  const result = this.env.model.dispatch("MOVE_COLUMNS_ROWS", {
50787
- sheetId: this.env.model.getters.getActiveSheetId(),
50949
+ sheetId: this.sheetId,
50788
50950
  dimension: "COL",
50789
50951
  base: this.state.base,
50790
50952
  elements,
@@ -50803,7 +50965,7 @@ class ColResizer extends AbstractResizer {
50803
50965
  _fitElementSize(index) {
50804
50966
  const cols = this.env.model.getters.getActiveCols();
50805
50967
  this.env.model.dispatch("AUTORESIZE_COLUMNS", {
50806
- sheetId: this.env.model.getters.getActiveSheetId(),
50968
+ sheetId: this.sheetId,
50807
50969
  cols: cols.has(index) ? [...cols] : [index],
50808
50970
  });
50809
50971
  }
@@ -50814,7 +50976,7 @@ class ColResizer extends AbstractResizer {
50814
50976
  return this.env.model.getters.getActiveCols();
50815
50977
  }
50816
50978
  _getPreviousVisibleElement(index) {
50817
- const sheetId = this.env.model.getters.getActiveSheetId();
50979
+ const sheetId = this.sheetId;
50818
50980
  let row;
50819
50981
  for (row = index - 1; row >= 0; row--) {
50820
50982
  if (!this.env.model.getters.isColHidden(sheetId, row)) {
@@ -50825,13 +50987,38 @@ class ColResizer extends AbstractResizer {
50825
50987
  }
50826
50988
  unhide(hiddenElements) {
50827
50989
  this.env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
50828
- sheetId: this.env.model.getters.getActiveSheetId(),
50990
+ sheetId: this.sheetId,
50829
50991
  elements: hiddenElements,
50830
50992
  dimension: "COL",
50831
50993
  });
50832
50994
  }
50833
- getUnhideButtonStyle(hiddenIndex) {
50834
- return cssPropertiesToCss({ left: this._getDimensionsInViewport(hiddenIndex).start + "px" });
50995
+ get mainUnhideHeadersProps() {
50996
+ const { left, right } = this.env.model.getters.getActiveMainViewport();
50997
+ const { xSplit } = this.env.model.getters.getPaneDivisions(this.sheetId);
50998
+ const hiddenGroups = this.env.model.getters.getHiddenColsGroups(this.sheetId);
50999
+ const index = hiddenGroups.findIndex((group) => group[0] >= xSplit - 1);
51000
+ return {
51001
+ headersGroups: hiddenGroups.slice(index),
51002
+ offset: this.env.model.getters.getMainViewportCoordinates().x,
51003
+ headerRange: { start: left, end: right },
51004
+ };
51005
+ }
51006
+ get frozenUnhideHeadersProps() {
51007
+ const { xSplit } = this.env.model.getters.getPaneDivisions(this.sheetId);
51008
+ const hiddenGroups = this.env.model.getters.getHiddenColsGroups(this.sheetId);
51009
+ const index = hiddenGroups.findIndex((group) => group[0] >= xSplit - 1);
51010
+ return {
51011
+ headersGroups: hiddenGroups.slice(0, index + 1),
51012
+ headerRange: { start: 0, end: xSplit - 1 },
51013
+ };
51014
+ }
51015
+ get frozenContainerStyle() {
51016
+ return cssPropertiesToCss({
51017
+ width: this.env.model.getters.getMainViewportCoordinates().x + "px",
51018
+ });
51019
+ }
51020
+ get hasFrozenPane() {
51021
+ return this.env.model.getters.getPaneDivisions(this.sheetId).xSplit > 0;
50835
51022
  }
50836
51023
  }
50837
51024
  css /* scss */ `
@@ -50841,7 +51028,7 @@ css /* scss */ `
50841
51028
  left: 0;
50842
51029
  right: 0;
50843
51030
  width: ${HEADER_WIDTH}px;
50844
- height: 100%;
51031
+ height: calc(100% - ${HEADER_HEIGHT + SCROLLBAR_WIDTH}px);
50845
51032
  &.o-dragging {
50846
51033
  cursor: grabbing;
50847
51034
  }
@@ -50891,6 +51078,7 @@ class RowResizer extends AbstractResizer {
50891
51078
  onOpenContextMenu: Function,
50892
51079
  };
50893
51080
  static template = "o-spreadsheet-RowResizer";
51081
+ static components = { UnhideRowHeaders };
50894
51082
  setup() {
50895
51083
  super.setup();
50896
51084
  this.rowResizerRef = useRef("rowResizer");
@@ -50899,6 +51087,9 @@ class RowResizer extends AbstractResizer {
50899
51087
  this.MIN_ELEMENT_SIZE = MIN_ROW_HEIGHT;
50900
51088
  }
50901
51089
  rowResizerRef;
51090
+ get sheetId() {
51091
+ return this.env.model.getters.getActiveSheetId();
51092
+ }
50902
51093
  _getEvOffset(ev) {
50903
51094
  return ev.offsetY;
50904
51095
  }
@@ -50921,10 +51112,10 @@ class RowResizer extends AbstractResizer {
50921
51112
  return this.env.model.getters.getEdgeScrollRow(position, position, position);
50922
51113
  }
50923
51114
  _getDimensionsInViewport(index) {
50924
- return this.env.model.getters.getRowDimensionsInViewport(this.env.model.getters.getActiveSheetId(), index);
51115
+ return this.env.model.getters.getRowDimensionsInViewport(this.sheetId, index);
50925
51116
  }
50926
51117
  _getElementSize(index) {
50927
- return this.env.model.getters.getRowSize(this.env.model.getters.getActiveSheetId(), index);
51118
+ return this.env.model.getters.getRowSize(this.sheetId, index);
50928
51119
  }
50929
51120
  _getMaxSize() {
50930
51121
  return this.rowResizerRef.el.clientHeight;
@@ -50935,7 +51126,7 @@ class RowResizer extends AbstractResizer {
50935
51126
  const rows = this.env.model.getters.getActiveRows();
50936
51127
  this.env.model.dispatch("RESIZE_COLUMNS_ROWS", {
50937
51128
  dimension: "ROW",
50938
- sheetId: this.env.model.getters.getActiveSheetId(),
51129
+ sheetId: this.sheetId,
50939
51130
  elements: rows.has(index) ? [...rows] : [index],
50940
51131
  size,
50941
51132
  });
@@ -50948,7 +51139,7 @@ class RowResizer extends AbstractResizer {
50948
51139
  elements.push(rowIndex);
50949
51140
  }
50950
51141
  const result = this.env.model.dispatch("MOVE_COLUMNS_ROWS", {
50951
- sheetId: this.env.model.getters.getActiveSheetId(),
51142
+ sheetId: this.sheetId,
50952
51143
  dimension: "ROW",
50953
51144
  base: this.state.base,
50954
51145
  elements,
@@ -50967,7 +51158,7 @@ class RowResizer extends AbstractResizer {
50967
51158
  _fitElementSize(index) {
50968
51159
  const rows = this.env.model.getters.getActiveRows();
50969
51160
  this.env.model.dispatch("AUTORESIZE_ROWS", {
50970
- sheetId: this.env.model.getters.getActiveSheetId(),
51161
+ sheetId: this.sheetId,
50971
51162
  rows: rows.has(index) ? [...rows] : [index],
50972
51163
  });
50973
51164
  }
@@ -50978,7 +51169,7 @@ class RowResizer extends AbstractResizer {
50978
51169
  return this.env.model.getters.getActiveRows();
50979
51170
  }
50980
51171
  _getPreviousVisibleElement(index) {
50981
- const sheetId = this.env.model.getters.getActiveSheetId();
51172
+ const sheetId = this.sheetId;
50982
51173
  let row;
50983
51174
  for (row = index - 1; row >= 0; row--) {
50984
51175
  if (!this.env.model.getters.isRowHidden(sheetId, row)) {
@@ -50987,15 +51178,33 @@ class RowResizer extends AbstractResizer {
50987
51178
  }
50988
51179
  return row;
50989
51180
  }
50990
- unhide(hiddenElements) {
50991
- this.env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
50992
- sheetId: this.env.model.getters.getActiveSheetId(),
50993
- dimension: "ROW",
50994
- elements: hiddenElements,
51181
+ get mainUnhideHeadersProps() {
51182
+ const { top, bottom } = this.env.model.getters.getActiveMainViewport();
51183
+ const { ySplit } = this.env.model.getters.getPaneDivisions(this.sheetId);
51184
+ const hiddenGroups = this.env.model.getters.getHiddenRowsGroups(this.sheetId);
51185
+ const index = hiddenGroups.findIndex((group) => group[0] >= ySplit - 1);
51186
+ return {
51187
+ headersGroups: hiddenGroups.slice(index),
51188
+ offset: this.env.model.getters.getMainViewportCoordinates().y,
51189
+ headerRange: { start: top, end: bottom },
51190
+ };
51191
+ }
51192
+ get frozenUnhideHeadersProps() {
51193
+ const { ySplit } = this.env.model.getters.getPaneDivisions(this.sheetId);
51194
+ const hiddenGroups = this.env.model.getters.getHiddenRowsGroups(this.sheetId);
51195
+ const index = hiddenGroups.findIndex((group) => group[0] >= ySplit - 1);
51196
+ return {
51197
+ headersGroups: hiddenGroups.slice(0, index + 1),
51198
+ headerRange: { start: 0, end: ySplit - 1 },
51199
+ };
51200
+ }
51201
+ get frozenContainerStyle() {
51202
+ return cssPropertiesToCss({
51203
+ height: this.env.model.getters.getMainViewportCoordinates().y + "px",
50995
51204
  });
50996
51205
  }
50997
- getUnhideButtonStyle(hiddenIndex) {
50998
- return cssPropertiesToCss({ top: this._getDimensionsInViewport(hiddenIndex).start + "px" });
51206
+ get hasFrozenPane() {
51207
+ return this.env.model.getters.getPaneDivisions(this.sheetId).ySplit > 0;
50999
51208
  }
51000
51209
  }
51001
51210
  css /* scss */ `
@@ -65192,12 +65401,7 @@ class SheetUIPlugin extends UIPlugin {
65192
65401
  }
65193
65402
  break;
65194
65403
  case "AUTORESIZE_ROWS":
65195
- this.dispatch("RESIZE_COLUMNS_ROWS", {
65196
- elements: cmd.rows,
65197
- dimension: "ROW",
65198
- size: null,
65199
- sheetId: cmd.sheetId,
65200
- });
65404
+ this.autoResizeRows(cmd.sheetId, cmd.rows);
65201
65405
  break;
65202
65406
  }
65203
65407
  }
@@ -65361,6 +65565,48 @@ class SheetUIPlugin extends UIPlugin {
65361
65565
  }
65362
65566
  return "Success" /* CommandResult.Success */;
65363
65567
  }
65568
+ autoResizeRows(sheetId, rows) {
65569
+ const rowSizes = [];
65570
+ for (const row of rows) {
65571
+ let evaluatedRowSize = 0;
65572
+ for (const cellId of this.getters.getRowCells(sheetId, row)) {
65573
+ const cell = this.getters.getCellById(cellId);
65574
+ if (!cell) {
65575
+ continue;
65576
+ }
65577
+ const position = this.getters.getCellPosition(cell.id);
65578
+ const colSize = this.getters.getColSize(sheetId, position.col);
65579
+ if (cell.isFormula) {
65580
+ const content = this.getters.getEvaluatedCell(position).formattedValue;
65581
+ const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
65582
+ if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
65583
+ evaluatedRowSize = evaluatedSize;
65584
+ }
65585
+ }
65586
+ else {
65587
+ const content = cell.content;
65588
+ const dynamicRowSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
65589
+ // Only keep the size of evaluated cells if it's bigger than the dynamic row size
65590
+ if (dynamicRowSize >= evaluatedRowSize && dynamicRowSize > DEFAULT_CELL_HEIGHT) {
65591
+ evaluatedRowSize = 0;
65592
+ }
65593
+ }
65594
+ }
65595
+ rowSizes.push(evaluatedRowSize || null);
65596
+ }
65597
+ const groupedSizes = new Map(rowSizes.map((size) => [size, []]));
65598
+ for (let i = 0; i < rowSizes.length; i++) {
65599
+ groupedSizes.get(rowSizes[i])?.push(rows[i]);
65600
+ }
65601
+ for (const [size, rows] of groupedSizes) {
65602
+ this.dispatch("RESIZE_COLUMNS_ROWS", {
65603
+ elements: rows,
65604
+ dimension: "ROW",
65605
+ size,
65606
+ sheetId,
65607
+ });
65608
+ }
65609
+ }
65364
65610
  }
65365
65611
 
65366
65612
  class TableComputedStylePlugin extends UIPlugin {
@@ -67765,7 +68011,7 @@ class InternalViewport {
67765
68011
  *
67766
68012
  */
67767
68013
  getFullRect(zone) {
67768
- const targetZone = intersection(zone, this);
68014
+ const targetZone = intersection(zone, this.boundaries);
67769
68015
  const scrollDeltaX = this.snapCorrection.x;
67770
68016
  const scrollDeltaY = this.snapCorrection.y;
67771
68017
  if (targetZone) {
@@ -68233,7 +68479,8 @@ class SheetViewPlugin extends UIPlugin {
68233
68479
  ? this.getters.getSheetViewVisibleCols()
68234
68480
  : this.getters.getSheetViewVisibleRows();
68235
68481
  const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
68236
- const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
68482
+ let endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
68483
+ endIndex = endIndex === -1 ? visibleHeaders.length : endIndex;
68237
68484
  const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
68238
68485
  let offset = 0;
68239
68486
  for (const i of relevantIndexes) {
@@ -68358,11 +68605,12 @@ class SheetViewPlugin extends UIPlugin {
68358
68605
  * column of the current viewport
68359
68606
  */
68360
68607
  getColDimensionsInViewport(sheetId, col) {
68608
+ const { top } = this.getMainInternalViewport(sheetId);
68361
68609
  const zone = {
68362
68610
  left: col,
68363
68611
  right: col,
68364
- top: 0,
68365
- bottom: this.getters.getNumberRows(sheetId) - 1,
68612
+ top: top,
68613
+ bottom: top,
68366
68614
  };
68367
68615
  const { x, width } = this.getVisibleRect(zone);
68368
68616
  const start = x - this.gridOffsetX;
@@ -68373,9 +68621,10 @@ class SheetViewPlugin extends UIPlugin {
68373
68621
  * of the current viewport
68374
68622
  */
68375
68623
  getRowDimensionsInViewport(sheetId, row) {
68624
+ const { left } = this.getMainInternalViewport(sheetId);
68376
68625
  const zone = {
68377
68626
  left: 0,
68378
- right: this.getters.getNumberCols(sheetId) - 1,
68627
+ right: left,
68379
68628
  top: row,
68380
68629
  bottom: row,
68381
68630
  };
@@ -74327,7 +74576,7 @@ function addStyles(styles) {
74327
74576
  }
74328
74577
  if (alignAttrs.length > 0) {
74329
74578
  attributes.push(["applyAlignment", "1"]); // for Libre Office
74330
- styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}>${escapeXml /*xml*/ `<alignment ${formatAttributes(alignAttrs)} />`}</xf> `);
74579
+ styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}><alignment ${formatAttributes(alignAttrs)} /></xf> `);
74331
74580
  }
74332
74581
  else {
74333
74582
  styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)} />`);
@@ -74495,6 +74744,9 @@ function addColumns(cols) {
74495
74744
  }
74496
74745
  function addRows(construct, data, sheet) {
74497
74746
  const rowNodes = [];
74747
+ const styles = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.styles));
74748
+ const borders = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.borders));
74749
+ const formats = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.formats));
74498
74750
  for (let r = 0; r < sheet.rowNumber; r++) {
74499
74751
  const rowAttrs = [["r", r + 1]];
74500
74752
  const row = sheet.rows[r] || {};
@@ -74510,9 +74762,6 @@ function addRows(construct, data, sheet) {
74510
74762
  if (row.collapsed) {
74511
74763
  rowAttrs.push(["collapsed", 1]);
74512
74764
  }
74513
- const styles = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.styles));
74514
- const borders = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.borders));
74515
- const formats = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.formats));
74516
74765
  const cellNodes = [];
74517
74766
  for (let c = 0; c < sheet.colNumber; c++) {
74518
74767
  const xc = toXC(c, r);
@@ -75772,6 +76021,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
75772
76021
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, 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 };
75773
76022
 
75774
76023
 
75775
- __info__.version = "18.2.2";
75776
- __info__.date = "2025-03-07T10:41:04.411Z";
75777
- __info__.hash = "f567932";
76024
+ __info__.version = "18.2.4";
76025
+ __info__.date = "2025-03-19T08:20:57.717Z";
76026
+ __info__.hash = "958936a";