@odoo/o-spreadsheet 18.2.13 → 18.2.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.2.13
6
- * @date 2025-05-20T05:57:00.985Z
7
- * @hash 9872529
5
+ * @version 18.2.15
6
+ * @date 2025-05-30T08:45:53.952Z
7
+ * @hash 607492d
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -4150,6 +4150,113 @@
4150
4150
  }
4151
4151
  return generateMatrix(matrix[0].length, matrix.length, (i, j) => matrix[j][i]);
4152
4152
  }
4153
+ /**
4154
+ * Enables a formula function to accept matrix or vector inputs instead of simple value, computing results across multiple dimensions.
4155
+ *
4156
+ * ```
4157
+ * / |‾ ‾| \ |‾ ‾|
4158
+ * | | [A] | | | compute(A, D, E), compute(A, D, F), compute(A, D, G) |
4159
+ * applyVectorization| compute, | [B], D, [E, F, G] | | <=> | compute(B, D, E), compute(B, D, F), compute(B, D, G) |
4160
+ * | | [C] | | | compute(C, D, E), compute(C, D, F), compute(C, D, G) |
4161
+ * \ |_ _| / |_ _|
4162
+ * ```
4163
+ *
4164
+ * By default, all arguments are vectorized. To control which arguments are vectorized,
4165
+ * pass an `acceptToVectorize` boolean array of the same length as `args`:
4166
+ * - `true` enables vectorization for that argument
4167
+ * - `false` disables vectorization for that argument
4168
+ *
4169
+ * For example, with `[true, true, false]` on previous example you get:
4170
+ *
4171
+ * ```
4172
+ * |‾ ‾|
4173
+ * | compute(A, D, [E, F, G]) |
4174
+ * | compute(B, D, [E, F, G]) |
4175
+ * | compute(C, D, [E, F, G]) |
4176
+ * |_ _|
4177
+ * ```
4178
+ *
4179
+ * @remarks
4180
+ * This helper is automatically applied (by default) to **all** `compute` functions
4181
+ * across the various spreadsheet formula modules:
4182
+ * - If an argument is declared **scalar** (not `"range"`), it is vectorized.
4183
+ * - If **all** arguments are declared **ranges**, no vectorization occurs.
4184
+ * - e.g. `SUM(A1:B2)` returns a 1×1 sum over the range.
4185
+ * - e.g. `COS(A1:B2)` over `A1:B2` returns a 2×2 element-wise result.
4186
+ * - For special behaviors (e.g. the `IF` function), you may declare all arguments
4187
+ * as ranges and invoke this helper directly within your `compute` implementation.
4188
+ */
4189
+ function applyVectorization(formula, args, acceptToVectorize = undefined) {
4190
+ let countVectorizedCol = 1;
4191
+ let countVectorizedRow = 1;
4192
+ let vectorizedColLimit = Infinity;
4193
+ let vectorizedRowLimit = Infinity;
4194
+ let vectorArgsType = undefined;
4195
+ for (let i = 0; i < args.length; i++) {
4196
+ const arg = args[i];
4197
+ if (isMatrix(arg) && (acceptToVectorize === undefined || acceptToVectorize[i])) {
4198
+ const nColumns = arg.length;
4199
+ const nRows = arg[0].length;
4200
+ if (nColumns !== 1 || nRows !== 1) {
4201
+ vectorArgsType ??= new Array(args.length);
4202
+ if (nColumns !== 1 && nRows !== 1) {
4203
+ vectorArgsType[i] = "matrix";
4204
+ countVectorizedCol = Math.max(countVectorizedCol, nColumns);
4205
+ countVectorizedRow = Math.max(countVectorizedRow, nRows);
4206
+ vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
4207
+ vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
4208
+ }
4209
+ else if (nColumns !== 1) {
4210
+ vectorArgsType[i] = "horizontal";
4211
+ countVectorizedCol = Math.max(countVectorizedCol, nColumns);
4212
+ vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
4213
+ }
4214
+ else if (nRows !== 1) {
4215
+ vectorArgsType[i] = "vertical";
4216
+ countVectorizedRow = Math.max(countVectorizedRow, nRows);
4217
+ vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
4218
+ }
4219
+ }
4220
+ else {
4221
+ args[i] = arg[0][0];
4222
+ }
4223
+ }
4224
+ }
4225
+ if (countVectorizedCol === 1 && countVectorizedRow === 1) {
4226
+ // either this function is not vectorized or it ends up with a 1x1 dimension
4227
+ return formula(...args);
4228
+ }
4229
+ const getArgOffset = (i, j) => args.map((arg, index) => {
4230
+ switch (vectorArgsType?.[index]) {
4231
+ case "matrix":
4232
+ return arg[i][j];
4233
+ case "horizontal":
4234
+ return arg[i][0];
4235
+ case "vertical":
4236
+ return arg[0][j];
4237
+ case undefined:
4238
+ return arg;
4239
+ }
4240
+ });
4241
+ return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
4242
+ if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
4243
+ return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
4244
+ }
4245
+ const singleCellComputeResult = formula(...getArgOffset(col, row));
4246
+ // In the case where the user tries to vectorize arguments of an array formula, we will get an
4247
+ // array for every combination of the vectorized arguments, which will lead to a 3D matrix and
4248
+ // we won't be able to return the values.
4249
+ // In this case, we keep the first element of each spreading part, just as Excel does, and
4250
+ // create an array with these parts.
4251
+ // For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
4252
+ // range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
4253
+ // for the value in A2). In this case, we will simply take the first value of each matrix and
4254
+ // return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
4255
+ return isMatrix(singleCellComputeResult)
4256
+ ? singleCellComputeResult[0][0]
4257
+ : singleCellComputeResult;
4258
+ });
4259
+ }
4153
4260
  // -----------------------------------------------------------------------------
