@extend-ai/react-xlsx 0.19.0 → 0.20.1

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.
Files changed (69) hide show
  1. package/README.md +2 -1
  2. package/dist/{chart-renderer-LHXMRBGR.cjs → chart-renderer-K2VM257E.cjs} +44 -39
  3. package/dist/chart-renderer-K2VM257E.cjs.map +1 -0
  4. package/dist/{chart-renderer-HVOEAQXK.cjs → chart-renderer-K6GORT3R.cjs} +44 -39
  5. package/dist/chart-renderer-K6GORT3R.cjs.map +1 -0
  6. package/dist/{chart-renderer-R2B4I2HL.js → chart-renderer-KGLAI4DN.js} +25 -20
  7. package/dist/chart-renderer-KGLAI4DN.js.map +1 -0
  8. package/dist/{chart-renderer-3K2VKB5I.js → chart-renderer-RXO7WP4Q.js} +25 -20
  9. package/dist/chart-renderer-RXO7WP4Q.js.map +1 -0
  10. package/dist/{chunk-ZIO47YMT.cjs → chunk-2MVEKDY2.cjs} +4 -4
  11. package/dist/{chunk-ZIO47YMT.cjs.map → chunk-2MVEKDY2.cjs.map} +1 -1
  12. package/dist/{chunk-3O2QY6LA.js → chunk-3JTCYAUX.js} +3 -3
  13. package/dist/{chunk-4VX5HTCF.cjs → chunk-54YBFWL3.cjs} +4 -4
  14. package/dist/{chunk-4VX5HTCF.cjs.map → chunk-54YBFWL3.cjs.map} +1 -1
  15. package/dist/{chunk-T5WZHPIN.cjs → chunk-AD4CGQN2.cjs} +2 -2
  16. package/dist/{chunk-T5WZHPIN.cjs.map → chunk-AD4CGQN2.cjs.map} +1 -1
  17. package/dist/{chunk-Y737JKUG.js → chunk-GXJO6CK6.js} +136 -33
  18. package/dist/chunk-GXJO6CK6.js.map +1 -0
  19. package/dist/{chunk-TYJLNPNE.cjs → chunk-HAHCVXCU.cjs} +922 -819
  20. package/dist/chunk-HAHCVXCU.cjs.map +1 -0
  21. package/dist/{chunk-E2VSYCP2.cjs → chunk-O3V2MCOC.cjs} +18 -2
  22. package/dist/chunk-O3V2MCOC.cjs.map +1 -0
  23. package/dist/{chunk-BAAMDEDS.js → chunk-VXBNYHW5.js} +18 -2
  24. package/dist/{chunk-BAAMDEDS.js.map → chunk-VXBNYHW5.js.map} +1 -1
  25. package/dist/{chunk-O7S3Y6II.js → chunk-WSQDFXDW.js} +3 -3
  26. package/dist/index.cjs +617 -530
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +5 -0
  29. package/dist/index.d.ts +5 -0
  30. package/dist/index.js +115 -28
  31. package/dist/index.js.map +1 -1
  32. package/dist/{internal-DSz8QMhK.d.cts → internal-trWFv9In.d.cts} +5 -0
  33. package/dist/{internal-DSz8QMhK.d.ts → internal-trWFv9In.d.ts} +5 -0
  34. package/dist/internal.cjs +4 -4
  35. package/dist/internal.d.cts +1 -1
  36. package/dist/internal.d.ts +1 -1
  37. package/dist/internal.js +2 -2
  38. package/dist/{region-map-geography-6TGXBY3V.cjs → region-map-geography-VEN5CPRS.cjs} +2 -2
  39. package/dist/{region-map-geography-6TGXBY3V.cjs.map → region-map-geography-VEN5CPRS.cjs.map} +1 -1
  40. package/dist/{spreadsheet-font-assets-4AHYDTAQ.cjs → spreadsheet-font-assets-6FKCVICP.cjs} +2 -2
  41. package/dist/{spreadsheet-font-assets-4AHYDTAQ.cjs.map → spreadsheet-font-assets-6FKCVICP.cjs.map} +1 -1
  42. package/dist/{surface-regl-MAPCPD7W.cjs → surface-regl-2NNG62KS.cjs} +18 -15
  43. package/dist/surface-regl-2NNG62KS.cjs.map +1 -0
  44. package/dist/{surface-regl-NWR5ZZ5D.js → surface-regl-7CDGGVDG.js} +10 -7
  45. package/dist/surface-regl-7CDGGVDG.js.map +1 -0
  46. package/dist/{surface-regl-PWTZWQQS.cjs → surface-regl-SUJ2TFZA.cjs} +18 -15
  47. package/dist/surface-regl-SUJ2TFZA.cjs.map +1 -0
  48. package/dist/{surface-regl-KW4JL325.js → surface-regl-TJUWTLAZ.js} +10 -7
  49. package/dist/surface-regl-TJUWTLAZ.js.map +1 -0
  50. package/dist/vanilla.cjs +4 -4
  51. package/dist/vanilla.d.cts +2 -2
  52. package/dist/vanilla.d.ts +2 -2
  53. package/dist/vanilla.js +2 -2
  54. package/dist/xlsx-worker.js +67 -1
  55. package/dist/xlsx-worker.js.map +1 -1
  56. package/package.json +1 -1
  57. package/dist/chart-renderer-3K2VKB5I.js.map +0 -1
  58. package/dist/chart-renderer-HVOEAQXK.cjs.map +0 -1
  59. package/dist/chart-renderer-LHXMRBGR.cjs.map +0 -1
  60. package/dist/chart-renderer-R2B4I2HL.js.map +0 -1
  61. package/dist/chunk-E2VSYCP2.cjs.map +0 -1
  62. package/dist/chunk-TYJLNPNE.cjs.map +0 -1
  63. package/dist/chunk-Y737JKUG.js.map +0 -1
  64. package/dist/surface-regl-KW4JL325.js.map +0 -1
  65. package/dist/surface-regl-MAPCPD7W.cjs.map +0 -1
  66. package/dist/surface-regl-NWR5ZZ5D.js.map +0 -1
  67. package/dist/surface-regl-PWTZWQQS.cjs.map +0 -1
  68. /package/dist/{chunk-3O2QY6LA.js.map → chunk-3JTCYAUX.js.map} +0 -0
  69. /package/dist/{chunk-O7S3Y6II.js.map → chunk-WSQDFXDW.js.map} +0 -0
