@odoo/o-spreadsheet 19.0.45 → 19.0.47

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.0.45
6
- * @date 2026-07-30T06:52:43.792Z
7
- * @hash eb4c9d3
5
+ * @version 19.0.47
6
+ * @date 2026-08-21T15:28:59.913Z
7
+ * @hash 59a9b1b
8
8
  */
9
9
 
10
10
  (function(exports, _odoo_owl) {
@@ -2921,6 +2921,18 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2921
2921
  default: return "";
2922
2922
  }
2923
2923
  }
2924
+ /**
2925
+ * Only converts the decimal separator, ignore number format such as % or dates
2926
+ */
2927
+ function toLocaleString(data, locale) {
2928
+ const value = toValue(data);
2929
+ switch (typeof value) {
2930
+ case "string": return value;
2931
+ case "number": return value.toString().replace(".", locale.decimalSeparator);
2932
+ case "boolean": return value ? "TRUE" : "FALSE";
2933
+ default: return "";
2934
+ }
2935
+ }
2924
2936
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
2925
2937
  const normalizeString = memoize(function normalizeString(str) {
2926
2938
  return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
@@ -3110,19 +3122,58 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3110
3122
  }
3111
3123
  }
3112
3124
  if (countVectorizedCol === 1 && countVectorizedRow === 1) return formula(...args);
3113
- const getArgOffset = (i, j) => args.map((arg, index) => {
3114
- switch (vectorArgsType?.[index]) {
3115
- case "matrix": return arg[i][j];
3116
- case "horizontal": return arg[i][0];
3117
- case "vertical": return arg[0][j];
3118
- case void 0: return arg;
3125
+ const argsBuffer = new Array(args.length);
3126
+ const argGetters = [];
3127
+ const vectorizedIndices = [];
3128
+ for (let k = 0; k < args.length; k++) {
3129
+ const arg = args[k];
3130
+ switch (vectorArgsType?.[k]) {
3131
+ case "matrix":
3132
+ argGetters.push((i, j) => arg[i][j]);
3133
+ vectorizedIndices.push(k);
3134
+ break;
3135
+ case "horizontal":
3136
+ argGetters.push((i) => arg[i][0]);
3137
+ vectorizedIndices.push(k);
3138
+ break;
3139
+ case "vertical":
3140
+ argGetters.push((_i, j) => arg[0][j]);
3141
+ vectorizedIndices.push(k);
3142
+ break;
3143
+ case void 0:
3144
+ argsBuffer[k] = arg;
3145
+ break;
3119
3146
  }
3120
- });
3121
- return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
3122
- if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
3123
- const singleCellComputeResult = formula(...getArgOffset(col, row));
3124
- return isMatrix(singleCellComputeResult) ? singleCellComputeResult[0][0] : singleCellComputeResult;
3125
- });
3147
+ }
3148
+ const nbVectorized = vectorizedIndices.length;
3149
+ let callFormula;
3150
+ switch (argsBuffer.length) {
3151
+ case 1:
3152
+ callFormula = () => formula(argsBuffer[0]);
3153
+ break;
3154
+ case 2:
3155
+ callFormula = () => formula(argsBuffer[0], argsBuffer[1]);
3156
+ break;
3157
+ case 3:
3158
+ callFormula = () => formula(argsBuffer[0], argsBuffer[1], argsBuffer[2]);
3159
+ break;
3160
+ default: callFormula = () => formula(...argsBuffer);
3161
+ }
3162
+ const result = new Array(countVectorizedCol);
3163
+ for (let col = 0; col < countVectorizedCol; col++) {
3164
+ const column = new Array(countVectorizedRow);
3165
+ result[col] = column;
3166
+ for (let row = 0; row < countVectorizedRow; row++) {
3167
+ if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
3168
+ column[row] = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
3169
+ continue;
3170
+ }
3171
+ for (let k = 0; k < nbVectorized; k++) argsBuffer[vectorizedIndices[k]] = argGetters[k](col, row);
3172
+ const singleCellComputeResult = callFormula();
3173
+ column[row] = isMatrix(singleCellComputeResult) ? singleCellComputeResult[0][0] : singleCellComputeResult;
3174
+ }
3175
+ }
3176
+ return result;
3126
3177
  }