4154
4261
  // CONDITIONAL EXPLORE FUNCTIONS
4155
4262
  // -----------------------------------------------------------------------------
@@ -7441,14 +7548,20 @@
7441
7548
  /**
7442
7549
  * Return the input if it's a scalar or the first element of the input if it's a matrix.
7443
7550
  */
7444
- function toScalar(matrix) {
7445
- if (!isMatrix(matrix)) {
7446
- return matrix;
7551
+ function toScalar(arg) {
7552
+ if (!isMatrix(arg)) {
7553
+ return arg;
7447
7554
  }
7448
- if (matrix.length !== 1 || matrix[0].length !== 1) {
7555
+ if (!isSingleElementMatrix(arg)) {
7449
7556
  throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
7450
7557
  }
7451
- return matrix[0][0];
7558
+ return arg[0][0];
7559
+ }
7560
+ function isSingleElementMatrix(matrix) {
7561
+ return matrix.length === 1 && matrix[0].length === 1;
7562
+ }
7563
+ function isMultipleElementMatrix(arg) {
7564
+ return isMatrix(arg) && !isSingleElementMatrix(arg);
7452
7565
  }
7453
7566
 
7454
7567
  function assertSameNumberOfElements(...args) {
@@ -8190,9 +8303,10 @@
8190
8303
  avg: _t("Average"),
8191
8304
  sum: _t("Sum"),
8192
8305
  };
8306
+ const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
8193
8307
  const AGGREGATORS_BY_FIELD_TYPE = {
8194
- integer: ["max", "min", "avg", "sum", "count_distinct", "count"],
8195
- char: ["count_distinct", "count"],
8308
+ integer: NUMBER_CHAR_AGGREGATORS,
8309
+ char: NUMBER_CHAR_AGGREGATORS,
8196
8310
  boolean: ["count_distinct", "count", "bool_and", "bool_or"],
8197
8311
  datetime: ["max", "min", "count_distinct", "count"],
8198
8312
  };
@@ -15456,7 +15570,7 @@ stores.inject(MyMetaStore, storeInstance);
15456
15570
  }
15457
15571
  return mode === "row" ? transposeMatrix(result) : result;
15458
15572
  },
15459
- isExported: true,
15573
+ isExported: false,
15460
15574
  };