package/dist/index.d.cts CHANGED
@@ -961,6 +961,8 @@ interface XlsxScrollerRenderProps {
961
961
  };
962
962
  }
963
963
  interface UseXlsxViewerControllerOptions {
964
+ /** BCP 47 locale for numeric decimal and grouping separators. Defaults to en-US. */
965
+ locale?: string;
964
966
  /**
965
967
  * Allows row and column resizing even while editing is disabled by `readOnly`.
966
968
  *
@@ -1073,11 +1075,14 @@ interface XlsxViewerController {
1073
1075
  deferredLoadFileSize: number | null;
1074
1076
  defineNamedRange: (name: string, range?: XlsxCellRange | null) => void;
1075
1077
  displayFileName: string;
1078
+ locale: string;
1076
1079
  download: () => void;
1077
1080
  charts: XlsxChart[];
1078
1081
  chartsheets: XlsxChartsheet[];
1079
1082
  exportCsv: () => void;
1080
1083
  exportXlsx: () => void;
1084
+ /** The current workbook as XLSX bytes, the same bytes `exportXlsx()` downloads; `null` before a workbook loads. */
1085
+ getXlsxBytes: () => Uint8Array | null;
1081
1086
  error: Error | null;
1082
1087
  file?: ArrayBuffer;
1083
1088
  fillSelection: (targetRange: XlsxCellRange) => void;
package/dist/index.d.ts CHANGED
@@ -961,6 +961,8 @@ interface XlsxScrollerRenderProps {
961
961
  };
962
962
  }
