@odoo/o-spreadsheet 18.1.21 → 18.1.23

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.1.21
6
- * @date 2025-05-20T05:54:45.398Z
7
- * @hash 89ed6a9
5
+ * @version 18.1.23
6
+ * @date 2025-05-30T08:45:44.408Z
7
+ * @hash a21fa01
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -4141,6 +4141,113 @@
4141
4141
  }
4142
4142
  return generateMatrix(matrix[0].length, matrix.length, (i, j) => matrix[j][i]);
4143
4143
  }
4144
+ /**
4145
+ * Enables a formula function to accept matrix or vector inputs instead of simple value, computing results across multiple dimensions.
4146
+ *
4147
+ * ```
4148
+ * / |‾ ‾| \ |‾ ‾|
4149
+ * | | [A] | | | compute(A, D, E), compute(A, D, F), compute(A, D, G) |
4150
+ * applyVectorization| compute, | [B], D, [E, F, G] | | <=> | compute(B, D, E), compute(B, D, F), compute(B, D, G) |
4151
+ * | | [C] | | | compute(C, D, E), compute(C, D, F), compute(C, D, G) |
4152
+ * \ |_ _| / |_ _|
4153
+ * ```
4154
+ *
4155
+ * By default, all arguments are vectorized. To control which arguments are vectorized,
4156
+ * pass an `acceptToVectorize` boolean array of the same length as `args`:
4157
+ * - `true` enables vectorization for that argument
4158
+ * - `false` disables vectorization for that argument
4159
+ *
4160
+ * For example, with `[true, true, false]` on previous example you get:
4161
+ *
4162
+ * ```
4163
+ * |‾ ‾|
4164
+ * | compute(A, D, [E, F, G]) |
4165
+ * | compute(B, D, [E, F, G]) |
4166
+ * | compute(C, D, [E, F, G]) |
4167
+ * |_ _|
4168
+ * ```
4169
+ *
4170
+ * @remarks
4171
+ * This helper is automatically applied (by default) to **all** `compute` functions
4172
+ * across the various spreadsheet formula modules:
4173
+ * - If an argument is declared **scalar** (not `"range"`), it is vectorized.
4174
+ * - If **all** arguments are declared **ranges**, no vectorization occurs.
4175
+ * - e.g. `SUM(A1:B2)` returns a 1×1 sum over the range.
4176
+ * - e.g. `COS(A1:B2)` over `A1:B2` returns a 2×2 element-wise result.
4177
+ * - For special behaviors (e.g. the `IF` function), you may declare all arguments
4178
+ * as ranges and invoke this helper directly within your `compute` implementation.
4179
+ */
4180
+ function applyVectorization(formula, args, acceptToVectorize = undefined) {
4181
+ let countVectorizedCol = 1;
4182
+ let countVectorizedRow = 1;
4183
+ let vectorizedColLimit = Infinity;
4184
+ let vectorizedRowLimit = Infinity;
4185
+ let vectorArgsType = undefined;
4186
+ for (let i = 0; i < args.length; i++) {
4187
+ const arg = args[i];
4188
+ if (isMatrix(arg) && (acceptToVectorize === undefined || acceptToVectorize[i])) {
4189
+ const nColumns = arg.length;
4190
+ const nRows = arg[0].length;
4191
+ if (nColumns !== 1 || nRows !== 1) {
4192
+ vectorArgsType ??= new Array(args.length);
4193
+ if (nColumns !== 1 && nRows !== 1) {
4194
+ vectorArgsType[i] = "matrix";
4195
+ countVectorizedCol = Math.max(countVectorizedCol, nColumns);
4196
+ countVectorizedRow = Math.max(countVectorizedRow, nRows);
4197
+ vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
4198
+ vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
4199
+ }
4200
+ else if (nColumns !== 1) {
4201
+ vectorArgsType[i] = "horizontal";
4202
+ countVectorizedCol = Math.max(countVectorizedCol, nColumns);
4203
+ vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
4204
+ }
4205
+ else if (nRows !== 1) {
4206
+ vectorArgsType[i] = "vertical";
4207
+ countVectorizedRow = Math.max(countVectorizedRow, nRows);
4208
+ vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
4209
+ }
4210
+ }
4211
+ else {
4212
+ args[i] = arg[0][0];
4213
+ }
4214
+ }
4215
+ }
4216
+ if (countVectorizedCol === 1 && countVectorizedRow === 1) {
4217
+ // either this function is not vectorized or it ends up with a 1x1 dimension
4218
+ return formula(...args);
4219
+ }
4220
+ const getArgOffset = (i, j) => args.map((arg, index) => {
4221
+ switch (vectorArgsType?.[index]) {
4222
+ case "matrix":
4223
+ return arg[i][j];
4224
+ case "horizontal":
4225
+ return arg[i][0];
4226
+ case "vertical":
4227
+ return arg[0][j];
4228
+ case undefined:
4229
+ return arg;
4230
+ }
4231
+ });
4232
+ return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
4233
+ if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
4234
+ return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
4235
+ }
4236
+ const singleCellComputeResult = formula(...getArgOffset(col, row));
4237
+ // In the case where the user tries to vectorize arguments of an array formula, we will get an
4238
+ // array for every combination of the vectorized arguments, which will lead to a 3D matrix and
4239
+ // we won't be able to return the values.
4240
+ // In this case, we keep the first element of each spreading part, just as Excel does, and
4241
+ // create an array with these parts.
4242
+ // For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
4243
+ // range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
4244
+ // for the value in A2). In this case, we will simply take the first value of each matrix and
4245
+ // return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
4246
+ return isMatrix(singleCellComputeResult)
4247
+ ? singleCellComputeResult[0][0]
4248
+ : singleCellComputeResult;
4249
+ });
4250
+ }
4144
4251
  // -----------------------------------------------------------------------------
