@odoo/o-spreadsheet 18.0.29 → 18.0.30

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