@odoo/o-spreadsheet 19.1.30 → 19.1.32

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 19.1.30
6
- * @date 2026-07-30T06:53:53.625Z
7
- * @hash b4f7ab8
5
+ * @version 19.1.32
6
+ * @date 2026-08-21T15:29:31.737Z
7
+ * @hash d34d0e7
8
8
  */
9
9
  :root {
10
10
  --os-gray-100: light-dark(#f9fafb, #1b1d26);
@@ -291,6 +291,7 @@
291
291
  .os-input {
292
292
  border-width: 0 0 1px 0;
293
293
  border-color: transparent;
294
+ border-style: solid;
294
295
  outline: none;
295
296
  text-overflow: ellipsis;
296
297
  color: var(--os-text-body);
@@ -542,6 +543,7 @@
542
543
  width: 100%;
543
544
  outline: none;
544
545
  border-color: var(--os-border-color);
546
+ border-style: solid;
545
547
  color: var(--os-gray-900);
546
548
 
547
549
  &::placeholder {
@@ -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 19.1.30
6
- * @date 2026-07-30T06:53:51.978Z
7
- * @hash b4f7ab8
5
+ * @version 19.1.32
6
+ * @date 2026-08-21T15:29:30.638Z
7
+ * @hash d34d0e7
8
8
  */
9
9
 
10
10
  import { App, Component, blockDom, markRaw, onMounted, onPatched, onWillPatch, onWillStart, onWillUnmount, onWillUpdateProps, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, whenReady, xml } from "@odoo/owl";
@@ -3726,6 +3726,18 @@ function toString(data) {
3726
3726
  default: return "";
3727
3727
  }
3728
3728
  }
3729
+ /**
3730
+ * Only converts the decimal separator, ignore number format such as % or dates
3731
+ */
3732
+ function toLocaleString(data, locale) {
3733
+ const value = toValue(data);
3734
+ switch (typeof value) {
3735
+ case "string": return value;
3736
+ case "number": return value.toString().replace(".", locale.decimalSeparator);
3737
+ case "boolean": return value ? "TRUE" : "FALSE";
3738
+ default: return "";
3739
+ }
3740
+ }
3729
3741
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
3730
3742
  const normalizeString = memoize(function normalizeString(str) {
3731
3743
  return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
@@ -3915,19 +3927,58 @@ function applyVectorization(formula, args, acceptToVectorize = void 0) {
3915
3927
  }
3916
3928
  }
3917
3929
  if (countVectorizedCol === 1 && countVectorizedRow === 1) return formula(...args);
3918
- const getArgOffset = (i, j) => args.map((arg, index) => {
3919
- switch (vectorArgsType?.[index]) {
3920
- case "matrix": return arg[i][j];
3921
- case "horizontal": return arg[i][0];
3922
- case "vertical": return arg[0][j];
3923
- case void 0: return arg;
3930
+ const argsBuffer = new Array(args.length);
3931
+ const argGetters = [];
3932
+ const vectorizedIndices = [];
3933
+ for (let k = 0; k < args.length; k++) {
3934
+ const arg = args[k];
3935
+ switch (vectorArgsType?.[k]) {
3936
+ case "matrix":
3937
+ argGetters.push((i, j) => arg[i][j]);
3938
+ vectorizedIndices.push(k);
3939
+ break;
3940
+ case "horizontal":
3941
+ argGetters.push((i) => arg[i][0]);
3942
+ vectorizedIndices.push(k);
3943
+ break;
3944
+ case "vertical":
3945
+ argGetters.push((_i, j) => arg[0][j]);
3946
+ vectorizedIndices.push(k);
3947
+ break;
3948
+ case void 0:
3949
+ argsBuffer[k] = arg;
3950
+ break;
3924
3951
  }
3925
- });
3926
- return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
3927
- if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
3928
- const singleCellComputeResult = formula(...getArgOffset(col, row));
3929
- return isMatrix(singleCellComputeResult) ? singleCellComputeResult[0][0] : singleCellComputeResult;
3930
- });
3952
+ }
3953
+ const nbVectorized = vectorizedIndices.length;
3954
+ let callFormula;
3955
+ switch (argsBuffer.length) {
3956
+ case 1:
3957
+ callFormula = () => formula(argsBuffer[0]);
3958
+ break;
3959
+ case 2:
3960
+ callFormula = () => formula(argsBuffer[0], argsBuffer[1]);
3961
+ break;
3962
+ case 3:
3963
+ callFormula = () => formula(argsBuffer[0], argsBuffer[1], argsBuffer[2]);
3964
+ break;
3965
+ default: callFormula = () => formula(...argsBuffer);
3966
+ }
3967
+ const result = new Array(countVectorizedCol);
3968
+ for (let col = 0; col < countVectorizedCol; col++) {
3969
+ const column = new Array(countVectorizedRow);
3970
+ result[col] = column;
3971
+ for (let row = 0; row < countVectorizedRow; row++) {
3972
+ if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
3973
+ column[row] = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
3974
+ continue;
3975
+ }
3976
+ for (let k = 0; k < nbVectorized; k++) argsBuffer[vectorizedIndices[k]] = argGetters[k](col, row);
3977
+ const singleCellComputeResult = callFormula();
3978
+ column[row] = isMatrix(singleCellComputeResult) ? singleCellComputeResult[0][0] : singleCellComputeResult;
3979
+ }
3980
+ }
3981
+ return result;
3931
3982
  }
3932
3983
  /**
3933
3984
  * This function allows to visit arguments and stop the visit if necessary.
@@ -17264,7 +17315,7 @@ var FigureComponent = class extends Component {
17264
17315
  case "ArrowLeft":
17265
17316
  case "ArrowRight":
17266
17317
  case "ArrowUp":
17267
- const { col, row, offset } = this.postionInBoundary(this.props.figureUI, ev.key);
17318
+ const { col, row, offset } = this.postionInBoundary(this.env.model.getters.getActiveSheetId(), this.props.figureUI, ev.key);
17268
17319
  this.env.model.dispatch("UPDATE_FIGURE", {
17269
17320
  sheetId: this.env.model.getters.getActiveSheetId(),
17270
17321
  figureId: this.props.figureUI.id,
@@ -17288,34 +17339,52 @@ var FigureComponent = class extends Component {
17288
17339
  break;
17289
17340
  }
17290
17341
  }
17291
- postionInBoundary(position, key) {
17292
- const sheetId = this.env.model.getters.getActiveSheetId();
17293
- let { col, row, offset } = position;
17342
+ postionInBoundary(sheetId, figure, key) {
17343
+ let { col, row, offset } = figure;
17294
17344
  offset = { ...offset };
17345
+ const maxAnchor = this.env.model.getters.getMaxAnchorOffset(sheetId, figure.height, figure.width);
17295
17346
  switch (key) {
17296
17347
  case "ArrowUp":
17297
17348
  if (offset.y === 0) {
17298
17349
  row--;
17350
+ while (row > 0 && this.env.model.getters.isRowHiddenByUser(sheetId, row)) row--;
17299
17351
  offset.y = this.env.model.getters.getRowSize(sheetId, row) - 1;
17300
17352
  } else offset.y--;
17301
17353
  break;
17302
17354
  case "ArrowLeft":
17303
17355
  if (offset.x === 0) {
17304
17356
  col--;
17357
+ while (col > 0 && this.env.model.getters.isColHiddenByUser(sheetId, col)) col--;
17305
17358
  offset.x = this.env.model.getters.getColSize(sheetId, col) - 1;
17306
17359
  } else offset.x--;
17307
17360
  break;
17308
17361
  case "ArrowDown":
17309
17362
  if (offset.y === this.env.model.getters.getRowSize(sheetId, row)) {
17310
17363
  row++;
17364
+ while (row <= maxAnchor.row && this.env.model.getters.isRowHiddenByUser(sheetId, row)) row++;
17311
17365
  offset.y = 0;
17312
17366
  } else offset.y++;
17313
17367
  break;
17314
17368
  case "ArrowRight": if (offset.x === this.env.model.getters.getColSize(sheetId, row)) {
17315
17369
  col++;
17370
+ while (col <= maxAnchor.col && this.env.model.getters.isColHiddenByUser(sheetId, col)) col++;
17316
17371
  offset.x = 0;
17317
17372
  } else offset.x++;
17318
17373
  }
17374
+ if (col < 0) {
17375
+ col = 0;
17376
+ offset.x = 0;
17377
+ } else if (col > maxAnchor.col || col === maxAnchor.col && offset.x > maxAnchor.offset.x) {
17378
+ col = maxAnchor.col;
17379
+ offset.x = maxAnchor.offset.x;
17380
+ }
17381
+ if (row < 0) {
17382
+ row = 0;
17383
+ offset.y = 0;
17384
+ } else if (row > maxAnchor.row || row === maxAnchor.row && offset.y > maxAnchor.offset.y) {
17385
+ row = maxAnchor.row;
17386
+ offset.y = maxAnchor.offset.y;
17387
+ }
17319
17388
  return {
17320
17389
  col,
17321
17390
  row,
@@ -18480,12 +18549,15 @@ function validateArguments(descr) {
18480
18549
  //#endregion
18481
18550
  //#region src/functions/create_compute_function.ts
18482
18551
  function createComputeFunction(descr) {
18552
+ let currentArgDefinitions = [];
18483
18553
  function vectorizedCompute(...args) {
18484
18554
  const acceptToVectorize = [];
18555
+ currentArgDefinitions = new Array(args.length);
18485
18556
  const getArgToFocus = argTargeting(descr, args.length);
18486
18557
  for (let i = 0; i < args.length; i++) {
18487
18558
  const argIndex = getArgToFocus(i).index ?? -1;
18488
18559
  const argDefinition = descr.args[argIndex];
18560
+ currentArgDefinitions[i] = argDefinition;
18489
18561
  const arg = args[i];
18490
18562
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", descr.name, (i + 1).toString()));
18491
18563
  acceptToVectorize.push(!argDefinition.acceptMatrix);
@@ -18500,8 +18572,7 @@ function createComputeFunction(descr) {
18500
18572
  function errorHandlingCompute(...args) {
18501
18573
  for (let i = 0; i < args.length; i++) {
18502
18574
  const arg = args[i];
18503
- const getArgToFocus = argTargeting(descr, args.length);
18504
- if (!descr.args[getArgToFocus(i).index ?? i].acceptErrors && !isMatrix(arg) && isEvaluationError(arg?.value)) return arg;
18575
+ if (!currentArgDefinitions[i].acceptErrors && !isMatrix(arg) && isEvaluationError(arg?.value)) return arg;
18505
18576
  }
18506
18577
  try {
18507
18578
  return computeFunctionToObject.apply(this, args);
@@ -19001,7 +19072,7 @@ const ARRAYTOTEXT = {
19001
19072
  else if (_format === 0) {
19002
19073
  const rowSeparator = this.locale.decimalSeparator === "," ? "/" : ",";
19003
19074
  return transposeMatrix(_array).flatMap((row) => row.map((value) => {
19004
- return isEvaluationError(value.value) ? value.value : toString(value);
19075
+ return isEvaluationError(value.value) ? value.value : toLocaleString(value, this.locale);
19005
19076
  })).join(rowSeparator);
19006
19077
  } else return new EvaluationError(_t("Format must be 0 or 1"));
19007
19078
  },
@@ -24987,7 +25058,7 @@ const CONCAT = {
24987
25058
  description: _t("Concatenation of two values."),
24988
25059
  args: [arg("value1 (string)", _t("The value to which value2 will be appended.")), arg("value2 (string)", _t("The value to append to value1."))],
24989
25060
  compute: function(value1, value2) {
24990
- return toString(value1) + toString(value2);
25061
+ return toLocaleString(value1, this.locale) + toLocaleString(value2, this.locale);
24991
25062
  },
24992
25063
  isExported: true
24993
25064
  };
@@ -25819,7 +25890,7 @@ const CLEAN = {
25819
25890
  description: _t("Remove non-printable characters from a piece of text."),
25820
25891
  args: [arg("text (string)", _t("The text whose non-printable characters are to be removed."))],
25821
25892
  compute: function(text) {
25822
- const _text = toString(text);
25893
+ const _text = toLocaleString(text, this.locale);
25823
25894
  let cleanedStr = "";
25824
25895
  for (const char of _text) if (char && char.charCodeAt(0) > 31) cleanedStr += char;
25825
25896
  return cleanedStr;
@@ -25830,7 +25901,7 @@ const CONCATENATE = {
25830
25901
  description: _t("Appends strings to one another."),
25831
25902
  args: [arg("string (string, range<string>, repeating)", _t("String to append in sequence."))],
25832
25903
  compute: function(...datas) {
25833
- return reduceAny(datas, (acc, a) => acc + toString(a), "");
25904
+ return reduceAny(datas, (acc, a) => acc + toLocaleString(a, this.locale), "");
25834
25905
  },
25835
25906
  isExported: true
25836
25907
  };
@@ -25838,7 +25909,7 @@ const EXACT = {
25838
25909
  description: _t("Tests whether two strings are identical."),
25839
25910
  args: [arg("string1 (string)", _t("The first string to compare.")), arg("string2 (string)", _t("The second string to compare."))],
25840
25911
  compute: function(string1, string2) {
25841
- return toString(string1) === toString(string2);
25912
+ return toLocaleString(string1, this.locale) === toLocaleString(string2, this.locale);
25842
25913
  },
25843
25914
  isExported: true
25844
25915
  };
@@ -25850,8 +25921,8 @@ const FIND = {
25850
25921
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
25851
25922
  ],
25852
25923
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
25853
- const _searchFor = toString(searchFor);
25854
- const _textToSearch = toString(textToSearch);
25924
+ const _searchFor = toLocaleString(searchFor, this.locale);
25925
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
25855
25926
  const _startingAt = toNumber(startingAt, this.locale);
25856
25927
  if (_textToSearch === "") return new EvaluationError(_t("The text_to_search must be non-empty."));
25857
25928
  if (_startingAt < 1) return new EvaluationError(_t("The starting_at (%s) must be greater than or equal to 1.", _startingAt));
@@ -25865,8 +25936,8 @@ const JOIN = {
25865
25936
  description: _t("Concatenates elements of arrays with delimiter."),
25866
25937
  args: [arg("delimiter (string)", _t("The character or string to place between each concatenated value.")), arg("value_or_array (string, range<string>, repeating)", _t("Value to be appended using delimiter."))],
25867
25938
  compute: function(delimiter, ...valuesOrArrays) {
25868
- const _delimiter = toString(delimiter);
25869
- return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
25939
+ const _delimiter = toLocaleString(delimiter, this.locale);
25940
+ return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toLocaleString(a, this.locale), "");
25870
25941
  }
25871
25942
  };
25872
25943
  const LEFT = {
@@ -25875,7 +25946,7 @@ const LEFT = {
25875
25946
  compute: function(text, ...args) {
25876
25947
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
25877
25948
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters));
25878
- return toString(text).substring(0, _numberOfCharacters);
25949
+ return toLocaleString(text, this.locale).substring(0, _numberOfCharacters);
25879
25950
  },
25880
25951
  isExported: true
25881
25952
  };
@@ -25883,7 +25954,7 @@ const LEN = {
25883
25954
  description: _t("Length of a string."),
25884
25955
  args: [arg("text (string)", _t("The string whose length will be returned."))],
25885
25956
  compute: function(text) {
25886
- return toString(text).length;
25957
+ return toLocaleString(text, this.locale).length;
25887
25958
  },
25888
25959
  isExported: true
25889
25960
  };
@@ -25891,7 +25962,7 @@ const LOWER = {
25891
25962
  description: _t("Converts a specified string to lowercase."),
25892
25963
  args: [arg("text (string)", _t("The string to convert to lowercase."))],
25893
25964
  compute: function(text) {
25894
- return toString(text).toLowerCase();
25965
+ return toLocaleString(text, this.locale).toLowerCase();
25895
25966
  },
25896
25967
  isExported: true
25897
25968
  };
@@ -25903,7 +25974,7 @@ const MID = {
25903
25974
  arg("extract_length (number)", _t("The length of the segment to extract."))
25904
25975
  ],
25905
25976
  compute: function(text, starting_at, extract_length) {
25906
- const _text = toString(text);
25977
+ const _text = toLocaleString(text, this.locale);
25907
25978
  const _starting_at = toNumber(starting_at, this.locale);
25908
25979
  const _extract_length = toNumber(extract_length, this.locale);
25909
25980
  if (_starting_at < 1) return new EvaluationError(_t("The starting_at argument (%s) must be positive greater than one.", _starting_at.toString()));
@@ -25916,7 +25987,7 @@ const PROPER = {
25916
25987
  description: _t("Capitalizes each word in a specified string."),
25917
25988
  args: [arg("text_to_capitalize (string)", _t("The text which will be returned with the first letter of each word in uppercase and all other letters in lowercase."))],
25918
25989
  compute: function(text) {
25919
- return toString(text).replace(wordRegex, (word) => {
25990
+ return toLocaleString(text, this.locale).replace(wordRegex, (word) => {
25920
25991
  return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
25921
25992
  });
25922
25993
  },
@@ -25991,9 +26062,9 @@ const REPLACE = {
25991
26062
  compute: function(text, position, length, newText) {
25992
26063
  const _position = toNumber(position, this.locale);
25993
26064
  if (_position < 1) return new EvaluationError(_t("The position (%s) must be greater than or equal to 1.", _position));
25994
- const _text = toString(text);
26065
+ const _text = toLocaleString(text, this.locale);
25995
26066
  const _length = toNumber(length, this.locale);
25996
- const _newText = toString(newText);
26067
+ const _newText = toLocaleString(newText, this.locale);
25997
26068
  return _text.substring(0, _position - 1) + _newText + _text.substring(_position - 1 + _length);
25998
26069
  },
25999
26070
  isExported: true
@@ -26004,7 +26075,7 @@ const RIGHT = {
26004
26075
  compute: function(text, ...args) {
26005
26076
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
26006
26077
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters));
26007
- const _text = toString(text);
26078
+ const _text = toLocaleString(text, this.locale);
26008
26079
  const stringLength = _text.length;
26009
26080
  return _text.substring(stringLength - _numberOfCharacters, stringLength);
26010
26081
  },
@@ -26018,8 +26089,8 @@ const SEARCH = {
26018
26089
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
26019
26090
  ],
26020
26091
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
26021
- const _searchFor = toString(searchFor).toLowerCase();
26022
- const _textToSearch = toString(textToSearch).toLowerCase();
26092
+ const _searchFor = toLocaleString(searchFor, this.locale).toLowerCase();
26093
+ const _textToSearch = toLocaleString(textToSearch, this.locale).toLowerCase();
26023
26094
  const _startingAt = toNumber(startingAt, this.locale);
26024
26095
  if (_textToSearch === "") return {
26025
26096
  value: CellErrorType.GenericError,
@@ -26049,8 +26120,8 @@ const SPLIT = {
26049
26120
  arg(`remove_empty_text (boolean, default=${SPLIT_DEFAULT_REMOVE_EMPTY_TEXT})`, _t("Whether or not to remove empty text messages from the split results. The default behavior is to treat consecutive delimiters as one (if TRUE). If FALSE, empty cells values are added between consecutive delimiters."))
26050
26121
  ],
26051
26122
  compute: function(text, delimiter, splitByEach = { value: SPLIT_DEFAULT_SPLIT_BY_EACH }, removeEmptyText = { value: SPLIT_DEFAULT_REMOVE_EMPTY_TEXT }) {
26052
- const _text = toString(text);
26053
- const _delimiter = escapeRegExp(toString(delimiter));
26123
+ const _text = toLocaleString(text, this.locale);
26124
+ const _delimiter = escapeRegExp(toLocaleString(delimiter, this.locale));
26054
26125
  const _splitByEach = toBoolean(splitByEach);
26055
26126
  const _removeEmptyText = toBoolean(removeEmptyText);
26056
26127
  if (_delimiter.length <= 0) return new EvaluationError(_t("The delimiter (%s) must be not be empty.", _delimiter));
@@ -26072,10 +26143,10 @@ const SUBSTITUTE = {
26072
26143
  compute: function(textToSearch, searchFor, replaceWith, occurrenceNumber) {
26073
26144
  const _occurrenceNumber = toNumber(occurrenceNumber, this.locale);
26074
26145
  if (_occurrenceNumber < 0) return new EvaluationError(_t("The occurrenceNumber (%s) must be positive or null.", _occurrenceNumber));
26075
- const _textToSearch = toString(textToSearch);
26076
- const _searchFor = toString(searchFor);
26146
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
26147
+ const _searchFor = toLocaleString(searchFor, this.locale);
26077
26148
  if (_searchFor === "") return _textToSearch;
26078
- const _replaceWith = toString(replaceWith);
26149
+ const _replaceWith = toLocaleString(replaceWith, this.locale);
26079
26150
  const reg = new RegExp(escapeRegExp(_searchFor), "g");
26080
26151
  if (_occurrenceNumber === 0) return _textToSearch.replace(reg, _replaceWith);
26081
26152
  let n = 0;
@@ -26098,10 +26169,10 @@ const TEXTJOIN = {
26098
26169
  arg("texts (string, range<string>, repeating)", _t("Text item to join."))
26099
26170
  ],
26100
26171
  compute: function(delimiter, ignoreEmpty = { value: TEXTJOIN_DEFAULT_IGNORE_EMPTY }, ...textsOrArrays) {
26101
- const _delimiter = toString(delimiter);
26172
+ const _delimiter = toLocaleString(delimiter, this.locale);
26102
26173
  const _ignoreEmpty = toBoolean(ignoreEmpty);
26103
26174
  let n = 0;
26104
- return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toString(a) === "") ? (n++ ? acc + _delimiter : "") + toString(a) : acc, "");
26175
+ return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toLocaleString(a, this.locale) === "") ? (n++ ? acc + _delimiter : "") + toLocaleString(a, this.locale) : acc, "");
26105
26176
  },
26106
26177
  isExported: true
26107
26178
  };
@@ -26154,7 +26225,7 @@ const TRIM = {
26154
26225
  description: _t("Removes space characters."),
26155
26226
  args: [arg("text (string)", _t("The text or reference to a cell containing text to be trimmed."))],
26156
26227
  compute: function(text) {
26157
- return trimContent(toString(text));
26228
+ return trimContent(toLocaleString(text, this.locale));
26158
26229
  },
26159
26230
  isExported: true
26160
26231
  };
@@ -26162,7 +26233,7 @@ const UPPER = {
26162
26233
  description: _t("Converts a specified string to uppercase."),
26163
26234
  args: [arg("text (string)", _t("The string to convert to uppercase."))],
26164
26235
  compute: function(text) {
26165
- return toString(text).toUpperCase();
26236
+ return toLocaleString(text, this.locale).toUpperCase();
26166
26237
  },
26167
26238
  isExported: true
26168
26239
  };
@@ -26259,7 +26330,7 @@ const HYPERLINK = {
26259
26330
  args: [arg("url (string)", _t("The full URL of the link enclosed in quotation marks.")), arg("link_label (string, optional)", _t("The text to display in the cell, enclosed in quotation marks."))],
26260
26331
  compute: function(url, linkLabel) {
26261
26332
  const processedUrl = toString(url).trim();
26262
- const processedLabel = toString(linkLabel) || processedUrl;
26333
+ const processedLabel = toLocaleString(linkLabel, this.locale) || processedUrl;
26263
26334
  if (processedUrl === "") return processedLabel;
26264
26335
  return markdownLink(processedLabel, processedUrl);
26265
26336
  },
@@ -30583,12 +30654,13 @@ var FilterMenu = class extends Component {
30583
30654
  }
30584
30655
  sortFilterZone(sortDirection) {
30585
30656
  const filterPosition = this.props.filterPosition;
30586
- const tableZone = this.table?.range.zone;
30657
+ const table = this.table;
30658
+ const tableZone = table?.range.zone;
30587
30659
  if (!filterPosition || !tableZone || tableZone.top === tableZone.bottom) return;
30588
30660
  const sheetId = this.env.model.getters.getActiveSheetId();
30589
30661
  const contentZone = {
30590
30662
  ...tableZone,
30591
- top: tableZone.top + 1
30663
+ top: tableZone.top + table.config.numberOfHeaders
30592
30664
  };
30593
30665
  const sortAnchor = {
30594
30666
  col: filterPosition.col,
@@ -68941,6 +69013,10 @@ function inverseCreateFigure(cmd) {
68941
69013
  }
68942
69014
  function inverseCreateChart(cmd) {
68943
69015
  return [{
69016
+ type: "DELETE_CHART",
69017
+ chartId: cmd.chartId,
69018
+ sheetId: cmd.sheetId
69019
+ }, {
68944
69020
  type: "DELETE_FIGURE",
68945
69021
  figureId: cmd.figureId,
68946
69022
  sheetId: cmd.sheetId
@@ -79119,6 +79195,6 @@ const chartHelpers = {
79119
79195
  //#endregion
79120
79196
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DEFAULT_LOCALE, DEFAULT_LOCALES, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, categories, chartHelpers, components, constants, convertAstNodes, coreTypes, createAutocompleteArgumentsProvider, findCellInNewZone, functionCache, getCaretDownSvg, getCaretUpSvg, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
79121
79197
 
79122
- __info__.version = "19.1.30";
79123
- __info__.date = "2026-07-30T06:53:51.978Z";
79124
- __info__.hash = "b4f7ab8";
79198
+ __info__.version = "19.1.32";
79199
+ __info__.date = "2026-08-21T15:29:30.638Z";
79200
+ __info__.hash = "d34d0e7";