@odoo/o-spreadsheet 18.2.13 → 18.2.14

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.14
6
+ * @date 2025-05-26T12:35:51.528Z
7
+ * @hash db90fca
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -4149,6 +4149,113 @@ function transposeMatrix(matrix) {
4149
4149
  }
4150
4150
  return generateMatrix(matrix[0].length, matrix.length, (i, j) => matrix[j][i]);
4151
4151
  }
4152
+ /**
4153
+ * Enables a formula function to accept matrix or vector inputs instead of simple value, computing results across multiple dimensions.
4154
+ *
4155
+ * ```
4156
+ * / |‾ ‾| \ |‾ ‾|
4157
+ * | | [A] | | | compute(A, D, E), compute(A, D, F), compute(A, D, G) |
4158
+ * applyVectorization| compute, | [B], D, [E, F, G] | | <=> | compute(B, D, E), compute(B, D, F), compute(B, D, G) |
4159
+ * | | [C] | | | compute(C, D, E), compute(C, D, F), compute(C, D, G) |
4160
+ * \ |_ _| / |_ _|
4161
+ * ```
4162
+ *
4163
+ * By default, all arguments are vectorized. To control which arguments are vectorized,
4164
+ * pass an `acceptToVectorize` boolean array of the same length as `args`:
4165
+ * - `true` enables vectorization for that argument
4166
+ * - `false` disables vectorization for that argument
4167
+ *
4168
+ * For example, with `[true, true, false]` on previous example you get:
4169
+ *
4170
+ * ```
4171
+ * |‾ ‾|
4172
+ * | compute(A, D, [E, F, G]) |
4173
+ * | compute(B, D, [E, F, G]) |
4174
+ * | compute(C, D, [E, F, G]) |
4175
+ * |_ _|
4176
+ * ```
4177
+ *
4178
+ * @remarks
4179
+ * This helper is automatically applied (by default) to **all** `compute` functions
4180
+ * across the various spreadsheet formula modules:
4181
+ * - If an argument is declared **scalar** (not `"range"`), it is vectorized.
4182
+ * - If **all** arguments are declared **ranges**, no vectorization occurs.
4183
+ * - e.g. `SUM(A1:B2)` returns a 1×1 sum over the range.
4184
+ * - e.g. `COS(A1:B2)` over `A1:B2` returns a 2×2 element-wise result.
4185
+ * - For special behaviors (e.g. the `IF` function), you may declare all arguments
4186
+ * as ranges and invoke this helper directly within your `compute` implementation.
4187
+ */
4188
+ function applyVectorization(formula, args, acceptToVectorize = undefined) {
4189
+ let countVectorizedCol = 1;
4190
+ let countVectorizedRow = 1;
4191
+ let vectorizedColLimit = Infinity;
4192
+ let vectorizedRowLimit = Infinity;
4193
+ let vectorArgsType = undefined;
4194
+ for (let i = 0; i < args.length; i++) {
4195
+ const arg = args[i];
4196
+ if (isMatrix(arg) && (acceptToVectorize === undefined || acceptToVectorize[i])) {
4197
+ const nColumns = arg.length;
4198
+ const nRows = arg[0].length;
4199
+ if (nColumns !== 1 || nRows !== 1) {
4200
+ vectorArgsType ??= new Array(args.length);
4201
+ if (nColumns !== 1 && nRows !== 1) {
4202
+ vectorArgsType[i] = "matrix";
4203
+ countVectorizedCol = Math.max(countVectorizedCol, nColumns);
4204
+ countVectorizedRow = Math.max(countVectorizedRow, nRows);
4205
+ vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
4206
+ vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
4207
+ }
4208
+ else if (nColumns !== 1) {
4209
+ vectorArgsType[i] = "horizontal";
4210
+ countVectorizedCol = Math.max(countVectorizedCol, nColumns);
4211
+ vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
4212
+ }
4213
+ else if (nRows !== 1) {
4214
+ vectorArgsType[i] = "vertical";
4215
+ countVectorizedRow = Math.max(countVectorizedRow, nRows);
4216
+ vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
4217
+ }
4218
+ }
4219
+ else {
4220
+ args[i] = arg[0][0];
4221
+ }
4222
+ }
4223
+ }
4224
+ if (countVectorizedCol === 1 && countVectorizedRow === 1) {
4225
+ // either this function is not vectorized or it ends up with a 1x1 dimension
4226
+ return formula(...args);
4227
+ }
4228
+ const getArgOffset = (i, j) => args.map((arg, index) => {
4229
+ switch (vectorArgsType?.[index]) {
4230
+ case "matrix":
4231
+ return arg[i][j];
4232
+ case "horizontal":
4233
+ return arg[i][0];
4234
+ case "vertical":
4235
+ return arg[0][j];
4236
+ case undefined:
4237
+ return arg;
4238
+ }
4239
+ });
4240
+ return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
4241
+ if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
4242
+ return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
4243
+ }
4244
+ const singleCellComputeResult = formula(...getArgOffset(col, row));
4245
+ // In the case where the user tries to vectorize arguments of an array formula, we will get an
4246
+ // array for every combination of the vectorized arguments, which will lead to a 3D matrix and
4247
+ // we won't be able to return the values.
4248
+ // In this case, we keep the first element of each spreading part, just as Excel does, and
4249
+ // create an array with these parts.
4250
+ // For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
4251
+ // range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
4252
+ // for the value in A2). In this case, we will simply take the first value of each matrix and
4253
+ // return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
4254
+ return isMatrix(singleCellComputeResult)
4255
+ ? singleCellComputeResult[0][0]
4256
+ : singleCellComputeResult;
4257
+ });
4258
+ }
4152
4259
  // -----------------------------------------------------------------------------