4145
4252
  // CONDITIONAL EXPLORE FUNCTIONS
4146
4253
  // -----------------------------------------------------------------------------
@@ -7432,14 +7539,20 @@
7432
7539
  /**
7433
7540
  * Return the input if it's a scalar or the first element of the input if it's a matrix.
7434
7541
  */
7435
- function toScalar(matrix) {
7436
- if (!isMatrix(matrix)) {
7437
- return matrix;
7542
+ function toScalar(arg) {
7543
+ if (!isMatrix(arg)) {
7544
+ return arg;
7438
7545
  }
7439
- if (matrix.length !== 1 || matrix[0].length !== 1) {
7546
+ if (!isSingleElementMatrix(arg)) {
7440
7547
  throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
7441
7548
  }
7442
- return matrix[0][0];
7549
+ return arg[0][0];
7550
+ }
7551
+ function isSingleElementMatrix(matrix) {
7552
+ return matrix.length === 1 && matrix[0].length === 1;
7553
+ }
7554
+ function isMultipleElementMatrix(arg) {
7555
+ return isMatrix(arg) && !isSingleElementMatrix(arg);
7443
7556
  }
7444
7557
 
7445
7558
  function assertSameNumberOfElements(...args) {
@@ -8181,9 +8294,10 @@
8181
8294
  avg: _t("Average"),
8182
8295
  sum: _t("Sum"),
8183
8296
  };
8297
+ const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
8184
8298
  const AGGREGATORS_BY_FIELD_TYPE = {
8185
- integer: ["max", "min", "avg", "sum", "count_distinct", "count"],
8186
- char: ["count_distinct", "count"],
8299
+ integer: NUMBER_CHAR_AGGREGATORS,
8300
+ char: NUMBER_CHAR_AGGREGATORS,
8187
8301
  boolean: ["count_distinct", "count", "bool_and", "bool_or"],
8188
8302
  };
8189
8303
  const AGGREGATORS = {};
@@ -15283,7 +15397,7 @@ stores.inject(MyMetaStore, storeInstance);
15283
15397
  }
15284
15398
  return mode === "row" ? transposeMatrix(result) : result;
15285
15399
  },
15286
- isExported: true,
15400
+ isExported: false,
15287
15401
  };
