@extend-ai/react-xlsx 0.20.0 → 0.20.2

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 (96) hide show
  1. package/README.md +1 -0
  2. package/dist/{chart-renderer-AAVZ34BF.cjs → chart-renderer-3QDNTMRN.cjs} +526 -604
  3. package/dist/chart-renderer-3QDNTMRN.cjs.map +1 -0
  4. package/dist/{chart-renderer-RXO7WP4Q.js → chart-renderer-7DTEXXG6.js} +19 -97
  5. package/dist/chart-renderer-7DTEXXG6.js.map +1 -0
  6. package/dist/{chart-renderer-KGLAI4DN.js → chart-renderer-F355CYSE.js} +13 -92
  7. package/dist/chart-renderer-F355CYSE.js.map +1 -0
  8. package/dist/{chart-renderer-NM5UVCTO.cjs → chart-renderer-LGW4EH4M.cjs} +287 -366
  9. package/dist/chart-renderer-LGW4EH4M.cjs.map +1 -0
  10. package/dist/{chunk-WSQDFXDW.js → chunk-3LMOGW6A.js} +22 -6
  11. package/dist/chunk-3LMOGW6A.js.map +1 -0
  12. package/dist/chunk-A4S3AMON.js +108 -0
  13. package/dist/chunk-A4S3AMON.js.map +1 -0
  14. package/dist/{chunk-T5WZHPIN.cjs → chunk-AD4CGQN2.cjs} +2 -2
  15. package/dist/{chunk-T5WZHPIN.cjs.map → chunk-AD4CGQN2.cjs.map} +1 -1
  16. package/dist/chunk-AJT23BDP.js +111 -0
  17. package/dist/chunk-AJT23BDP.js.map +1 -0
  18. package/dist/{chunk-CJBI5F6V.cjs → chunk-AZWBTFJI.cjs} +12 -93
  19. package/dist/chunk-AZWBTFJI.cjs.map +1 -0
  20. package/dist/{chunk-6K3NSKDJ.cjs → chunk-D2UA4P6N.cjs} +15 -4
  21. package/dist/chunk-D2UA4P6N.cjs.map +1 -0
  22. package/dist/{chunk-QN3D3JS2.js → chunk-GXYDJPHM.js} +162 -40
  23. package/dist/chunk-GXYDJPHM.js.map +1 -0
  24. package/dist/chunk-IDNIGBUM.cjs +108 -0
  25. package/dist/chunk-IDNIGBUM.cjs.map +1 -0
  26. package/dist/{chunk-3JTCYAUX.js → chunk-IYGZTLDY.js} +14 -3
  27. package/dist/chunk-IYGZTLDY.js.map +1 -0
  28. package/dist/chunk-M55TBS4X.cjs +111 -0
  29. package/dist/chunk-M55TBS4X.cjs.map +1 -0
  30. package/dist/{chunk-MCFUTO4J.cjs → chunk-OCF75R75.cjs} +25 -9
  31. package/dist/chunk-OCF75R75.cjs.map +1 -0
  32. package/dist/{chunk-NBH72POD.js → chunk-PUI6QI4U.js} +11 -92
  33. package/dist/chunk-PUI6QI4U.js.map +1 -0
  34. package/dist/{chunk-2YBG7XQ3.cjs → chunk-ZJ76CZAL.cjs} +1683 -1561
  35. package/dist/chunk-ZJ76CZAL.cjs.map +1 -0
  36. package/dist/index.cjs +626 -529
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +13 -0
  39. package/dist/index.d.ts +13 -0
  40. package/dist/index.js +124 -27
  41. package/dist/index.js.map +1 -1
  42. package/dist/{internal-DrXSHYJZ.d.cts → internal-BJsg5os3.d.cts} +13 -0
  43. package/dist/{internal-DrXSHYJZ.d.ts → internal-BJsg5os3.d.ts} +13 -0
  44. package/dist/internal.cjs +6 -5
  45. package/dist/internal.cjs.map +1 -1
  46. package/dist/internal.d.cts +1 -1
  47. package/dist/internal.d.ts +1 -1
  48. package/dist/internal.js +4 -3
  49. package/dist/preact-LICENSE.txt +21 -0
  50. package/dist/region-map-geography-24TXETDP.cjs +184 -0
  51. package/dist/region-map-geography-24TXETDP.cjs.map +1 -0
  52. package/dist/region-map-geography-OR6DHAF7.js +182 -0
  53. package/dist/region-map-geography-OR6DHAF7.js.map +1 -0
  54. package/dist/shared-chart-3STFRVWT.js +215 -0
  55. package/dist/shared-chart-3STFRVWT.js.map +1 -0
  56. package/dist/shared-chart-BFQNYOIQ.js +221 -0
  57. package/dist/shared-chart-BFQNYOIQ.js.map +1 -0
  58. package/dist/shared-chart-DVC5S2P6.cjs +222 -0
  59. package/dist/shared-chart-DVC5S2P6.cjs.map +1 -0
  60. package/dist/shared-chart-MFQSQG4K.cjs +216 -0
  61. package/dist/shared-chart-MFQSQG4K.cjs.map +1 -0
  62. package/dist/{spreadsheet-font-assets-4AHYDTAQ.cjs → spreadsheet-font-assets-6FKCVICP.cjs} +2 -2
  63. package/dist/{spreadsheet-font-assets-4AHYDTAQ.cjs.map → spreadsheet-font-assets-6FKCVICP.cjs.map} +1 -1
  64. package/dist/{surface-regl-AY7JZVYY.cjs → surface-regl-BBJ6OIKK.cjs} +15 -13
  65. package/dist/surface-regl-BBJ6OIKK.cjs.map +1 -0
  66. package/dist/{surface-regl-TJUWTLAZ.js → surface-regl-R2N54JT2.js} +7 -5
  67. package/dist/{surface-regl-TJUWTLAZ.js.map → surface-regl-R2N54JT2.js.map} +1 -1
  68. package/dist/{surface-regl-5Z6IVOID.cjs → surface-regl-SUJ2TFZA.cjs} +2 -2
  69. package/dist/{surface-regl-5Z6IVOID.cjs.map → surface-regl-SUJ2TFZA.cjs.map} +1 -1
  70. package/dist/us-atlas-LICENSE.txt +13 -0
  71. package/dist/vanilla.cjs +6 -5
  72. package/dist/vanilla.cjs.map +1 -1
  73. package/dist/vanilla.d.cts +2 -2
  74. package/dist/vanilla.d.ts +2 -2
  75. package/dist/vanilla.js +4 -3
  76. package/dist/world-atlas-LICENSE.txt +13 -0
  77. package/dist/xlsx-worker.js +82 -1
  78. package/dist/xlsx-worker.js.map +1 -1
  79. package/package.json +7 -6
  80. package/dist/chart-renderer-AAVZ34BF.cjs.map +0 -1
  81. package/dist/chart-renderer-KGLAI4DN.js.map +0 -1
  82. package/dist/chart-renderer-NM5UVCTO.cjs.map +0 -1
  83. package/dist/chart-renderer-RXO7WP4Q.js.map +0 -1
  84. package/dist/chunk-2YBG7XQ3.cjs.map +0 -1
  85. package/dist/chunk-3JTCYAUX.js.map +0 -1
  86. package/dist/chunk-6K3NSKDJ.cjs.map +0 -1
  87. package/dist/chunk-CJBI5F6V.cjs.map +0 -1
  88. package/dist/chunk-MCFUTO4J.cjs.map +0 -1
  89. package/dist/chunk-NBH72POD.js.map +0 -1
  90. package/dist/chunk-QN3D3JS2.js.map +0 -1
  91. package/dist/chunk-WSQDFXDW.js.map +0 -1
  92. package/dist/region-map-geography-6TGXBY3V.cjs +0 -184
  93. package/dist/region-map-geography-6TGXBY3V.cjs.map +0 -1
  94. package/dist/region-map-geography-YD54DI3H.js +0 -182
  95. package/dist/region-map-geography-YD54DI3H.js.map +0 -1
  96. package/dist/surface-regl-AY7JZVYY.cjs.map +0 -1
