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