963
963
  interface UseXlsxViewerControllerOptions {
964
+ /** BCP 47 locale for numeric decimal and grouping separators. Defaults to en-US. */
965
+ locale?: string;
964
966
  /**
965
967
  * Allows row and column resizing even while editing is disabled by `readOnly`.
966
968
  *
@@ -1073,11 +1075,14 @@ interface XlsxViewerController {
1073
1075
  deferredLoadFileSize: number | null;
1074
1076
  defineNamedRange: (name: string, range?: XlsxCellRange | null) => void;
1075
1077
  displayFileName: string;
1078
+ locale: string;
1076
1079
  download: () => void;
1077
1080
  charts: XlsxChart[];
1078
1081
  chartsheets: XlsxChartsheet[];
1079
1082
  exportCsv: () => void;
1080
1083
  exportXlsx: () => void;
1084
+ /** The current workbook as XLSX bytes, the same bytes `exportXlsx()` downloads; `null` before a workbook loads. */
1085
+ getXlsxBytes: () => Uint8Array | null;
1081
1086
  error: Error | null;
1082
1087
  file?: ArrayBuffer;
1083
1088
  fillSelection: (targetRange: XlsxCellRange) => void;
package/dist/index.js CHANGED
@@ -1,10 +1,73 @@
1
- import "./chunk-3O2QY6LA.js";
1
+ import "./chunk-3JTCYAUX.js";
2
2
  import {
3
3
  getBuiltinChartColor,
4
4
  getBuiltinChartSurfaceStyle,
5
5
  resolveBuiltinChartColor
6
6
  } from "./chunk-VWGKYABF.js";
7
7
 
8
+ // src/number-locale.ts
9
+ var separators = /* @__PURE__ */ new Map();
10
+ function parseLocaleNumber(text, locale) {
11
+ if (locale === "en-US") return void 0;
12
+ const parts = new Intl.NumberFormat(locale).formatToParts(12345.6);
13
+ const decimal = parts.find((part) => part.type === "decimal")?.value ?? ".";
14
+ const group = parts.find((part) => part.type === "group")?.value ?? ",";
15
+ let normalized = text.trim();
16
+ const percent = normalized.endsWith("%");
17
+ if (percent) normalized = normalized.slice(0, -1).trim();
18
+ normalized = group.trim() === "" ? normalized.replace(/[ \u00a0\u202f]/g, "") : normalized.split(group).join("");
19
+ normalized = normalized.replace(decimal, ".");
20
+ if (!/^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/.test(normalized)) return void 0;
21
+ const value = Number(normalized) / (percent ? 100 : 1);
22
+ return Number.isFinite(value) ? value : void 0;
23
+ }
24
+ function localizeCellNumber(worksheet, row, col, text, locale = "en-US") {
25
+ if (locale === "en-US" || !text) return text;
26
+ const value = worksheet.getCalculatedValueAt(row, col);
27
+ try {
28
+ if (!value.is_number) return text;
29
+ } finally {
30
+ value.free();
31
+ }
32
+ const style = worksheet.getCellStyleAt(row, col);
33
+ const format = style?.numberFormat;
34
+ if (format?.isDateFormat) return text;
35
+ let symbols = separators.get(locale);
36
+ if (!symbols) {
37
+ const parts = new Intl.NumberFormat(locale).formatToParts(12345.6);
38
+ symbols = {
39
+ decimal: parts.find((part) => part.type === "decimal")?.value ?? ".",
40
+ group: parts.find((part) => part.type === "group")?.value ?? ","
41
+ };
42
+ if (separators.size >= 100) separators.clear();
43
+ separators.set(locale, symbols);
44
+ }
45
+ if (symbols.decimal === "." && symbols.group === ",") return text;
46
+ const protectedPositions = /* @__PURE__ */ new Set();
47
+ const code = format?.formatString ?? "";
48
+ const literalPattern = /"[^"]*"|\\.|\[[^\]]*\]/g;
49
+ const firstPlaceholder = code.replace(literalPattern, (token) => " ".repeat(token.length)).search(/[0#?]/);
50
+ const literals = [...code.matchAll(literalPattern)];
51
+ let suffixEnd = text.length;
52
+ let prefixStart = 0;
53
+ const protect = (token, suffix) => {
54
+ const literal = token.startsWith('"') ? token.slice(1, -1) : token.startsWith("\\") ? token.slice(1) : token.startsWith("[$") ? token.slice(2, -1).split("-")[0] : "";
55
+ if (!literal) return;
56
+ const offset = suffix ? text.lastIndexOf(literal, suffixEnd - literal.length) : text.indexOf(literal, prefixStart);
57
+ if (offset >= 0) {
58
+ for (let i = offset; i < offset + literal.length; i++) protectedPositions.add(i);
59
+ if (suffix) suffixEnd = offset;
60
+ else prefixStart = offset + literal.length;
61
+ }
62
+ };
63
+ for (const token of literals.filter((token2) => token2.index < firstPlaceholder)) protect(token[0], false);
64
+ for (const token of literals.filter((token2) => token2.index >= firstPlaceholder).reverse()) protect(token[0], true);
65
+ return text.replace(
66
+ /\d[\d,]*(?:\.\d*)?|\.\d+/g,
67
+ (number, offset) => number.replace(/[.,]/g, (separator, index) => protectedPositions.has(offset + index) ? separator : separator === "." ? symbols.decimal : symbols.group)
68
+ );
69
+ }
70
+
8
71
  // src/spreadsheet-fonts.ts
9
72
  var fontLoadPromise;
10
73
  var SPREADSHEET_FALLBACK_FONT = "React XLSX Carlito";
@@ -6818,10 +6881,10 @@ var XlsxWorkerClient = class {
6818
6881
  type: "load"
6819
6882
  }, [workerBuffer]);
6820
6883
  }
