@odoo/o-spreadsheet 18.0.29 → 18.0.31

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.29
6
- * @date 2025-05-20T05:54:57.329Z
7
- * @hash 8213c0e
5
+ * @version 18.0.31
6
+ * @date 2025-05-30T08:43:10.315Z
7
+ * @hash d201086
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -3972,6 +3972,113 @@
3972
3972
  }
3973
3973
  return generateMatrix(matrix[0].length, matrix.length, (i, j) => matrix[j][i]);
3974
3974
  }
3975
+ /**
3976
+ * Enables a formula function to accept matrix or vector inputs instead of simple value, computing results across multiple dimensions.
3977
+ *
3978
+ * ```
3979
+ * / |‾ ‾| \ |‾ ‾|
3980
+ * | | [A] | | | compute(A, D, E), compute(A, D, F), compute(A, D, G) |
3981
+ * applyVectorization| compute, | [B], D, [E, F, G] | | <=> | compute(B, D, E), compute(B, D, F), compute(B, D, G) |
3982
+ * | | [C] | | | compute(C, D, E), compute(C, D, F), compute(C, D, G) |
3983
+ * \ |_ _| / |_ _|
3984
+ * ```
3985
+ *
3986
+ * By default, all arguments are vectorized. To control which arguments are vectorized,
3987
+ * pass an `acceptToVectorize` boolean array of the same length as `args`:
3988
+ * - `true` enables vectorization for that argument
3989
+ * - `false` disables vectorization for that argument
3990
+ *
3991
+ * For example, with `[true, true, false]` on previous example you get:
3992
+ *
3993
+ * ```
3994
+ * |‾ ‾|
3995
+ * | compute(A, D, [E, F, G]) |
3996
+ * | compute(B, D, [E, F, G]) |
3997
+ * | compute(C, D, [E, F, G]) |
3998
+ * |_ _|
3999
+ * ```
4000
+ *
4001
+ * @remarks
4002
+ * This helper is automatically applied (by default) to **all** `compute` functions
4003
+ * across the various spreadsheet formula modules:
4004
+ * - If an argument is declared **scalar** (not `"range"`), it is vectorized.
4005
+ * - If **all** arguments are declared **ranges**, no vectorization occurs.
4006
+ * - e.g. `SUM(A1:B2)` returns a 1×1 sum over the range.
4007
+ * - e.g. `COS(A1:B2)` over `A1:B2` returns a 2×2 element-wise result.
4008
+ * - For special behaviors (e.g. the `IF` function), you may declare all arguments
4009
+ * as ranges and invoke this helper directly within your `compute` implementation.
4010
+ */
4011
+ function applyVectorization(formula, args, acceptToVectorize = undefined) {
4012
+ let countVectorizedCol = 1;
4013
+ let countVectorizedRow = 1;
4014
+ let vectorizedColLimit = Infinity;
4015
+ let vectorizedRowLimit = Infinity;
4016
+ let vectorArgsType = undefined;
4017
+ for (let i = 0; i < args.length; i++) {
4018
+ const arg = args[i];
4019
+ if (isMatrix(arg) && (acceptToVectorize === undefined || acceptToVectorize[i])) {
4020
+ const nColumns = arg.length;
4021
+ const nRows = arg[0].length;
4022
+ if (nColumns !== 1 || nRows !== 1) {
4023
+ vectorArgsType ??= new Array(args.length);
4024
+ if (nColumns !== 1 && nRows !== 1) {
4025
+ vectorArgsType[i] = "matrix";
4026
+ countVectorizedCol = Math.max(countVectorizedCol, nColumns);
4027
+ countVectorizedRow = Math.max(countVectorizedRow, nRows);
4028
+ vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
4029
+ vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
4030
+ }
4031
+ else if (nColumns !== 1) {
4032
+ vectorArgsType[i] = "horizontal";
4033
+ countVectorizedCol = Math.max(countVectorizedCol, nColumns);
4034
+ vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
4035
+ }
4036
+ else if (nRows !== 1) {
4037
+ vectorArgsType[i] = "vertical";
4038
+ countVectorizedRow = Math.max(countVectorizedRow, nRows);
4039
+ vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
4040
+ }
4041
+ }
4042
+ else {
4043
+ args[i] = arg[0][0];
4044
+ }
4045
+ }
4046
+ }
4047
+ if (countVectorizedCol === 1 && countVectorizedRow === 1) {
4048
+ // either this function is not vectorized or it ends up with a 1x1 dimension
4049
+ return formula(...args);
4050
+ }
4051
+ const getArgOffset = (i, j) => args.map((arg, index) => {
4052
+ switch (vectorArgsType?.[index]) {
4053
+ case "matrix":
4054
+ return arg[i][j];
4055
+ case "horizontal":
4056
+ return arg[i][0];
4057
+ case "vertical":
4058
+ return arg[0][j];
4059
+ case undefined:
4060
+ return arg;
4061
+ }
4062
+ });
4063
+ return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
4064
+ if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
4065
+ return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
4066
+ }
4067
+ const singleCellComputeResult = formula(...getArgOffset(col, row));
4068
+ // In the case where the user tries to vectorize arguments of an array formula, we will get an
4069
+ // array for every combination of the vectorized arguments, which will lead to a 3D matrix and
4070
+ // we won't be able to return the values.
4071
+ // In this case, we keep the first element of each spreading part, just as Excel does, and
4072
+ // create an array with these parts.
4073
+ // For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
4074
+ // range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
4075
+ // for the value in A2). In this case, we will simply take the first value of each matrix and
4076
+ // return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
4077
+ return isMatrix(singleCellComputeResult)
4078
+ ? singleCellComputeResult[0][0]
4079
+ : singleCellComputeResult;
4080
+ });
4081
+ }
3975
4082
  // -----------------------------------------------------------------------------