4153
4260
  // CONDITIONAL EXPLORE FUNCTIONS
4154
4261
  // -----------------------------------------------------------------------------
@@ -7440,14 +7547,20 @@ function multiplyMatrices(matrix1, matrix2) {
7440
7547
  /**
7441
7548
  * Return the input if it's a scalar or the first element of the input if it's a matrix.
7442
7549
  */
7443
- function toScalar(matrix) {
7444
- if (!isMatrix(matrix)) {
7445
- return matrix;
7550
+ function toScalar(arg) {
7551
+ if (!isMatrix(arg)) {
7552
+ return arg;
7446
7553
  }
7447
- if (matrix.length !== 1 || matrix[0].length !== 1) {
7554
+ if (!isSingleElementMatrix(arg)) {
7448
7555
  throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
7449
7556
  }
7450
- return matrix[0][0];
7557
+ return arg[0][0];
7558
+ }
7559
+ function isSingleElementMatrix(matrix) {
7560
+ return matrix.length === 1 && matrix[0].length === 1;
7561
+ }
7562
+ function isMultipleElementMatrix(arg) {
7563
+ return isMatrix(arg) && !isSingleElementMatrix(arg);
7451
7564
  }
7452
7565
 
7453
7566
  function assertSameNumberOfElements(...args) {
@@ -15455,7 +15568,7 @@ const FILTER = {
15455
15568
  }
15456
15569
  return mode === "row" ? transposeMatrix(result) : result;
15457
15570
  },
15458
- isExported: true,
15571
+ isExported: false,
15459
15572
  };
15460
15573
  // -----------------------------------------------------------------------------
15461
15574
  // SORT
@@ -18586,16 +18699,23 @@ const FALSE = {
18586
18699
  const IF = {
18587
18700
  description: _t("Returns value depending on logical expression."),
18588
18701
  args: [
18589
- 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.")),
18590
- arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
18591
- arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
18702
+ 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.")),
18703
+ arg("value_if_true (any, range)", _t("The value the function returns if logical_expression is TRUE.")),
18704
+ arg("value_if_false (any, range, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
18592
18705
  ],
18593
18706
  compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
18594
- const result = toBoolean(logicalExpression?.value) ? valueIfTrue : valueIfFalse;
18707
+ if (isMultipleElementMatrix(logicalExpression)) {
18708
+ return applyVectorization(IF.compute, [logicalExpression, valueIfTrue, valueIfFalse]);
18709
+ }
18710
+ let result = toBoolean(toScalar(logicalExpression)) ? valueIfTrue : valueIfFalse;
18711
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18712
+ if (!isMultipleElementMatrix(result)) {
18713
+ result = toScalar(result);
18714
+ }
18595
18715
  if (result === undefined) {
18596
18716
  return { value: "" };
18597
18717
  }
18598
- if (result.value === null) {
18718
+ if (!isMatrix(result) && result.value === null) {
18599
18719
  return { ...result, value: "" };
18600
18720
  }
18601
18721
  return result;
@@ -18608,15 +18728,22 @@ const IF = {
18608
18728
  const IFERROR = {
18609
18729
  description: _t("Value if it is not an error, otherwise 2nd argument."),
18610
18730
  args: [
18611
- arg("value (any)", _t("The value to return if value itself is not an error.")),
18612
- arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
18731
+ arg("value (any, range)", _t("The value to return if value itself is not an error.")),
18732
+ arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an error.")),
18613
18733
  ],
18614
- compute: function (value, valueIfError = { value: "" }) {
18615
- const result = isEvaluationError(value?.value) ? valueIfError : value;
18734
+ compute: function (value, valueIfError) {
18735
+ if (isMultipleElementMatrix(value)) {
18736
+ return applyVectorization(IFERROR.compute, [value, valueIfError]);
18737
+ }
18738
+ let result = isEvaluationError(toScalar(value)?.value) ? valueIfError : value;
18739
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18740
+ if (!isMultipleElementMatrix(result)) {
18741
+ result = toScalar(result);
18742
+ }
18616
18743
  if (result === undefined) {
18617
18744
  return { value: "" };
18618
18745
  }
18619
- if (result.value === null) {
18746
+ if (!isMatrix(result) && result.value === null) {
18620
18747
  return { ...result, value: "" };
18621
18748
  }
18622
18749
  return result;
@@ -18629,15 +18756,22 @@ const IFERROR = {
18629
18756
  const IFNA = {
18630
18757
  description: _t("Value if it is not an #N/A error, otherwise 2nd argument."),
18631
18758
  args: [
18632
- arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
18633
- arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
18759
+ arg("value (any, range)", _t("The value to return if value itself is not #N/A an error.")),
18760
+ arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
18634
18761
  ],
18635
- compute: function (value, valueIfError = { value: "" }) {
18636
- const result = value?.value === CellErrorType.NotAvailable ? valueIfError : value;
18762
+ compute: function (value, valueIfError) {
18763
+ if (isMultipleElementMatrix(value)) {
18764
+ return applyVectorization(IFNA.compute, [value, valueIfError]);
18765
+ }
18766
+ let result = toScalar(value)?.value === CellErrorType.NotAvailable ? valueIfError : value;
18767
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18768
+ if (!isMultipleElementMatrix(result)) {
18769
+ result = toScalar(result);
18770
+ }
18637
18771
  if (result === undefined) {
18638
18772
  return { value: "" };
18639
18773
  }
18640
- if (result.value === null) {
18774
+ if (!isMatrix(result) && result.value === null) {
18641
18775
  return { ...result, value: "" };
18642
18776
  }
18643
18777
  return result;
@@ -18650,23 +18784,31 @@ const IFNA = {
18650
18784
  const IFS = {
18651
18785
  description: _t("Returns a value depending on multiple logical expressions."),
18652
18786
  args: [
18653
- 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.")),
18654
- arg("value1 (any)", _t("The returned value if condition1 is TRUE.")),
18655
- arg("condition2 (boolean, any, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
18656
- arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
18787
+ 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.")),
18788
+ arg("value1 (any, range)", _t("The returned value if condition1 is TRUE.")),
18789
+ arg("condition2 (boolean, any, range, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
18790
+ arg("value2 (any, range, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
18657
18791
  ],
18658
18792
  compute: function (...values) {
18659
18793
  assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
18660
- for (let n = 0; n < values.length - 1; n += 2) {
18661
- if (toBoolean(values[n]?.value)) {
18662
- const result = values[n + 1];
18663
- if (result === undefined) {
18794
+ while (values.length > 0) {
18795
+ if (isMultipleElementMatrix(values[0])) {
18796
+ return applyVectorization(IFS.compute, values);
18797
+ }
18798
+ const condition = toBoolean(toScalar(values.shift()));
18799
+ let valueIfTrue = values.shift();
18800
+ if (condition) {
18801
+ // useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
18802
+ if (!isMultipleElementMatrix(valueIfTrue)) {
18803
+ valueIfTrue = toScalar(valueIfTrue);
18804
+ }
18805
+ if (valueIfTrue === undefined) {
18664
18806
  return { value: "" };
18665
18807
  }
18666
- if (result.value === null) {
18667
- return { ...result, value: "" };
18808
+ if (!isMatrix(valueIfTrue) && valueIfTrue.value === null) {
18809
+ return { ...valueIfTrue, value: "" };
18668
18810
  }
18669
- return result;
18811
+ return valueIfTrue;
18670
18812
  }
18671
18813
  }
18672
18814
  return new EvaluationError(_t("No match."));
@@ -20328,7 +20470,7 @@ const SPLIT = {
20328
20470
  }
20329
20471
  return transposeMatrix([result]);
20330
20472
  },
20331
- isExported: true,
20473
+ isExported: false,
20332
20474
  };
20333
20475
  // -----------------------------------------------------------------------------
20334
20476
  // SUBSTITUTE
@@ -20521,86 +20663,21 @@ for (let category of categories) {
20521
20663
  functionRegistry.add(name, { isExported: false, ...addDescr });
20522
20664
  }
20523
20665
  }
20524
- const notAvailableError = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
20666
+ //------------------------------------------------------------------------------
20667
+ // CREATE COMPUTE FUNCTION
20668
+ //------------------------------------------------------------------------------
20525
20669
  function createComputeFunction(descr, functionName) {
20526
20670
  function vectorizedCompute(...args) {
20527
- let countVectorizableCol = 1;
20528
- let countVectorizableRow = 1;
20529
- let vectorizableColLimit = Infinity;
20530
- let vectorizableRowLimit = Infinity;
20531
- let vectorArgsType = undefined;
20532
- //#region Compute vectorisation limits
20671
+ const acceptToVectorize = [];
20533
20672
  for (let i = 0; i < args.length; i++) {
20534
20673
  const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
20535
20674
  const arg = args[i];
20536
- if (isMatrix(arg) && !argDefinition.acceptMatrix) {
20537
- // if argDefinition does not accept a matrix but arg is still a matrix
20538
- // --> triggers the arguments vectorization
20539
- const nColumns = arg.length;
20540
- const nRows = arg[0].length;
20541
- if (nColumns !== 1 || nRows !== 1) {
20542
- vectorArgsType ??= new Array(args.length);
20543
- if (nColumns !== 1 && nRows !== 1) {
20544
- vectorArgsType[i] = "matrix";
20545
- countVectorizableCol = Math.max(countVectorizableCol, nColumns);
20546
- countVectorizableRow = Math.max(countVectorizableRow, nRows);
20547
- vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
20548
- vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
20549
- }
20550
- else if (nColumns !== 1) {
20551
- vectorArgsType[i] = "horizontal";
20552
- countVectorizableCol = Math.max(countVectorizableCol, nColumns);
20553
- vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
20554
- }
20555
- else if (nRows !== 1) {
20556
- vectorArgsType[i] = "vertical";
20557
- countVectorizableRow = Math.max(countVectorizableRow, nRows);
20558
- vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
20559
- }
20560
- }
20561
- else {
20562
- args[i] = arg[0][0];
20563
- }
20564
- }
20565
20675
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
20566
20676
  throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", functionName, (i + 1).toString()));
20567
20677
  }
20678
+ acceptToVectorize.push(!argDefinition.acceptMatrix);
20568
20679
  }
20569
- //#endregion
20570
- if (countVectorizableCol === 1 && countVectorizableRow === 1) {
20571
- // either this function is not vectorized or it ends up with a 1x1 dimension
20572
- return errorHandlingCompute.apply(this, args);
20573
- }
20574
- const getArgOffset = (i, j) => args.map((arg, index) => {
20575
- switch (vectorArgsType?.[index]) {
20576
- case "matrix":
20577
- return arg[i][j];
20578
- case "horizontal":
20579
- return arg[i][0];
20580
- case "vertical":
20581
- return arg[0][j];
20582
- case undefined:
20583
- return arg;
20584
- }
20585
- });
20586
- return generateMatrix(countVectorizableCol, countVectorizableRow, (col, row) => {
20587
- if (col > vectorizableColLimit - 1 || row > vectorizableRowLimit - 1) {
20588
- return notAvailableError;
20589
- }
20590
- const singleCellComputeResult = errorHandlingCompute.apply(this, getArgOffset(col, row));
20591
- // In the case where the user tries to vectorize arguments of an array formula, we will get an
20592
- // array for every combination of the vectorized arguments, which will lead to a 3D matrix and
20593
- // we won't be able to return the values.
20594
- // In this case, we keep the first element of each spreading part, just as Excel does, and
20595
- // create an array with these parts.
20596
- // For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
20597
- // range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
20598
- // for the value in A2). In this case, we will simply take the first value of each matrix and
20599
- // return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
20600
- return isMatrix(singleCellComputeResult)
20601
- ? singleCellComputeResult[0][0]
20602
- : singleCellComputeResult;
20603
- });
20680
+ return applyVectorization(errorHandlingCompute.bind(this), args, acceptToVectorize);
20604
20681
  }
20605
20682
  function errorHandlingCompute(...args) {
20606
20683
  for (let i = 0; i < args.length; i++) {
@@ -21445,7 +21522,7 @@ class AbstractComposerStore extends SpreadsheetStore {
21445
21522
  proposals &&
21446
21523
  !["ARG_SEPARATOR", "LEFT_PAREN", "OPERATOR"].includes(tokenAtCursor.type)) {
21447
21524
  const filteredProposals = fuzzyLookup(searchTerm, proposals, (p) => p.fuzzySearchKey || p.text);
21448
- if (!exactMatch || filteredProposals.length > 1) {
21525
+ if (!exactMatch || filteredProposals.length) {
21449
21526
  proposals = filteredProposals;
21450
21527
  }
21451
21528
  }
@@ -46481,7 +46558,9 @@ function compareDimensionValues(dimension, a, b) {
46481
46558
  return dimension.order === "asc" ? -1 : 1;
46482
46559
  }
46483
46560
  if (dimension.type === "integer" || dimension.type === "datetime") {
46484
- return dimension.order === "asc" ? Number(a) - Number(b) : Number(b) - Number(a);
46561
+ return dimension.order === "asc"
46562
+ ? toNumber(a, DEFAULT_LOCALE) - toNumber(b, DEFAULT_LOCALE)
46563
+ : toNumber(b, DEFAULT_LOCALE) - toNumber(a, DEFAULT_LOCALE);
46485
46564
  }
46486
46565
  return dimension.order === "asc" ? a.localeCompare(b) : b.localeCompare(a);
46487
46566
  }
@@ -49244,8 +49323,7 @@ class CellComposerStore extends AbstractComposerStore {
49244
49323
  if (!spreader) {
49245
49324
  return undefined;
49246
49325
  }
49247
- const cell = this.getters.getCell(spreader);
49248
- return cell?.content;
49326
+ return this.getters.getCellText(spreader, { showFormula: true });
49249
49327
  }
49250
49328
  get currentEditedCell() {
49251
49329
  return {
@@ -52166,6 +52244,7 @@ function useGridDrawing(refName, model, canvasSize) {
52166
52244
  const friction = 0.95;
52167
52245
  const verticalScrollFactor = 1;
52168
52246
  const horizontalScrollFactor = 1;
52247
+ const resetTimeoutDuration = 100;
52169
52248
  function useTouchScroll(ref, updateScroll, canMoveUp) {
52170
52249
  let lastX = 0;
52171
52250
  let lastY = 0;
@@ -52173,6 +52252,7 @@ function useTouchScroll(ref, updateScroll, canMoveUp) {
52173
52252
  let velocityY = 0;
52174
52253
  let isMouseDown = false;
52175
52254
  let lastTime = 0;
52255
+ let resetTimeout = null;
52176
52256
  useRefListener(ref, "touchstart", onTouchStart, { capture: false });
52177
52257
  useRefListener(ref, "touchmove", onTouchMove, { capture: false });
52178
52258
  useRefListener(ref, "touchend", onTouchEnd, { capture: false });
@@ -52185,6 +52265,10 @@ function useTouchScroll(ref, updateScroll, canMoveUp) {
52185
52265
  function onTouchMove(event) {
52186
52266
  if (!isMouseDown)
52187
52267
  return;
52268
+ if (resetTimeout) {
52269
+ clearTimeout(resetTimeout);
52270
+ resetTimeout = null;
52271
+ }
52188
52272
  const currentTime = Date.now();
52189
52273
  const { clientX, clientY } = event.touches[0];
52190
52274
  let deltaX = lastX - clientX;
@@ -52201,6 +52285,10 @@ function useTouchScroll(ref, updateScroll, canMoveUp) {
52201
52285
  }
52202
52286
  event.stopPropagation();
52203
52287
  }
52288
+ resetTimeout = setTimeout(() => {
52289
+ velocityX = 0;
52290
+ velocityY = 0;
52291
+ }, resetTimeoutDuration);
52204
52292
  updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
52205
52293
  }
52206
52294
  function onTouchEnd(ev) {
@@ -76780,6 +76868,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
76780
76868
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
76781
76869
 
76782
76870
 
76783
- __info__.version = "18.2.13";
76784
- __info__.date = "2025-05-20T05:57:00.985Z";
76785
- __info__.hash = "9872529";
76871
+ __info__.version = "18.2.14";
76872
+ __info__.date = "2025-05-26T12:35:51.528Z";
76873
+ __info__.hash = "db90fca";