6821
- getCellSnapshot(workbookSheetIndex, row, col) {
6884
+ getCellSnapshot(workbookSheetIndex, row, col, locale) {
6822
6885
  return this.request({
6823
6886
  id: 0,
6824
- payload: { col, row, workbookSheetIndex },
6887
+ payload: { col, row, workbookSheetIndex, locale },
6825
6888
  type: "getCellSnapshot"
6826
6889
  });
6827
6890
  }
@@ -6838,10 +6901,10 @@ var XlsxWorkerClient = class {
6838
6901
  type: "parseCharts"
6839
6902
  }, [workerBuffer]);
6840
6903
  }
6841
- getRowsBatch(workbookSheetIndex, startRow, rowCount) {
6904
+ getRowsBatch(workbookSheetIndex, startRow, rowCount, locale) {
6842
6905
  return this.request({
6843
6906
  id: 0,
6844
- payload: { rowCount, startRow, workbookSheetIndex },
6907
+ payload: { rowCount, startRow, workbookSheetIndex, locale },
6845
6908
  type: "getRowsBatch"
6846
6909
  });
6847
6910
  }
@@ -7965,7 +8028,7 @@ function cloneCellStyle(style) {
7965
8028
  return style;
7966
8029
  }
7967
8030
  }
7968
- function coerceUserEnteredValue(value) {
8031
+ function coerceUserEnteredValue(value, locale = "en-US") {
7969
8032
  const trimmed = value.trim();
7970
8033
  if (!trimmed) {
7971
8034
  return "";
@@ -7976,6 +8039,8 @@ function coerceUserEnteredValue(value) {
7976
8039
  if (/^(true|false)$/i.test(trimmed)) {
7977
8040
  return trimmed.toLowerCase() === "true";
7978
8041
  }
8042
+ const localizedNumber = parseLocaleNumber(trimmed, locale);
8043
+ if (localizedNumber !== void 0) return localizedNumber;
7979
8044
  if (/^[+-]?(?:\d+\.?\d*|\.\d+)$/.test(trimmed)) {
7980
8045
  const parsed = Number(trimmed);
7981
8046
  if (Number.isFinite(parsed)) {
@@ -8395,6 +8460,7 @@ function useXlsxViewerController(options) {
8395
8460
  deferLoadingAboveBytes = DEFAULT_DEFER_LOADING_ABOVE_BYTES,
8396
8461
  file,
8397
8462
  fileName,
8463
+ locale = "en-US",
8398
8464
  maxFileSizeBytes = DEFAULT_MAX_FILE_SIZE_BYTES,
8399
8465
  readOnly: requestedReadOnly = false,
8400
8466
  readOnlyAboveBytes = 0,
@@ -9209,14 +9275,14 @@ function useXlsxViewerController(options) {
9209
9275
  formula: ""
9210
9276
  });
9211
9277
  }
9212
- return getWorkerClient().getCellSnapshot(workbookSheetIndex, row, col);
9213
- }, [getWorkerClient, isWorkerBacked]);
9278
+ return getWorkerClient().getCellSnapshot(workbookSheetIndex, row, col, locale);
9279
+ }, [getWorkerClient, isWorkerBacked, locale]);
9214
9280
  const getRowsBatchAsync = React.useCallback((workbookSheetIndex, startRow, rowCount) => {
9215
9281
  if (!isWorkerBacked) {
9216
9282
  return Promise.resolve(null);
9217
9283
  }
9218
- return getWorkerClient().getRowsBatch(workbookSheetIndex, startRow, rowCount);
9219
- }, [getWorkerClient, isWorkerBacked]);
9284
+ return getWorkerClient().getRowsBatch(workbookSheetIndex, startRow, rowCount, locale);
9285
+ }, [getWorkerClient, isWorkerBacked, locale]);
9220
9286
  const visibleSheetIndexByWorkbookSheetIndex = React.useMemo(
9221
9287
  () => new Map(sheets.map((sheet, index) => [sheet.workbookSheetIndex, index])),
9222
9288
  [sheets]
@@ -9429,7 +9495,7 @@ function useXlsxViewerController(options) {
9429
9495
  }, [activeSheet?.showGridLines, activeSheet?.workbookSheetIndex]);