package/dist/index.d.cts CHANGED
@@ -814,7 +814,17 @@ interface XlsxChartWall {
814
814
  lineColor?: string;
815
815
  thickness?: number;
816
816
  }
817
+ interface XlsxChartRenderSource {
818
+ kind: "bar" | "line";
819
+ xml: string;
820
+ themeColors?: Record<string, string>;
821
+ themeOverrideXml?: string;
822
+ styleXml?: string;
823
+ colorStyleXml?: string;
824
+ }
817
825
  interface XlsxChart {
826
+ /** Original chart appearance used with the current workbook values during rendering. */
827
+ renderSource?: XlsxChartRenderSource;
818
828
  anchor: XlsxImageAnchor;
819
829
  autoTitleDeleted?: boolean;
820
830
  axes: XlsxChartAxis[];
@@ -961,6 +971,8 @@ interface XlsxScrollerRenderProps {
961
971
  };
962
972
  }
963
973
  interface UseXlsxViewerControllerOptions {
974
+ /** BCP 47 locale for numeric decimal and grouping separators. Defaults to en-US. */
975
+ locale?: string;
964
976
  /**
965
977
  * Allows row and column resizing even while editing is disabled by `readOnly`.
966
978
  *
@@ -1073,6 +1085,7 @@ interface XlsxViewerController {
1073
1085
  deferredLoadFileSize: number | null;
1074
1086
  defineNamedRange: (name: string, range?: XlsxCellRange | null) => void;
1075
1087
  displayFileName: string;
1088
+ locale: string;
1076
1089
  download: () => void;
1077
1090
  charts: XlsxChart[];
1078
1091
  chartsheets: XlsxChartsheet[];
package/dist/index.d.ts CHANGED
@@ -814,7 +814,17 @@ interface XlsxChartWall {
814
814
  lineColor?: string;
815
815
  thickness?: number;
816
816
  }
817
+ interface XlsxChartRenderSource {
818
+ kind: "bar" | "line";
819
+ xml: string;
820
+ themeColors?: Record<string, string>;
821
+ themeOverrideXml?: string;
822
+ styleXml?: string;
823
+ colorStyleXml?: string;
824
+ }
817
825
  interface XlsxChart {
826
+ /** Original chart appearance used with the current workbook values during rendering. */
827
+ renderSource?: XlsxChartRenderSource;
818
828
  anchor: XlsxImageAnchor;
819
829
  autoTitleDeleted?: boolean;
820
830
  axes: XlsxChartAxis[];
@@ -961,6 +971,8 @@ interface XlsxScrollerRenderProps {
961
971
  };
962
972
  }
