@odoo/o-spreadsheet 19.2.25 → 19.2.27

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.2.25
6
- * @date 2026-08-12T09:16:52.703Z
7
- * @hash 685ffda
5
+ * @version 19.2.27
6
+ * @date 2026-08-29T09:15:16.412Z
7
+ * @hash 9e63c60
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);
@@ -571,6 +572,7 @@
571
572
  width: 100%;
572
573
  outline: none;
573
574
  border-color: var(--os-border-color);
575
+ border-style: solid;
574
576
  color: var(--os-gray-900);
575
577
 
576
578
  &::placeholder {
@@ -1381,6 +1383,12 @@
1381
1383
  background-color: var(--os-action-color);
1382
1384
  border-color: var(--os-action-color) !important;
1383
1385
  }
1386
+
1387
+ &:focus {
1388
+ outline: none;
1389
+ box-shadow: 0 0 0 0.25rem rgba(113, 75, 103, 0.25);
1390
+ border-color: var(--os-action-color);
1391
+ }
1384
1392
  }
1385
1393
  }
1386
1394
  }
@@ -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.2.25
6
- * @date 2026-08-12T09:16:51.116Z
7
- * @hash 685ffda
5
+ * @version 19.2.27
6
+ * @date 2026-08-29T09:15:15.122Z
7
+ * @hash 9e63c60
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";
@@ -3751,6 +3751,18 @@ function toString(data) {
3751
3751
  default: return "";
3752
3752
  }
3753
3753
  }