3976
4083
  // CONDITIONAL EXPLORE FUNCTIONS
3977
4084
  // -----------------------------------------------------------------------------
@@ -7278,14 +7385,20 @@
7278
7385
  /**
7279
7386
  * Return the input if it's a scalar or the first element of the input if it's a matrix.
7280
7387
  */
7281
- function toScalar(matrix) {
7282
- if (!isMatrix(matrix)) {
7283
- return matrix;
7388
+ function toScalar(arg) {
7389
+ if (!isMatrix(arg)) {
7390
+ return arg;
7284
7391
  }
7285
- if (matrix.length !== 1 || matrix[0].length !== 1) {
7392
+ if (!isSingleElementMatrix(arg)) {
7286
7393
  throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
7287
7394
  }
7288
- return matrix[0][0];
7395
+ return arg[0][0];
7396
+ }
7397
+ function isSingleElementMatrix(matrix) {
7398
+ return matrix.length === 1 && matrix[0].length === 1;
7399
+ }
7400
+ function isMultipleElementMatrix(arg) {
7401
+ return isMatrix(arg) && !isSingleElementMatrix(arg);
7289
7402
  }
7290
7403
 
7291
7404
  function assertSameNumberOfElements(...args) {
@@ -8002,9 +8115,10 @@
8002
8115
  avg: _t("Average"),
8003
8116
  sum: _t("Sum"),
8004
8117
  };
8118
+ const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
8005
8119
  const AGGREGATORS_BY_FIELD_TYPE = {
8006
- integer: ["max", "min", "avg", "sum", "count_distinct", "count"],
8007
- char: ["count_distinct", "count"],
8120
+ integer: NUMBER_CHAR_AGGREGATORS,
8121
+ char: NUMBER_CHAR_AGGREGATORS,
8008
8122
  boolean: ["count_distinct", "count", "bool_and", "bool_or"],
8009
8123
  };
8010
8124
  const AGGREGATORS = {};
@@ -21486,7 +21600,7 @@ stores.inject(MyMetaStore, storeInstance);
21486
21600
  }
21487
21601
  return mode === "row" ? transposeMatrix(result) : result;
21488
21602
  },
21489
- isExported: true,
21603
+ isExported: false,
21490
21604
  };
21491
21605
  // -----------------------------------------------------------------------------
21492
21606
  // SORT