9430
9496
  const getCellDisplayValue2 = React.useCallback((cell) => {
9431
9497
  if (cell && activeSheet) {
9432
- const workerSnapshot = workerCellSnapshotCacheRef.current.get(`${activeSheet.workbookSheetIndex}:${cell.row}:${cell.col}`);
9498
+ const workerSnapshot = workerCellSnapshotCacheRef.current.get(`${locale}:${activeSheet.workbookSheetIndex}:${cell.row}:${cell.col}`);
9433
9499
  if (workerSnapshot) {
9434
9500
  return workerSnapshot.displayValue;
9435
9501
  }
@@ -9442,7 +9508,7 @@ function useXlsxViewerController(options) {
9442
9508
  const cachedFormulaValue = formula ? activeSheet?.cachedFormulaValues?.[cellAddressToA1(cell)] : void 0;
9443
9509
  const formatted = worksheet.getFormattedValueAt(cell.row, cell.col);
9444
9510
  if (formatted && !(formula && cachedFormulaValue !== void 0 && formatted.startsWith("#"))) {
9445
- return decodeHtmlEntities(formatted);
9511
+ return localizeCellNumber(worksheet, cell.row, cell.col, decodeHtmlEntities(formatted), locale);
9446
9512
  }
9447
9513
  const calculated = worksheet.getCalculatedValueAt(cell.row, cell.col);
9448
9514
  if (formula && cachedFormulaValue !== void 0 && calculated.is_error) {
@@ -9455,10 +9521,10 @@ function useXlsxViewerController(options) {
9455
9521
  return "";
9456
9522
  }
9457
9523
  return calculated.toString();
9458
- }, [activeSheet, getActiveWorksheet]);
9524
+ }, [activeSheet, getActiveWorksheet, locale]);
9459
9525
  const getCellFormula = React.useCallback((cell) => {
9460
9526
  if (cell && activeSheet) {
9461
- const workerSnapshot = workerCellSnapshotCacheRef.current.get(`${activeSheet.workbookSheetIndex}:${cell.row}:${cell.col}`);
9527
+ const workerSnapshot = workerCellSnapshotCacheRef.current.get(`${locale}:${activeSheet.workbookSheetIndex}:${cell.row}:${cell.col}`);
9462
9528
  if (workerSnapshot) {
9463
9529
  return workerSnapshot.formula;
9464
9530
  }
@@ -9468,7 +9534,7 @@ function useXlsxViewerController(options) {
9468
9534
  return "";
9469
9535
  }
9470
9536
  return worksheet.getFormulaAt(cell.row, cell.col) ?? "";
9471
- }, [activeSheet, getActiveWorksheet]);
9537
+ }, [activeSheet, getActiveWorksheet, locale]);
9472
9538
  const getClipboardData = React.useCallback(() => {
9473
9539
  const worksheet = getActiveWorksheet();
9474
9540
  const targetRange = selection ?? (activeCell ? { start: activeCell, end: activeCell } : null);
@@ -9588,7 +9654,7 @@ function useXlsxViewerController(options) {
9588
9654
  if (!isWorkerBacked || !deferredMetadataSheet || !deferredMetadataCell) {
9589
9655
  return;
9590
9656
  }
9591
- const cacheKey = `${deferredMetadataSheet.workbookSheetIndex}:${deferredMetadataCell.row}:${deferredMetadataCell.col}`;
9657
+ const cacheKey = `${locale}:${deferredMetadataSheet.workbookSheetIndex}:${deferredMetadataCell.row}:${deferredMetadataCell.col}`;
9592
9658
  if (workerCellSnapshotCacheRef.current.has(cacheKey)) {
9593
9659
  return;
9594
9660
  }
@@ -9612,7 +9678,7 @@ function useXlsxViewerController(options) {
9612
9678
  return () => {
9613
9679
  isCurrent = false;
9614
9680
  };
9615
- }, [deferredMetadataCell, deferredMetadataSheet, getCellSnapshotAsync, isWorkerBacked]);
9681
+ }, [deferredMetadataCell, deferredMetadataSheet, getCellSnapshotAsync, isWorkerBacked, locale]);
9616
9682
  const activeCellAddress = React.useMemo(() => activeCell ? cellAddressToA1(activeCell) : null, [activeCell]);
