@odoo/o-spreadsheet 18.2.27 → 18.2.29

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.27
6
- * @date 2025-08-26T10:07:14.516Z
7
- * @hash fbf9445
5
+ * @version 18.2.29
6
+ * @date 2025-09-11T08:44:31.801Z
7
+ * @hash 665bc43
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';
@@ -3476,6 +3476,7 @@ const invalidateBordersCommands = new Set([
3476
3476
  "AUTOFILL_CELL",
3477
3477
  "SET_BORDER",
3478
3478
  "SET_ZONE_BORDERS",
3479
+ "SET_BORDERS_ON_TARGET",
3479
3480
  ]);
3480
3481
  const readonlyAllowedCommands = new Set([
3481
3482
  "START",
@@ -6902,7 +6903,7 @@ class ClipboardHandler {
6902
6903
  this.getters = getters;
6903
6904
  this.dispatch = dispatch;
6904
6905
  }
6905
- copy(data) {
6906
+ copy(data, mode = "copyPaste") {
6906
6907
  return;
6907
6908
  }
6908
6909
  paste(target, clippedContent, options) { }
@@ -6921,7 +6922,7 @@ class ClipboardHandler {
6921
6922
  }
6922
6923
 
6923
6924
  class AbstractCellClipboardHandler extends ClipboardHandler {
6924
- copy(data) {
6925
+ copy(data, mode = "copyPaste") {
6925
6926
  return;
6926
6927
  }
6927
6928
  pasteFromCopy(sheetId, target, content, options) {
@@ -7526,8 +7527,11 @@ function invertMatrix(M) {
7526
7527
  // (a) Swap 2 rows. This multiply the determinant by -1.
7527
7528
  // (b) Multiply a row by a scalar. This multiply the determinant by that scalar.
7528
7529
  // (c) Add to a row a multiple of another row. This does not change the determinant.
7530
+ if (M.length < 1 || M[0].length < 1) {
7531
+ throw new Error("invertMatrix: an empty matrix cannot be inverted.");
7532
+ }
7529
7533
  if (M.length !== M[0].length) {
7530
- throw new EvaluationError(_t("Function [[FUNCTION_NAME]] invert matrix error, only square matrices are invertible"));
7534
+ throw new Error("invertMatrix: only square matrices are invertible");
7531
7535
  }
7532
7536
  let determinant = 1;
7533
7537
  const dim = M.length;
@@ -7596,8 +7600,11 @@ function swapMatrixRows(matrix, row1, row2) {
7596
7600
  * Note: we use indexing [col][row] instead of the standard mathematical notation [row][col]
7597
7601
  */
7598
7602
  function multiplyMatrices(matrix1, matrix2) {
7603
+ if (matrix1.length < 1 || matrix2.length < 1) {
7604
+ throw new Error("multiplyMatrices: empty matrices cannot be multiplied.");
7605
+ }
7599
7606
  if (matrix1.length !== matrix2[0].length) {
7600
- throw new EvaluationError(_t("Cannot multiply matrices : incompatible matrices size."));
7607
+ throw new Error("multiplyMatrices: incompatible matrices size.");
7601
7608
  }
7602
7609
  const rowsM1 = matrix1[0].length;
7603
7610
  const colsM2 = matrix2.length;
@@ -7623,7 +7630,7 @@ function toScalar(arg) {
7623
7630
  return arg;
7624
7631
  }
7625
7632
  if (!isSingleElementMatrix(arg)) {
7626
- throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
7633
+ throw new Error("The value should be a scalar or a 1x1 matrix");
7627
7634
  }
7628
7635
  return arg[0][0];
7629
7636
  }
@@ -7860,6 +7867,16 @@ function getMovingAverageValues(dataset, labels, windowSize = DEFAULT_WINDOW_SIZ
7860
7867
  }
7861
7868
  return values;
7862
7869
  }
7870
+ function assertNonEmptyMatrix(matrix, argName) {
7871
+ assert(() => matrix.length > 0 && matrix[0].length > 0, _t("[[FUNCTION_NAME]] expects the provided values of %(argName)s to be a non-empty matrix.", {
7872
+ argName,
7873
+ }));
7874
+ }
7875
+ function assertNonEmpty(...data) {
7876
+ if (data.length === 0 || data.some((arg) => arg.length === 0)) {
7877
+ throw new NotAvailableError(_t("[[FUNCTION_NAME]] has no valid input data."));
7878
+ }
7879
+ }
7863
7880
 
7864
7881
  const PREVIOUS_VALUE = "(previous)";
7865
7882
  const NEXT_VALUE = "(next)";
@@ -8622,7 +8639,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8622
8639
  }
8623
8640
  return "Success" /* CommandResult.Success */;
8624
8641
  }
8625
- copy(data) {
8642
+ copy(data, mode = "copyPaste") {
8626
8643
  const sheetId = data.sheetId;
8627
8644
  const { clippedZones, rowsIndexes, columnsIndexes } = data;
8628
8645
  const clippedCells = [];
@@ -8635,7 +8652,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8635
8652
  const evaluatedCell = this.getters.getEvaluatedCell(position);
8636
8653
  const pivotId = this.getters.getPivotIdFromPosition(position);
8637
8654
  const spreader = this.getters.getArrayFormulaSpreadingOn(position);
8638
- if (pivotId && spreader) {
8655
+ if (mode !== "shiftCells" && pivotId && spreader) {
8639
8656
  const pivotZone = this.getters.getSpreadZone(spreader);
8640
8657
  if ((!deepEquals(spreader, position) || !isCopyingOneCell) &&
8641
8658
  pivotZone &&
@@ -8653,7 +8670,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8653
8670
  };
8654
8671
  }
8655
8672
  }
8656
- else {
8673
+ else if (mode !== "shiftCells") {
8657
8674
  if (spreader && !deepEquals(spreader, position)) {
8658
8675
  const isSpreaderCopied = rowsIndexes.includes(spreader.row) && columnsIndexes.includes(spreader.col);
8659
8676
  const content = isSpreaderCopied
@@ -9346,7 +9363,7 @@ class SheetClipboardHandler extends AbstractCellClipboardHandler {
9346
9363
  }
9347
9364
 
9348
9365
  class TableClipboardHandler extends AbstractCellClipboardHandler {
9349
- copy(data) {
9366
+ copy(data, mode = "copyPaste") {
9350
9367
  const sheetId = data.sheetId;
9351
9368
  const { rowsIndexes, columnsIndexes, zones } = data;
9352
9369
  const copiedTablesIds = new Set();
@@ -9376,11 +9393,13 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
9376
9393
  type: coreTable.type,
9377
9394
  };
9378
9395
  }
9379
- tableCellsInRow.push({
9380
- table: copiedTable,
9381
- style: this.getTableStyleToCopy(position),
9382
- isWholeTableCopied: copiedTablesIds.has(table.id),
9383
- });
9396
+ if (mode !== "shiftCells") {
9397
+ tableCellsInRow.push({
9398
+ table: copiedTable,
9399
+ style: this.getTableStyleToCopy(position),
9400
+ isWholeTableCopied: copiedTablesIds.has(table.id),
9401
+ });
9402
+ }
9384
9403
  }
9385
9404
  }
9386
9405
  return {
@@ -11797,6 +11816,7 @@ const MMULT = {
11797
11816
  compute: function (matrix1, matrix2) {
11798
11817
  const _matrix1 = toNumberMatrix(matrix1, "matrix1");
11799
11818
  const _matrix2 = toNumberMatrix(matrix2, "matrix2");
11819
+ assert(() => _matrix1.length > 0 && _matrix2.length > 0, _t("The first and second arguments of [[FUNCTION_NAME]] must be non-empty matrices."));
11800
11820
  assert(() => _matrix1.length === _matrix2[0].length, _t("In [[FUNCTION_NAME]], the number of columns of the first matrix (%s) must be equal to the \
11801
11821
  number of rows of the second matrix (%s).", _matrix1.length.toString(), _matrix2[0].length.toString()));
11802
11822
  return multiplyMatrices(_matrix1, _matrix2);
@@ -13592,6 +13612,7 @@ const FORECAST = {
13592
13612
  ],
13593
13613
  compute: function (x, dataY, dataX) {
13594
13614
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13615
+ assertNonEmpty(flatDataX, flatDataY);
13595
13616
  return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
13596
13617
  },
13597
13618
  isExported: true,
@@ -13608,6 +13629,7 @@ const GROWTH = {
13608
13629
  arg("b (boolean, default=TRUE)", _t("Given a general exponential form of y = b*m^x for a curve fit, calculates b if TRUE or forces b to be 1 and only calculates the m values if FALSE.")),
13609
13630
  ],
13610
13631
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13632
+ assertNonEmptyMatrix(knownDataY, "known_data_y");
13611
13633
  return expM(predictLinearValues(logM(toNumberMatrix(knownDataY, "the first argument (known_data_y)")), toNumberMatrix(knownDataX, "the second argument (known_data_x)"), toNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b)));
13612
13634
  },
13613
13635
  };
@@ -13622,6 +13644,7 @@ const INTERCEPT = {
13622
13644
  ],
13623
13645
  compute: function (dataY, dataX) {
13624
13646
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13647
+ assertNonEmpty(flatDataX, flatDataY);
13625
13648
  const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
13626
13649
  return intercept;
13627
13650
  },
@@ -13671,6 +13694,7 @@ const LINEST = {
13671
13694
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13672
13695
  ],
13673
13696
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13697
+ assertNonEmptyMatrix(dataY, "data_y");
13674
13698
  return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13675
13699
  },
13676
13700
  isExported: true,
@@ -13687,6 +13711,7 @@ const LOGEST = {
13687
13711
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13688
13712
  ],
13689
13713
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13714
+ assertNonEmptyMatrix(dataY, "data_y");
13690
13715
  const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13691
13716
  for (let i = 0; i < coeffs.length; i++) {
13692
13717
  coeffs[i][0] = Math.exp(coeffs[i][0]);
@@ -13708,9 +13733,7 @@ const MATTHEWS = {
13708
13733
  const flatX = dataX.flat();
13709
13734
  const flatY = dataY.flat();
13710
13735
  assertSameNumberOfElements(flatX, flatY);
13711
- if (flatX.length === 0) {
13712
- return new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
13713
- }
13736
+ assertNonEmpty(flatX, flatY);
13714
13737
  const n = flatX.length;
13715
13738
  let trueN = 0, trueP = 0, falseP = 0, falseN = 0;
13716
13739
  for (let i = 0; i < n; ++i) {
@@ -13874,12 +13897,7 @@ const MINIFS = {
13874
13897
  // -----------------------------------------------------------------------------
13875
13898
  function pearson(dataY, dataX) {
13876
13899
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13877
- if (flatDataX.length === 0) {
13878
- throw new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
13879
- }
13880
- if (flatDataX.length < 2) {
13881
- throw new EvaluationError(_t("[[FUNCTION_NAME]] needs at least two values for both parameters."));
13882
- }
13900
+ assertNonEmpty(flatDataX, flatDataY);
13883
13901
  const n = flatDataX.length;
13884
13902
  let sumX = 0, sumY = 0, sumXY = 0, sumXX = 0, sumYY = 0;
13885
13903
  for (let i = 0; i < n; i++) {
@@ -13968,6 +13986,7 @@ const POLYFIT_COEFFS = {
13968
13986
  ],
13969
13987
  compute: function (dataY, dataX, order, intercept = { value: true }) {
13970
13988
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13989
+ assertNonEmpty(flatDataX, flatDataY);
13971
13990
  return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
13972
13991
  },
13973
13992
  isExported: false,
@@ -13987,6 +14006,7 @@ const POLYFIT_FORECAST = {
13987
14006
  compute: function (x, dataY, dataX, order, intercept = { value: true }) {
13988
14007
  const _order = toNumber(order, this.locale);
13989
14008
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14009
+ assertNonEmpty(flatDataX, flatDataY);
13990
14010
  const coeffs = polynomialRegression(flatDataY, flatDataX, _order, toBoolean(intercept)).flat();
13991
14011
  return matrixMap(toMatrix(x), (xij) => evaluatePolynomial(coeffs, toNumber(xij, this.locale), _order));
13992
14012
  },
@@ -14103,6 +14123,7 @@ const SLOPE = {
14103
14123
  ],
14104
14124
  compute: function (dataY, dataX) {
14105
14125
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14126
+ assertNonEmpty(flatDataX, flatDataY);
14106
14127
  const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
14107
14128
  return slope;
14108
14129
  },
@@ -14151,6 +14172,7 @@ const SPEARMAN = {
14151
14172
  ],
14152
14173
  compute: function (dataX, dataY) {
14153
14174
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14175
+ assertNonEmpty(flatDataX, flatDataY);
14154
14176
  const n = flatDataX.length;
14155
14177
  const order = flatDataX.map((e, i) => [e, flatDataY[i]]);
14156
14178
  order.sort((a, b) => a[0] - b[0]);
@@ -14261,6 +14283,7 @@ const STEYX = {
14261
14283
  ],
14262
14284
  compute: function (dataY, dataX) {
14263
14285
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14286
+ assertNonEmpty(flatDataX, flatDataY);
14264
14287
  const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
14265
14288
  return data[1][2];
14266
14289
  },
@@ -14278,6 +14301,7 @@ const TREND = {
14278
14301
  arg("b (boolean, optional, default=TRUE)", _t("Given a general linear form of y = m*x+b for a curve fit, calculates b if TRUE or forces b to be 0 and only calculates the m values if FALSE, i.e. forces the curve fit to pass through the origin.")),
14279
14302
  ],
14280
14303
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
14304
+ assertNonEmptyMatrix(knownDataY, "known_data_y");
14281
14305
  return predictLinearValues(toNumberMatrix(knownDataY, "the first argument (known_data_y)"), toNumberMatrix(knownDataX, "the second argument (known_data_x)"), toNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b));
14282
14306
  },
14283
14307
  };
@@ -23771,7 +23795,7 @@ const SUPPORTED_HORIZONTAL_ALIGNMENTS = [
23771
23795
  ];
23772
23796
  const SUPPORTED_VERTICAL_ALIGNMENTS = ["top", "center", "bottom"];
23773
23797
  const SUPPORTED_FONTS = ["Arial"];
23774
- const SUPPORTED_FILL_PATTERNS = ["solid"];
23798
+ const SUPPORTED_FILL_PATTERNS = ["solid", "none"];
23775
23799
  const SUPPORTED_CF_TYPES = [
23776
23800
  "expression",
23777
23801
  "cellIs",
@@ -23956,7 +23980,7 @@ const SUBTOTAL_FUNCTION_CONVERSION_MAP = {
23956
23980
  };
23957
23981
  /** Mapping between Excel format indexes (see XLSX_FORMAT_MAP) and some supported formats */
23958
23982
  const XLSX_FORMATS_CONVERSION_MAP = {
23959
- 0: "",
23983
+ 0: "General",
23960
23984
  1: "0",
23961
23985
  2: "0.00",
23962
23986
  3: "#,#00",
@@ -24282,11 +24306,11 @@ const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/
24282
24306
  * Excel format are defined in openXML §18.8.31
24283
24307
  */
24284
24308
  function convertXlsxFormat(numFmtId, formats, warningManager) {
24285
- if (numFmtId === 0) {
24286
- return undefined;
24287
- }
24288
24309
  // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
24289
24310
  let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || formats.find((f) => f.id === numFmtId)?.format;
24311
+ if (format === "General") {
24312
+ return undefined;
24313
+ }
24290
24314
  if (format) {
24291
24315
  try {
24292
24316
  let convertedFormat = format.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
@@ -24484,9 +24508,9 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
24484
24508
  if (!rule.operator || !rule.formula || rule.formula.length === 0)
24485
24509
  continue;
24486
24510
  operator = convertCFCellIsOperator(rule.operator);
24487
- values.push(rule.formula[0]);
24511
+ values.push(prefixFormula(rule.formula[0]));
24488
24512
  if (rule.formula.length === 2) {
24489
- values.push(rule.formula[1]);
24513
+ values.push(prefixFormula(rule.formula[1]));
24490
24514
  }
24491
24515
  break;
24492
24516
  }
@@ -24644,6 +24668,11 @@ function convertIcons(xlsxIconSet, index) {
24644
24668
  ? ICON_SETS[iconSet].neutral
24645
24669
  : ICON_SETS[iconSet].good;
24646
24670
  }
24671
+ /** Prefix the string by "=" if the string looks like a formula */
24672
+ function prefixFormula(formula) {
24673
+ const tokens = tokenize(formula);
24674
+ return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
24675
+ }
24647
24676
  // ---------------------------------------------------------------------------
24648
24677
  // Warnings
24649
24678
  // ---------------------------------------------------------------------------
@@ -27242,10 +27271,11 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
27242
27271
  });
27243
27272
  }
27244
27273
  extractRows(worksheet) {
27274
+ const spilledCells = new Set();
27245
27275
  return this.mapOnElements({ parent: worksheet, query: "sheetData row" }, (rowElement) => {
27246
27276
  return {
27247
27277
  index: this.extractAttr(rowElement, "r", { required: true })?.asNum(),
27248
- cells: this.extractCells(rowElement),
27278
+ cells: this.extractCells(rowElement, spilledCells),
27249
27279
  height: this.extractAttr(rowElement, "ht")?.asNum(),
27250
27280
  customHeight: this.extractAttr(rowElement, "customHeight")?.asBool(),
27251
27281
  hidden: this.extractAttr(rowElement, "hidden")?.asBool(),
@@ -27255,14 +27285,26 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
27255
27285
  };
27256
27286
  });
27257
27287
  }
27258
- extractCells(row) {
27288
+ extractCells(row, spilledCells) {
27259
27289
  return this.mapOnElements({ parent: row, query: "c" }, (cellElement) => {
27290
+ const xc = this.extractAttr(cellElement, "r", { required: true })?.asString();
27291
+ const formula = this.extractCellFormula(cellElement);
27292
+ if (formula?.ref && formula.sharedIndex === undefined) {
27293
+ const zone = toZone(formula.ref);
27294
+ for (const { col, row } of positions(zone)) {
27295
+ const followerXc = toXC(col, row);
27296
+ if (followerXc !== xc) {
27297
+ spilledCells.add(followerXc);
27298
+ }
27299
+ }
27300
+ }
27301
+ const isSpilled = spilledCells.has(xc);
27260
27302
  return {
27261
- xc: this.extractAttr(cellElement, "r", { required: true })?.asString(),
27303
+ xc,
27262
27304
  styleIndex: this.extractAttr(cellElement, "s")?.asNum(),
27263
27305
  type: CELL_TYPE_CONVERSION_MAP[this.extractAttr(cellElement, "t", { default: "n" })?.asString()],
27264
- value: this.extractChildTextContent(cellElement, "v"),
27265
- formula: this.extractCellFormula(cellElement),
27306
+ value: isSpilled ? undefined : this.extractChildTextContent(cellElement, "v") ?? undefined,
27307
+ formula: isSpilled ? undefined : formula,
27266
27308
  };
27267
27309
  });
27268
27310
  }
@@ -27270,11 +27312,14 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
27270
27312
  const formulaElement = this.querySelector(cellElement, "f");
27271
27313
  if (!formulaElement)
27272
27314
  return undefined;
27273
- return {
27274
- content: this.extractTextContent(formulaElement),
27275
- sharedIndex: this.extractAttr(formulaElement, "si")?.asNum(),
27276
- ref: this.extractAttr(formulaElement, "ref")?.asString(),
27277
- };
27315
+ const content = this.extractTextContent(formulaElement);
27316
+ const sharedIndex = this.extractAttr(formulaElement, "si")?.asNum();
27317
+ const ref = this.extractAttr(formulaElement, "ref")?.asString();
27318
+ // This is the case of spilled cells of array formulas where <f> is empty
27319
+ if ((content === undefined || content.trim() === "") && sharedIndex === undefined) {
27320
+ return undefined;
27321
+ }
27322
+ return { content, sharedIndex, ref };
27278
27323
  }
27279
27324
  extractHyperLinks(worksheet) {
27280
27325
  return this.mapOnElements({ parent: worksheet, query: "hyperlink" }, (linkElement) => {
@@ -36168,7 +36213,7 @@ const splitToColumns = {
36168
36213
  const reinsertDynamicPivotMenu = {
36169
36214
  id: "reinsert_dynamic_pivot",
36170
36215
  name: _t("Re-insert dynamic pivot"),
36171
- sequence: 1020,
36216
+ sequence: 60,
36172
36217
  icon: "o-spreadsheet-Icon.INSERT_PIVOT",
36173
36218
  children: [REINSERT_DYNAMIC_PIVOT_CHILDREN],
36174
36219
  isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
@@ -36176,7 +36221,7 @@ const reinsertDynamicPivotMenu = {
36176
36221
  const reinsertStaticPivotMenu = {
36177
36222
  id: "reinsert_static_pivot",
36178
36223
  name: _t("Re-insert static pivot"),
36179
- sequence: 1020,
36224
+ sequence: 70,
36180
36225
  icon: "o-spreadsheet-Icon.INSERT_PIVOT",
36181
36226
  children: [REINSERT_STATIC_PIVOT_CHILDREN],
36182
36227
  isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
@@ -37914,8 +37959,9 @@ topbarMenuRegistry
37914
37959
  sequence: 40,
37915
37960
  separator: true,
37916
37961
  })
37917
- .addChild("data_sources_data", ["data"], (env) => {
37962
+ .addChild("pivot_data_sources", ["data"], (env) => {
37918
37963
  const sequence = 50;
37964
+ const numberOfPivots = env.model.getters.getPivotIds().length;
37919
37965
  return env.model.getters.getPivotIds().map((pivotId, index) => {
37920
37966
  const highlightProvider = {
37921
37967
  get highlights() {
@@ -37925,7 +37971,7 @@ topbarMenuRegistry
37925
37971
  return {
37926
37972
  id: `item_pivot_${env.model.getters.getPivotFormulaId(pivotId)}`,
37927
37973
  name: env.model.getters.getPivotDisplayName(pivotId),
37928
- sequence: sequence + index,
37974
+ sequence: sequence + index / numberOfPivots,
37929
37975
  isReadonlyAllowed: true,
37930
37976
  execute: (env) => env.openSidePanel("PivotSidePanel", { pivotId }),
37931
37977
  onStartHover: (env) => env.getStore(HighlightStore).register(highlightProvider),
@@ -63897,7 +63943,7 @@ class PivotUIPlugin extends CoreViewPlugin {
63897
63943
  if (!result) {
63898
63944
  return EMPTY_PIVOT_CELL;
63899
63945
  }
63900
- const { functionName, args } = result;
63946
+ let { functionName, args } = result;
63901
63947
  const formulaId = args[0];
63902
63948
  if (!formulaId) {
63903
63949
  return EMPTY_PIVOT_CELL;
@@ -63927,6 +63973,9 @@ class PivotUIPlugin extends CoreViewPlugin {
63927
63973
  return pivotCells[pivotCol][pivotRow];
63928
63974
  }
63929
63975
  try {
63976
+ const offsetRow = position.row - mainPosition.row;
63977
+ const offsetCol = position.col - mainPosition.col;
63978
+ args = args.map((arg) => (isMatrix(arg) ? arg[offsetCol][offsetRow] : arg));
63930
63979
  if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
63931
63980
  const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
63932
63981
  return {
@@ -67775,12 +67824,12 @@ class ClipboardPlugin extends UIPlugin {
67775
67824
  }
67776
67825
  case "INSERT_CELL": {
67777
67826
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
67778
- const copiedData = this.copy(cut);
67827
+ const copiedData = this.copy(cut, "shiftCells");
67779
67828
  return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
67780
67829
  }
67781
67830
  case "DELETE_CELL": {
67782
67831
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
67783
- const copiedData = this.copy(cut);
67832
+ const copiedData = this.copy(cut, "shiftCells");
67784
67833
  return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
67785
67834
  }
67786
67835
  }
@@ -67870,13 +67919,13 @@ class ClipboardPlugin extends UIPlugin {
67870
67919
  });
67871
67920
  break;
67872
67921
  }
67873
- const copiedData = this.copy(cut);
67922
+ const copiedData = this.copy(cut, "shiftCells");
67874
67923
  this.paste(paste, copiedData, { isCutOperation: true });
67875
67924
  break;
67876
67925
  }
67877
67926
  case "INSERT_CELL": {
67878
67927
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
67879
- const copiedData = this.copy(cut);
67928
+ const copiedData = this.copy(cut, "shiftCells");
67880
67929
  this.paste(paste, copiedData, { isCutOperation: true });
67881
67930
  break;
67882
67931
  }
@@ -67991,11 +68040,11 @@ class ClipboardPlugin extends UIPlugin {
67991
68040
  }
67992
68041
  return false;
67993
68042
  }
67994
- copy(zones) {
68043
+ copy(zones, mode = "copyPaste") {
67995
68044
  let copiedData = {};
67996
68045
  const clipboardData = this.getClipboardData(zones);
67997
68046
  for (const { handlerName, handler } of this.selectClipboardHandlers(clipboardData)) {
67998
- const data = handler.copy(clipboardData);
68047
+ const data = handler.copy(clipboardData, mode);
67999
68048
  copiedData[handlerName] = data;
68000
68049
  const minimalKeys = ["sheetId", "cells", "zones", "figureId"];
68001
68050
  for (const key of minimalKeys) {
@@ -68859,7 +68908,7 @@ class GridSelectionPlugin extends UIPlugin {
68859
68908
  ];
68860
68909
  for (const Handler of clipboardHandlersRegistries.cellHandlers.getAll()) {
68861
68910
  const handler = new Handler(this.getters, this.dispatch);
68862
- const data = handler.copy(getClipboardDataPositions(sheetId, target));
68911
+ const data = handler.copy(getClipboardDataPositions(sheetId, target), "shiftCells");
68863
68912
  if (!data) {
68864
68913
  continue;
68865
68914
  }
@@ -77238,6 +77287,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
77238
77287
  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 };
77239
77288
 
77240
77289
 
77241
- __info__.version = "18.2.27";
77242
- __info__.date = "2025-08-26T10:07:14.516Z";
77243
- __info__.hash = "fbf9445";
77290
+ __info__.version = "18.2.29";
77291
+ __info__.date = "2025-09-11T08:44:31.801Z";
77292
+ __info__.hash = "665bc43";