3754
+ /**
3755
+ * Only converts the decimal separator, ignore number format such as % or dates
3756
+ */
3757
+ function toLocaleString(data, locale) {
3758
+ const value = toValue(data);
3759
+ switch (typeof value) {
3760
+ case "string": return value;
3761
+ case "number": return value.toString().replace(".", locale.decimalSeparator);
3762
+ case "boolean": return value ? "TRUE" : "FALSE";
3763
+ default: return "";
3764
+ }
3765
+ }
3754
3766
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
3755
3767
  const normalizeString = memoize(function normalizeString(str) {
3756
3768
  return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
@@ -9160,6 +9172,7 @@ function getRadarChartDatasets(definition, args) {
9160
9172
  hidden,
9161
9173
  borderColor,
9162
9174
  backgroundColor: borderColor,
9175
+ pointBackgroundColor: borderColor,
9163
9176
  pointRadius: definition.hideDataMarkers ? 0 : 3
9164
9177
  };
9165
9178
  if (fill) {
@@ -18291,7 +18304,7 @@ const ARRAYTOTEXT = {
18291
18304
  else if (_format === 0) {
18292
18305
  const rowSeparator = this.locale.decimalSeparator === "," ? "/" : ",";
18293
18306
  return transposeMatrix(_array).flatMap((row) => row.map((value) => {
18294
- return isEvaluationError(value.value) ? value.value : toString(value);
18307
+ return isEvaluationError(value.value) ? value.value : toLocaleString(value, this.locale);
18295
18308
  })).join(rowSeparator);
18296
18309
  } else return new EvaluationError(_t("Format must be 0 or 1"));
18297
18310
  },
@@ -24334,7 +24347,7 @@ const CONCAT = {
24334
24347
  description: _t("Concatenation of two values."),
24335
24348
  args: [arg("value1 (string)", _t("The value to which value2 will be appended.")), arg("value2 (string)", _t("The value to append to value1."))],
24336
24349
  compute: function(value1, value2) {
24337
- return toString(value1) + toString(value2);
24350
+ return toLocaleString(value1, this.locale) + toLocaleString(value2, this.locale);
24338
24351
  },
24339
24352
  isExported: true
24340
24353
  };
@@ -25203,7 +25216,7 @@ const CLEAN = {
25203
25216
  description: _t("Remove non-printable characters from a piece of text."),
25204
25217
  args: [arg("text (string)", _t("The text whose non-printable characters are to be removed."))],
25205
25218
  compute: function(text) {
25206
- const _text = toString(text);
25219
+ const _text = toLocaleString(text, this.locale);
25207
25220
  let cleanedStr = "";
25208
25221
  for (const char of _text) if (char && char.charCodeAt(0) > 31) cleanedStr += char;
25209
25222
  return cleanedStr;
@@ -25214,7 +25227,7 @@ const CONCATENATE = {
25214
25227
  description: _t("Appends strings to one another."),
25215
25228
  args: [arg("string (string, range<string>, repeating)", _t("String to append in sequence."))],
25216
25229
  compute: function(...datas) {
25217
- return reduceAny(datas, (acc, a) => acc + toString(a), "");
25230
+ return reduceAny(datas, (acc, a) => acc + toLocaleString(a, this.locale), "");
25218
25231
  },
25219
25232
  isExported: true
25220
25233
  };
@@ -25222,7 +25235,7 @@ const EXACT = {
25222
25235
  description: _t("Tests whether two strings are identical."),
25223
25236
  args: [arg("string1 (string)", _t("The first string to compare.")), arg("string2 (string)", _t("The second string to compare."))],
25224
25237
  compute: function(string1, string2) {
25225
- return toString(string1) === toString(string2);
25238
+ return toLocaleString(string1, this.locale) === toLocaleString(string2, this.locale);
25226
25239
  },
25227
25240
  isExported: true
25228
25241
  };
@@ -25234,8 +25247,8 @@ const FIND = {
25234
25247
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
25235
25248
  ],
25236
25249
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
25237
- const _searchFor = toString(searchFor);
25238
- const _textToSearch = toString(textToSearch);
25250
+ const _searchFor = toLocaleString(searchFor, this.locale);
25251
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
25239
25252
  const _startingAt = toNumber(startingAt, this.locale);
25240
25253
  if (_textToSearch === "") return new EvaluationError(_t("The text_to_search must be non-empty."));
25241
25254
  if (_startingAt < 1) return new EvaluationError(_t("The starting_at (%s) must be greater than or equal to 1.", _startingAt));
@@ -25272,8 +25285,8 @@ const JOIN = {
25272
25285
  description: _t("Concatenates elements of arrays with delimiter."),
25273
25286
  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."))],
25274
25287
  compute: function(delimiter, ...valuesOrArrays) {
25275
- const _delimiter = toString(delimiter);
25276
- return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
25288
+ const _delimiter = toLocaleString(delimiter, this.locale);
25289
+ return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toLocaleString(a, this.locale), "");
25277
25290
  }
25278
25291
  };
25279
25292
  const LEFT = {
@@ -25282,7 +25295,7 @@ const LEFT = {
25282
25295
  compute: function(text, ...args) {
25283
25296
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
25284
25297
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters));
25285
- return toString(text).substring(0, _numberOfCharacters);
25298
+ return toLocaleString(text, this.locale).substring(0, _numberOfCharacters);
25286
25299
  },
25287
25300
  isExported: true
25288
25301
  };
@@ -25290,7 +25303,7 @@ const LEN = {
25290
25303
  description: _t("Length of a string."),
25291
25304
  args: [arg("text (string)", _t("The string whose length will be returned."))],
25292
25305
  compute: function(text) {
25293
- return toString(text).length;
25306
+ return toLocaleString(text, this.locale).length;
25294
25307
  },
25295
25308
  isExported: true
25296
25309
  };
@@ -25298,7 +25311,7 @@ const LOWER = {
25298
25311
  description: _t("Converts a specified string to lowercase."),
25299
25312
  args: [arg("text (string)", _t("The string to convert to lowercase."))],
25300
25313
  compute: function(text) {
25301
- return toString(text).toLowerCase();
25314
+ return toLocaleString(text, this.locale).toLowerCase();
25302
25315
  },
25303
25316
  isExported: true
25304
25317
  };
@@ -25310,7 +25323,7 @@ const MID = {
25310
25323
  arg("extract_length (number)", _t("The length of the segment to extract."))
25311
25324
  ],
25312
25325
  compute: function(text, starting_at, extract_length) {
25313
- const _text = toString(text);
25326
+ const _text = toLocaleString(text, this.locale);
25314
25327
  const _starting_at = toNumber(starting_at, this.locale);
25315
25328
  const _extract_length = toNumber(extract_length, this.locale);
25316
25329
  if (_starting_at < 1) return new EvaluationError(_t("The starting_at argument (%s) must be positive greater than one.", _starting_at.toString()));
@@ -25323,7 +25336,7 @@ const PROPER = {
25323
25336
  description: _t("Capitalizes each word in a specified string."),
25324
25337
  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."))],
25325
25338
  compute: function(text) {
25326
- return toString(text).replace(wordRegex, (word) => {
25339
+ return toLocaleString(text, this.locale).replace(wordRegex, (word) => {
25327
25340
  return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
25328
25341
  });
25329
25342
  },
@@ -25471,9 +25484,9 @@ const REPLACE = {
25471
25484
  compute: function(text, position, length, newText) {
25472
25485
  const _position = toNumber(position, this.locale);
25473
25486
  if (_position < 1) return new EvaluationError(_t("The position (%s) must be greater than or equal to 1.", _position));
25474
- const _text = toString(text);
25487
+ const _text = toLocaleString(text, this.locale);
25475
25488
  const _length = toNumber(length, this.locale);
25476
- const _newText = toString(newText);
25489
+ const _newText = toLocaleString(newText, this.locale);
25477
25490
  return _text.substring(0, _position - 1) + _newText + _text.substring(_position - 1 + _length);
25478
25491
  },
25479
25492
  isExported: true
@@ -25484,7 +25497,7 @@ const RIGHT = {
25484
25497
  compute: function(text, ...args) {
25485
25498
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
25486
25499
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters));
25487
- const _text = toString(text);
25500
+ const _text = toLocaleString(text, this.locale);
25488
25501
  const stringLength = _text.length;
25489
25502
  return _text.substring(stringLength - _numberOfCharacters, stringLength);
25490
25503
  },
@@ -25498,8 +25511,8 @@ const SEARCH = {
25498
25511
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
25499
25512
  ],
25500
25513
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
25501
- const _searchFor = toString(searchFor).toLowerCase();
25502
- const _textToSearch = toString(textToSearch).toLowerCase();
25514
+ const _searchFor = toLocaleString(searchFor, this.locale).toLowerCase();
25515
+ const _textToSearch = toLocaleString(textToSearch, this.locale).toLowerCase();
25503
25516
  const _startingAt = toNumber(startingAt, this.locale);
25504
25517
  if (_textToSearch === "") return {
25505
25518
  value: CellErrorType.GenericError,
@@ -25529,8 +25542,8 @@ const SPLIT = {
25529
25542
  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."))
25530
25543
  ],
25531
25544
  compute: function(text, delimiter, splitByEach = { value: SPLIT_DEFAULT_SPLIT_BY_EACH }, removeEmptyText = { value: SPLIT_DEFAULT_REMOVE_EMPTY_TEXT }) {
25532
- const _text = toString(text);
25533
- const _delimiter = escapeRegExp(toString(delimiter));
25545
+ const _text = toLocaleString(text, this.locale);
25546
+ const _delimiter = escapeRegExp(toLocaleString(delimiter, this.locale));
25534
25547
  const _splitByEach = toBoolean(splitByEach);
25535
25548
  const _removeEmptyText = toBoolean(removeEmptyText);
25536
25549
  if (_delimiter.length <= 0) return new EvaluationError(_t("The delimiter (%s) must be not be empty.", _delimiter));
@@ -25552,10 +25565,10 @@ const SUBSTITUTE = {
25552
25565
  compute: function(textToSearch, searchFor, replaceWith, occurrenceNumber) {
25553
25566
  const _occurrenceNumber = toNumber(occurrenceNumber, this.locale);
25554
25567
  if (_occurrenceNumber < 0) return new EvaluationError(_t("The occurrenceNumber (%s) must be positive or null.", _occurrenceNumber));
25555
- const _textToSearch = toString(textToSearch);
25556
- const _searchFor = toString(searchFor);
25568
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
25569
+ const _searchFor = toLocaleString(searchFor, this.locale);
25557
25570
  if (_searchFor === "") return _textToSearch;
25558
- const _replaceWith = toString(replaceWith);
25571
+ const _replaceWith = toLocaleString(replaceWith, this.locale);
25559
25572
  const reg = new RegExp(escapeRegExp(_searchFor), "g");
25560
25573
  if (_occurrenceNumber === 0) return _textToSearch.replace(reg, _replaceWith);
25561
25574
  let n = 0;
@@ -25578,10 +25591,10 @@ const TEXTJOIN = {
25578
25591
  arg("texts (string, range<string>, repeating)", _t("Text item to join."))
25579
25592
  ],
25580
25593
  compute: function(delimiter, ignoreEmpty = { value: TEXTJOIN_DEFAULT_IGNORE_EMPTY }, ...textsOrArrays) {
25581
- const _delimiter = toString(delimiter);
25594
+ const _delimiter = toLocaleString(delimiter, this.locale);
25582
25595
  const _ignoreEmpty = toBoolean(ignoreEmpty);
25583
25596
  let n = 0;
25584
- return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toString(a) === "") ? (n++ ? acc + _delimiter : "") + toString(a) : acc, "");
25597
+ return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toLocaleString(a, this.locale) === "") ? (n++ ? acc + _delimiter : "") + toLocaleString(a, this.locale) : acc, "");
25585
25598
  },
25586
25599
  isExported: true
25587
25600
  };
@@ -25634,7 +25647,7 @@ const TRIM = {
25634
25647
  description: _t("Removes space characters."),
25635
25648
  args: [arg("text (string)", _t("The text or reference to a cell containing text to be trimmed."))],
25636
25649
  compute: function(text) {
25637
- return trimContent(toString(text));
25650
+ return trimContent(toLocaleString(text, this.locale));
25638
25651
  },
25639
25652
  isExported: true
25640
25653
  };
@@ -25642,7 +25655,7 @@ const UPPER = {
25642
25655
  description: _t("Converts a specified string to uppercase."),
25643
25656
  args: [arg("text (string)", _t("The string to convert to uppercase."))],
25644
25657
  compute: function(text) {
25645
- return toString(text).toUpperCase();
25658
+ return toLocaleString(text, this.locale).toUpperCase();
25646
25659
  },
25647
25660
  isExported: true
25648
25661
  };
@@ -25739,7 +25752,7 @@ const HYPERLINK = {
25739
25752
  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."))],
25740
25753
  compute: function(url, linkLabel) {
25741
25754
  const processedUrl = toString(url).trim();
25742
- const processedLabel = toString(linkLabel) || processedUrl;
25755
+ const processedLabel = toLocaleString(linkLabel, this.locale) || processedUrl;
25743
25756
  if (processedUrl === "") return processedLabel;
25744
25757
  return markdownLink(processedLabel, processedUrl);
25745
25758
  },
@@ -36229,12 +36242,13 @@ var FilterMenu = class extends Component {
36229
36242
  }
36230
36243
  sortFilterZone(sortDirection) {
36231
36244
  const filterPosition = this.props.filterPosition;
36232
- const tableZone = this.table?.range.zone;
36245
+ const table = this.table;
36246
+ const tableZone = table?.range.zone;
36233
36247
  if (!filterPosition || !tableZone || tableZone.top === tableZone.bottom) return;
36234
36248
  const sheetId = this.env.model.getters.getActiveSheetId();
36235
36249
  const contentZone = {
36236
36250
  ...tableZone,
36237
- top: tableZone.top + 1
36251
+ top: tableZone.top + table.config.numberOfHeaders
36238
36252
  };
36239
36253
  const sortAnchor = {
36240
36254
  col: filterPosition.col,
@@ -81811,6 +81825,6 @@ const chartHelpers = {
81811
81825
  //#endregion
81812
81826
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CompiledFormula, CorePlugin, CoreViewPlugin, DEFAULT_LOCALE, DEFAULT_LOCALES, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, canExecuteInReadonly, categories, chartHelpers, components, constants, convertAstNodes, coreTypes, createAutocompleteArgumentsProvider, findCellInNewZone, functionCache, getCaretDownSvg, getCaretUpSvg, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, isCoreCommand, isSheetDependent, iterateAstNodes, links, load, lockedSheetAllowedCommands, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
81813
81827
 
81814
- __info__.version = "19.2.25";
81815
- __info__.date = "2026-08-12T09:16:51.116Z";
81816
- __info__.hash = "685ffda";
81828
+ __info__.version = "19.2.27";
81829
+ __info__.date = "2026-08-29T09:15:15.122Z";
81830
+ __info__.hash = "9e63c60";
@@ -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.2.25
6
- * @date 2026-08-12T09:16:51.116Z
7
- * @hash 685ffda
5
+ * @version 19.2.27
6
+ * @date 2026-08-29T09:15:15.122Z
7
+ * @hash 9e63c60
8
8
  */
9
9
 
10
10
  (function(exports, _odoo_owl) {
@@ -3753,6 +3753,18 @@ stores.inject(MyMetaStore, storeInstance);
3753
3753
  default: return "";
3754
3754
  }
3755
3755
  }
3756
+ /**
3757
+ * Only converts the decimal separator, ignore number format such as % or dates
3758
+ */
3759
+ function toLocaleString(data, locale) {
3760
+ const value = toValue(data);
3761
+ switch (typeof value) {
3762
+ case "string": return value;
3763
+ case "number": return value.toString().replace(".", locale.decimalSeparator);
3764
+ case "boolean": return value ? "TRUE" : "FALSE";
3765
+ default: return "";
3766
+ }
3767
+ }
3756
3768
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
3757
3769
  const normalizeString = memoize(function normalizeString(str) {
3758
3770
  return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
@@ -9162,6 +9174,7 @@ stores.inject(MyMetaStore, storeInstance);
9162
9174
  hidden,
9163
9175
  borderColor,
9164
9176
  backgroundColor: borderColor,
9177
+ pointBackgroundColor: borderColor,
9165
9178
  pointRadius: definition.hideDataMarkers ? 0 : 3
9166
9179
  };
9167
9180
  if (fill) {
@@ -18293,7 +18306,7 @@ stores.inject(MyMetaStore, storeInstance);
18293
18306
  else if (_format === 0) {
18294
18307
  const rowSeparator = this.locale.decimalSeparator === "," ? "/" : ",";
18295
18308
  return transposeMatrix(_array).flatMap((row) => row.map((value) => {
18296
- return isEvaluationError(value.value) ? value.value : toString(value);
18309
+ return isEvaluationError(value.value) ? value.value : toLocaleString(value, this.locale);
18297
18310
  })).join(rowSeparator);
18298
18311
  } else return new EvaluationError(_t("Format must be 0 or 1"));
18299
18312
  },
@@ -24336,7 +24349,7 @@ stores.inject(MyMetaStore, storeInstance);
24336
24349
  description: _t("Concatenation of two values."),
24337
24350
  args: [arg("value1 (string)", _t("The value to which value2 will be appended.")), arg("value2 (string)", _t("The value to append to value1."))],
24338
24351
  compute: function(value1, value2) {
24339
- return toString(value1) + toString(value2);
24352
+ return toLocaleString(value1, this.locale) + toLocaleString(value2, this.locale);
24340
24353
  },
24341
24354
  isExported: true
24342
24355
  };
@@ -25205,7 +25218,7 @@ stores.inject(MyMetaStore, storeInstance);
25205
25218
  description: _t("Remove non-printable characters from a piece of text."),
25206
25219
  args: [arg("text (string)", _t("The text whose non-printable characters are to be removed."))],
25207
25220
  compute: function(text) {
25208
- const _text = toString(text);
25221
+ const _text = toLocaleString(text, this.locale);
25209
25222
  let cleanedStr = "";
25210
25223
  for (const char of _text) if (char && char.charCodeAt(0) > 31) cleanedStr += char;
25211
25224
  return cleanedStr;
@@ -25216,7 +25229,7 @@ stores.inject(MyMetaStore, storeInstance);
25216
25229
  description: _t("Appends strings to one another."),
25217
25230
  args: [arg("string (string, range<string>, repeating)", _t("String to append in sequence."))],
25218
25231
  compute: function(...datas) {
25219
- return reduceAny(datas, (acc, a) => acc + toString(a), "");
25232
+ return reduceAny(datas, (acc, a) => acc + toLocaleString(a, this.locale), "");
25220
25233
  },
25221
25234
  isExported: true
25222
25235
  };
@@ -25224,7 +25237,7 @@ stores.inject(MyMetaStore, storeInstance);
25224
25237
  description: _t("Tests whether two strings are identical."),
25225
25238
  args: [arg("string1 (string)", _t("The first string to compare.")), arg("string2 (string)", _t("The second string to compare."))],
25226
25239
  compute: function(string1, string2) {
25227
- return toString(string1) === toString(string2);
25240
+ return toLocaleString(string1, this.locale) === toLocaleString(string2, this.locale);
25228
25241
  },
25229
25242
  isExported: true
25230
25243
  };
@@ -25236,8 +25249,8 @@ stores.inject(MyMetaStore, storeInstance);
25236
25249
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
25237
25250
  ],
25238
25251
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
25239
- const _searchFor = toString(searchFor);
25240
- const _textToSearch = toString(textToSearch);
25252
+ const _searchFor = toLocaleString(searchFor, this.locale);
25253
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
25241
25254
  const _startingAt = toNumber(startingAt, this.locale);
25242
25255
  if (_textToSearch === "") return new EvaluationError(_t("The text_to_search must be non-empty."));
25243
25256
  if (_startingAt < 1) return new EvaluationError(_t("The starting_at (%s) must be greater than or equal to 1.", _startingAt));
@@ -25274,8 +25287,8 @@ stores.inject(MyMetaStore, storeInstance);
25274
25287
  description: _t("Concatenates elements of arrays with delimiter."),
25275
25288
  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."))],
25276
25289
  compute: function(delimiter, ...valuesOrArrays) {
25277
- const _delimiter = toString(delimiter);
25278
- return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
25290
+ const _delimiter = toLocaleString(delimiter, this.locale);
25291
+ return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toLocaleString(a, this.locale), "");
25279
25292
  }
25280
25293
  };
25281
25294
  const LEFT = {
@@ -25284,7 +25297,7 @@ stores.inject(MyMetaStore, storeInstance);
25284
25297
  compute: function(text, ...args) {
25285
25298
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
25286
25299
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters));
25287
- return toString(text).substring(0, _numberOfCharacters);
25300
+ return toLocaleString(text, this.locale).substring(0, _numberOfCharacters);
25288
25301
  },
25289
25302
  isExported: true
25290
25303
  };
@@ -25292,7 +25305,7 @@ stores.inject(MyMetaStore, storeInstance);
25292
25305
  description: _t("Length of a string."),
25293
25306
  args: [arg("text (string)", _t("The string whose length will be returned."))],
25294
25307
  compute: function(text) {
25295
- return toString(text).length;
25308
+ return toLocaleString(text, this.locale).length;
25296
25309
  },
25297
25310
  isExported: true
25298
25311
  };
@@ -25300,7 +25313,7 @@ stores.inject(MyMetaStore, storeInstance);
25300
25313
  description: _t("Converts a specified string to lowercase."),
25301
25314
  args: [arg("text (string)", _t("The string to convert to lowercase."))],
25302
25315
  compute: function(text) {
25303
- return toString(text).toLowerCase();
25316
+ return toLocaleString(text, this.locale).toLowerCase();
25304
25317
  },
25305
25318
  isExported: true
25306
25319
  };
@@ -25312,7 +25325,7 @@ stores.inject(MyMetaStore, storeInstance);
25312
25325
  arg("extract_length (number)", _t("The length of the segment to extract."))
25313
25326
  ],
25314
25327
  compute: function(text, starting_at, extract_length) {
25315
- const _text = toString(text);
25328
+ const _text = toLocaleString(text, this.locale);
25316
25329
  const _starting_at = toNumber(starting_at, this.locale);
25317
25330
  const _extract_length = toNumber(extract_length, this.locale);
25318
25331
  if (_starting_at < 1) return new EvaluationError(_t("The starting_at argument (%s) must be positive greater than one.", _starting_at.toString()));
@@ -25325,7 +25338,7 @@ stores.inject(MyMetaStore, storeInstance);
25325
25338
  description: _t("Capitalizes each word in a specified string."),
25326
25339
  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."))],
25327
25340
  compute: function(text) {
25328
- return toString(text).replace(wordRegex, (word) => {
25341
+ return toLocaleString(text, this.locale).replace(wordRegex, (word) => {
25329
25342
  return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
25330
25343
  });
25331
25344
  },
@@ -25473,9 +25486,9 @@ stores.inject(MyMetaStore, storeInstance);
25473
25486
  compute: function(text, position, length, newText) {
25474
25487
  const _position = toNumber(position, this.locale);
25475
25488
  if (_position < 1) return new EvaluationError(_t("The position (%s) must be greater than or equal to 1.", _position));
25476
- const _text = toString(text);
25489
+ const _text = toLocaleString(text, this.locale);
25477
25490
  const _length = toNumber(length, this.locale);
25478
- const _newText = toString(newText);
25491
+ const _newText = toLocaleString(newText, this.locale);
25479
25492
  return _text.substring(0, _position - 1) + _newText + _text.substring(_position - 1 + _length);
25480
25493
  },
25481
25494
  isExported: true
@@ -25486,7 +25499,7 @@ stores.inject(MyMetaStore, storeInstance);
25486
25499
  compute: function(text, ...args) {
25487
25500
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
25488
25501
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters));
25489
- const _text = toString(text);
25502
+ const _text = toLocaleString(text, this.locale);
25490
25503
  const stringLength = _text.length;
25491
25504
  return _text.substring(stringLength - _numberOfCharacters, stringLength);
25492
25505
  },
@@ -25500,8 +25513,8 @@ stores.inject(MyMetaStore, storeInstance);
25500
25513
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
25501
25514
  ],
25502
25515
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
25503
- const _searchFor = toString(searchFor).toLowerCase();
25504
- const _textToSearch = toString(textToSearch).toLowerCase();
25516
+ const _searchFor = toLocaleString(searchFor, this.locale).toLowerCase();
25517
+ const _textToSearch = toLocaleString(textToSearch, this.locale).toLowerCase();
25505
25518
  const _startingAt = toNumber(startingAt, this.locale);
25506
25519
  if (_textToSearch === "") return {
25507
25520
  value: CellErrorType.GenericError,
@@ -25531,8 +25544,8 @@ stores.inject(MyMetaStore, storeInstance);
25531
25544
  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."))
25532
25545
  ],
25533
25546
  compute: function(text, delimiter, splitByEach = { value: SPLIT_DEFAULT_SPLIT_BY_EACH }, removeEmptyText = { value: SPLIT_DEFAULT_REMOVE_EMPTY_TEXT }) {
25534
- const _text = toString(text);
25535
- const _delimiter = escapeRegExp(toString(delimiter));
25547
+ const _text = toLocaleString(text, this.locale);
25548
+ const _delimiter = escapeRegExp(toLocaleString(delimiter, this.locale));
25536
25549
  const _splitByEach = toBoolean(splitByEach);
25537
25550
  const _removeEmptyText = toBoolean(removeEmptyText);
25538
25551
  if (_delimiter.length <= 0) return new EvaluationError(_t("The delimiter (%s) must be not be empty.", _delimiter));
@@ -25554,10 +25567,10 @@ stores.inject(MyMetaStore, storeInstance);
25554
25567
  compute: function(textToSearch, searchFor, replaceWith, occurrenceNumber) {
25555
25568
  const _occurrenceNumber = toNumber(occurrenceNumber, this.locale);
25556
25569
  if (_occurrenceNumber < 0) return new EvaluationError(_t("The occurrenceNumber (%s) must be positive or null.", _occurrenceNumber));
25557
- const _textToSearch = toString(textToSearch);
25558
- const _searchFor = toString(searchFor);
25570
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
25571
+ const _searchFor = toLocaleString(searchFor, this.locale);
25559
25572
  if (_searchFor === "") return _textToSearch;
25560
- const _replaceWith = toString(replaceWith);
25573
+ const _replaceWith = toLocaleString(replaceWith, this.locale);
25561
25574
  const reg = new RegExp(escapeRegExp(_searchFor), "g");
25562
25575
  if (_occurrenceNumber === 0) return _textToSearch.replace(reg, _replaceWith);
25563
25576
  let n = 0;
@@ -25580,10 +25593,10 @@ stores.inject(MyMetaStore, storeInstance);
25580
25593
  arg("texts (string, range<string>, repeating)", _t("Text item to join."))
25581
25594
  ],
25582
25595
  compute: function(delimiter, ignoreEmpty = { value: TEXTJOIN_DEFAULT_IGNORE_EMPTY }, ...textsOrArrays) {
25583
- const _delimiter = toString(delimiter);
25596
+ const _delimiter = toLocaleString(delimiter, this.locale);
25584
25597
  const _ignoreEmpty = toBoolean(ignoreEmpty);
25585
25598
  let n = 0;
25586
- return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toString(a) === "") ? (n++ ? acc + _delimiter : "") + toString(a) : acc, "");
25599
+ return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toLocaleString(a, this.locale) === "") ? (n++ ? acc + _delimiter : "") + toLocaleString(a, this.locale) : acc, "");
25587
25600
  },