15288
15402
  // -----------------------------------------------------------------------------
15289
15403
  // SORT
@@ -18414,16 +18528,23 @@ stores.inject(MyMetaStore, storeInstance);
18414
18528
  const IF = {
18415
18529
  description: _t("Returns value depending on logical expression."),
18416
18530
  args: [
18417
- 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.")),
18418
- arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
18419
- arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
18531
+ 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.")),
18532
+ arg("value_if_true (any, range)", _t("The value the function returns if logical_expression is TRUE.")),
18533
+ arg("value_if_false (any, range, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
18420
18534
  ],
18421
18535
  compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
18422
- const result = toBoolean(logicalExpression?.value) ? valueIfTrue : valueIfFalse;
18536
+ if (isMultipleElementMatrix(logicalExpression)) {
18537
+ return applyVectorization(IF.compute, [logicalExpression, valueIfTrue, valueIfFalse]);
18538
+ }
18539
+ let result = toBoolean(toScalar(logicalExpression)) ? valueIfTrue : valueIfFalse;
18540
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18541
+ if (!isMultipleElementMatrix(result)) {
18542
+ result = toScalar(result);
18543
+ }
18423
18544
  if (result === undefined) {
18424
18545
  return { value: "" };
18425
18546
  }
18426
- if (result.value === null) {
18547
+ if (!isMatrix(result) && result.value === null) {
18427
18548
  return { ...result, value: "" };
18428
18549
  }
18429
18550
  return result;
@@ -18436,15 +18557,22 @@ stores.inject(MyMetaStore, storeInstance);
18436
18557
  const IFERROR = {
18437
18558
  description: _t("Value if it is not an error, otherwise 2nd argument."),
18438
18559
  args: [
18439
- arg("value (any)", _t("The value to return if value itself is not an error.")),
18440
- arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
18560
+ arg("value (any, range)", _t("The value to return if value itself is not an error.")),
18561
+ arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an error.")),
18441
18562
  ],
18442
- compute: function (value, valueIfError = { value: "" }) {
18443
- const result = isEvaluationError(value?.value) ? valueIfError : value;
18563
+ compute: function (value, valueIfError) {
18564
+ if (isMultipleElementMatrix(value)) {
18565
+ return applyVectorization(IFERROR.compute, [value, valueIfError]);
18566
+ }
18567
+ let result = isEvaluationError(toScalar(value)?.value) ? valueIfError : value;
18568
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18569
+ if (!isMultipleElementMatrix(result)) {
18570
+ result = toScalar(result);
18571
+ }
18444
18572
  if (result === undefined) {
18445
18573
  return { value: "" };
18446
18574
  }
18447
- if (result.value === null) {
18575
+ if (!isMatrix(result) && result.value === null) {
18448
18576
  return { ...result, value: "" };
18449
18577
  }
18450
18578
  return result;
@@ -18457,15 +18585,22 @@ stores.inject(MyMetaStore, storeInstance);
18457
18585
  const IFNA = {
18458
18586
  description: _t("Value if it is not an #N/A error, otherwise 2nd argument."),
18459
18587
  args: [
18460
- arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
18461
- arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
18588
+ arg("value (any, range)", _t("The value to return if value itself is not #N/A an error.")),
18589
+ arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
18462
18590
  ],
18463
- compute: function (value, valueIfError = { value: "" }) {
18464
- const result = value?.value === CellErrorType.NotAvailable ? valueIfError : value;
18591
+ compute: function (value, valueIfError) {
18592
+ if (isMultipleElementMatrix(value)) {
18593
+ return applyVectorization(IFNA.compute, [value, valueIfError]);
18594
+ }
18595
+ let result = toScalar(value)?.value === CellErrorType.NotAvailable ? valueIfError : value;
18596
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18597
+ if (!isMultipleElementMatrix(result)) {
18598
+ result = toScalar(result);
18599
+ }
18465
18600
  if (result === undefined) {
18466
18601
  return { value: "" };
18467
18602
  }
18468
- if (result.value === null) {
18603
+ if (!isMatrix(result) && result.value === null) {
18469
18604
  return { ...result, value: "" };
18470
18605
  }
18471
18606
  return result;
@@ -18478,23 +18613,31 @@ stores.inject(MyMetaStore, storeInstance);
18478
18613
  const IFS = {
18479
18614
  description: _t("Returns a value depending on multiple logical expressions."),
18480
18615
  args: [
18481
- 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.")),
18482
- arg("value1 (any)", _t("The returned value if condition1 is TRUE.")),
18483
- arg("condition2 (boolean, any, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
18484
- arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
18616
+ 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.")),
18617
+ arg("value1 (any, range)", _t("The returned value if condition1 is TRUE.")),
18618
+ arg("condition2 (boolean, any, range, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
18619
+ arg("value2 (any, range, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
18485
18620
  ],
18486
18621
  compute: function (...values) {
18487
18622
  assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
18488
- for (let n = 0; n < values.length - 1; n += 2) {
18489
- if (toBoolean(values[n]?.value)) {
18490
- const result = values[n + 1];
18491
- if (result === undefined) {
18623
+ while (values.length > 0) {
18624
+ if (isMultipleElementMatrix(values[0])) {
18625
+ return applyVectorization(IFS.compute, values);
18626
+ }
18627
+ const condition = toBoolean(toScalar(values.shift()));
18628
+ let valueIfTrue = values.shift();
18629
+ if (condition) {
18630
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18631
+ if (!isMultipleElementMatrix(valueIfTrue)) {
18632
+ valueIfTrue = toScalar(valueIfTrue);
18633
+ }
18634
+ if (valueIfTrue === undefined) {
18492
18635
  return { value: "" };
18493
18636
  }
18494
- if (result.value === null) {
18495
- return { ...result, value: "" };
18637
+ if (!isMatrix(valueIfTrue) && valueIfTrue.value === null) {
18638
+ return { ...valueIfTrue, value: "" };
18496
18639
  }
18497
- return result;
18640
+ return valueIfTrue;
18498
18641
  }
18499
18642
  }
18500
18643
  return new EvaluationError(_t("No match."));
@@ -20156,7 +20299,7 @@ stores.inject(MyMetaStore, storeInstance);
20156
20299
  }
20157
20300
  return transposeMatrix([result]);
20158
20301
  },
20159
- isExported: true,
20302
+ isExported: false,
20160
20303
  };
20161
20304
  // -----------------------------------------------------------------------------
20162
20305
  // SUBSTITUTE
@@ -20349,86 +20492,21 @@ stores.inject(MyMetaStore, storeInstance);
20349
20492
  functionRegistry.add(name, { isExported: false, ...addDescr });
20350
20493
  }
20351
20494
  }
20352
- const notAvailableError = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
20495
+ //------------------------------------------------------------------------------
20496
+ // CREATE COMPUTE FUNCTION
20497
+ //------------------------------------------------------------------------------
20353
20498
  function createComputeFunction(descr, functionName) {
20354
20499
  function vectorizedCompute(...args) {
20355
- let countVectorizableCol = 1;
20356
- let countVectorizableRow = 1;
20357
- let vectorizableColLimit = Infinity;
20358
- let vectorizableRowLimit = Infinity;
20359
- let vectorArgsType = undefined;
20360
- //#region Compute vectorisation limits
20500
+ const acceptToVectorize = [];
20361
20501
  for (let i = 0; i < args.length; i++) {
20362
20502
  const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
20363
20503
  const arg = args[i];
20364
- if (isMatrix(arg) && !argDefinition.acceptMatrix) {
20365
- // if argDefinition does not accept a matrix but arg is still a matrix
20366
- // --> triggers the arguments vectorization
20367
- const nColumns = arg.length;
20368
- const nRows = arg[0].length;
20369
- if (nColumns !== 1 || nRows !== 1) {
20370
- vectorArgsType ??= new Array(args.length);
20371
- if (nColumns !== 1 && nRows !== 1) {
20372
- vectorArgsType[i] = "matrix";
20373
- countVectorizableCol = Math.max(countVectorizableCol, nColumns);
20374
- countVectorizableRow = Math.max(countVectorizableRow, nRows);
20375
- vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
20376
- vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
20377
- }
20378
- else if (nColumns !== 1) {
20379
- vectorArgsType[i] = "horizontal";
20380
- countVectorizableCol = Math.max(countVectorizableCol, nColumns);
20381
- vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
20382
- }
20383
- else if (nRows !== 1) {
20384
- vectorArgsType[i] = "vertical";
20385
- countVectorizableRow = Math.max(countVectorizableRow, nRows);
20386
- vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
20387
- }
20388
- }
20389
- else {
20390
- args[i] = arg[0][0];
20391
- }
20392
- }
20393
20504
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
20394
20505
  throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", functionName, (i + 1).toString()));
20395
20506
  }
20507
+ acceptToVectorize.push(!argDefinition.acceptMatrix);
20396
20508
  }
20397
- //#endregion
20398
- if (countVectorizableCol === 1 && countVectorizableRow === 1) {
20399
- // either this function is not vectorized or it ends up with a 1x1 dimension
20400
- return errorHandlingCompute.apply(this, args);
20401
- }
20402
- const getArgOffset = (i, j) => args.map((arg, index) => {
20403
- switch (vectorArgsType?.[index]) {
20404
- case "matrix":
20405
- return arg[i][j];
20406
- case "horizontal":
20407
- return arg[i][0];
20408
- case "vertical":
20409
- return arg[0][j];
20410
- case undefined:
20411
- return arg;
20412
- }
20413
- });
20414
- return generateMatrix(countVectorizableCol, countVectorizableRow, (col, row) => {
20415
- if (col > vectorizableColLimit - 1 || row > vectorizableRowLimit - 1) {
20416
- return notAvailableError;
20417
- }
20418
- const singleCellComputeResult = errorHandlingCompute.apply(this, getArgOffset(col, row));
20419
- // In the case where the user tries to vectorize arguments of an array formula, we will get an
20420
- // array for every combination of the vectorized arguments, which will lead to a 3D matrix and
20421
- // we won't be able to return the values.
20422
- // In this case, we keep the first element of each spreading part, just as Excel does, and
20423
- // create an array with these parts.
20424
- // For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
20425
- // range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
20426
- // for the value in A2). In this case, we will simply take the first value of each matrix and
20427
- // return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
20428
- return isMatrix(singleCellComputeResult)
20429
- ? singleCellComputeResult[0][0]
20430
- : singleCellComputeResult;
20431
- });
20509
+ return applyVectorization(errorHandlingCompute.bind(this), args, acceptToVectorize);
20432
20510
  }
20433
20511
  function errorHandlingCompute(...args) {
20434
20512
  for (let i = 0; i < args.length; i++) {
@@ -21273,7 +21351,7 @@ stores.inject(MyMetaStore, storeInstance);
21273
21351
  proposals &&
21274
21352
  !["ARG_SEPARATOR", "LEFT_PAREN", "OPERATOR"].includes(tokenAtCursor.type)) {
21275
21353
  const filteredProposals = fuzzyLookup(searchTerm, proposals, (p) => p.fuzzySearchKey || p.text);
21276
- if (!exactMatch || filteredProposals.length > 1) {
21354
+ if (!exactMatch || filteredProposals.length) {
21277
21355
  proposals = filteredProposals;
21278
21356
  }
21279
21357
  }
@@ -46140,7 +46218,9 @@ stores.inject(MyMetaStore, storeInstance);
46140
46218
  return dimension.order === "asc" ? -1 : 1;
46141
46219
  }
46142
46220
  if (dimension.type === "integer" || dimension.type === "datetime") {
46143
- return dimension.order === "asc" ? Number(a) - Number(b) : Number(b) - Number(a);
46221
+ return dimension.order === "asc"
46222
+ ? toNumber(a, DEFAULT_LOCALE) - toNumber(b, DEFAULT_LOCALE)
46223
+ : toNumber(b, DEFAULT_LOCALE) - toNumber(a, DEFAULT_LOCALE);
46144
46224
  }
46145
46225
  return dimension.order === "asc" ? a.localeCompare(b) : b.localeCompare(a);
46146
46226
  }
@@ -46676,12 +46756,7 @@ stores.inject(MyMetaStore, storeInstance);
46676
46756
  entry[field.name] = { value: null, type: CellValueType.empty, formattedValue: "" };
46677
46757
  }
46678
46758
  else {
46679
- if (field.type === "char") {
46680
- entry[field.name] = { ...cell, value: cell.formattedValue || null };
46681
- }
46682
- else {
46683
- entry[field.name] = cell;
46684
- }
46759
+ entry[field.name] = cell;
46685
46760
  }
46686
46761
  }
46687
46762
  entry["__count"] = { value: 1, type: CellValueType.number, formattedValue: "1" };
@@ -48906,8 +48981,7 @@ stores.inject(MyMetaStore, storeInstance);
48906
48981
  if (!spreader) {
48907
48982
  return undefined;
48908
48983
  }
48909
- const cell = this.getters.getCell(spreader);
48910
- return cell?.content;
48984
+ return this.getters.getCellText(spreader, { showFormula: true });
48911
48985
  }
48912
48986
  get currentEditedCell() {
48913
48987
  return {
@@ -51718,6 +51792,7 @@ stores.inject(MyMetaStore, storeInstance);
51718
51792
  const friction = 0.95;
51719
51793
  const verticalScrollFactor = 1;
51720
51794
  const horizontalScrollFactor = 1;
51795
+ const resetTimeoutDuration = 100;
51721
51796
  function useTouchScroll(ref, updateScroll, canMoveUp) {
51722
51797
  let lastX = 0;
51723
51798
  let lastY = 0;
@@ -51725,6 +51800,7 @@ stores.inject(MyMetaStore, storeInstance);
51725
51800
  let velocityY = 0;
51726
51801
  let isMouseDown = false;
51727
51802
  let lastTime = 0;
51803
+ let resetTimeout = null;
51728
51804
  useRefListener(ref, "touchstart", onTouchStart, { capture: false });
51729
51805
  useRefListener(ref, "touchmove", onTouchMove, { capture: false });
51730
51806
  useRefListener(ref, "touchend", onTouchEnd, { capture: false });
@@ -51737,6 +51813,10 @@ stores.inject(MyMetaStore, storeInstance);
51737
51813
  function onTouchMove(event) {
51738
51814
  if (!isMouseDown)
51739
51815
  return;
51816
+ if (resetTimeout) {
51817
+ clearTimeout(resetTimeout);
51818
+ resetTimeout = null;
51819
+ }
51740
51820
  const currentTime = Date.now();
51741
51821
  const { clientX, clientY } = event.touches[0];
51742
51822
  let deltaX = lastX - clientX;
@@ -51753,6 +51833,10 @@ stores.inject(MyMetaStore, storeInstance);
51753
51833
  }
51754
51834
  event.stopPropagation();
51755
51835
  }
51836
+ resetTimeout = setTimeout(() => {
51837
+ velocityX = 0;
51838
+ velocityY = 0;
51839
+ }, resetTimeoutDuration);
51756
51840
  updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
51757
51841
  }
51758
51842
  function onTouchEnd(ev) {
@@ -76348,9 +76432,9 @@ stores.inject(MyMetaStore, storeInstance);
76348
76432
  exports.tokenize = tokenize;
76349
76433
 
76350
76434
 
76351
- __info__.version = "18.1.21";
76352
- __info__.date = "2025-05-20T05:54:45.398Z";
76353
- __info__.hash = "89ed6a9";
76435
+ __info__.version = "18.1.23";
76436
+ __info__.date = "2025-05-30T08:45:44.408Z";
76437
+ __info__.hash = "a21fa01";
76354
76438
 
76355
76439
 
76356
76440
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);