@extend-ai/react-xlsx 0.11.0 → 0.12.0

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.
package/dist/index.cjs CHANGED
@@ -6473,7 +6473,7 @@ function getSheetsWasmModule() {
6473
6473
  if (!wasmModulePromise) {
6474
6474
  wasmModulePromise = import("@dukelib/sheets-wasm").then(async (mod) => {
6475
6475
  if (configuredWasmSource !== void 0) {
6476
- await mod.default(configuredWasmSource);
6476
+ await mod.default({ module_or_path: configuredWasmSource });
6477
6477
  } else {
6478
6478
  await mod.default();
6479
6479
  }
@@ -7212,6 +7212,22 @@ function pushHistoryEntry(stack, entry) {
7212
7212
  function normalizeCellValue(value) {
7213
7213
  return value ?? "";
7214
7214
  }
7215
+ function cloneCellStyle(style) {
7216
+ if (!style || typeof style !== "object") {
7217
+ return style;
7218
+ }
7219
+ if (typeof structuredClone === "function") {
7220
+ try {
7221
+ return structuredClone(style);
7222
+ } catch {
7223
+ }
7224
+ }
7225
+ try {
7226
+ return JSON.parse(JSON.stringify(style));
7227
+ } catch {
7228
+ return style;
7229
+ }
7230
+ }
7215
7231
  function coerceUserEnteredValue(value) {
7216
7232
  const trimmed = value.trim();
7217
7233
  if (!trimmed) {
@@ -7234,9 +7250,12 @@ function coerceUserEnteredValue(value) {
7234
7250
  function applyCellMutationState(worksheet, cell, state) {
7235
7251
  if (state.formula) {
7236
7252
  worksheet.setFormula(cellAddressToA1(cell), state.formula);
7237
- return;
7253
+ } else {
7254
+ worksheet.setCell(cellAddressToA1(cell), normalizeCellValue(state.value));
7255
+ }
7256
+ if (state.style && typeof state.style === "object") {
7257
+ worksheet.setCellStyleAt(cell.row, cell.col, state.style);
7238
7258
  }
7239
- worksheet.setCell(cellAddressToA1(cell), normalizeCellValue(state.value));
7240
7259
  }
7241
7260
  function escapeHtml(value) {
7242
7261
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
@@ -7968,7 +7987,11 @@ function useXlsxViewerController(options) {
7968
7987
  return false;
7969
7988
  }, []);
7970
7989
  const ensureChartAssetsHydrated = React.useCallback((targetWorkbook, targetSheets) => {
7971
- if (chartAssetsRef.current || !targetWorkbook || !imageAssetsRef.current) {
7990
+ const currentAssets = chartAssetsRef.current;
7991
+ if (currentAssets && (currentAssets.chartOriginsById.size > 0 || !targetWorkbook || !imageAssetsRef.current)) {
7992
+ return currentAssets;
7993
+ }
7994
+ if (!targetWorkbook || !imageAssetsRef.current) {
7972
7995
  return chartAssetsRef.current;
7973
7996
  }
7974
7997
  const assets = loadWorkbookChartAssets(
@@ -8943,6 +8966,7 @@ function useXlsxViewerController(options) {
8943
8966
  }
8944
8967
  return {
8945
8968
  formula: worksheet.getFormulaAt(cell.row, cell.col) ?? null,
8969
+ style: worksheet.getCellStyleAt(cell.row, cell.col),
8946
8970
  value: worksheet.getCellAt(cell.row, cell.col).toJs()
8947
8971
  };
8948
8972
  }, [getActiveWorksheet]);
@@ -9087,6 +9111,7 @@ function useXlsxViewerController(options) {
9087
9111
  for (let col = startCol; col <= endCol; col += 1) {
9088
9112
  cells.push({
9089
9113
  formula: worksheet.getFormulaAt(row, col) ?? null,
9114
+ style: worksheet.getCellStyleAt(row, col),
9090
9115
  value: worksheet.getCellAt(row, col).toJs()
9091
9116
  });
9092
9117
  }
@@ -9253,11 +9278,27 @@ function useXlsxViewerController(options) {
9253
9278
  }, [getColumnWidthPx, getRowHeightPx]);
9254
9279
  const setChartRect = React.useCallback((id, rect) => {
9255
9280
  const hydratedChartAssets = ensureChartAssetsHydrated(workbook, sheets);
9281
+ console.info("[react-xlsx debug] setChartRect", {
9282
+ hasActiveSheet: Boolean(activeSheet),
9283
+ hasHydratedChartAssets: Boolean(hydratedChartAssets),
9284
+ hasImageAssets: Boolean(imageAssetsRef.current),
9285
+ hasWorkbook: Boolean(workbook),
9286
+ id,
9287
+ readOnly,
9288
+ rect
9289
+ });
9256
9290
  if (readOnly || !workbook || !activeSheet || !imageAssetsRef.current || !hydratedChartAssets) {
9257
9291
  return;
9258
9292
  }
9259
9293
  const worksheet = workbook.getSheet(activeSheet.workbookSheetIndex);
9260
9294
  const currentChart = getChartById(id);
9295
+ console.info("[react-xlsx debug] currentChart", {
9296
+ activeWorkbookSheetIndex: activeSheet.workbookSheetIndex,
9297
+ editable: currentChart?.editable,
9298
+ found: Boolean(currentChart),
9299
+ originCount: hydratedChartAssets.chartOriginsById.size,
9300
+ workbookSheetIndex: currentChart?.workbookSheetIndex
9301
+ });
9261
9302
  if (!currentChart || currentChart.editable === false || currentChart.workbookSheetIndex !== activeSheet.workbookSheetIndex) {
9262
9303
  return;
9263
9304
  }
@@ -9268,7 +9309,8 @@ function useXlsxViewerController(options) {
9268
9309
  getRowHeightPx: (row) => getRowHeightPx(worksheet, row)
9269
9310
  });
9270
9311
  recordHistoryBeforeMutation();
9271
- updateWorkbookChartAnchor(imageAssetsRef.current, hydratedChartAssets, id, nextAnchor);
9312
+ const didUpdateAnchor = updateWorkbookChartAnchor(imageAssetsRef.current, hydratedChartAssets, id, nextAnchor);
9313
+ console.info("[react-xlsx debug] updateWorkbookChartAnchor", { didUpdateAnchor, nextAnchor });
9272
9314
  hydratedChartAssets.chartsByWorkbookSheetIndex = hydratedChartAssets.chartsByWorkbookSheetIndex.map((sheetCharts) => sheetCharts.map((chart) => chart.id === id ? { ...chart, anchor: nextAnchor } : chart));
9273
9315
  setChartsByWorkbookSheetIndex((current) => current.map((sheetCharts) => sheetCharts.map((chart) => chart.id === id ? { ...chart, anchor: nextAnchor } : chart)));
9274
9316
  setRevision((current) => current + 1);
@@ -9484,8 +9526,12 @@ function useXlsxViewerController(options) {
9484
9526
  continue;
9485
9527
  }
9486
9528
  worksheet.setCell(cellAddressToA1({ row, col }), "");
9529
+ const after = captureCellMutationState(cell);
9530
+ if (!after) {
9531
+ continue;
9532
+ }
9487
9533
  mutations.push({
9488
- after: { formula: null, value: "" },
9534
+ after,
9489
9535
  before,
9490
9536
  cell
9491
9537
  });
@@ -9516,9 +9562,13 @@ function useXlsxViewerController(options) {
9516
9562
  }
9517
9563
  const nextValue = coerceUserEnteredValue(value);
9518
9564
  worksheet.setCell(cellAddressToA1(cell), nextValue);
9565
+ const after = captureCellMutationState(cell);
9566
+ if (!after) {
9567
+ return;
9568
+ }
9519
9569
  maybeRecalculateWorkbook(workbook);
9520
9570
  refreshWorkbookState(workbook);
9521
- recordCellEditHistory(cell, before, { formula: null, value: nextValue });
9571
+ recordCellEditHistory(cell, before, after);
9522
9572
  }, [captureCellMutationState, getActiveWorksheet, maybeRecalculateWorkbook, readOnly, recordCellEditHistory, refreshWorkbookState, workbook]);
9523
9573
  const setCellFormula = React.useCallback((cell, formula) => {
9524
9574
  const worksheet = getActiveWorksheet();
@@ -9535,13 +9585,31 @@ function useXlsxViewerController(options) {
9535
9585
  } else {
9536
9586
  worksheet.setFormula(cellAddressToA1(cell), formula);
9537
9587
  }
9588
+ const after = captureCellMutationState(cell);
9589
+ if (!after) {
9590
+ return;
9591
+ }
9538
9592
  maybeRecalculateWorkbook(workbook);
9539
9593
  refreshWorkbookState(workbook);
9540
- recordCellEditHistory(cell, before, {
9541
- formula: trimmedFormula || null,
9542
- value: trimmedFormula ? null : ""
9543
- });
9594
+ recordCellEditHistory(cell, before, after);
9544
9595
  }, [captureCellMutationState, getActiveWorksheet, maybeRecalculateWorkbook, readOnly, recordCellEditHistory, refreshWorkbookState, workbook]);
9596
+ const setCellStyle = React.useCallback((cell, style) => {
9597
+ const worksheet = getActiveWorksheet();
9598
+ if (readOnly || !worksheet || !workbook) {
9599
+ return;
9600
+ }
9601
+ const before = captureCellMutationState(cell);
9602
+ if (!before) {
9603
+ return;
9604
+ }
9605
+ worksheet.setCellStyleAt(cell.row, cell.col, style);
9606
+ const after = captureCellMutationState(cell);
9607
+ if (!after) {
9608
+ return;
9609
+ }
9610
+ refreshWorkbookState(workbook);
9611
+ recordCellEditHistory(cell, before, after);
9612
+ }, [captureCellMutationState, getActiveWorksheet, readOnly, recordCellEditHistory, refreshWorkbookState, workbook]);
9545
9613
  const setSelectedCellValue = React.useCallback((value) => {
9546
9614
  if (!activeCell) {
9547
9615
  return;
@@ -9554,6 +9622,51 @@ function useXlsxViewerController(options) {
9554
9622
  }
9555
9623
  setCellFormula(activeCell, formula);
9556
9624
  }, [activeCell, setCellFormula]);
9625
+ const setSelectedCellStyle = React.useCallback((style) => {
9626
+ if (!activeCell) {
9627
+ return;
9628
+ }
9629
+ setCellStyle(activeCell, style);
9630
+ }, [activeCell, setCellStyle]);
9631
+ const setRangeStyle = React.useCallback((range, style) => {
9632
+ const worksheet = getActiveWorksheet();
9633
+ if (readOnly || !worksheet || !workbook) {
9634
+ return;
9635
+ }
9636
+ const normalized = normalizeRange(range);
9637
+ const beforeStates = [];
9638
+ for (let row = normalized.start.row; row <= normalized.end.row; row += 1) {
9639
+ for (let col = normalized.start.col; col <= normalized.end.col; col += 1) {
9640
+ const cell = { row, col };
9641
+ const before = captureCellMutationState(cell);
9642
+ if (!before) {
9643
+ continue;
9644
+ }
9645
+ beforeStates.push({
9646
+ before,
9647
+ cell
9648
+ });
9649
+ }
9650
+ }
9651
+ if (beforeStates.length === 0) {
9652
+ return;
9653
+ }
9654
+ worksheet.setRangeStyle(rangeToA1(normalized), style);
9655
+ const mutations = [];
9656
+ for (const mutation of beforeStates) {
9657
+ const after = captureCellMutationState(mutation.cell);
9658
+ if (!after) {
9659
+ continue;
9660
+ }
9661
+ mutations.push({
9662
+ after,
9663
+ before: mutation.before,
9664
+ cell: mutation.cell
9665
+ });
9666
+ }
9667
+ refreshWorkbookState(workbook);
9668
+ recordRangeEditHistory(mutations, selection, activeCell);
9669
+ }, [activeCell, captureCellMutationState, getActiveWorksheet, readOnly, recordRangeEditHistory, refreshWorkbookState, selection, workbook]);
9557
9670
  const fillSelection = React.useCallback((targetRange) => {
9558
9671
  const worksheet = getActiveWorksheet();
9559
9672
  if (readOnly || !worksheet || !workbook || !selection) {
@@ -9580,19 +9693,22 @@ function useXlsxViewerController(options) {
9580
9693
  const sourceRow = sourceRange.start.row + (row - nextRange.start.row) % sourceHeight;
9581
9694
  const sourceCol = sourceRange.start.col + (col - nextRange.start.col) % sourceWidth;
9582
9695
  const sourceFormula = worksheet.getFormulaAt(sourceRow, sourceCol);
9696
+ const sourceStyle = cloneCellStyle(worksheet.getCellStyleAt(sourceRow, sourceCol));
9583
9697
  if (sourceFormula) {
9584
9698
  worksheet.setFormula(cellAddressToA1(targetCell), sourceFormula);
9585
- mutations.push({
9586
- after: { formula: sourceFormula, value: null },
9587
- before,
9588
- cell: targetCell
9589
- });
9699
+ } else {
9700
+ const sourceValue = normalizeCellValue(worksheet.getCellAt(sourceRow, sourceCol).toJs());
9701
+ worksheet.setCell(cellAddressToA1(targetCell), sourceValue);
9702
+ }
9703
+ if (sourceStyle && typeof sourceStyle === "object") {
9704
+ worksheet.setCellStyleAt(targetCell.row, targetCell.col, sourceStyle);
9705
+ }
9706
+ const after = captureCellMutationState(targetCell);
9707
+ if (!after) {
9590
9708
  continue;
9591
9709
  }
9592
- const sourceValue = normalizeCellValue(worksheet.getCellAt(sourceRow, sourceCol).toJs());
9593
- worksheet.setCell(cellAddressToA1(targetCell), sourceValue);
9594
9710
  mutations.push({
9595
- after: { formula: null, value: sourceValue },
9711
+ after,
9596
9712
  before,
9597
9713
  cell: targetCell
9598
9714
  });
@@ -9732,16 +9848,24 @@ function useXlsxViewerController(options) {
9732
9848
  }
9733
9849
  if (rawValue.startsWith("=") && rawValue.length > 1) {
9734
9850
  worksheet.setFormula(cellAddressToA1(nextCell), rawValue);
9851
+ const after = captureCellMutationState(nextCell);
9852
+ if (!after) {
9853
+ continue;
9854
+ }
9735
9855
  mutations.push({
9736
- after: { formula: rawValue, value: null },
9856
+ after,
9737
9857
  before,
9738
9858
  cell: nextCell
9739
9859
  });
9740
9860
  } else {
9741
9861
  const nextValue = coerceUserEnteredValue(rawValue);
9742
9862
  worksheet.setCell(cellAddressToA1(nextCell), nextValue);
9863
+ const after = captureCellMutationState(nextCell);
9864
+ if (!after) {
9865
+ continue;
9866
+ }
9743
9867
  mutations.push({
9744
- after: { formula: null, value: nextValue },
9868
+ after,
9745
9869
  before,
9746
9870
  cell: nextCell
9747
9871
  });
@@ -9792,8 +9916,12 @@ function useXlsxViewerController(options) {
9792
9916
  if (cell.formula) {
9793
9917
  worksheet.setFormula(cellAddressToA1(nextCell), cell.formula);
9794
9918
  if (before) {
9919
+ const after = captureCellMutationState(nextCell);
9920
+ if (!after) {
9921
+ continue;
9922
+ }
9795
9923
  mutations.push({
9796
- after: { formula: cell.formula, value: null },
9924
+ after,
9797
9925
  before,
9798
9926
  cell: nextCell
9799
9927
  });
@@ -9801,8 +9929,12 @@ function useXlsxViewerController(options) {
9801
9929
  } else {
9802
9930
  worksheet.setCell(cellAddressToA1(nextCell), cell.value);
9803
9931
  if (before) {
9932
+ const after = captureCellMutationState(nextCell);
9933
+ if (!after) {
9934
+ continue;
9935
+ }
9804
9936
  mutations.push({
9805
- after: { formula: null, value: cell.value },
9937
+ after,
9806
9938
  before,
9807
9939
  cell: nextCell
9808
9940
  });
@@ -10019,7 +10151,9 @@ function useXlsxViewerController(options) {
10019
10151
  resizeColumn,
10020
10152
  resizeRow,
10021
10153
  setCellFormula,
10154
+ setCellStyle,
10022
10155
  setCellValue,
10156
+ setRangeStyle,
10023
10157
  setZoomScale,
10024
10158
  setChartRect,
10025
10159
  setImageRect,
@@ -10038,6 +10172,7 @@ function useXlsxViewerController(options) {
10038
10172
  setActiveSheetIndex,
10039
10173
  setActiveTabIndex,
10040
10174
  setSelectedCellFormula,
10175
+ setSelectedCellStyle,
10041
10176
  setSelectedCellValue,
10042
10177
  sheets,
10043
10178
  shapes,
@@ -10121,7 +10256,9 @@ function useXlsxViewerController(options) {
10121
10256
  resizeColumn,
10122
10257
  resizeRow,
10123
10258
  setCellFormula,
10259
+ setCellStyle,
10124
10260
  setCellValue,
10261
+ setRangeStyle,
10125
10262
  setZoomScale,
10126
10263
  setChartRect,
10127
10264
  setImageRect,
@@ -10140,6 +10277,7 @@ function useXlsxViewerController(options) {
10140
10277
  setActiveSheetIndex,
10141
10278
  setActiveTabIndex,
10142
10279
  setSelectedCellFormula,
10280
+ setSelectedCellStyle,
10143
10281
  setSelectedCellValue,
10144
10282
  sheets,
10145
10283
  shapes,
@@ -16618,6 +16756,9 @@ var WHEEL_ZOOM_SENSITIVITY = 25e-5;
16618
16756
  var WHEEL_LINE_DELTA_PX = 16;
16619
16757
  var CHART_SOURCE_HIGHLIGHT_COLORS = ["#2563eb", "#dc2626", "#7c3aed", "#059669", "#ea580c", "#db2777"];
16620
16758
  var SHEET_SURFACE = "#ffffff";
16759
+ var DRAWING_SELECTION_STROKE = "#64748b";
16760
+ var DRAWING_SELECTION_HANDLE_FILL = "#ffffff";
16761
+ var DRAWING_SELECTION_HANDLE_SHADOW = "rgba(15, 23, 42, 0.18)";
16621
16762
  var DEFAULT_CELL_PADDING = "0 4px";
16622
16763
  var IMAGE_HANDLE_POSITIONS = ["nw", "n", "ne", "e", "se", "s", "sw", "w"];
16623
16764
  var CANVAS_CELL_STYLE_CACHE_LIMIT = 4096;
@@ -16703,6 +16844,38 @@ function measureCanvasTextWidth(context, text) {
16703
16844
  CANVAS_TEXT_MEASURE_CACHE_LIMIT
16704
16845
  );
16705
16846
  }
16847
+ function drawCanvasTextDecorations(context, {
16848
+ align,
16849
+ color,
16850
+ decoration,
16851
+ ellipsize = false,
16852
+ lineThroughY,
16853
+ maxWidth,
16854
+ text,
16855
+ textX,
16856
+ underlineY,
16857
+ zoomFactor
16858
+ }) {
16859
+ if (!decoration || text.length === 0) {
16860
+ return;
16861
+ }
16862
+ const measured = ellipsize && maxWidth !== void 0 ? Math.min(maxWidth, measureCanvasTextWidth(context, text)) : measureCanvasTextWidth(context, text);
16863
+ const startX = align === "right" ? textX - measured : align === "center" ? textX - measured / 2 : textX;
16864
+ context.strokeStyle = color;
16865
+ context.lineWidth = Math.max(1, zoomFactor * 0.75);
16866
+ if (decoration.includes("underline")) {
16867
+ context.beginPath();
16868
+ context.moveTo(startX, underlineY);
16869
+ context.lineTo(startX + measured, underlineY);
16870
+ context.stroke();
16871
+ }
16872
+ if (decoration.includes("line-through")) {
16873
+ context.beginPath();
16874
+ context.moveTo(startX, lineThroughY);
16875
+ context.lineTo(startX + measured, lineThroughY);
16876
+ context.stroke();
16877
+ }
16878
+ }
16706
16879
  function getCachedCanvasPath2D(path) {
16707
16880
  if (typeof Path2D === "undefined") {
16708
16881
  return null;
@@ -18748,7 +18921,9 @@ function resolveImageHandleStyle(position, stroke, surface, scale = 1) {
18748
18921
  const style = {
18749
18922
  backgroundColor: surface,
18750
18923
  border: `${Math.max(1, scale)}px solid ${stroke}`,
18751
- borderRadius: 6 * scale,
18924
+ borderRadius: 3 * scale,
18925
+ boxShadow: `0 1px ${3 * scale}px ${DRAWING_SELECTION_HANDLE_SHADOW}`,
18926
+ boxSizing: "border-box",
18752
18927
  cursor: IMAGE_HANDLE_CURSOR[position],
18753
18928
  height: handleSize,
18754
18929
  pointerEvents: "auto",
@@ -26263,16 +26438,17 @@ function XlsxGrid({
26263
26438
  wrappedLines.forEach((line, lineIndex) => {
26264
26439
  const textY = textBlockTop + lineIndex * lineHeight + lineHeight / 2;
26265
26440
  paneContext.fillText(line, textX, textY);
26266
- if (canvasCellStyle.textDecoration?.includes("underline") && line.length > 0) {
26267
- const measured = Math.min(maxTextWidth, measureCanvasTextWidth(paneContext, line));
26268
- const underlineStartX = align === "right" ? textX - measured : align === "center" ? textX - measured / 2 : textX;
26269
- paneContext.beginPath();
26270
- paneContext.moveTo(underlineStartX, textY + Math.max(2, lineHeight * 0.24));
26271
- paneContext.lineTo(underlineStartX + measured, textY + Math.max(2, lineHeight * 0.24));
26272
- paneContext.strokeStyle = textColor;
26273
- paneContext.lineWidth = Math.max(1, zoomFactor * 0.75);
26274
- paneContext.stroke();
26275
- }
26441
+ drawCanvasTextDecorations(paneContext, {
26442
+ align,
26443
+ color: textColor,
26444
+ decoration: canvasCellStyle.textDecoration,
26445
+ lineThroughY: textY,
26446
+ maxWidth: maxTextWidth,
26447
+ text: line,
26448
+ textX,
26449
+ underlineY: textY + Math.max(2, lineHeight * 0.24),
26450
+ zoomFactor
26451
+ });
26276
26452
  });
26277
26453
  } else if (spillMaxWidth != null) {
26278
26454
  const text = shouldEllipsizeText ? truncateCanvasText(paneContext, rawText, maxTextWidth) : rawText;
@@ -26291,22 +26467,25 @@ function XlsxGrid({
26291
26467
  textDecoration: canvasCellStyle.textDecoration,
26292
26468
  textX,
26293
26469
  textY,
26470
+ lineThroughY: textY,
26294
26471
  underlineY: textY + 6 * zoomFactor
26295
26472
  });
26296
26473
  } else {
26297
26474
  const text = cellData.shrinkToFit ? rawText : shouldEllipsizeText ? truncateCanvasText(paneContext, rawText, maxTextWidth) : rawText;
26298
26475
  const textY = contentTop + contentHeight / 2;
26299
26476
  paneContext.fillText(text, textX, textY);
26300
- if (canvasCellStyle.textDecoration?.includes("underline") && text.length > 0) {
26301
- const measured = shouldEllipsizeText ? Math.min(maxTextWidth, measureCanvasTextWidth(paneContext, text)) : measureCanvasTextWidth(paneContext, text);
26302
- const underlineStartX = align === "right" ? textX - measured : align === "center" ? textX - measured / 2 : textX;
26303
- paneContext.beginPath();
26304
- paneContext.moveTo(underlineStartX, textY + 6 * zoomFactor);
26305
- paneContext.lineTo(underlineStartX + measured, textY + 6 * zoomFactor);
26306
- paneContext.strokeStyle = textColor;
26307
- paneContext.lineWidth = Math.max(1, zoomFactor * 0.75);
26308
- paneContext.stroke();
26309
- }
26477
+ drawCanvasTextDecorations(paneContext, {
26478
+ align,
26479
+ color: textColor,
26480
+ decoration: canvasCellStyle.textDecoration,
26481
+ ellipsize: shouldEllipsizeText,
26482
+ lineThroughY: textY,
26483
+ maxWidth: maxTextWidth,
26484
+ text,
26485
+ textX,
26486
+ underlineY: textY + 6 * zoomFactor,
26487
+ zoomFactor
26488
+ });
26310
26489
  }
26311
26490
  }
26312
26491
  if (cellData.conditionalIcon) {
@@ -26340,16 +26519,18 @@ function XlsxGrid({
26340
26519
  paneContext.textAlign = spillText.align;
26341
26520
  paneContext.textBaseline = "middle";
26342
26521
  paneContext.fillText(spillText.text, spillText.textX, spillText.textY);
26343
- if (spillText.textDecoration?.includes("underline") && spillText.text.length > 0) {
26344
- const measured = spillText.ellipsize ? Math.min(spillText.maxWidth, measureCanvasTextWidth(paneContext, spillText.text)) : measureCanvasTextWidth(paneContext, spillText.text);
26345
- const underlineStartX = spillText.align === "right" ? spillText.textX - measured : spillText.align === "center" ? spillText.textX - measured / 2 : spillText.textX;
26346
- paneContext.beginPath();
26347
- paneContext.moveTo(underlineStartX, spillText.underlineY);
26348
- paneContext.lineTo(underlineStartX + measured, spillText.underlineY);
26349
- paneContext.strokeStyle = spillText.color;
26350
- paneContext.lineWidth = Math.max(1, zoomFactor * 0.75);
26351
- paneContext.stroke();
26352
- }
26522
+ drawCanvasTextDecorations(paneContext, {
26523
+ align: spillText.align,
26524
+ color: spillText.color,
26525
+ decoration: spillText.textDecoration,
26526
+ ellipsize: spillText.ellipsize,
26527
+ lineThroughY: spillText.lineThroughY,
26528
+ maxWidth: spillText.maxWidth,
26529
+ text: spillText.text,
26530
+ textX: spillText.textX,
26531
+ underlineY: spillText.underlineY,
26532
+ zoomFactor
26533
+ });
26353
26534
  paneContext.restore();
26354
26535
  }
26355
26536
  }
@@ -27258,6 +27439,7 @@ function XlsxGrid({
27258
27439
  }
27259
27440
  const isFrozenDrawing = pane !== "scroll";
27260
27441
  const canEditImage = !readOnly && image.editable !== false;
27442
+ const drawingSelectionSurface = paletteIsDark(palette) ? palette.canvas : DRAWING_SELECTION_HANDLE_FILL;
27261
27443
  const style = {
27262
27444
  contain: "layout paint",
27263
27445
  height: rect.height,
@@ -27289,6 +27471,7 @@ function XlsxGrid({
27289
27471
  {
27290
27472
  style: {
27291
27473
  ...style,
27474
+ contain: "layout",
27292
27475
  overflow: "visible",
27293
27476
  pointerEvents: "none",
27294
27477
  zIndex: isFrozenDrawing ? image.zIndex + 22 : image.zIndex + 2
@@ -27298,8 +27481,8 @@ function XlsxGrid({
27298
27481
  "div",
27299
27482
  {
27300
27483
  style: {
27301
- border: `${Math.max(1, zoomFactor)}px solid ${selectionStroke}`,
27302
- boxShadow: `0 0 0 ${Math.max(1, zoomFactor)}px ${palette.surface}`,
27484
+ border: `${Math.max(1, zoomFactor)}px solid ${DRAWING_SELECTION_STROKE}`,
27485
+ boxShadow: `0 0 0 ${Math.max(1, zoomFactor)}px ${drawingSelectionSurface}`,
27303
27486
  boxSizing: "border-box",
27304
27487
  inset: 0,
27305
27488
  pointerEvents: "none",
@@ -27309,7 +27492,7 @@ function XlsxGrid({
27309
27492
  "div",
27310
27493
  {
27311
27494
  onPointerDown: (event) => startImageResize(event, image, rect, position),
27312
- style: resolveImageHandleStyle(position, selectionStroke, palette.surface, zoomFactor)
27495
+ style: resolveImageHandleStyle(position, DRAWING_SELECTION_STROKE, drawingSelectionSurface, zoomFactor)
27313
27496
  },
27314
27497
  position
27315
27498
  )) : null
@@ -27321,7 +27504,7 @@ function XlsxGrid({
27321
27504
  startImageResize(event, image, rect, position);
27322
27505
  }
27323
27506
  },
27324
- style: canEditImage ? resolveImageHandleStyle(position, selectionStroke, palette.surface, zoomFactor) : { ...resolveImageHandleStyle(position, selectionStroke, palette.surface, zoomFactor), display: "none" }
27507
+ style: canEditImage ? resolveImageHandleStyle(position, DRAWING_SELECTION_STROKE, drawingSelectionSurface, zoomFactor) : { ...resolveImageHandleStyle(position, DRAWING_SELECTION_STROKE, drawingSelectionSurface, zoomFactor), display: "none" }
27325
27508
  }),
27326
27509
  image,
27327
27510
  rect
@@ -27329,8 +27512,8 @@ function XlsxGrid({
27329
27512
  "div",
27330
27513
  {
27331
27514
  style: {
27332
- border: `${Math.max(1, zoomFactor)}px solid ${selectionStroke}`,
27333
- boxShadow: `0 0 0 ${Math.max(1, zoomFactor)}px ${palette.surface}`,
27515
+ border: `${Math.max(1, zoomFactor)}px solid ${DRAWING_SELECTION_STROKE}`,
27516
+ boxShadow: `0 0 0 ${Math.max(1, zoomFactor)}px ${drawingSelectionSurface}`,
27334
27517
  boxSizing: "border-box",
27335
27518
  inset: 0,
27336
27519
  pointerEvents: "none",
@@ -27340,7 +27523,7 @@ function XlsxGrid({
27340
27523
  "div",
27341
27524
  {
27342
27525
  onPointerDown: (event) => startImageResize(event, image, rect, position),
27343
- style: resolveImageHandleStyle(position, selectionStroke, palette.surface, zoomFactor)
27526
+ style: resolveImageHandleStyle(position, DRAWING_SELECTION_STROKE, drawingSelectionSurface, zoomFactor)
27344
27527
  },
27345
27528
  position
27346
27529
  )) : null
@@ -27378,6 +27561,7 @@ function XlsxGrid({
27378
27561
  }
27379
27562
  const isFrozenDrawing = pane !== "scroll";
27380
27563
  const canEditChart = !readOnly && chart.editable !== false;
27564
+ const drawingSelectionSurface = paletteIsDark(palette) ? palette.canvas : DRAWING_SELECTION_HANDLE_FILL;
27381
27565
  const style = {
27382
27566
  contain: "layout paint",
27383
27567
  height: rect.height,
@@ -27394,6 +27578,7 @@ function XlsxGrid({
27394
27578
  {
27395
27579
  style: {
27396
27580
  ...style,
27581
+ contain: "layout",
27397
27582
  overflow: "visible",
27398
27583
  pointerEvents: "none",
27399
27584
  zIndex: isFrozenDrawing ? chart.zIndex + 22 : chart.zIndex + 2
@@ -27402,8 +27587,8 @@ function XlsxGrid({
27402
27587
  "div",
27403
27588
  {
27404
27589
  style: {
27405
- border: `${Math.max(1, zoomFactor)}px solid ${selectionStroke}`,
27406
- boxShadow: `0 0 0 ${Math.max(1, zoomFactor)}px ${palette.surface}`,
27590
+ border: `${Math.max(1, zoomFactor)}px solid ${DRAWING_SELECTION_STROKE}`,
27591
+ boxShadow: `0 0 0 ${Math.max(1, zoomFactor)}px ${drawingSelectionSurface}`,
27407
27592
  boxSizing: "border-box",
27408
27593
  inset: 0,
27409
27594
  pointerEvents: "none",
@@ -27413,7 +27598,7 @@ function XlsxGrid({
27413
27598
  "div",
27414
27599
  {
27415
27600
  onPointerDown: (event) => startChartResize(event, chart, rect, position),
27416
- style: resolveImageHandleStyle(position, selectionStroke, palette.surface, zoomFactor)
27601
+ style: resolveImageHandleStyle(position, DRAWING_SELECTION_STROKE, drawingSelectionSurface, zoomFactor)
27417
27602
  },
27418
27603
  position
27419
27604
  )) : null
@@ -27693,6 +27878,22 @@ function XlsxGrid({
27693
27878
  }
27694
27879
  function installImageInteractionListeners(pointerId) {
27695
27880
  imageInteractionCleanupRef.current?.();
27881
+ const resolveInteractionRect = (interaction, clientX, clientY) => {
27882
+ const deltaX = clientX - interaction.startClientX;
27883
+ const deltaY = clientY - interaction.startClientY;
27884
+ return clampImageRect(
27885
+ interaction.type === "move" ? {
27886
+ ...interaction.baseRect,
27887
+ left: interaction.baseRect.left + deltaX,
27888
+ top: interaction.baseRect.top + deltaY
27889
+ } : resizeImageRect(interaction.baseRect, interaction.handle, deltaX, deltaY, displayImageMinSize),
27890
+ {
27891
+ contentOffsetLeft: displayRowHeaderWidth,
27892
+ contentOffsetTop: displayHeaderHeight,
27893
+ minSizePx: displayImageMinSize
27894
+ }
27895
+ );
27896
+ };
27696
27897
  const handlePointerMove = (event) => {
27697
27898
  if (event.pointerId !== pointerId) {
27698
27899
  return;
@@ -27706,18 +27907,7 @@ function XlsxGrid({
27706
27907
  if (!interaction.didMove && (Math.abs(deltaX) > 3 || Math.abs(deltaY) > 3)) {
27707
27908
  interaction.didMove = true;
27708
27909
  }
27709
- const nextRect = clampImageRect(
27710
- interaction.type === "move" ? {
27711
- ...interaction.baseRect,
27712
- left: interaction.baseRect.left + deltaX,
27713
- top: interaction.baseRect.top + deltaY
27714
- } : resizeImageRect(interaction.baseRect, interaction.handle, deltaX, deltaY, displayImageMinSize),
27715
- {
27716
- contentOffsetLeft: displayRowHeaderWidth,
27717
- contentOffsetTop: displayHeaderHeight,
27718
- minSizePx: displayImageMinSize
27719
- }
27720
- );
27910
+ const nextRect = resolveInteractionRect(interaction, event.clientX, event.clientY);
27721
27911
  scheduleImagePreviewRect({ id: interaction.imageId, rect: nextRect });
27722
27912
  };
27723
27913
  const cleanup = () => {
@@ -27740,18 +27930,20 @@ function XlsxGrid({
27740
27930
  imagePreviewRectRef.current = pendingPreview;
27741
27931
  setImagePreviewRect(pendingPreview);
27742
27932
  }
27743
- const preview = pendingPreview ?? imagePreviewRectRef.current;
27933
+ const finalRect = interaction ? resolveInteractionRect(interaction, event.clientX, event.clientY) : null;
27744
27934
  imageInteractionRef.current = null;
27745
27935
  imageInteractionCleanupRef.current = null;
27746
27936
  setInteractionMode("idle");
27747
27937
  document.body.style.cursor = "";
27748
27938
  document.body.style.userSelect = "";
27749
27939
  cleanup();
27750
- if (interaction && preview && preview.id === interaction.imageId) {
27940
+ if (interaction) {
27751
27941
  if (interaction.didMove) {
27752
27942
  skipNextImageClickRef.current = interaction.imageId;
27753
27943
  }
27754
- setImageRect(interaction.imageId, toLogicalRect(preview.rect));
27944
+ if (interaction.didMove && finalRect) {
27945
+ setImageRect(interaction.imageId, toLogicalRect(finalRect));
27946
+ }
27755
27947
  }
27756
27948
  imagePreviewRectRef.current = null;
27757
27949
  setImagePreviewRect(null);
@@ -27763,6 +27955,22 @@ function XlsxGrid({
27763
27955
  }
27764
27956
  function installChartInteractionListeners(pointerId) {
27765
27957
  chartInteractionCleanupRef.current?.();
27958
+ const resolveInteractionRect = (interaction, clientX, clientY) => {
27959
+ const deltaX = clientX - interaction.startClientX;
27960
+ const deltaY = clientY - interaction.startClientY;
27961
+ return clampImageRect(
27962
+ interaction.type === "move" ? {
27963
+ ...interaction.baseRect,
27964
+ left: interaction.baseRect.left + deltaX,
27965
+ top: interaction.baseRect.top + deltaY
27966
+ } : resizeImageRect(interaction.baseRect, interaction.handle, deltaX, deltaY, 48 * zoomFactor),
27967
+ {
27968
+ contentOffsetLeft: displayRowHeaderWidth,
27969
+ contentOffsetTop: displayHeaderHeight,
27970
+ minSizePx: 48 * zoomFactor
27971
+ }
27972
+ );
27973
+ };
27766
27974
  const handlePointerMove = (event) => {
27767
27975
  if (event.pointerId !== pointerId) {
27768
27976
  return;
@@ -27776,18 +27984,7 @@ function XlsxGrid({
27776
27984
  if (!interaction.didMove && (Math.abs(deltaX) > 3 || Math.abs(deltaY) > 3)) {
27777
27985
  interaction.didMove = true;
27778
27986
  }
27779
- const nextRect = clampImageRect(
27780
- interaction.type === "move" ? {
27781
- ...interaction.baseRect,
27782
- left: interaction.baseRect.left + deltaX,
27783
- top: interaction.baseRect.top + deltaY
27784
- } : resizeImageRect(interaction.baseRect, interaction.handle, deltaX, deltaY, 48 * zoomFactor),
27785
- {
27786
- contentOffsetLeft: displayRowHeaderWidth,
27787
- contentOffsetTop: displayHeaderHeight,
27788
- minSizePx: 48 * zoomFactor
27789
- }
27790
- );
27987
+ const nextRect = resolveInteractionRect(interaction, event.clientX, event.clientY);
27791
27988
  scheduleChartPreviewRect({ id: interaction.chartId, rect: nextRect });
27792
27989
  };
27793
27990
  const cleanup = () => {
@@ -27810,18 +28007,20 @@ function XlsxGrid({
27810
28007
  chartPreviewRectRef.current = pendingPreview;
27811
28008
  setChartPreviewRect(pendingPreview);
27812
28009
  }
27813
- const preview = pendingPreview ?? chartPreviewRectRef.current;
28010
+ const finalRect = interaction ? resolveInteractionRect(interaction, event.clientX, event.clientY) : null;
27814
28011
  chartInteractionRef.current = null;
27815
28012
  chartInteractionCleanupRef.current = null;
27816
28013
  setInteractionMode("idle");
27817
28014
  document.body.style.cursor = "";
27818
28015
  document.body.style.userSelect = "";
27819
28016
  cleanup();
27820
- if (interaction && preview && preview.id === interaction.chartId) {
28017
+ if (interaction) {
27821
28018
  if (interaction.didMove) {
27822
28019
  skipNextChartClickRef.current = interaction.chartId;
27823
28020
  }
27824
- setChartRect(interaction.chartId, toLogicalRect(preview.rect));
28021
+ if (interaction.didMove && finalRect) {
28022
+ setChartRect(interaction.chartId, toLogicalRect(finalRect));
28023
+ }
27825
28024
  }
27826
28025
  chartPreviewRectRef.current = null;
27827
28026
  setChartPreviewRect(null);
@@ -28124,7 +28323,6 @@ function XlsxGrid({
28124
28323
  }
28125
28324
  gridKeyboardHandlerRef.current = handleGridKeyDown;
28126
28325
  const scrollerViewportProps = {
28127
- key: activeTabIndex,
28128
28326
  ref: scrollRef,
28129
28327
  "aria-colcount": Math.max(activeSheet?.colCount ?? 0, displayColLimit),
28130
28328
  "aria-keyshortcuts": "ArrowUp ArrowDown ArrowLeft ArrowRight Home End PageUp PageDown Control+Home Control+End",
@@ -28762,7 +28960,7 @@ function XlsxGrid({
28762
28960
  )
28763
28961
  }
28764
28962
  );
28765
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { backgroundColor: palette.canvas, display: "flex", flex: 1, minHeight: 0, minWidth: 0 }, children: renderScroller ? renderScroller({ children: scrollerContent, viewportProps: scrollerViewportProps }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ...scrollerViewportProps, children: scrollerContent }) });
28963
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { backgroundColor: palette.canvas, display: "flex", flex: 1, minHeight: 0, minWidth: 0 }, children: renderScroller ? renderScroller({ children: scrollerContent, viewportProps: scrollerViewportProps }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ...scrollerViewportProps, children: scrollerContent }, activeTabIndex) });
28766
28964
  }
28767
28965
  function XlsxViewerInner({
28768
28966
  allowResizeInReadOnly = false,
@@ -28967,8 +29165,11 @@ function useXlsxViewerEditing() {
28967
29165
  selectedFormula,
28968
29166
  selectedValue,
28969
29167
  setCellFormula,
29168
+ setCellStyle,
28970
29169
  setCellValue,
29170
+ setRangeStyle,
28971
29171
  setSelectedCellFormula,
29172
+ setSelectedCellStyle,
28972
29173
  setSelectedCellValue,
28973
29174
  undo,
28974
29175
  unmergeSelection
@@ -28995,8 +29196,11 @@ function useXlsxViewerEditing() {
28995
29196
  selectedFormula,
28996
29197
  selectedValue,
28997
29198
  setCellFormula,
29199
+ setCellStyle,
28998
29200
  setCellValue,
29201
+ setRangeStyle,
28999
29202
  setSelectedCellFormula,
29203
+ setSelectedCellStyle,
29000
29204
  setSelectedCellValue,
29001
29205
  undo,
29002
29206
  unmergeSelection
@@ -29022,8 +29226,11 @@ function useXlsxViewerEditing() {
29022
29226
  selectedFormula,
29023
29227
  selectedValue,
29024
29228
  setCellFormula,
29229
+ setCellStyle,
29025
29230
  setCellValue,
29231
+ setRangeStyle,
29026
29232
  setSelectedCellFormula,
29233
+ setSelectedCellStyle,
29027
29234
  setSelectedCellValue,
29028
29235
  undo,
29029
29236
  unmergeSelection