25588
25601
  isExported: true
25589
25602
  };
@@ -25636,7 +25649,7 @@ stores.inject(MyMetaStore, storeInstance);
25636
25649
  description: _t("Removes space characters."),
25637
25650
  args: [arg("text (string)", _t("The text or reference to a cell containing text to be trimmed."))],
25638
25651
  compute: function(text) {
25639
- return trimContent(toString(text));
25652
+ return trimContent(toLocaleString(text, this.locale));
25640
25653
  },
25641
25654
  isExported: true
25642
25655
  };
@@ -25644,7 +25657,7 @@ stores.inject(MyMetaStore, storeInstance);
25644
25657
  description: _t("Converts a specified string to uppercase."),
25645
25658
  args: [arg("text (string)", _t("The string to convert to uppercase."))],
25646
25659
  compute: function(text) {
25647
- return toString(text).toUpperCase();
25660
+ return toLocaleString(text, this.locale).toUpperCase();
25648
25661
  },
25649
25662
  isExported: true
25650
25663
  };
@@ -25741,7 +25754,7 @@ stores.inject(MyMetaStore, storeInstance);
25741
25754
  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."))],
25742
25755
  compute: function(url, linkLabel) {
25743
25756
  const processedUrl = toString(url).trim();
25744
- const processedLabel = toString(linkLabel) || processedUrl;
25757
+ const processedLabel = toLocaleString(linkLabel, this.locale) || processedUrl;
25745
25758
  if (processedUrl === "") return processedLabel;
25746
25759
  return markdownLink(processedLabel, processedUrl);
25747
25760
  },