3127
3178
  /**
3128
3179
  * This function allows to visit arguments and stop the visit if necessary.
@@ -17127,7 +17178,7 @@ stores.inject(MyMetaStore, storeInstance);
17127
17178
  description: _t("Concatenation of two values."),
17128
17179
  args: [arg("value1 (string)", _t("The value to which value2 will be appended.")), arg("value2 (string)", _t("The value to append to value1."))],
17129
17180
  compute: function(value1, value2) {
17130
- return toString(value1) + toString(value2);
17181
+ return toLocaleString(value1, this.locale) + toLocaleString(value2, this.locale);
17131
17182
  },
17132
17183
  isExported: true
17133
17184
  };
@@ -17959,7 +18010,7 @@ stores.inject(MyMetaStore, storeInstance);
17959
18010
  description: _t("Remove non-printable characters from a piece of text."),
17960
18011
  args: [arg("text (string)", _t("The text whose non-printable characters are to be removed."))],
17961
18012
  compute: function(text) {
17962
- const _text = toString(text);
18013
+ const _text = toLocaleString(text, this.locale);
17963
18014
  let cleanedStr = "";
17964
18015
  for (const char of _text) if (char && char.charCodeAt(0) > 31) cleanedStr += char;
17965
18016
  return cleanedStr;
@@ -17970,7 +18021,7 @@ stores.inject(MyMetaStore, storeInstance);
17970
18021
  description: _t("Appends strings to one another."),
17971
18022
  args: [arg("string1 (string, range<string>)", _t("The initial string.")), arg("string2 (string, range<string>, repeating)", _t("More strings to append in sequence."))],
17972
18023
  compute: function(...datas) {
17973
- return reduceAny(datas, (acc, a) => acc + toString(a), "");
18024
+ return reduceAny(datas, (acc, a) => acc + toLocaleString(a, this.locale), "");
17974
18025
  },
17975
18026
  isExported: true
17976
18027
  };
@@ -17978,7 +18029,7 @@ stores.inject(MyMetaStore, storeInstance);
17978
18029
  description: _t("Tests whether two strings are identical."),
17979
18030
  args: [arg("string1 (string)", _t("The first string to compare.")), arg("string2 (string)", _t("The second string to compare."))],
17980
18031
  compute: function(string1, string2) {
17981
- return toString(string1) === toString(string2);
18032
+ return toLocaleString(string1, this.locale) === toLocaleString(string2, this.locale);
17982
18033
  },
17983
18034
  isExported: true
17984
18035
  };
@@ -17990,8 +18041,8 @@ stores.inject(MyMetaStore, storeInstance);
17990
18041
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
17991
18042
  ],
17992
18043
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
17993
- const _searchFor = toString(searchFor);
17994
- const _textToSearch = toString(textToSearch);
18044
+ const _searchFor = toLocaleString(searchFor, this.locale);
18045
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
17995
18046
  const _startingAt = toNumber(startingAt, this.locale);
17996
18047
  if (_textToSearch === "") return new EvaluationError(_t("The text_to_search must be non-empty."));
17997
18048
  if (_startingAt < 1) return new EvaluationError(_t("The starting_at (%s) must be greater than or equal to 1.", _startingAt));
@@ -18009,8 +18060,8 @@ stores.inject(MyMetaStore, storeInstance);
18009
18060
  arg("value_or_array2 (string, range<string>, repeating)", _t("More values to be appended using delimiter."))
18010
18061
  ],
18011
18062
  compute: function(delimiter, ...valuesOrArrays) {
18012
- const _delimiter = toString(delimiter);
18013
- return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
18063
+ const _delimiter = toLocaleString(delimiter, this.locale);
18064
+ return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toLocaleString(a, this.locale), "");
18014
18065
  }
18015
18066
  };
18016
18067
  const LEFT = {
@@ -18019,7 +18070,7 @@ stores.inject(MyMetaStore, storeInstance);
18019
18070
  compute: function(text, ...args) {
18020
18071
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
18021
18072
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters));
18022
- return toString(text).substring(0, _numberOfCharacters);
18073
+ return toLocaleString(text, this.locale).substring(0, _numberOfCharacters);
18023
18074
  },
18024
18075
  isExported: true
18025
18076
  };
@@ -18027,7 +18078,7 @@ stores.inject(MyMetaStore, storeInstance);
18027
18078
  description: _t("Length of a string."),
18028
18079
  args: [arg("text (string)", _t("The string whose length will be returned."))],
18029
18080
  compute: function(text) {
18030
- return toString(text).length;
18081
+ return toLocaleString(text, this.locale).length;
18031
18082
  },
18032
18083
  isExported: true
18033
18084
  };
@@ -18035,7 +18086,7 @@ stores.inject(MyMetaStore, storeInstance);
18035
18086
  description: _t("Converts a specified string to lowercase."),
18036
18087
  args: [arg("text (string)", _t("The string to convert to lowercase."))],
18037
18088
  compute: function(text) {
18038
- return toString(text).toLowerCase();
18089
+ return toLocaleString(text, this.locale).toLowerCase();
18039
18090
  },
18040
18091
  isExported: true
18041
18092
  };
@@ -18047,7 +18098,7 @@ stores.inject(MyMetaStore, storeInstance);
18047
18098
  arg("extract_length (number)", _t("The length of the segment to extract."))
18048
18099
  ],
18049
18100
  compute: function(text, starting_at, extract_length) {
18050
- const _text = toString(text);
18101
+ const _text = toLocaleString(text, this.locale);
18051
18102
  const _starting_at = toNumber(starting_at, this.locale);
18052
18103
  const _extract_length = toNumber(extract_length, this.locale);
18053
18104
  if (_starting_at < 1) return new EvaluationError(_t("The starting_at argument (%s) must be positive greater than one.", _starting_at.toString()));
@@ -18060,7 +18111,7 @@ stores.inject(MyMetaStore, storeInstance);
18060
18111
  description: _t("Capitalizes each word in a specified string."),
18061
18112
  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."))],
18062
18113
  compute: function(text) {
18063
- return toString(text).replace(wordRegex, (word) => {
18114
+ return toLocaleString(text, this.locale).replace(wordRegex, (word) => {
18064
18115
  return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
18065
18116
  });
18066
18117
  },
@@ -18135,9 +18186,9 @@ stores.inject(MyMetaStore, storeInstance);
18135
18186
  compute: function(text, position, length, newText) {
18136
18187
  const _position = toNumber(position, this.locale);
18137
18188
  if (_position < 1) return new EvaluationError(_t("The position (%s) must be greater than or equal to 1.", _position));
18138
- const _text = toString(text);
18189
+ const _text = toLocaleString(text, this.locale);
18139
18190
  const _length = toNumber(length, this.locale);
18140
- const _newText = toString(newText);
18191
+ const _newText = toLocaleString(newText, this.locale);
18141
18192
  return _text.substring(0, _position - 1) + _newText + _text.substring(_position - 1 + _length);
18142
18193
  },
18143
18194
  isExported: true
@@ -18148,7 +18199,7 @@ stores.inject(MyMetaStore, storeInstance);
18148
18199
  compute: function(text, ...args) {
18149
18200
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
18150
18201
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters));
18151
- const _text = toString(text);
18202
+ const _text = toLocaleString(text, this.locale);
18152
18203
  const stringLength = _text.length;
18153
18204
  return _text.substring(stringLength - _numberOfCharacters, stringLength);
18154
18205
  },
@@ -18162,8 +18213,8 @@ stores.inject(MyMetaStore, storeInstance);
18162
18213
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
18163
18214
  ],
18164
18215
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
18165
- const _searchFor = toString(searchFor).toLowerCase();
18166
- const _textToSearch = toString(textToSearch).toLowerCase();
18216
+ const _searchFor = toLocaleString(searchFor, this.locale).toLowerCase();
18217
+ const _textToSearch = toLocaleString(textToSearch, this.locale).toLowerCase();
18167
18218
  const _startingAt = toNumber(startingAt, this.locale);
18168
18219
  if (_textToSearch === "") return {
18169
18220
  value: CellErrorType.GenericError,
@@ -18193,8 +18244,8 @@ stores.inject(MyMetaStore, storeInstance);
18193
18244
  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."))
18194
18245
  ],
18195
18246
  compute: function(text, delimiter, splitByEach = { value: SPLIT_DEFAULT_SPLIT_BY_EACH }, removeEmptyText = { value: SPLIT_DEFAULT_REMOVE_EMPTY_TEXT }) {
18196
- const _text = toString(text);
18197
- const _delimiter = escapeRegExp(toString(delimiter));
18247
+ const _text = toLocaleString(text, this.locale);
18248
+ const _delimiter = escapeRegExp(toLocaleString(delimiter, this.locale));
18198
18249
  const _splitByEach = toBoolean(splitByEach);
18199
18250
  const _removeEmptyText = toBoolean(removeEmptyText);
18200
18251
  if (_delimiter.length <= 0) return new EvaluationError(_t("The delimiter (%s) must be not be empty.", _delimiter));
@@ -18216,10 +18267,10 @@ stores.inject(MyMetaStore, storeInstance);
18216
18267
  compute: function(textToSearch, searchFor, replaceWith, occurrenceNumber) {
18217
18268
  const _occurrenceNumber = toNumber(occurrenceNumber, this.locale);
18218
18269
  if (_occurrenceNumber < 0) return new EvaluationError(_t("The occurrenceNumber (%s) must be positive or null.", _occurrenceNumber));
18219
- const _textToSearch = toString(textToSearch);
18220
- const _searchFor = toString(searchFor);
18270
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
18271
+ const _searchFor = toLocaleString(searchFor, this.locale);
18221
18272
  if (_searchFor === "") return _textToSearch;
18222
- const _replaceWith = toString(replaceWith);
18273
+ const _replaceWith = toLocaleString(replaceWith, this.locale);
18223
18274
  const reg = new RegExp(escapeRegExp(_searchFor), "g");
18224
18275
  if (_occurrenceNumber === 0) return _textToSearch.replace(reg, _replaceWith);
18225
18276
  let n = 0;
@@ -18243,10 +18294,10 @@ stores.inject(MyMetaStore, storeInstance);
18243
18294
  arg("text2 (string, range<string>, repeating)", _t("Additional text item(s)."))
18244
18295
  ],
18245
18296
  compute: function(delimiter, ignoreEmpty = { value: TEXTJOIN_DEFAULT_IGNORE_EMPTY }, ...textsOrArrays) {
18246
- const _delimiter = toString(delimiter);
18297
+ const _delimiter = toLocaleString(delimiter, this.locale);
18247
18298
  const _ignoreEmpty = toBoolean(ignoreEmpty);
18248
18299
  let n = 0;
18249
- return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toString(a) === "") ? (n++ ? acc + _delimiter : "") + toString(a) : acc, "");
18300
+ return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toLocaleString(a, this.locale) === "") ? (n++ ? acc + _delimiter : "") + toLocaleString(a, this.locale) : acc, "");
18250
18301
  },
18251
18302
  isExported: true
18252
18303
  };
@@ -18299,7 +18350,7 @@ stores.inject(MyMetaStore, storeInstance);
18299
18350
  description: _t("Removes space characters."),
18300
18351
  args: [arg("text (string)", _t("The text or reference to a cell containing text to be trimmed."))],
18301
18352
  compute: function(text) {
18302
- return trimContent(toString(text));
18353
+ return trimContent(toLocaleString(text, this.locale));
18303
18354
  },
18304
18355
  isExported: true
18305
18356
  };
@@ -18307,7 +18358,7 @@ stores.inject(MyMetaStore, storeInstance);
18307
18358
  description: _t("Converts a specified string to uppercase."),
18308
18359
  args: [arg("text (string)", _t("The string to convert to uppercase."))],
18309
18360
  compute: function(text) {
18310
- return toString(text).toUpperCase();
18361
+ return toLocaleString(text, this.locale).toUpperCase();
18311
18362
  },
18312
18363
  isExported: true
18313
18364
  };
@@ -18404,7 +18455,7 @@ stores.inject(MyMetaStore, storeInstance);
18404
18455
  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."))],
18405
18456
  compute: function(url, linkLabel) {
18406
18457
  const processedUrl = toString(url).trim();
18407
- const processedLabel = toString(linkLabel) || processedUrl;
18458
+ const processedLabel = toLocaleString(linkLabel, this.locale) || processedUrl;
18408
18459
  if (processedUrl === "") return processedLabel;
18409
18460
  return markdownLink(processedLabel, processedUrl);
18410
18461
  },
@@ -18512,12 +18563,15 @@ stores.inject(MyMetaStore, storeInstance);
18512
18563
  }
18513
18564
  }
18514
18565
  function createComputeFunction(descr) {
18566
+ let currentArgDefinitions = [];
18515
18567
  function vectorizedCompute(...args) {
18516
18568
  const acceptToVectorize = [];
18569
+ currentArgDefinitions = new Array(args.length);
18517
18570
  const getArgToFocus = argTargeting(descr, args.length);
18518
18571
  for (let i = 0; i < args.length; i++) {
18519
18572
  const argIndex = getArgToFocus(i) ?? -1;
18520
18573
  const argDefinition = descr.args[argIndex];
18574
+ currentArgDefinitions[i] = argDefinition;
18521
18575
  const arg = args[i];
18522
18576
  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()));
18523
18577
  acceptToVectorize.push(!argDefinition.acceptMatrix);
@@ -18532,8 +18586,7 @@ stores.inject(MyMetaStore, storeInstance);
18532
18586
  function errorHandlingCompute(...args) {
18533
18587
  for (let i = 0; i < args.length; i++) {
18534
18588
  const arg = args[i];
18535
- const getArgToFocus = argTargeting(descr, args.length);
18536
- if (!descr.args[getArgToFocus(i) || i].acceptErrors && !isMatrix(arg) && isEvaluationError(arg?.value)) return arg;
18589
+ if (!currentArgDefinitions[i].acceptErrors && !isMatrix(arg) && isEvaluationError(arg?.value)) return arg;
18537
18590
  }
18538
18591
  try {
18539
18592
  return computeFunctionToObject.apply(this, args);
@@ -28236,7 +28289,7 @@ stores.inject(MyMetaStore, storeInstance);
28236
28289
  case "ArrowLeft":
28237
28290
  case "ArrowRight":
28238
28291
  case "ArrowUp":
28239
- const { col, row, offset } = this.postionInBoundary(this.props.figureUI, ev.key);
28292
+ const { col, row, offset } = this.postionInBoundary(this.env.model.getters.getActiveSheetId(), this.props.figureUI, ev.key);
28240
28293
  this.env.model.dispatch("UPDATE_FIGURE", {
28241
28294
  sheetId: this.env.model.getters.getActiveSheetId(),
28242
28295
  figureId: this.props.figureUI.id,
@@ -28260,34 +28313,52 @@ stores.inject(MyMetaStore, storeInstance);
28260
28313
  break;
28261
28314
  }
28262
28315
  }
28263
- postionInBoundary(position, key) {
28264
- const sheetId = this.env.model.getters.getActiveSheetId();
28265
- let { col, row, offset } = position;
28316
+ postionInBoundary(sheetId, figure, key) {
28317
+ let { col, row, offset } = figure;
28266
28318
  offset = { ...offset };
28319
+ const maxAnchor = this.env.model.getters.getMaxAnchorOffset(sheetId, figure.height, figure.width);
28267
28320
  switch (key) {
28268
28321
  case "ArrowUp":
28269
28322
  if (offset.y === 0) {
28270
28323
  row--;
28324
+ while (row > 0 && this.env.model.getters.isRowHiddenByUser(sheetId, row)) row--;
28271
28325
  offset.y = this.env.model.getters.getRowSize(sheetId, row) - 1;
28272
28326
  } else offset.y--;
28273
28327
  break;
28274
28328
  case "ArrowLeft":
28275
28329
  if (offset.x === 0) {
28276
28330
  col--;
28331
+ while (col > 0 && this.env.model.getters.isColHiddenByUser(sheetId, col)) col--;
28277
28332
  offset.x = this.env.model.getters.getColSize(sheetId, col) - 1;
28278
28333
  } else offset.x--;
28279
28334
  break;
28280
28335
  case "ArrowDown":
28281
28336
  if (offset.y === this.env.model.getters.getRowSize(sheetId, row)) {
28282
28337
  row++;
28338
+ while (row <= maxAnchor.row && this.env.model.getters.isRowHiddenByUser(sheetId, row)) row++;
28283
28339
  offset.y = 0;
28284
28340
  } else offset.y++;
28285
28341
  break;
28286
28342
  case "ArrowRight": if (offset.x === this.env.model.getters.getColSize(sheetId, row)) {
28287
28343
  col++;
28344
+ while (col <= maxAnchor.col && this.env.model.getters.isColHiddenByUser(sheetId, col)) col++;
28288
28345
  offset.x = 0;
28289
28346
  } else offset.x++;
28290
28347
  }
28348
+ if (col < 0) {
28349
+ col = 0;
28350
+ offset.x = 0;
28351
+ } else if (col > maxAnchor.col || col === maxAnchor.col && offset.x > maxAnchor.offset.x) {
28352
+ col = maxAnchor.col;
28353
+ offset.x = maxAnchor.offset.x;
28354
+ }
28355
+ if (row < 0) {
28356
+ row = 0;
28357
+ offset.y = 0;
28358
+ } else if (row > maxAnchor.row || row === maxAnchor.row && offset.y > maxAnchor.offset.y) {
28359
+ row = maxAnchor.row;
28360
+ offset.y = maxAnchor.offset.y;
28361
+ }
28291
28362
  return {
28292
28363
  col,
28293
28364
  row,
@@ -33132,12 +33203,13 @@ stores.inject(MyMetaStore, storeInstance);
33132
33203
  }
33133
33204
  sortFilterZone(sortDirection) {
33134
33205
  const filterPosition = this.props.filterPosition;
33135
- const tableZone = this.table?.range.zone;
33206
+ const table = this.table;
33207
+ const tableZone = table?.range.zone;
33136
33208
  if (!filterPosition || !tableZone || tableZone.top === tableZone.bottom) return;
33137
33209
  const sheetId = this.env.model.getters.getActiveSheetId();
33138
33210
  const contentZone = {
33139
33211
  ...tableZone,
33140
- top: tableZone.top + 1
33212
+ top: tableZone.top + table.config.numberOfHeaders
33141
33213
  };
33142
33214
  const sortAnchor = {
33143
33215
  col: filterPosition.col,
@@ -47240,6 +47312,7 @@ stores.inject(MyMetaStore, storeInstance);
47240
47312
  .o-spreadsheet {
47241
47313
  .os-input {
47242
47314
  border-width: 0 0 1px 0;
47315
+ border-style: solid;
47243
47316
  border-color: transparent;
47244
47317
  outline: none;
47245
47318
  text-overflow: ellipsis;
@@ -71279,6 +71352,10 @@ stores.inject(MyMetaStore, storeInstance);
71279
71352
  }
71280
71353
  function inverseCreateChart(cmd) {
71281
71354
  return [{
71355
+ type: "DELETE_CHART",
71356
+ chartId: cmd.chartId,
71357
+ sheetId: cmd.sheetId
71358
+ }, {
71282
71359
  type: "DELETE_FIGURE",
71283
71360
  figureId: cmd.figureId,
71284
71361
  sheetId: cmd.sheetId
@@ -74772,6 +74849,7 @@ stores.inject(MyMetaStore, storeInstance);
74772
74849
  width: 100%;
74773
74850
  outline: none;
74774
74851
  border-color: ${GRAY_300};
74852
+ border-style: solid;
74775
74853
  color: ${GRAY_900};
74776
74854
 
74777
74855
  &::placeholder {
@@ -79429,8 +79507,8 @@ exports.stores = stores;
79429
79507
  exports.tokenColors = tokenColors;
79430
79508
  exports.tokenize = tokenize;
79431
79509
 
79432
- __info__.version = "19.0.45";
79433
- __info__.date = "2026-07-30T06:52:43.792Z";
79434
- __info__.hash = "eb4c9d3";
79510
+ __info__.version = "19.0.47";
79511
+ __info__.date = "2026-08-21T15:28:59.913Z";
79512
+ __info__.hash = "59a9b1b";
79435
79513
 
79436
79514
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);