963
973
  interface UseXlsxViewerControllerOptions {
974
+ /** BCP 47 locale for numeric decimal and grouping separators. Defaults to en-US. */
975
+ locale?: string;
964
976
  /**
965
977
  * Allows row and column resizing even while editing is disabled by `readOnly`.
966
978
  *
@@ -1073,6 +1085,7 @@ interface XlsxViewerController {
1073
1085
  deferredLoadFileSize: number | null;
1074
1086
  defineNamedRange: (name: string, range?: XlsxCellRange | null) => void;
1075
1087
  displayFileName: string;
1088
+ locale: string;
1076
1089
  download: () => void;
1077
1090
  charts: XlsxChart[];
1078
1091
  chartsheets: XlsxChartsheet[];
package/dist/index.js CHANGED
@@ -1,10 +1,73 @@
1
- import "./chunk-3JTCYAUX.js";
1
+ import "./chunk-IYGZTLDY.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";
@@ -1566,6 +1629,21 @@ function applyChartStyleFromXml(chart, chartPath, archive, themePalette) {
1566
1629
  chart.axes = [...chart.axes, seriesAxis];
1567
1630
  }
1568
1631
  }
1632
+ const kind = chartTypeNode.localName === "lineChart" && chart.chartType === "Line" ? "line" : chartTypeNode.localName === "barChart" && chart.chartType === "ColumnClustered" ? "bar" : null;
1633
+ const groupCount = Array.from(plotArea.children).filter((entry) => entry.localName.endsWith("Chart")).length;
1634
+ if (kind && groupCount === 1 && !chart.is3d && !plotArea.querySelector("trendline, errBars, dropLines, hiLowLines, upDownBars, dateAx, multiLvlStrRef, pictureOptions") && getLocalChildren(chartTypeNode, "ser").length === chart.series.length) {
1635
+ chart.renderSource = {
1636
+ kind,
1637
+ xml: chartXml,
1638
+ themeColors: themePalette ? Object.fromEntries(Object.entries(THEME_COLOR_INDEX_BY_NAME).flatMap(([key, index]) => {
1639
+ const color = themePalette.colorsByIndex[index];
1640
+ return color ? [[key, color]] : [];
1641
+ })) : void 0,
1642
+ themeOverrideXml: readArchiveText(archive, relationships.get("http://schemas.openxmlformats.org/officeDocument/2006/relationships/themeOverride")) ?? void 0,
1643
+ styleXml: readArchiveText(archive, relationships.get(CHART_STYLE_REL_TYPE)) ?? void 0,
1644
+ colorStyleXml: readArchiveText(archive, relationships.get(CHART_COLOR_STYLE_REL_TYPE)) ?? void 0
1645
+ };
1646
+ }
1569
1647
  applyChartSeriesStyleFromXml(chart, chartTypeNode, themePalette);
1570
1648
  applyFallbackSeriesStyles();
1571
1649
  applyBuiltinChartDefaults(chart, themePalette);
@@ -6818,10 +6896,10 @@ var XlsxWorkerClient = class {
6818
6896
  type: "load"
6819
6897
  }, [workerBuffer]);
6820
6898
  }
6821
- getCellSnapshot(workbookSheetIndex, row, col) {
6899
+ getCellSnapshot(workbookSheetIndex, row, col, locale) {
6822
6900
  return this.request({
6823
6901
  id: 0,
6824
- payload: { col, row, workbookSheetIndex },
6902
+ payload: { col, row, workbookSheetIndex, locale },
6825
6903
  type: "getCellSnapshot"
6826
6904
  });
6827
6905
  }
@@ -6838,10 +6916,10 @@ var XlsxWorkerClient = class {
6838
6916
  type: "parseCharts"
6839
6917
  }, [workerBuffer]);
6840
6918
  }
6841
- getRowsBatch(workbookSheetIndex, startRow, rowCount) {
6919
+ getRowsBatch(workbookSheetIndex, startRow, rowCount, locale) {
6842
6920
  return this.request({
6843
6921
  id: 0,
6844
- payload: { rowCount, startRow, workbookSheetIndex },
6922
+ payload: { rowCount, startRow, workbookSheetIndex, locale },
6845
6923
  type: "getRowsBatch"
6846
6924
  });
6847
6925
  }
@@ -7965,7 +8043,7 @@ function cloneCellStyle(style) {
7965
8043
  return style;
7966
8044
  }
7967
8045
  }
7968
- function coerceUserEnteredValue(value) {
8046
+ function coerceUserEnteredValue(value, locale = "en-US") {
7969
8047
  const trimmed = value.trim();
7970
8048
  if (!trimmed) {
7971
8049
  return "";
@@ -7976,6 +8054,8 @@ function coerceUserEnteredValue(value) {
7976
8054
  if (/^(true|false)$/i.test(trimmed)) {
7977
8055
  return trimmed.toLowerCase() === "true";
7978
8056
  }
8057
+ const localizedNumber = parseLocaleNumber(trimmed, locale);
8058
+ if (localizedNumber !== void 0) return localizedNumber;
7979
8059
  if (/^[+-]?(?:\d+\.?\d*|\.\d+)$/.test(trimmed)) {
7980
8060
  const parsed = Number(trimmed);
7981
8061
  if (Number.isFinite(parsed)) {
@@ -8395,6 +8475,7 @@ function useXlsxViewerController(options) {
8395
8475
  deferLoadingAboveBytes = DEFAULT_DEFER_LOADING_ABOVE_BYTES,
8396
8476
  file,
8397
8477
  fileName,
8478
+ locale = "en-US",
8398
8479
  maxFileSizeBytes = DEFAULT_MAX_FILE_SIZE_BYTES,
8399
8480
  readOnly: requestedReadOnly = false,
8400
8481
  readOnlyAboveBytes = 0,
@@ -9209,14 +9290,14 @@ function useXlsxViewerController(options) {
9209
9290
  formula: ""
9210
9291
  });
9211
9292
  }
9212
- return getWorkerClient().getCellSnapshot(workbookSheetIndex, row, col);
9213
- }, [getWorkerClient, isWorkerBacked]);
9293
+ return getWorkerClient().getCellSnapshot(workbookSheetIndex, row, col, locale);
9294
+ }, [getWorkerClient, isWorkerBacked, locale]);
9214
9295
  const getRowsBatchAsync = React.useCallback((workbookSheetIndex, startRow, rowCount) => {
9215
9296
  if (!isWorkerBacked) {
9216
9297
  return Promise.resolve(null);
9217
9298
  }
9218
- return getWorkerClient().getRowsBatch(workbookSheetIndex, startRow, rowCount);
9219
- }, [getWorkerClient, isWorkerBacked]);
9299
+ return getWorkerClient().getRowsBatch(workbookSheetIndex, startRow, rowCount, locale);
9300
+ }, [getWorkerClient, isWorkerBacked, locale]);
9220
9301
  const visibleSheetIndexByWorkbookSheetIndex = React.useMemo(
9221
9302
  () => new Map(sheets.map((sheet, index) => [sheet.workbookSheetIndex, index])),
9222
9303
  [sheets]
@@ -9429,7 +9510,7 @@ function useXlsxViewerController(options) {
9429
9510
  }, [activeSheet?.showGridLines, activeSheet?.workbookSheetIndex]);
9430
9511
  const getCellDisplayValue2 = React.useCallback((cell) => {
9431
9512
  if (cell && activeSheet) {
9432
- const workerSnapshot = workerCellSnapshotCacheRef.current.get(`${activeSheet.workbookSheetIndex}:${cell.row}:${cell.col}`);
9513
+ const workerSnapshot = workerCellSnapshotCacheRef.current.get(`${locale}:${activeSheet.workbookSheetIndex}:${cell.row}:${cell.col}`);
9433
9514
  if (workerSnapshot) {
9434
9515
  return workerSnapshot.displayValue;
9435
9516
  }
@@ -9442,7 +9523,7 @@ function useXlsxViewerController(options) {
9442
9523
  const cachedFormulaValue = formula ? activeSheet?.cachedFormulaValues?.[cellAddressToA1(cell)] : void 0;
9443
9524
  const formatted = worksheet.getFormattedValueAt(cell.row, cell.col);
9444
9525
  if (formatted && !(formula && cachedFormulaValue !== void 0 && formatted.startsWith("#"))) {
9445
- return decodeHtmlEntities(formatted);
9526
+ return localizeCellNumber(worksheet, cell.row, cell.col, decodeHtmlEntities(formatted), locale);
9446
9527
  }
9447
9528
  const calculated = worksheet.getCalculatedValueAt(cell.row, cell.col);
9448
9529
  if (formula && cachedFormulaValue !== void 0 && calculated.is_error) {
@@ -9455,10 +9536,10 @@ function useXlsxViewerController(options) {
9455
9536
  return "";
9456
9537
  }
9457
9538
  return calculated.toString();
9458
- }, [activeSheet, getActiveWorksheet]);
9539
+ }, [activeSheet, getActiveWorksheet, locale]);
9459
9540
  const getCellFormula = React.useCallback((cell) => {
9460
9541
  if (cell && activeSheet) {
9461
- const workerSnapshot = workerCellSnapshotCacheRef.current.get(`${activeSheet.workbookSheetIndex}:${cell.row}:${cell.col}`);
9542
+ const workerSnapshot = workerCellSnapshotCacheRef.current.get(`${locale}:${activeSheet.workbookSheetIndex}:${cell.row}:${cell.col}`);
9462
9543
  if (workerSnapshot) {
9463
9544
  return workerSnapshot.formula;
9464
9545
  }
@@ -9468,7 +9549,7 @@ function useXlsxViewerController(options) {
9468
9549
  return "";
9469
9550
  }
9470
9551
  return worksheet.getFormulaAt(cell.row, cell.col) ?? "";
9471
- }, [activeSheet, getActiveWorksheet]);
9552
+ }, [activeSheet, getActiveWorksheet, locale]);
9472
9553
  const getClipboardData = React.useCallback(() => {
9473
9554
  const worksheet = getActiveWorksheet();
9474
9555
  const targetRange = selection ?? (activeCell ? { start: activeCell, end: activeCell } : null);
@@ -9588,7 +9669,7 @@ function useXlsxViewerController(options) {
9588
9669
  if (!isWorkerBacked || !deferredMetadataSheet || !deferredMetadataCell) {
9589
9670
  return;
9590
9671
  }
9591
- const cacheKey = `${deferredMetadataSheet.workbookSheetIndex}:${deferredMetadataCell.row}:${deferredMetadataCell.col}`;
9672
+ const cacheKey = `${locale}:${deferredMetadataSheet.workbookSheetIndex}:${deferredMetadataCell.row}:${deferredMetadataCell.col}`;
9592
9673
  if (workerCellSnapshotCacheRef.current.has(cacheKey)) {
9593
9674
  return;
9594
9675
  }
@@ -9612,7 +9693,7 @@ function useXlsxViewerController(options) {
9612
9693
  return () => {
9613
9694
  isCurrent = false;
9614
9695
  };
9615
- }, [deferredMetadataCell, deferredMetadataSheet, getCellSnapshotAsync, isWorkerBacked]);
9696
+ }, [deferredMetadataCell, deferredMetadataSheet, getCellSnapshotAsync, isWorkerBacked, locale]);
9616
9697
  const activeCellAddress = React.useMemo(() => activeCell ? cellAddressToA1(activeCell) : null, [activeCell]);
9617
9698
  const selectedRangeAddress = React.useMemo(() => selection ? rangeToA1(selection) : null, [selection]);
9618
9699
  const selectedValue = React.useMemo(
@@ -10361,7 +10442,11 @@ function useXlsxViewerController(options) {
10361
10442
  if (imageAssetsRef.current && hydratedChartAssets) {
10362
10443
  updateWorkbookChartDefinition(imageAssetsRef.current, hydratedChartAssets, id, patch);
10363
10444
  }
10364
- setChartsByWorkbookSheetIndex((current) => current.map((sheetCharts) => sheetCharts.map((chart) => chart.id === id ? { ...chart, ...patch } : chart)));
10445
+ setChartsByWorkbookSheetIndex((current) => current.map((sheetCharts) => sheetCharts.map((chart) => {
10446
+ if (chart.id !== id) return chart;
10447
+ const appearanceUnchanged = Object.keys(patch).every((key) => key === "anchor" || key === "title");
10448
+ return { ...chart, renderSource: appearanceUnchanged ? chart.renderSource : void 0, ...patch };
10449
+ })));
10365
10450
  setRevision((current) => current + 1);
10366
10451
  }, [ensureChartAssetsHydrated, getChartById, readOnly, recordHistoryBeforeMutation, sheets, workbook]);
10367
10452
  const setChartSeriesFormula = React.useCallback((chartId, seriesIndex, formula) => {
@@ -10376,7 +10461,7 @@ function useXlsxViewerController(options) {
10376
10461
  if (!nextChart) {
10377
10462
  return false;
10378
10463
  }
10379
- updateChart(chartId, { series: nextChart.series });
10464
+ updateChart(chartId, { series: nextChart.series, renderSource: chart.renderSource });
10380
10465
  const selectedSeries = nextChart.series[seriesIndex];
10381
10466
  if (selectedSeries) {
10382
10467
  setSelectedChartElement((current) => current && current.chartId === chartId && current.kind !== "chart" ? {
@@ -10469,7 +10554,8 @@ function useXlsxViewerController(options) {
10469
10554
  if (!before) {
10470
10555
  return;
10471
10556
  }
10472
- const nextValue = coerceUserEnteredValue(value);
10557
+ if (locale !== "en-US" && value === getCellDisplayValue2(cell)) return;
10558
+ const nextValue = coerceUserEnteredValue(value, locale);
10473
10559
  worksheet.setCell(cellAddressToA1(cell), nextValue);
10474
10560
  const after = captureCellMutationState(cell);
10475
10561
  if (!after) {
@@ -10478,7 +10564,7 @@ function useXlsxViewerController(options) {
10478
10564
  maybeRecalculateWorkbook(workbook);
10479
10565
  refreshWorkbookState(workbook);
10480
10566
  recordCellEditHistory(cell, before, after);
10481
- }, [captureCellMutationState, getActiveWorksheet, maybeRecalculateWorkbook, readOnly, recordCellEditHistory, refreshWorkbookState, workbook]);
10567
+ }, [captureCellMutationState, getActiveWorksheet, getCellDisplayValue2, locale, maybeRecalculateWorkbook, readOnly, recordCellEditHistory, refreshWorkbookState, workbook]);
10482
10568
  const setCellFormula = React.useCallback((cell, formula) => {
10483
10569
  const worksheet = getActiveWorksheet();
10484
10570
  if (readOnly || !worksheet || !workbook) {
@@ -10819,7 +10905,7 @@ function useXlsxViewerController(options) {
10819
10905
  cell: nextCell
10820
10906
  });
10821
10907
  } else {
10822
- const nextValue = coerceUserEnteredValue(rawValue);
10908
+ const nextValue = coerceUserEnteredValue(rawValue, locale);
10823
10909
  worksheet.setCell(cellAddressToA1(nextCell), nextValue);
10824
10910
  const after = captureCellMutationState(nextCell);
10825
10911
  if (!after) {
@@ -10847,7 +10933,7 @@ function useXlsxViewerController(options) {
10847
10933
  selectionAnchorRef.current = targetCell;
10848
10934
  recordRangeEditHistory(mutations, nextRange, targetCell);
10849
10935
  return true;
10850
- }, [activeCell, captureCellMutationState, getActiveWorksheet, maybeRecalculateWorkbook, readOnly, recordRangeEditHistory, refreshWorkbookState, selection, workbook]);
10936
+ }, [activeCell, captureCellMutationState, getActiveWorksheet, locale, maybeRecalculateWorkbook, readOnly, recordRangeEditHistory, refreshWorkbookState, selection, workbook]);
10851
10937
  const pasteStructuredClipboardData = React.useCallback((serializedPayload) => {
10852
10938
  const worksheet = getActiveWorksheet();
10853
10939
  const targetCell = activeCell ?? selection?.start ?? null;
@@ -11120,6 +11206,7 @@ function useXlsxViewerController(options) {
11120
11206
  deferredLoadFileSize,
11121
11207
  defineNamedRange,
11122
11208
  displayFileName,
11209
+ locale,
11123
11210
  download,
11124
11211
  exportCsv,
11125
11212
  exportXlsx,
@@ -11243,6 +11330,7 @@ function useXlsxViewerController(options) {
11243
11330
  deferredLoadFileSize,
11244
11331
  defineNamedRange,
11245
11332
  displayFileName,
11333
+ locale,
11246
11334
  download,
11247
11335
  error,
11248
11336
  exportCsv,
@@ -13575,12 +13663,12 @@ function measureTextWidth(value, style) {
13575
13663
  context.font = buildCanvasFont(style);
13576
13664
  return measureCanvasTextWidth(context, value);
13577
13665
  }
13578
- function getCellDisplayValue(worksheet, row, col, activeSheet) {
13666
+ function getCellDisplayValue(worksheet, row, col, activeSheet, locale = "en-US") {
13579
13667
  const formula = worksheet.getFormulaAt(row, col);
13580
13668
  const cachedFormulaValue = formula ? activeSheet?.cachedFormulaValues?.[cellAddressToA12({ row, col })] : void 0;
13581
13669
  const formatted = worksheet.getFormattedValueAt(row, col);
13582
13670
  if (formatted && !(formula && cachedFormulaValue !== void 0 && formatted.startsWith("#"))) {
13583
- return decodeHtmlEntities2(formatted);
13671
+ return localizeCellNumber(worksheet, row, col, decodeHtmlEntities2(formatted), locale);
13584
13672
  }
13585
13673
  const cellValue = worksheet.getCalculatedValueAt(row, col);
13586
13674
  if (formula && cachedFormulaValue !== void 0 && cellValue.is_error) {
@@ -13630,6 +13718,7 @@ function getBatchedCellNumericValue(cell) {
13630
13718
  if (!cell) {
13631
13719
  return null;
13632
13720
  }
13721
+ if (cell.numericValue !== void 0) return cell.numericValue;
13633
13722
  const text = cell.value.trim();
13634
13723
  if (text.length === 0) {
13635
13724
  return null;
@@ -13845,6 +13934,7 @@ function buildWorksheetBatchWindow(rows, activeSheet, startRow, endRow) {
13845
13934
  const formula = typeof cellEntry.formula === "string" ? cellEntry.formula : null;
13846
13935
  cells.set(`${row}:${col}`, {
13847
13936
  formula,
13937
+ numericValue: typeof cellEntry.numericValue === "number" ? cellEntry.numericValue : cellEntry.numericValue === null ? null : void 0,
13848
13938
  generalAlignment: cellEntry.generalAlignment === "right" || cellEntry.generalAlignment === "center" ? cellEntry.generalAlignment : "left",
13849
13939
  hyperlink: normalizeBatchedHyperlink(cellEntry.hyperlink),
13850
13940
  isMergedSecondary: cellEntry.isMergedSecondary === true,
@@ -15730,6 +15820,7 @@ function useXlsxViewerThumbnails(options = {}) {
15730
15820
  getSheetFormControls,
15731
15821
  getSheetImages,
15732
15822
  getSheetShapes,
15823
+ locale,
15733
15824
  workbook,
15734
15825
  sheets
15735
15826
  } = useXlsxViewer();
@@ -15751,6 +15842,11 @@ function useXlsxViewerThumbnails(options = {}) {
15751
15842
  isMountedRef.current = false;
15752
15843
  };
15753
15844
  }, []);
15845
+ React4.useEffect(() => {
15846
+ workerThumbnailRowBatchCacheRef.current.clear();
15847
+ workerThumbnailRowBatchRequestRef.current.clear();
15848
+ setWorkerThumbnailRowBatchVersion((version) => version + 1);
15849
+ }, [locale]);
15754
15850
  React4.useEffect(() => {
15755
15851
  const currentSheets = new Set(sheets);
15756
15852
  for (const sheet of workerThumbnailRowBatchCacheRef.current.keys()) {
@@ -16099,7 +16195,7 @@ function useXlsxViewerThumbnails(options = {}) {
16099
16195
  col,
16100
16196
  sheet,
16101
16197
  () => worksheet ? getCellNumericValue(worksheet, row, col) : getBatchedCellNumericValue(batchedCell),
16102
- () => worksheet ? getCellDisplayValue(worksheet, row, col, sheet) : batchedCell?.value ?? "",
16198
+ () => worksheet ? getCellDisplayValue(worksheet, row, col, sheet, locale) : batchedCell?.value ?? "",
16103
16199
  worksheet,
16104
16200
  workerRowBatch?.cells
16105
16201
  );
@@ -16136,7 +16232,7 @@ function useXlsxViewerThumbnails(options = {}) {
16136
16232
  showGridLines
16137
16233
  }),
16138
16234
  textRotationDeg: resolveSpreadsheetTextRotation(alignment?.rotation ?? alignment?.textRotation),
16139
- value: sparkline ? "" : checkboxState !== null ? "" : worksheet ? getCellDisplayValue(worksheet, row, col, sheet) : batchedCell?.value ?? ""
16235
+ value: sparkline ? "" : checkboxState !== null ? "" : worksheet ? getCellDisplayValue(worksheet, row, col, sheet, locale) : batchedCell?.value ?? ""
16140
16236
  };
16141
16237
  nextData.canvas = buildCanvasCellStyleCache(nextData.style);
16142
16238
  cellRenderCache.set(cacheKey, nextData);
@@ -16408,6 +16504,7 @@ function useXlsxViewerThumbnails(options = {}) {
16408
16504
  sheets,
16409
16505
  thumbnailImageLoadVersion,
16410
16506
  workerThumbnailRowBatchVersion,
16507
+ locale,
16411
16508
  workbook
16412
16509
  ]);
16413
16510
  const paintThumbnail = React4.useCallback(