9617
9683
  const selectedRangeAddress = React.useMemo(() => selection ? rangeToA1(selection) : null, [selection]);
9618
9684
  const selectedValue = React.useMemo(
@@ -9994,12 +10060,19 @@ function useXlsxViewerController(options) {
9994
10060
  downloadUrl(src, displayFileName);
9995
10061
  }
9996
10062
  }, [displayFileName, file, src]);
9997
- const exportXlsx = React.useCallback(() => {
10063
+ const getXlsxBytes = React.useCallback(() => {
9998
10064
  if (!workbook) {
10065
+ return null;
10066
+ }
10067
+ return createSavedWorkbookBytes(workbook);
10068
+ }, [createSavedWorkbookBytes, workbook]);
10069
+ const exportXlsx = React.useCallback(() => {
10070
+ const bytes = getXlsxBytes();
10071
+ if (!bytes) {
9999
10072
  return;
10000
10073
  }
10001
- downloadBytes(createSavedWorkbookBytes(workbook), `${fileStem(displayFileName)}.xlsx`, XLSX_MIME_TYPE);
10002
- }, [createSavedWorkbookBytes, displayFileName, workbook]);
10074
+ downloadBytes(bytes, `${fileStem(displayFileName)}.xlsx`, XLSX_MIME_TYPE);
10075
+ }, [displayFileName, getXlsxBytes]);
10003
10076
  const exportCsv = React.useCallback(() => {
10004
10077
  if (!workbook) {
10005
10078
  return;
@@ -10462,7 +10535,8 @@ function useXlsxViewerController(options) {
10462
10535
  if (!before) {
10463
10536
  return;
10464
10537
  }
10465
- const nextValue = coerceUserEnteredValue(value);
10538
+ if (locale !== "en-US" && value === getCellDisplayValue2(cell)) return;
10539
+ const nextValue = coerceUserEnteredValue(value, locale);
10466
10540
  worksheet.setCell(cellAddressToA1(cell), nextValue);
10467
10541
  const after = captureCellMutationState(cell);
10468
10542
  if (!after) {
@@ -10471,7 +10545,7 @@ function useXlsxViewerController(options) {
10471
10545
  maybeRecalculateWorkbook(workbook);
10472
10546
  refreshWorkbookState(workbook);
10473
10547
  recordCellEditHistory(cell, before, after);
10474
- }, [captureCellMutationState, getActiveWorksheet, maybeRecalculateWorkbook, readOnly, recordCellEditHistory, refreshWorkbookState, workbook]);
10548
+ }, [captureCellMutationState, getActiveWorksheet, getCellDisplayValue2, locale, maybeRecalculateWorkbook, readOnly, recordCellEditHistory, refreshWorkbookState, workbook]);
10475
10549
  const setCellFormula = React.useCallback((cell, formula) => {
10476
10550
  const worksheet = getActiveWorksheet();
10477
10551
  if (readOnly || !worksheet || !workbook) {
@@ -10812,7 +10886,7 @@ function useXlsxViewerController(options) {
10812
10886
  cell: nextCell
10813
10887
  });
10814
10888
  } else {
10815
- const nextValue = coerceUserEnteredValue(rawValue);
10889
+ const nextValue = coerceUserEnteredValue(rawValue, locale);
10816
10890
  worksheet.setCell(cellAddressToA1(nextCell), nextValue);
10817
10891
  const after = captureCellMutationState(nextCell);
10818
10892
  if (!after) {
@@ -10840,7 +10914,7 @@ function useXlsxViewerController(options) {
10840
10914
  selectionAnchorRef.current = targetCell;
10841
10915
  recordRangeEditHistory(mutations, nextRange, targetCell);
10842
10916
  return true;
10843
- }, [activeCell, captureCellMutationState, getActiveWorksheet, maybeRecalculateWorkbook, readOnly, recordRangeEditHistory, refreshWorkbookState, selection, workbook]);
10917
+ }, [activeCell, captureCellMutationState, getActiveWorksheet, locale, maybeRecalculateWorkbook, readOnly, recordRangeEditHistory, refreshWorkbookState, selection, workbook]);
10844
10918
  const pasteStructuredClipboardData = React.useCallback((serializedPayload) => {
10845
10919
  const worksheet = getActiveWorksheet();
10846
10920
  const targetCell = activeCell ?? selection?.start ?? null;
@@ -11113,9 +11187,11 @@ function useXlsxViewerController(options) {
11113
11187
  deferredLoadFileSize,
11114
11188
  defineNamedRange,
11115
11189
  displayFileName,
11190
+ locale,
11116
11191
  download,
11117
11192
  exportCsv,
11118
11193
  exportXlsx,
11194
+ getXlsxBytes,
11119
11195
  error,
11120
11196
  fillSelection,
11121
11197
  formControls,
@@ -11235,10 +11311,12 @@ function useXlsxViewerController(options) {
11235
11311
  deferredLoadFileSize,
11236
11312
  defineNamedRange,
11237
11313
  displayFileName,
11314
+ locale,
11238
11315
  download,
11239
11316
  error,
11240
11317
  exportCsv,
11241
11318
  exportXlsx,
11319
+ getXlsxBytes,
11242
11320
  file,
11243
11321
  fillSelection,
11244
11322
  formControls,
@@ -13566,12 +13644,12 @@ function measureTextWidth(value, style) {
13566
13644
  context.font = buildCanvasFont(style);
13567
13645
  return measureCanvasTextWidth(context, value);
13568
13646
  }
13569
- function getCellDisplayValue(worksheet, row, col, activeSheet) {
13647
+ function getCellDisplayValue(worksheet, row, col, activeSheet, locale = "en-US") {
13570
13648
  const formula = worksheet.getFormulaAt(row, col);
13571
13649
  const cachedFormulaValue = formula ? activeSheet?.cachedFormulaValues?.[cellAddressToA12({ row, col })] : void 0;
13572
13650
  const formatted = worksheet.getFormattedValueAt(row, col);
13573
13651
  if (formatted && !(formula && cachedFormulaValue !== void 0 && formatted.startsWith("#"))) {
13574
- return decodeHtmlEntities2(formatted);
13652
+ return localizeCellNumber(worksheet, row, col, decodeHtmlEntities2(formatted), locale);
13575
13653
  }
13576
13654
  const cellValue = worksheet.getCalculatedValueAt(row, col);
13577
13655
  if (formula && cachedFormulaValue !== void 0 && cellValue.is_error) {
@@ -13621,6 +13699,7 @@ function getBatchedCellNumericValue(cell) {
13621
13699
  if (!cell) {
13622
13700
  return null;
13623
13701
  }
13702
+ if (cell.numericValue !== void 0) return cell.numericValue;
13624
13703
  const text = cell.value.trim();
13625
13704
  if (text.length === 0) {
13626
13705
  return null;
@@ -13836,6 +13915,7 @@ function buildWorksheetBatchWindow(rows, activeSheet, startRow, endRow) {
13836
13915
  const formula = typeof cellEntry.formula === "string" ? cellEntry.formula : null;
13837
13916
  cells.set(`${row}:${col}`, {
13838
13917
  formula,
13918
+ numericValue: typeof cellEntry.numericValue === "number" ? cellEntry.numericValue : cellEntry.numericValue === null ? null : void 0,
13839
13919
  generalAlignment: cellEntry.generalAlignment === "right" || cellEntry.generalAlignment === "center" ? cellEntry.generalAlignment : "left",
13840
13920
  hyperlink: normalizeBatchedHyperlink(cellEntry.hyperlink),
13841
13921
  isMergedSecondary: cellEntry.isMergedSecondary === true,
@@ -15721,6 +15801,7 @@ function useXlsxViewerThumbnails(options = {}) {
15721
15801
  getSheetFormControls,
15722
15802
  getSheetImages,
15723
15803
  getSheetShapes,
15804
+ locale,
15724
15805
  workbook,
15725
15806
  sheets
15726
15807
  } = useXlsxViewer();
@@ -15742,6 +15823,11 @@ function useXlsxViewerThumbnails(options = {}) {
15742
15823
  isMountedRef.current = false;
15743
15824
  };
15744
15825
  }, []);
15826
+ React4.useEffect(() => {
15827
+ workerThumbnailRowBatchCacheRef.current.clear();
15828
+ workerThumbnailRowBatchRequestRef.current.clear();
15829
+ setWorkerThumbnailRowBatchVersion((version) => version + 1);
15830
+ }, [locale]);
15745
15831
  React4.useEffect(() => {
15746
15832
  const currentSheets = new Set(sheets);
15747
15833
  for (const sheet of workerThumbnailRowBatchCacheRef.current.keys()) {
@@ -16090,7 +16176,7 @@ function useXlsxViewerThumbnails(options = {}) {
16090
16176
  col,
16091
16177
  sheet,
16092
16178
  () => worksheet ? getCellNumericValue(worksheet, row, col) : getBatchedCellNumericValue(batchedCell),
16093
- () => worksheet ? getCellDisplayValue(worksheet, row, col, sheet) : batchedCell?.value ?? "",
16179
+ () => worksheet ? getCellDisplayValue(worksheet, row, col, sheet, locale) : batchedCell?.value ?? "",
16094
16180
  worksheet,
16095
16181
  workerRowBatch?.cells
16096
16182
  );
@@ -16127,7 +16213,7 @@ function useXlsxViewerThumbnails(options = {}) {
16127
16213
  showGridLines
16128
16214
  }),
16129
16215
  textRotationDeg: resolveSpreadsheetTextRotation(alignment?.rotation ?? alignment?.textRotation),
16130
- value: sparkline ? "" : checkboxState !== null ? "" : worksheet ? getCellDisplayValue(worksheet, row, col, sheet) : batchedCell?.value ?? ""
16216
+ value: sparkline ? "" : checkboxState !== null ? "" : worksheet ? getCellDisplayValue(worksheet, row, col, sheet, locale) : batchedCell?.value ?? ""
16131
16217
  };
16132
16218
  nextData.canvas = buildCanvasCellStyleCache(nextData.style);
16133
16219
  cellRenderCache.set(cacheKey, nextData);
@@ -16399,6 +16485,7 @@ function useXlsxViewerThumbnails(options = {}) {
16399
16485
  sheets,
16400
16486
  thumbnailImageLoadVersion,
16401
16487
  workerThumbnailRowBatchVersion,
16488
+ locale,
16402
16489
  workbook
16403
16490
  ]);
16404
16491
  const paintThumbnail = React4.useCallback(