@@ -36231,12 +36244,13 @@ stores.inject(MyMetaStore, storeInstance);
36231
36244
  }
36232
36245
  sortFilterZone(sortDirection) {
36233
36246
  const filterPosition = this.props.filterPosition;
36234
- const tableZone = this.table?.range.zone;
36247
+ const table = this.table;
36248
+ const tableZone = table?.range.zone;
36235
36249
  if (!filterPosition || !tableZone || tableZone.top === tableZone.bottom) return;
36236
36250
  const sheetId = this.env.model.getters.getActiveSheetId();
36237
36251
  const contentZone = {
36238
36252
  ...tableZone,
36239
- top: tableZone.top + 1
36253
+ top: tableZone.top + table.config.numberOfHeaders
36240
36254
  };
36241
36255
  const sortAnchor = {
36242
36256
  col: filterPosition.col,
@@ -81871,8 +81885,8 @@ exports.stores = stores;
81871
81885
  exports.tokenColors = tokenColors;
81872
81886
  exports.tokenize = tokenize;
81873
81887
 
81874
- __info__.version = "19.2.25";
81875
- __info__.date = "2026-08-12T09:16:51.116Z";
81876
- __info__.hash = "685ffda";
81888
+ __info__.version = "19.2.27";
81889
+ __info__.date = "2026-08-29T09:15:15.122Z";
81890
+ __info__.hash = "9e63c60";
81877
81891
 
81878
81892
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);