@@ -24454,16 +24568,23 @@ stores.inject(MyMetaStore, storeInstance);
24454
24568
  const IF = {
24455
24569
  description: _t("Returns value depending on logical expression."),
24456
24570
  args: [
24457
- arg("logical_expression (boolean)", _t("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE.")),
24458
- arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
24459
- arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
24571
+ arg("logical_expression (boolean, range<boolean>)", _t("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE.")),
24572
+ arg("value_if_true (any, range)", _t("The value the function returns if logical_expression is TRUE.")),
24573
+ arg("value_if_false (any, range, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
24460
24574
  ],
24461
24575
  compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
24462
- const result = toBoolean(logicalExpression?.value) ? valueIfTrue : valueIfFalse;
24576
+ if (isMultipleElementMatrix(logicalExpression)) {
24577
+ return applyVectorization(IF.compute, [logicalExpression, valueIfTrue, valueIfFalse]);
24578
+ }
24579
+ let result = toBoolean(toScalar(logicalExpression)) ? valueIfTrue : valueIfFalse;
24580
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
24581
+ if (!isMultipleElementMatrix(result)) {
24582
+ result = toScalar(result);
24583
+ }
24463
24584
  if (result === undefined) {
24464
24585
  return { value: "" };
24465
24586
  }
24466
- if (result.value === null) {
24587
+ if (!isMatrix(result) && result.value === null) {
24467
24588
  return { ...result, value: "" };
24468
24589
  }
24469
24590
  return result;
@@ -24476,15 +24597,22 @@ stores.inject(MyMetaStore, storeInstance);
24476
24597
  const IFERROR = {
24477
24598
  description: _t("Value if it is not an error, otherwise 2nd argument."),
24478
24599
  args: [
24479
- arg("value (any)", _t("The value to return if value itself is not an error.")),
24480
- arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
24600
+ arg("value (any, range)", _t("The value to return if value itself is not an error.")),
24601
+ arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an error.")),
24481
24602
  ],
24482
- compute: function (value, valueIfError = { value: "" }) {
24483
- const result = isEvaluationError(value?.value) ? valueIfError : value;
24603
+ compute: function (value, valueIfError) {
24604
+ if (isMultipleElementMatrix(value)) {
24605
+ return applyVectorization(IFERROR.compute, [value, valueIfError]);
24606
+ }
24607
+ let result = isEvaluationError(toScalar(value)?.value) ? valueIfError : value;
24608
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
24609
+ if (!isMultipleElementMatrix(result)) {
24610
+ result = toScalar(result);
24611
+ }
24484
24612
  if (result === undefined) {
24485
24613
  return { value: "" };
24486
24614
  }
24487
- if (result.value === null) {
24615
+ if (!isMatrix(result) && result.value === null) {
24488
24616
  return { ...result, value: "" };
24489
24617
  }
24490
24618
  return result;
@@ -24497,15 +24625,22 @@ stores.inject(MyMetaStore, storeInstance);
24497
24625
  const IFNA = {
24498
24626
  description: _t("Value if it is not an #N/A error, otherwise 2nd argument."),
24499
24627
  args: [
24500
- arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
24501
- arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
24628
+ arg("value (any, range)", _t("The value to return if value itself is not #N/A an error.")),
24629
+ arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
24502
24630
  ],
24503
- compute: function (value, valueIfError = { value: "" }) {
24504
- const result = value?.value === CellErrorType.NotAvailable ? valueIfError : value;
24631
+ compute: function (value, valueIfError) {
24632
+ if (isMultipleElementMatrix(value)) {
24633
+ return applyVectorization(IFNA.compute, [value, valueIfError]);
24634
+ }
24635
+ let result = toScalar(value)?.value === CellErrorType.NotAvailable ? valueIfError : value;
24636
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
24637
+ if (!isMultipleElementMatrix(result)) {
24638
+ result = toScalar(result);
24639
+ }
24505
24640
  if (result === undefined) {
24506
24641
  return { value: "" };
24507
24642
  }
24508
- if (result.value === null) {
24643
+ if (!isMatrix(result) && result.value === null) {
24509
24644
  return { ...result, value: "" };
24510
24645
  }
24511
24646
  return result;
@@ -24518,23 +24653,31 @@ stores.inject(MyMetaStore, storeInstance);
24518
24653
  const IFS = {
24519
24654
  description: _t("Returns a value depending on multiple logical expressions."),
24520
24655
  args: [
24521
- arg("condition1 (boolean)", _t("The first condition to be evaluated. This can be a boolean, a number, an array, or a reference to any of those.")),
24522
- arg("value1 (any)", _t("The returned value if condition1 is TRUE.")),
24523
- arg("condition2 (boolean, any, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
24524
- arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
24656
+ arg("condition1 (boolean, range<boolean>)", _t("The first condition to be evaluated. This can be a boolean, a number, an array, or a reference to any of those.")),
24657
+ arg("value1 (any, range)", _t("The returned value if condition1 is TRUE.")),
24658
+ arg("condition2 (boolean, any, range, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
24659
+ arg("value2 (any, range, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
24525
24660
  ],
24526
24661
  compute: function (...values) {
24527
24662
  assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
24528
- for (let n = 0; n < values.length - 1; n += 2) {
24529
- if (toBoolean(values[n]?.value)) {
24530
- const result = values[n + 1];
24531
- if (result === undefined) {
24663
+ while (values.length > 0) {
24664
+ if (isMultipleElementMatrix(values[0])) {
24665
+ return applyVectorization(IFS.compute, values);
24666
+ }
24667
+ const condition = toBoolean(toScalar(values.shift()));
24668
+ let valueIfTrue = values.shift();
24669
+ if (condition) {
24670
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
24671
+ if (!isMultipleElementMatrix(valueIfTrue)) {
24672
+ valueIfTrue = toScalar(valueIfTrue);
24673
+ }
24674
+ if (valueIfTrue === undefined) {
24532
24675
  return { value: "" };
24533
24676
  }
24534
- if (result.value === null) {
24535
- return { ...result, value: "" };
24677
+ if (!isMatrix(valueIfTrue) && valueIfTrue.value === null) {
24678
+ return { ...valueIfTrue, value: "" };
24536
24679
  }
24537
- return result;
24680
+ return valueIfTrue;
24538
24681
  }
24539
24682
  }
24540
24683
  return new EvaluationError(_t("No match."));
@@ -26178,7 +26321,7 @@ stores.inject(MyMetaStore, storeInstance);
26178
26321
  }
26179
26322
  return transposeMatrix([result]);
26180
26323
  },
26181
- isExported: true,
26324
+ isExported: false,
26182
26325
  };
26183
26326
  // -----------------------------------------------------------------------------
26184
26327
  // SUBSTITUTE
@@ -26371,86 +26514,21 @@ stores.inject(MyMetaStore, storeInstance);
26371
26514
  functionRegistry.add(name, { isExported: false, ...addDescr });
26372
26515
  }
26373
26516
  }
26374
- const notAvailableError = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
26517
+ //------------------------------------------------------------------------------
26518
+ // CREATE COMPUTE FUNCTION
26519
+ //------------------------------------------------------------------------------
26375
26520
  function createComputeFunction(descr, functionName) {
26376
26521
  function vectorizedCompute(...args) {
26377
- let countVectorizableCol = 1;
26378
- let countVectorizableRow = 1;
26379
- let vectorizableColLimit = Infinity;
26380
- let vectorizableRowLimit = Infinity;
26381
- let vectorArgsType = undefined;
26382
- //#region Compute vectorisation limits
26522
+ const acceptToVectorize = [];
26383
26523
  for (let i = 0; i < args.length; i++) {
26384
26524
  const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
26385
26525
  const arg = args[i];
26386
- if (isMatrix(arg) && !argDefinition.acceptMatrix) {
26387
- // if argDefinition does not accept a matrix but arg is still a matrix
26388
- // --> triggers the arguments vectorization
26389
- const nColumns = arg.length;
26390
- const nRows = arg[0].length;
26391
- if (nColumns !== 1 || nRows !== 1) {
26392
- vectorArgsType ??= new Array(args.length);
26393
- if (nColumns !== 1 && nRows !== 1) {
26394
- vectorArgsType[i] = "matrix";
26395
- countVectorizableCol = Math.max(countVectorizableCol, nColumns);
26396
- countVectorizableRow = Math.max(countVectorizableRow, nRows);
26397
- vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
26398
- vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
26399
- }
26400
- else if (nColumns !== 1) {
26401
- vectorArgsType[i] = "horizontal";
26402
- countVectorizableCol = Math.max(countVectorizableCol, nColumns);
26403
- vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
26404
- }
26405
- else if (nRows !== 1) {
26406
- vectorArgsType[i] = "vertical";
26407
- countVectorizableRow = Math.max(countVectorizableRow, nRows);
26408
- vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
26409
- }
26410
- }
26411
- else {
26412
- args[i] = arg[0][0];
26413
- }
26414
- }
26415
26526
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
26416
26527
  throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", functionName, (i + 1).toString()));
26417
26528
  }
26529
+ acceptToVectorize.push(!argDefinition.acceptMatrix);
26418
26530
  }
26419
- //#endregion
26420
- if (countVectorizableCol === 1 && countVectorizableRow === 1) {
26421
- // either this function is not vectorized or it ends up with a 1x1 dimension
26422
- return errorHandlingCompute.apply(this, args);
26423
- }
26424
- const getArgOffset = (i, j) => args.map((arg, index) => {
26425
- switch (vectorArgsType?.[index]) {
26426
- case "matrix":
26427
- return arg[i][j];
26428
- case "horizontal":
26429
- return arg[i][0];
26430
- case "vertical":
26431
- return arg[0][j];
26432
- case undefined:
26433
- return arg;
26434
- }
26435
- });
26436
- return generateMatrix(countVectorizableCol, countVectorizableRow, (col, row) => {
26437
- if (col > vectorizableColLimit - 1 || row > vectorizableRowLimit - 1) {
26438
- return notAvailableError;
26439
- }
26440
- const singleCellComputeResult = errorHandlingCompute.apply(this, getArgOffset(col, row));
26441
- // In the case where the user tries to vectorize arguments of an array formula, we will get an
26442
- // array for every combination of the vectorized arguments, which will lead to a 3D matrix and
26443
- // we won't be able to return the values.
26444
- // In this case, we keep the first element of each spreading part, just as Excel does, and
26445
- // create an array with these parts.
26446
- // For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
26447
- // range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
26448
- // for the value in A2). In this case, we will simply take the first value of each matrix and
26449
- // return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
26450
- return isMatrix(singleCellComputeResult)
26451
- ? singleCellComputeResult[0][0]
26452
- : singleCellComputeResult;
26453
- });
26531
+ return applyVectorization(errorHandlingCompute.bind(this), args, acceptToVectorize);
26454
26532
  }
26455
26533
  function errorHandlingCompute(...args) {
26456
26534
  for (let i = 0; i < args.length; i++) {
@@ -39439,7 +39517,7 @@ stores.inject(MyMetaStore, storeInstance);
39439
39517
  proposals &&
39440
39518
  !["ARG_SEPARATOR", "LEFT_PAREN", "OPERATOR"].includes(tokenAtCursor.type)) {
39441
39519
  const filteredProposals = fuzzyLookup(searchTerm, proposals, (p) => p.fuzzySearchKey || p.text);
39442
- if (!exactMatch || filteredProposals.length > 1) {
39520
+ if (!exactMatch || filteredProposals.length) {
39443
39521
  proposals = filteredProposals;
39444
39522
  }
39445
39523
  }
@@ -44048,7 +44126,9 @@ stores.inject(MyMetaStore, storeInstance);
44048
44126
  return dimension.order === "asc" ? -1 : 1;
44049
44127
  }
44050
44128
  if (dimension.type === "integer" || dimension.type === "datetime") {
44051
- return dimension.order === "asc" ? Number(a) - Number(b) : Number(b) - Number(a);
44129
+ return dimension.order === "asc"
44130
+ ? toNumber(a, DEFAULT_LOCALE) - toNumber(b, DEFAULT_LOCALE)
44131
+ : toNumber(b, DEFAULT_LOCALE) - toNumber(a, DEFAULT_LOCALE);
44052
44132
  }
44053
44133
  return dimension.order === "asc" ? a.localeCompare(b) : b.localeCompare(a);
44054
44134
  }
@@ -44584,12 +44664,7 @@ stores.inject(MyMetaStore, storeInstance);
44584
44664
  entry[field.name] = { value: null, type: CellValueType.empty, formattedValue: "" };
44585
44665
  }
44586
44666
  else {
44587
- if (field.type === "char") {
44588
- entry[field.name] = { ...cell, value: cell.formattedValue || null };
44589
- }
44590
- else {
44591
- entry[field.name] = cell;
44592
- }
44667
+ entry[field.name] = cell;
44593
44668
  }
44594
44669
  }
44595
44670
  entry["__count"] = { value: 1, type: CellValueType.number, formattedValue: "1" };
@@ -46789,8 +46864,7 @@ stores.inject(MyMetaStore, storeInstance);
46789
46864
  if (!spreader) {
46790
46865
  return undefined;
46791
46866
  }
46792
- const cell = this.getters.getCell(spreader);
46793
- return cell?.content;
46867
+ return this.getters.getCellText(spreader, { showFormula: true });
46794
46868
  }
46795
46869
  get currentEditedCell() {
46796
46870
  return {
@@ -49593,6 +49667,7 @@ stores.inject(MyMetaStore, storeInstance);
49593
49667
  const friction = 0.95;
49594
49668
  const verticalScrollFactor = 1;
49595
49669
  const horizontalScrollFactor = 1;
49670
+ const resetTimeoutDuration = 100;
49596
49671
  function useTouchScroll(ref, updateScroll, canMoveUp) {
49597
49672
  let lastX = 0;
49598
49673
  let lastY = 0;
@@ -49600,6 +49675,7 @@ stores.inject(MyMetaStore, storeInstance);
49600
49675
  let velocityY = 0;
49601
49676
  let isMouseDown = false;
49602
49677
  let lastTime = 0;
49678
+ let resetTimeout = null;
49603
49679
  useRefListener(ref, "touchstart", onTouchStart, { capture: false });
49604
49680
  useRefListener(ref, "touchmove", onTouchMove, { capture: false });
49605
49681
  useRefListener(ref, "touchend", onTouchEnd, { capture: false });
@@ -49612,6 +49688,10 @@ stores.inject(MyMetaStore, storeInstance);
49612
49688
  function onTouchMove(event) {
49613
49689
  if (!isMouseDown)
49614
49690
  return;
49691
+ if (resetTimeout) {
49692
+ clearTimeout(resetTimeout);
49693
+ resetTimeout = null;
49694
+ }
49615
49695
  const currentTime = Date.now();
49616
49696
  const { clientX, clientY } = event.touches[0];
49617
49697
  let deltaX = lastX - clientX;
@@ -49628,6 +49708,10 @@ stores.inject(MyMetaStore, storeInstance);
49628
49708
  }
49629
49709
  event.stopPropagation();
49630
49710
  }
49711
+ resetTimeout = setTimeout(() => {
49712
+ velocityX = 0;
49713
+ velocityY = 0;
49714
+ }, resetTimeoutDuration);
49631
49715
  updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
49632
49716
  }
49633
49717
  function onTouchEnd(ev) {
@@ -74315,9 +74399,9 @@ stores.inject(MyMetaStore, storeInstance);
74315
74399
  exports.tokenize = tokenize;
74316
74400
 
74317
74401
 
74318
- __info__.version = "18.0.29";
74319
- __info__.date = "2025-05-20T05:54:57.329Z";
74320
- __info__.hash = "8213c0e";
74402
+ __info__.version = "18.0.31";
74403
+ __info__.date = "2025-05-30T08:43:10.315Z";
74404
+ __info__.hash = "d201086";
74321
74405
 
74322
74406
 
74323
74407
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);