15461
15575
  // -----------------------------------------------------------------------------
15462
15576
  // SORT
@@ -18587,16 +18701,23 @@ stores.inject(MyMetaStore, storeInstance);
18587
18701
  const IF = {
18588
18702
  description: _t("Returns value depending on logical expression."),
18589
18703
  args: [
18590
- 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.")),
18591
- arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
18592
- arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
18704
+ 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.")),
18705
+ arg("value_if_true (any, range)", _t("The value the function returns if logical_expression is TRUE.")),
18706
+ arg("value_if_false (any, range, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
18593
18707
  ],
18594
18708
  compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
18595
- const result = toBoolean(logicalExpression?.value) ? valueIfTrue : valueIfFalse;
18709
+ if (isMultipleElementMatrix(logicalExpression)) {
18710
+ return applyVectorization(IF.compute, [logicalExpression, valueIfTrue, valueIfFalse]);
18711
+ }
18712
+ let result = toBoolean(toScalar(logicalExpression)) ? valueIfTrue : valueIfFalse;
18713
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18714
+ if (!isMultipleElementMatrix(result)) {
18715
+ result = toScalar(result);
18716
+ }
18596
18717
  if (result === undefined) {
18597
18718
  return { value: "" };
18598
18719
  }
18599
- if (result.value === null) {
18720
+ if (!isMatrix(result) && result.value === null) {
18600
18721
  return { ...result, value: "" };
18601
18722
  }
18602
18723
  return result;
@@ -18609,15 +18730,22 @@ stores.inject(MyMetaStore, storeInstance);
18609
18730
  const IFERROR = {
18610
18731
  description: _t("Value if it is not an error, otherwise 2nd argument."),
18611
18732
  args: [
18612
- arg("value (any)", _t("The value to return if value itself is not an error.")),
18613
- arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
18733
+ arg("value (any, range)", _t("The value to return if value itself is not an error.")),
18734
+ arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an error.")),
18614
18735
  ],
18615
- compute: function (value, valueIfError = { value: "" }) {
18616
- const result = isEvaluationError(value?.value) ? valueIfError : value;
18736
+ compute: function (value, valueIfError) {
18737
+ if (isMultipleElementMatrix(value)) {
18738
+ return applyVectorization(IFERROR.compute, [value, valueIfError]);
18739
+ }
18740
+ let result = isEvaluationError(toScalar(value)?.value) ? valueIfError : value;
18741
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18742
+ if (!isMultipleElementMatrix(result)) {
18743
+ result = toScalar(result);
18744
+ }
18617
18745
  if (result === undefined) {
18618
18746
  return { value: "" };
18619
18747
  }
18620
- if (result.value === null) {
18748
+ if (!isMatrix(result) && result.value === null) {
18621
18749
  return { ...result, value: "" };
18622
18750
  }
18623
18751
  return result;
@@ -18630,15 +18758,22 @@ stores.inject(MyMetaStore, storeInstance);
18630
18758
  const IFNA = {
18631
18759
  description: _t("Value if it is not an #N/A error, otherwise 2nd argument."),
18632
18760
  args: [
18633
- arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
18634
- arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
18761
+ arg("value (any, range)", _t("The value to return if value itself is not #N/A an error.")),
18762
+ arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
18635
18763
  ],
18636
- compute: function (value, valueIfError = { value: "" }) {
18637
- const result = value?.value === CellErrorType.NotAvailable ? valueIfError : value;
18764
+ compute: function (value, valueIfError) {
18765
+ if (isMultipleElementMatrix(value)) {
18766
+ return applyVectorization(IFNA.compute, [value, valueIfError]);
18767
+ }
18768
+ let result = toScalar(value)?.value === CellErrorType.NotAvailable ? valueIfError : value;
18769
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18770
+ if (!isMultipleElementMatrix(result)) {
18771
+ result = toScalar(result);
18772
+ }
18638
18773
  if (result === undefined) {
18639
18774
  return { value: "" };
18640
18775
  }
18641
- if (result.value === null) {
18776
+ if (!isMatrix(result) && result.value === null) {
18642
18777
  return { ...result, value: "" };
18643
18778
  }
18644
18779
  return result;
@@ -18651,23 +18786,31 @@ stores.inject(MyMetaStore, storeInstance);
18651
18786
  const IFS = {
18652
18787
  description: _t("Returns a value depending on multiple logical expressions."),
18653
18788
  args: [
18654
- 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.")),
18655
- arg("value1 (any)", _t("The returned value if condition1 is TRUE.")),
18656
- arg("condition2 (boolean, any, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
18657
- arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
18789
+ 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.")),
18790
+ arg("value1 (any, range)", _t("The returned value if condition1 is TRUE.")),
18791
+ arg("condition2 (boolean, any, range, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
18792
+ arg("value2 (any, range, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
18658
18793
  ],
18659
18794
  compute: function (...values) {
18660
18795
  assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
18661
- for (let n = 0; n < values.length - 1; n += 2) {
18662
- if (toBoolean(values[n]?.value)) {
18663
- const result = values[n + 1];
18664
- if (result === undefined) {
18796
+ while (values.length > 0) {
18797
+ if (isMultipleElementMatrix(values[0])) {
18798
+ return applyVectorization(IFS.compute, values);
18799
+ }
18800
+ const condition = toBoolean(toScalar(values.shift()));
18801
+ let valueIfTrue = values.shift();
18802
+ if (condition) {
18803
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18804
+ if (!isMultipleElementMatrix(valueIfTrue)) {
18805
+ valueIfTrue = toScalar(valueIfTrue);
18806
+ }
18807
+ if (valueIfTrue === undefined) {
18665
18808
  return { value: "" };
18666
18809
  }
18667
- if (result.value === null) {
18668
- return { ...result, value: "" };
18810
+ if (!isMatrix(valueIfTrue) && valueIfTrue.value === null) {
18811
+ return { ...valueIfTrue, value: "" };
18669
18812
  }
18670
- return result;
18813
+ return valueIfTrue;
18671
18814
  }
18672
18815
  }
18673
18816
  return new EvaluationError(_t("No match."));
@@ -20329,7 +20472,7 @@ stores.inject(MyMetaStore, storeInstance);
20329
20472
  }
20330
20473
  return transposeMatrix([result]);
20331
20474
  },
20332
- isExported: true,
20475
+ isExported: false,
20333
20476
  };
20334
20477
  // -----------------------------------------------------------------------------
20335
20478
  // SUBSTITUTE
@@ -20522,86 +20665,21 @@ stores.inject(MyMetaStore, storeInstance);
20522
20665
  functionRegistry.add(name, { isExported: false, ...addDescr });
20523
20666
  }
20524
20667
  }
20525
- const notAvailableError = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
20668
+ //------------------------------------------------------------------------------
20669
+ // CREATE COMPUTE FUNCTION
20670
+ //------------------------------------------------------------------------------
20526
20671
  function createComputeFunction(descr, functionName) {
20527
20672
  function vectorizedCompute(...args) {
20528
- let countVectorizableCol = 1;
20529
- let countVectorizableRow = 1;
20530
- let vectorizableColLimit = Infinity;
20531
- let vectorizableRowLimit = Infinity;
20532
- let vectorArgsType = undefined;
20533
- //#region Compute vectorisation limits
20673
+ const acceptToVectorize = [];
20534
20674
  for (let i = 0; i < args.length; i++) {
20535
20675
  const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
20536
20676
  const arg = args[i];
20537
- if (isMatrix(arg) && !argDefinition.acceptMatrix) {
20538
- // if argDefinition does not accept a matrix but arg is still a matrix
20539
- // --> triggers the arguments vectorization
20540
- const nColumns = arg.length;
20541
- const nRows = arg[0].length;
20542
- if (nColumns !== 1 || nRows !== 1) {
20543
- vectorArgsType ??= new Array(args.length);
20544
- if (nColumns !== 1 && nRows !== 1) {
20545
- vectorArgsType[i] = "matrix";
20546
- countVectorizableCol = Math.max(countVectorizableCol, nColumns);
20547
- countVectorizableRow = Math.max(countVectorizableRow, nRows);
20548
- vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
20549
- vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
20550
- }
20551
- else if (nColumns !== 1) {
20552
- vectorArgsType[i] = "horizontal";
20553
- countVectorizableCol = Math.max(countVectorizableCol, nColumns);
20554
- vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
20555
- }
20556
- else if (nRows !== 1) {
20557
- vectorArgsType[i] = "vertical";
20558
- countVectorizableRow = Math.max(countVectorizableRow, nRows);
20559
- vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
20560
- }
20561
- }
20562
- else {
20563
- args[i] = arg[0][0];
20564
- }
20565
- }
20566
20677
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
20567
20678
  throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", functionName, (i + 1).toString()));
20568
20679
  }
20680
+ acceptToVectorize.push(!argDefinition.acceptMatrix);
20569
20681
  }
20570
- //#endregion
20571
- if (countVectorizableCol === 1 && countVectorizableRow === 1) {
20572
- // either this function is not vectorized or it ends up with a 1x1 dimension
20573
- return errorHandlingCompute.apply(this, args);
20574
- }
20575
- const getArgOffset = (i, j) => args.map((arg, index) => {
20576
- switch (vectorArgsType?.[index]) {
20577
- case "matrix":
20578
- return arg[i][j];
20579
- case "horizontal":
20580
- return arg[i][0];
20581
- case "vertical":
20582
- return arg[0][j];
20583
- case undefined:
20584
- return arg;
20585
- }
20586
- });
20587
- return generateMatrix(countVectorizableCol, countVectorizableRow, (col, row) => {
20588
- if (col > vectorizableColLimit - 1 || row > vectorizableRowLimit - 1) {
20589
- return notAvailableError;
20590
- }
20591
- const singleCellComputeResult = errorHandlingCompute.apply(this, getArgOffset(col, row));
20592
- // In the case where the user tries to vectorize arguments of an array formula, we will get an
20593
- // array for every combination of the vectorized arguments, which will lead to a 3D matrix and
20594
- // we won't be able to return the values.
20595
- // In this case, we keep the first element of each spreading part, just as Excel does, and
20596
- // create an array with these parts.
20597
- // For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
20598
- // range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
20599
- // for the value in A2). In this case, we will simply take the first value of each matrix and
20600
- // return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
20601
- return isMatrix(singleCellComputeResult)
20602
- ? singleCellComputeResult[0][0]
20603
- : singleCellComputeResult;
20604
- });
20682
+ return applyVectorization(errorHandlingCompute.bind(this), args, acceptToVectorize);
20605
20683
  }
20606
20684
  function errorHandlingCompute(...args) {
20607
20685
  for (let i = 0; i < args.length; i++) {
@@ -21446,7 +21524,7 @@ stores.inject(MyMetaStore, storeInstance);
21446
21524
  proposals &&
21447
21525
  !["ARG_SEPARATOR", "LEFT_PAREN", "OPERATOR"].includes(tokenAtCursor.type)) {
21448
21526
  const filteredProposals = fuzzyLookup(searchTerm, proposals, (p) => p.fuzzySearchKey || p.text);
21449
- if (!exactMatch || filteredProposals.length > 1) {
21527
+ if (!exactMatch || filteredProposals.length) {
21450
21528
  proposals = filteredProposals;
21451
21529
  }
21452
21530
  }
@@ -46482,7 +46560,9 @@ stores.inject(MyMetaStore, storeInstance);
46482
46560
  return dimension.order === "asc" ? -1 : 1;
46483
46561
  }
46484
46562
  if (dimension.type === "integer" || dimension.type === "datetime") {
46485
- return dimension.order === "asc" ? Number(a) - Number(b) : Number(b) - Number(a);
46563
+ return dimension.order === "asc"
46564
+ ? toNumber(a, DEFAULT_LOCALE) - toNumber(b, DEFAULT_LOCALE)
46565
+ : toNumber(b, DEFAULT_LOCALE) - toNumber(a, DEFAULT_LOCALE);
46486
46566
  }
46487
46567
  return dimension.order === "asc" ? a.localeCompare(b) : b.localeCompare(a);
46488
46568
  }
@@ -47016,12 +47096,7 @@ stores.inject(MyMetaStore, storeInstance);
47016
47096
  entry[field.name] = { value: null, type: CellValueType.empty, formattedValue: "" };
47017
47097
  }
47018
47098
  else {
47019
- if (field.type === "char") {
47020
- entry[field.name] = { ...cell, value: cell.formattedValue || null };
47021
- }
47022
- else {
47023
- entry[field.name] = cell;
47024
- }
47099
+ entry[field.name] = cell;
47025
47100
  }
47026
47101
  }
47027
47102
  entry["__count"] = { value: 1, type: CellValueType.number, formattedValue: "1" };
@@ -49245,8 +49320,7 @@ stores.inject(MyMetaStore, storeInstance);
49245
49320
  if (!spreader) {
49246
49321
  return undefined;
49247
49322
  }
49248
- const cell = this.getters.getCell(spreader);
49249
- return cell?.content;
49323
+ return this.getters.getCellText(spreader, { showFormula: true });
49250
49324
  }
49251
49325
  get currentEditedCell() {
49252
49326
  return {
@@ -52167,6 +52241,7 @@ stores.inject(MyMetaStore, storeInstance);
52167
52241
  const friction = 0.95;
52168
52242
  const verticalScrollFactor = 1;
52169
52243
  const horizontalScrollFactor = 1;
52244
+ const resetTimeoutDuration = 100;
52170
52245
  function useTouchScroll(ref, updateScroll, canMoveUp) {
52171
52246
  let lastX = 0;
52172
52247
  let lastY = 0;
@@ -52174,6 +52249,7 @@ stores.inject(MyMetaStore, storeInstance);
52174
52249
  let velocityY = 0;
52175
52250
  let isMouseDown = false;
52176
52251
  let lastTime = 0;
52252
+ let resetTimeout = null;
52177
52253
  useRefListener(ref, "touchstart", onTouchStart, { capture: false });
52178
52254
  useRefListener(ref, "touchmove", onTouchMove, { capture: false });
52179
52255
  useRefListener(ref, "touchend", onTouchEnd, { capture: false });
@@ -52186,6 +52262,10 @@ stores.inject(MyMetaStore, storeInstance);
52186
52262
  function onTouchMove(event) {
52187
52263
  if (!isMouseDown)
52188
52264
  return;
52265
+ if (resetTimeout) {
52266
+ clearTimeout(resetTimeout);
52267
+ resetTimeout = null;
52268
+ }
52189
52269
  const currentTime = Date.now();
52190
52270
  const { clientX, clientY } = event.touches[0];
52191
52271
  let deltaX = lastX - clientX;
@@ -52202,6 +52282,10 @@ stores.inject(MyMetaStore, storeInstance);
52202
52282
  }
52203
52283
  event.stopPropagation();
52204
52284
  }
52285
+ resetTimeout = setTimeout(() => {
52286
+ velocityX = 0;
52287
+ velocityY = 0;
52288
+ }, resetTimeoutDuration);
52205
52289
  updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
52206
52290
  }
52207
52291
  function onTouchEnd(ev) {
@@ -76826,9 +76910,9 @@ stores.inject(MyMetaStore, storeInstance);
76826
76910
  exports.tokenize = tokenize;
76827
76911
 
76828
76912
 
76829
- __info__.version = "18.2.13";
76830
- __info__.date = "2025-05-20T05:57:00.985Z";
76831
- __info__.hash = "9872529";
76913
+ __info__.version = "18.2.15";
76914
+ __info__.date = "2025-05-30T08:45:53.952Z";
76915
+ __info__.hash = "607492d";
76832
76916
 
76833
76917
 
76834
76918
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);