@extend-ai/react-xlsx 0.10.0 → 0.10.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.
package/dist/index.js CHANGED
@@ -17344,6 +17344,18 @@ function rangesEqual(left, right) {
17344
17344
  function isPrintableKey(event) {
17345
17345
  return event.key.length === 1 && !event.altKey && !event.ctrlKey && !event.metaKey;
17346
17346
  }
17347
+ function getInteractiveFocusTarget(target) {
17348
+ if (!(target instanceof Element)) {
17349
+ return null;
17350
+ }
17351
+ return target.closest(
17352
+ "a[href], button, input, select, textarea, [contenteditable=''], [contenteditable='true'], [role='button'], [role='menu'], [role='menuitem'], [role='textbox'], [tabindex]:not([tabindex='-1'])"
17353
+ );
17354
+ }
17355
+ function isInteractiveFocusTarget(target, container) {
17356
+ const interactiveElement = getInteractiveFocusTarget(target);
17357
+ return Boolean(interactiveElement && interactiveElement !== container && container.contains(interactiveElement));
17358
+ }
17347
17359
  function buildPrefixSums(values) {
17348
17360
  const prefix = new Array(values.length + 1).fill(0);
17349
17361
  for (let index = 0; index < values.length; index += 1) {
@@ -21021,6 +21033,21 @@ function resolveFirstUsedVisibleIndex(visibleIndices, minUsedIndex) {
21021
21033
  const firstVisibleUsed = visibleIndices.find((index) => index >= minUsedIndex);
21022
21034
  return firstVisibleUsed ?? visibleIndices[0] ?? -1;
21023
21035
  }
21036
+ function resolveLastUsedVisibleIndex(visibleIndices, maxUsedIndex) {
21037
+ if (visibleIndices.length === 0) {
21038
+ return -1;
21039
+ }
21040
+ if (maxUsedIndex < 0) {
21041
+ return visibleIndices[visibleIndices.length - 1] ?? -1;
21042
+ }
21043
+ for (let index = visibleIndices.length - 1; index >= 0; index -= 1) {
21044
+ const visibleIndex = visibleIndices[index];
21045
+ if (visibleIndex !== void 0 && visibleIndex <= maxUsedIndex) {
21046
+ return visibleIndex;
21047
+ }
21048
+ }
21049
+ return visibleIndices[visibleIndices.length - 1] ?? -1;
21050
+ }
21024
21051
  function GridRow({
21025
21052
  actualRow,
21026
21053
  editingCell,
@@ -21032,8 +21059,10 @@ function GridRow({
21032
21059
  onCellClick,
21033
21060
  onCellDoubleClick,
21034
21061
  onCellPointerDown,
21062
+ onEditingBlur,
21035
21063
  onEditingCancel,
21036
21064
  onEditingCommit,
21065
+ onEditingNavigate,
21037
21066
  onEditingValueChange,
21038
21067
  onRowHeaderRef,
21039
21068
  onRowPointerDown,
@@ -21319,7 +21348,7 @@ function GridRow({
21319
21348
  "input",
21320
21349
  {
21321
21350
  autoFocus: true,
21322
- onBlur: onEditingCommit,
21351
+ onBlur: onEditingBlur,
21323
21352
  onChange: (event) => onEditingValueChange(event.target.value),
21324
21353
  onKeyDown: (event) => {
21325
21354
  event.stopPropagation();
@@ -21331,6 +21360,11 @@ function GridRow({
21331
21360
  if (event.key === "Escape") {
21332
21361
  event.preventDefault();
21333
21362
  onEditingCancel();
21363
+ return;
21364
+ }
21365
+ if (event.key === "ArrowDown" || event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "ArrowUp") {
21366
+ event.preventDefault();
21367
+ onEditingNavigate(event.key, event.currentTarget.value);
21334
21368
  }
21335
21369
  },
21336
21370
  style: {
@@ -21406,7 +21440,7 @@ function GridRow({
21406
21440
  ] });
21407
21441
  }
21408
21442
  var MemoGridRow = React4.memo(GridRow, (prev, next) => {
21409
- if (prev.actualRow !== next.actualRow || prev.rowHeight !== next.rowHeight || prev.headerLabelLiveScale !== next.headerLabelLiveScale || prev.palette !== next.palette || prev.readOnly !== next.readOnly || prev.visibleCols !== next.visibleCols || prev.leadingSpacerWidth !== next.leadingSpacerWidth || prev.rowHeaderWidth !== next.rowHeaderWidth || prev.stickyLeftByCol !== next.stickyLeftByCol || prev.stickyTop !== next.stickyTop || prev.trailingSpacerWidth !== next.trailingSpacerWidth || prev.zoomFactor !== next.zoomFactor || prev.getCellData !== next.getCellData || prev.onCellClick !== next.onCellClick || prev.onCellDoubleClick !== next.onCellDoubleClick || prev.onCellPointerDown !== next.onCellPointerDown || prev.onEditingCancel !== next.onEditingCancel || prev.onEditingCommit !== next.onEditingCommit || prev.onEditingValueChange !== next.onEditingValueChange || prev.onRowHeaderRef !== next.onRowHeaderRef || prev.onRowPointerDown !== next.onRowPointerDown || prev.onRowResizePointerDown !== next.onRowResizePointerDown || prev.renderCellAdornment !== next.renderCellAdornment) {
21443
+ if (prev.actualRow !== next.actualRow || prev.rowHeight !== next.rowHeight || prev.headerLabelLiveScale !== next.headerLabelLiveScale || prev.palette !== next.palette || prev.readOnly !== next.readOnly || prev.visibleCols !== next.visibleCols || prev.leadingSpacerWidth !== next.leadingSpacerWidth || prev.rowHeaderWidth !== next.rowHeaderWidth || prev.stickyLeftByCol !== next.stickyLeftByCol || prev.stickyTop !== next.stickyTop || prev.trailingSpacerWidth !== next.trailingSpacerWidth || prev.zoomFactor !== next.zoomFactor || prev.getCellData !== next.getCellData || prev.onCellClick !== next.onCellClick || prev.onCellDoubleClick !== next.onCellDoubleClick || prev.onCellPointerDown !== next.onCellPointerDown || prev.onEditingBlur !== next.onEditingBlur || prev.onEditingCancel !== next.onEditingCancel || prev.onEditingCommit !== next.onEditingCommit || prev.onEditingNavigate !== next.onEditingNavigate || prev.onEditingValueChange !== next.onEditingValueChange || prev.onRowHeaderRef !== next.onRowHeaderRef || prev.onRowPointerDown !== next.onRowPointerDown || prev.onRowResizePointerDown !== next.onRowResizePointerDown || prev.renderCellAdornment !== next.renderCellAdornment) {
21410
21444
  return false;
21411
21445
  }
21412
21446
  const prevEditingCol = prev.editingCell?.row === prev.actualRow ? prev.editingCell.col : -1;
@@ -21507,6 +21541,9 @@ function XlsxGrid({
21507
21541
  const scrollRef = React4.useRef(null);
21508
21542
  const wrapperRef = React4.useRef(null);
21509
21543
  const tableRef = React4.useRef(null);
21544
+ const gridKeyboardActiveRef = React4.useRef(false);
21545
+ const gridKeyboardHandlerRef = React4.useRef(null);
21546
+ const axisSelectionRef = React4.useRef(null);
21510
21547
  const scrollBodyCanvasRef = React4.useRef(null);
21511
21548
  const topBodyCanvasRef = React4.useRef(null);
21512
21549
  const leftBodyCanvasRef = React4.useRef(null);
@@ -23148,9 +23185,50 @@ function XlsxGrid({
23148
23185
  selectionPreviewRangeRef.current = null;
23149
23186
  setInteractionMode("idle");
23150
23187
  }, [activeSheetIndex, clearGlobalCursor, revision]);
23151
- const focusGrid = React4.useCallback(() => {
23152
- scrollRef.current?.focus();
23188
+ const focusGridElement = React4.useCallback((element, options) => {
23189
+ if (document.activeElement !== element) {
23190
+ element.focus(options ?? { preventScroll: true });
23191
+ }
23153
23192
  }, []);
23193
+ const focusGrid = React4.useCallback((options) => {
23194
+ const scroller = scrollRef.current;
23195
+ if (scroller) {
23196
+ gridKeyboardActiveRef.current = true;
23197
+ focusGridElement(scroller, options);
23198
+ }
23199
+ }, [focusGridElement]);
23200
+ React4.useEffect(() => {
23201
+ const handleDocumentPointerDown = (event) => {
23202
+ const scroller = scrollRef.current;
23203
+ if (!scroller || !(event.target instanceof Node) || !scroller.contains(event.target)) {
23204
+ gridKeyboardActiveRef.current = false;
23205
+ return;
23206
+ }
23207
+ if (isInteractiveFocusTarget(event.target, scroller)) {
23208
+ gridKeyboardActiveRef.current = false;
23209
+ return;
23210
+ }
23211
+ gridKeyboardActiveRef.current = true;
23212
+ focusGridElement(scroller);
23213
+ };
23214
+ const handleDocumentKeyDown = (event) => {
23215
+ if (!gridKeyboardActiveRef.current || event.defaultPrevented) {
23216
+ return;
23217
+ }
23218
+ const scroller = scrollRef.current;
23219
+ const interactiveTarget = getInteractiveFocusTarget(event.target);
23220
+ if (!scroller || interactiveTarget && interactiveTarget !== scroller) {
23221
+ return;
23222
+ }
23223
+ gridKeyboardHandlerRef.current?.(event);
23224
+ };
23225
+ document.addEventListener("pointerdown", handleDocumentPointerDown, true);
23226
+ document.addEventListener("keydown", handleDocumentKeyDown);
23227
+ return () => {
23228
+ document.removeEventListener("pointerdown", handleDocumentPointerDown, true);
23229
+ document.removeEventListener("keydown", handleDocumentKeyDown);
23230
+ };
23231
+ }, [focusGridElement]);
23154
23232
  const openHyperlink = React4.useCallback((target, location) => {
23155
23233
  const internalTarget = parseInternalSheetLink(location ?? target);
23156
23234
  if (internalTarget) {
@@ -23189,21 +23267,74 @@ function XlsxGrid({
23189
23267
  return;
23190
23268
  }
23191
23269
  if (readOnly) {
23270
+ editingCellRef.current = null;
23192
23271
  setEditingCell(null);
23193
23272
  setEditingValue("");
23194
23273
  focusGrid();
23195
23274
  return;
23196
23275
  }
23197
23276
  setCellValue(editingCell, editingValue);
23277
+ editingCellRef.current = null;
23198
23278
  setEditingCell(null);
23199
23279
  setEditingValue("");
23200
23280
  focusGrid();
23201
23281
  }, [editingCell, editingValue, focusGrid, readOnly, setCellValue]);
23202
23282
  const cancelEditing = React4.useCallback(() => {
23283
+ editingCellRef.current = null;
23203
23284
  setEditingCell(null);
23204
23285
  setEditingValue("");
23205
23286
  focusGrid();
23206
23287
  }, [focusGrid]);
23288
+ const handleEditingBlur = React4.useCallback(() => {
23289
+ if (!editingCellRef.current) {
23290
+ return;
23291
+ }
23292
+ commitEditing();
23293
+ }, [commitEditing]);
23294
+ const handleEditingNavigate = React4.useCallback((key, value) => {
23295
+ const cell = editingCellRef.current;
23296
+ if (!cell) {
23297
+ return;
23298
+ }
23299
+ const currentRowIndex = rowIndexByActual.get(cell.row);
23300
+ const currentColIndex = colIndexByActual.get(cell.col);
23301
+ if (currentRowIndex === void 0 || currentColIndex === void 0) {
23302
+ if (!readOnlyRef.current) {
23303
+ setCellValue(cell, value);
23304
+ }
23305
+ editingCellRef.current = null;
23306
+ setEditingCell(null);
23307
+ setEditingValue("");
23308
+ focusGrid();
23309
+ return;
23310
+ }
23311
+ let nextRowIndex = currentRowIndex;
23312
+ let nextColIndex = currentColIndex;
23313
+ switch (key) {
23314
+ case "ArrowDown":
23315
+ nextRowIndex += 1;
23316
+ break;
23317
+ case "ArrowLeft":
23318
+ nextColIndex -= 1;
23319
+ break;
23320
+ case "ArrowRight":
23321
+ nextColIndex += 1;
23322
+ break;
23323
+ case "ArrowUp":
23324
+ nextRowIndex -= 1;
23325
+ break;
23326
+ default:
23327
+ return;
23328
+ }
23329
+ if (!readOnlyRef.current) {
23330
+ setCellValue(cell, value);
23331
+ }
23332
+ editingCellRef.current = null;
23333
+ setEditingCell(null);
23334
+ setEditingValue("");
23335
+ moveSelection(nextRowIndex, nextColIndex, false);
23336
+ focusGrid();
23337
+ }, [colIndexByActual, focusGrid, rowIndexByActual, setCellValue, visibleCols, visibleRows]);
23207
23338
  React4.useEffect(() => {
23208
23339
  commitEditingRef.current = commitEditing;
23209
23340
  }, [commitEditing]);
@@ -24176,6 +24307,7 @@ function XlsxGrid({
24176
24307
  overlay.style.visibility = "visible";
24177
24308
  }, [getCellData, resolveOverlayRect, zoomFactor]);
24178
24309
  const commitSelectionRange = React4.useCallback((range) => {
24310
+ gridKeyboardActiveRef.current = true;
24179
24311
  const normalized = normalizeRange2(range);
24180
24312
  if (selectionRef.current && rangesEqual(selectionRef.current, normalized) && isSameCell(activeCellRef.current, normalized.end) && selectedChartIdRef.current === null && selectedImageIdRef.current === null) {
24181
24313
  return;
@@ -24469,6 +24601,23 @@ function XlsxGrid({
24469
24601
  if (nextRange && (dragState?.didDrag || !dragState?.committedOnPointerDown)) {
24470
24602
  selectionPreviewRangeRef.current = nextRange;
24471
24603
  displayedSelectionRef.current = nextRange;
24604
+ if (dragState?.axis === "column") {
24605
+ const normalized = normalizeRange2(nextRange);
24606
+ axisSelectionRef.current = {
24607
+ axis: "column",
24608
+ startCol: normalized.start.col,
24609
+ endCol: normalized.end.col
24610
+ };
24611
+ } else if (dragState?.axis === "row") {
24612
+ const normalized = normalizeRange2(nextRange);
24613
+ axisSelectionRef.current = {
24614
+ axis: "row",
24615
+ startRow: normalized.start.row,
24616
+ endRow: normalized.end.row
24617
+ };
24618
+ } else {
24619
+ axisSelectionRef.current = null;
24620
+ }
24472
24621
  commitSelectionRange(nextRange);
24473
24622
  } else if (!nextRange) {
24474
24623
  selectionPreviewRangeRef.current = null;
@@ -24587,6 +24736,7 @@ function XlsxGrid({
24587
24736
  }
24588
24737
  event.preventDefault();
24589
24738
  focusGrid();
24739
+ axisSelectionRef.current = null;
24590
24740
  const targetCell = event.currentTarget.colSpan > 1 || event.currentTarget.rowSpan > 1 ? resolvePointerCellFromGeometry(event.clientX, event.clientY) ?? cell : cell;
24591
24741
  const currentSelection = selectionRef.current;
24592
24742
  const anchor = event.shiftKey && currentSelection ? currentSelection.start : targetCell;
@@ -24662,6 +24812,7 @@ function XlsxGrid({
24662
24812
  event.clientX,
24663
24813
  event.clientY
24664
24814
  );
24815
+ axisSelectionRef.current = { axis: "row", startRow: anchorRow, endRow: actualRow };
24665
24816
  commitSelectionRange(initialRange);
24666
24817
  }, [commitSelectionRange, firstVisibleCol, focusGrid, lastVisibleCol, resolveRowPointerOrigin]);
24667
24818
  const handleColumnPointerDown = React4.useCallback((event, actualCol) => {
@@ -24693,6 +24844,7 @@ function XlsxGrid({
24693
24844
  event.clientX,
24694
24845
  event.clientY
24695
24846
  );
24847
+ axisSelectionRef.current = { axis: "column", startCol: anchorCol, endCol: actualCol };
24696
24848
  commitSelectionRange(initialRange);
24697
24849
  }, [commitSelectionRange, firstVisibleRow, focusGrid, lastVisibleRow, resolveColumnPointerOrigin]);
24698
24850
  const handleRowResizePointerDown = React4.useCallback((event, actualRow, rowHeight) => {
@@ -24949,6 +25101,7 @@ function XlsxGrid({
24949
25101
  }
24950
25102
  event.preventDefault();
24951
25103
  focusGrid();
25104
+ axisSelectionRef.current = null;
24952
25105
  const currentSelection = selectionRef.current;
24953
25106
  const anchor = event.shiftKey && currentSelection ? currentSelection.start : cell;
24954
25107
  const initialRange = normalizeRange2({ start: anchor, end: cell });
@@ -25058,6 +25211,7 @@ function XlsxGrid({
25058
25211
  event.clientX,
25059
25212
  event.clientY
25060
25213
  );
25214
+ axisSelectionRef.current = { axis: "column", startCol: anchorCol, endCol: actualCol };
25061
25215
  commitSelectionRange(initialRange);
25062
25216
  }, [
25063
25217
  colIndexByActual,
@@ -25116,6 +25270,7 @@ function XlsxGrid({
25116
25270
  event.clientX,
25117
25271
  event.clientY
25118
25272
  );
25273
+ axisSelectionRef.current = { axis: "row", startRow: anchorRow, endRow: actualRow };
25119
25274
  commitSelectionRange(initialRange);
25120
25275
  }, [
25121
25276
  colPrefixSums,
@@ -27575,17 +27730,298 @@ function XlsxGrid({
27575
27730
  }
27576
27731
  return { row: firstVisibleRow, col: firstVisibleCol };
27577
27732
  }
27733
+ function ensureCellVisible(rowIndex, colIndex) {
27734
+ const scroller = scrollRef.current;
27735
+ if (!scroller) {
27736
+ return;
27737
+ }
27738
+ let nextScrollTop = scroller.scrollTop;
27739
+ let nextScrollLeft = scroller.scrollLeft;
27740
+ const rowStart = displayHeaderHeight + (rowPrefixSums[rowIndex] ?? 0);
27741
+ const rowEnd = displayHeaderHeight + (rowPrefixSums[rowIndex + 1] ?? rowStart);
27742
+ const colStart = displayRowHeaderWidth + (colPrefixSums[colIndex] ?? 0);
27743
+ const colEnd = displayRowHeaderWidth + (colPrefixSums[colIndex + 1] ?? colStart);
27744
+ if (rowEnd > frozenPaneBottom) {
27745
+ const visibleTop = scroller.scrollTop + frozenPaneBottom;
27746
+ const visibleBottom = scroller.scrollTop + scroller.clientHeight;
27747
+ if (rowStart < visibleTop) {
27748
+ nextScrollTop = rowStart - frozenPaneBottom;
27749
+ } else if (rowEnd > visibleBottom) {
27750
+ nextScrollTop = rowEnd - scroller.clientHeight;
27751
+ }
27752
+ }
27753
+ if (colEnd > frozenPaneRight) {
27754
+ const visibleLeft = scroller.scrollLeft + frozenPaneRight;
27755
+ const visibleRight = scroller.scrollLeft + scroller.clientWidth;
27756
+ if (colStart < visibleLeft) {
27757
+ nextScrollLeft = colStart - frozenPaneRight;
27758
+ } else if (colEnd > visibleRight) {
27759
+ nextScrollLeft = colEnd - scroller.clientWidth;
27760
+ }
27761
+ }
27762
+ nextScrollTop = Math.max(0, Math.min(nextScrollTop, scroller.scrollHeight - scroller.clientHeight));
27763
+ nextScrollLeft = Math.max(0, Math.min(nextScrollLeft, scroller.scrollWidth - scroller.clientWidth));
27764
+ if (nextScrollTop !== scroller.scrollTop) {
27765
+ scroller.scrollTop = nextScrollTop;
27766
+ }
27767
+ if (nextScrollLeft !== scroller.scrollLeft) {
27768
+ scroller.scrollLeft = nextScrollLeft;
27769
+ }
27770
+ syncDrawingViewport(scroller, { immediate: true });
27771
+ }
27578
27772
  function moveSelection(nextRowIndex, nextColIndex, extend) {
27579
- const nextRow = visibleRows[nextRowIndex];
27580
- const nextCol = visibleCols[nextColIndex];
27773
+ const clampedRowIndex = Math.max(0, Math.min(nextRowIndex, visibleRows.length - 1));
27774
+ const clampedColIndex = Math.max(0, Math.min(nextColIndex, visibleCols.length - 1));
27775
+ const nextRow = visibleRows[clampedRowIndex];
27776
+ const nextCol = visibleCols[clampedColIndex];
27581
27777
  if (nextRow === void 0 || nextCol === void 0) {
27582
27778
  return;
27583
27779
  }
27780
+ const nextRange = { start: { row: nextRow, col: nextCol }, end: { row: nextRow, col: nextCol } };
27781
+ axisSelectionRef.current = null;
27782
+ selectionPreviewRangeRef.current = null;
27783
+ displayedSelectionRef.current = nextRange;
27784
+ applyPreviewOverlay(nextRange);
27584
27785
  selectCell({ row: nextRow, col: nextCol }, extend ? { extend: true } : void 0);
27786
+ ensureCellVisible(clampedRowIndex, clampedColIndex);
27585
27787
  }
27788
+ function resolvePageRowIndex(currentRowIndex, direction) {
27789
+ const scroller = scrollRef.current;
27790
+ const viewportHeight = Math.max(
27791
+ displayDefaultRowHeight,
27792
+ (scroller?.clientHeight ?? displayDefaultRowHeight * 20) - frozenPaneBottom
27793
+ );
27794
+ const currentOffset = rowPrefixSums[currentRowIndex] ?? 0;
27795
+ const targetOffset = direction > 0 ? currentOffset + viewportHeight : currentOffset - viewportHeight;
27796
+ return Math.max(0, Math.min(findIndexForOffsetPrefix(rowPrefixSums, targetOffset), visibleRows.length - 1));
27797
+ }
27798
+ function resolvePageColIndex(currentColIndex, direction) {
27799
+ const scroller = scrollRef.current;
27800
+ const viewportWidth = Math.max(
27801
+ displayDefaultColWidth,
27802
+ (scroller?.clientWidth ?? displayDefaultColWidth * 8) - frozenPaneRight
27803
+ );
27804
+ const currentOffset = colPrefixSums[currentColIndex] ?? 0;
27805
+ const targetOffset = direction > 0 ? currentOffset + viewportWidth : currentOffset - viewportWidth;
27806
+ return Math.max(0, Math.min(findIndexForOffsetPrefix(colPrefixSums, targetOffset), visibleCols.length - 1));
27807
+ }
27808
+ function resolveColumnSelectionNavigation(eventKey) {
27809
+ const axisSelection = axisSelectionRef.current;
27810
+ if (axisSelection?.axis !== "column" || firstVisibleRow === void 0) {
27811
+ return null;
27812
+ }
27813
+ const startCol = Math.min(axisSelection.startCol, axisSelection.endCol);
27814
+ const endCol = Math.max(axisSelection.startCol, axisSelection.endCol);
27815
+ const targetCol = eventKey === "ArrowLeft" ? startCol - 1 : eventKey === "ArrowRight" ? endCol + 1 : null;
27816
+ if (targetCol === null) {
27817
+ return null;
27818
+ }
27819
+ const rowIndex = rowIndexByActual.get(firstVisibleRow);
27820
+ const colIndex = colIndexByActual.get(targetCol);
27821
+ if (rowIndex === void 0 || colIndex === void 0) {
27822
+ return null;
27823
+ }
27824
+ return { colIndex, rowIndex };
27825
+ }
27826
+ function resolveRowSelectionNavigation(eventKey) {
27827
+ const axisSelection = axisSelectionRef.current;
27828
+ if (axisSelection?.axis !== "row" || firstVisibleCol === void 0) {
27829
+ return null;
27830
+ }
27831
+ const startRow = Math.min(axisSelection.startRow, axisSelection.endRow);
27832
+ const endRow = Math.max(axisSelection.startRow, axisSelection.endRow);
27833
+ const targetRow = eventKey === "ArrowUp" ? startRow - 1 : eventKey === "ArrowDown" ? endRow + 1 : null;
27834
+ if (targetRow === null) {
27835
+ return null;
27836
+ }
27837
+ const rowIndex = rowIndexByActual.get(targetRow);
27838
+ const colIndex = colIndexByActual.get(firstVisibleCol);
27839
+ if (rowIndex === void 0 || colIndex === void 0) {
27840
+ return null;
27841
+ }
27842
+ return { colIndex, rowIndex };
27843
+ }
27844
+ function handleGridKeyDown(event) {
27845
+ if (editingCell) {
27846
+ return;
27847
+ }
27848
+ if (!readOnly && (event.metaKey || event.ctrlKey) && !event.altKey) {
27849
+ const normalizedKey = event.key.toLowerCase();
27850
+ if (normalizedKey === "z" && event.shiftKey) {
27851
+ event.preventDefault();
27852
+ redo();
27853
+ return;
27854
+ }
27855
+ if (normalizedKey === "z") {
27856
+ event.preventDefault();
27857
+ undo();
27858
+ return;
27859
+ }
27860
+ if (normalizedKey === "y") {
27861
+ event.preventDefault();
27862
+ redo();
27863
+ return;
27864
+ }
27865
+ }
27866
+ const currentCell = resolveCurrentCell();
27867
+ if (!currentCell) {
27868
+ return;
27869
+ }
27870
+ const currentRowIndex = rowIndexByActual.get(currentCell.row) ?? 0;
27871
+ const currentColIndex = colIndexByActual.get(currentCell.col) ?? 0;
27872
+ const isCommandNavigation = event.ctrlKey || event.metaKey;
27873
+ if (!readOnly && isPrintableKey(event)) {
27874
+ event.preventDefault();
27875
+ startEditing(currentCell, event.key);
27876
+ return;
27877
+ }
27878
+ switch (event.key) {
27879
+ case "ArrowDown":
27880
+ event.preventDefault();
27881
+ if (!event.shiftKey && !isCommandNavigation) {
27882
+ const target = resolveRowSelectionNavigation(event.key);
27883
+ if (target) {
27884
+ moveSelection(target.rowIndex, target.colIndex, false);
27885
+ break;
27886
+ }
27887
+ }
27888
+ moveSelection(
27889
+ isCommandNavigation ? rowIndexByActual.get(resolveLastUsedVisibleIndex(visibleRows, activeSheet?.maxUsedRow ?? -1)) ?? visibleRows.length - 1 : currentRowIndex + 1,
27890
+ currentColIndex,
27891
+ event.shiftKey
27892
+ );
27893
+ break;
27894
+ case "ArrowUp":
27895
+ event.preventDefault();
27896
+ if (!event.shiftKey && !isCommandNavigation) {
27897
+ const target = resolveRowSelectionNavigation(event.key);
27898
+ if (target) {
27899
+ moveSelection(target.rowIndex, target.colIndex, false);
27900
+ break;
27901
+ }
27902
+ }
27903
+ moveSelection(
27904
+ isCommandNavigation ? rowIndexByActual.get(resolveFirstUsedVisibleIndex(visibleRows, activeSheet?.minUsedRow ?? -1)) ?? 0 : currentRowIndex - 1,
27905
+ currentColIndex,
27906
+ event.shiftKey
27907
+ );
27908
+ break;
27909
+ case "ArrowLeft":
27910
+ event.preventDefault();
27911
+ if (!event.shiftKey && !isCommandNavigation) {
27912
+ const target = resolveColumnSelectionNavigation(event.key);
27913
+ if (target) {
27914
+ moveSelection(target.rowIndex, target.colIndex, false);
27915
+ break;
27916
+ }
27917
+ }
27918
+ moveSelection(
27919
+ currentRowIndex,
27920
+ isCommandNavigation ? colIndexByActual.get(resolveFirstUsedVisibleIndex(visibleCols, activeSheet?.minUsedCol ?? -1)) ?? 0 : currentColIndex - 1,
27921
+ event.shiftKey
27922
+ );
27923
+ break;
27924
+ case "ArrowRight":
27925
+ event.preventDefault();
27926
+ if (!event.shiftKey && !isCommandNavigation) {
27927
+ const target = resolveColumnSelectionNavigation(event.key);
27928
+ if (target) {
27929
+ moveSelection(target.rowIndex, target.colIndex, false);
27930
+ break;
27931
+ }
27932
+ }
27933
+ moveSelection(
27934
+ currentRowIndex,
27935
+ isCommandNavigation ? colIndexByActual.get(resolveLastUsedVisibleIndex(visibleCols, activeSheet?.maxUsedCol ?? -1)) ?? visibleCols.length - 1 : currentColIndex + 1,
27936
+ event.shiftKey
27937
+ );
27938
+ break;
27939
+ case "Home":
27940
+ event.preventDefault();
27941
+ moveSelection(
27942
+ isCommandNavigation ? rowIndexByActual.get(resolveFirstUsedVisibleIndex(visibleRows, activeSheet?.minUsedRow ?? -1)) ?? 0 : currentRowIndex,
27943
+ colIndexByActual.get(resolveFirstUsedVisibleIndex(visibleCols, activeSheet?.minUsedCol ?? -1)) ?? 0,
27944
+ event.shiftKey
27945
+ );
27946
+ break;
27947
+ case "End":
27948
+ event.preventDefault();
27949
+ moveSelection(
27950
+ isCommandNavigation ? rowIndexByActual.get(resolveLastUsedVisibleIndex(visibleRows, activeSheet?.maxUsedRow ?? -1)) ?? visibleRows.length - 1 : currentRowIndex,
27951
+ colIndexByActual.get(resolveLastUsedVisibleIndex(visibleCols, activeSheet?.maxUsedCol ?? -1)) ?? visibleCols.length - 1,
27952
+ event.shiftKey
27953
+ );
27954
+ break;
27955
+ case "PageDown":
27956
+ event.preventDefault();
27957
+ if (event.altKey) {
27958
+ moveSelection(currentRowIndex, resolvePageColIndex(currentColIndex, 1), event.shiftKey);
27959
+ break;
27960
+ }
27961
+ moveSelection(resolvePageRowIndex(currentRowIndex, 1), currentColIndex, event.shiftKey);
27962
+ break;
27963
+ case "PageUp":
27964
+ event.preventDefault();
27965
+ if (event.altKey) {
27966
+ moveSelection(currentRowIndex, resolvePageColIndex(currentColIndex, -1), event.shiftKey);
27967
+ break;
27968
+ }
27969
+ moveSelection(resolvePageRowIndex(currentRowIndex, -1), currentColIndex, event.shiftKey);
27970
+ break;
27971
+ case "Tab":
27972
+ event.preventDefault();
27973
+ if (event.shiftKey) {
27974
+ moveSelection(
27975
+ currentColIndex > 0 ? currentRowIndex : currentRowIndex - 1,
27976
+ currentColIndex > 0 ? currentColIndex - 1 : visibleCols.length - 1,
27977
+ false
27978
+ );
27979
+ } else {
27980
+ moveSelection(
27981
+ currentColIndex < visibleCols.length - 1 ? currentRowIndex : currentRowIndex + 1,
27982
+ currentColIndex < visibleCols.length - 1 ? currentColIndex + 1 : 0,
27983
+ false
27984
+ );
27985
+ }
27986
+ break;
27987
+ case "Enter":
27988
+ event.preventDefault();
27989
+ if (event.metaKey || event.ctrlKey || event.altKey) {
27990
+ break;
27991
+ }
27992
+ if (event.shiftKey) {
27993
+ moveSelection(currentRowIndex - 1, currentColIndex, false);
27994
+ break;
27995
+ }
27996
+ moveSelection(currentRowIndex + 1, currentColIndex, false);
27997
+ break;
27998
+ case "Backspace":
27999
+ case "Delete":
28000
+ if (!readOnly) {
28001
+ event.preventDefault();
28002
+ clearSelectedCells();
28003
+ }
28004
+ break;
28005
+ case "F2":
28006
+ if (!readOnly) {
28007
+ event.preventDefault();
28008
+ startEditing(currentCell);
28009
+ }
28010
+ break;
28011
+ default:
28012
+ break;
28013
+ }
28014
+ }
28015
+ gridKeyboardHandlerRef.current = handleGridKeyDown;
27586
28016
  const scrollerViewportProps = {
27587
28017
  key: activeTabIndex,
27588
28018
  ref: scrollRef,
28019
+ "aria-colcount": Math.max(activeSheet?.colCount ?? 0, displayColLimit),
28020
+ "aria-keyshortcuts": "ArrowUp ArrowDown ArrowLeft ArrowRight Home End PageUp PageDown Control+Home Control+End",
28021
+ "aria-label": activeSheet ? `${activeSheet.name} worksheet grid` : "Workbook grid",
28022
+ "aria-readonly": readOnly,
28023
+ "aria-rowcount": Math.max(activeSheet?.rowCount ?? 0, displayRowLimit),
28024
+ role: "grid",
27589
28025
  onScroll: handleScrollerScroll,
27590
28026
  onCopy: (event) => {
27591
28027
  if (editingCell) {
@@ -27605,92 +28041,27 @@ function XlsxGrid({
27605
28041
  }
27606
28042
  void copySelectionToClipboard();
27607
28043
  },
27608
- onKeyDown: (event) => {
27609
- if (editingCell) {
28044
+ onPointerDownCapture: (event) => {
28045
+ if (event.button !== 0) {
27610
28046
  return;
27611
28047
  }
27612
- if (!readOnly && (event.metaKey || event.ctrlKey) && !event.altKey) {
27613
- const normalizedKey = event.key.toLowerCase();
27614
- if (normalizedKey === "z" && event.shiftKey) {
27615
- event.preventDefault();
27616
- redo();
27617
- return;
27618
- }
27619
- if (normalizedKey === "z") {
27620
- event.preventDefault();
27621
- undo();
27622
- return;
27623
- }
27624
- if (normalizedKey === "y") {
27625
- event.preventDefault();
27626
- redo();
27627
- return;
27628
- }
27629
- }
27630
- const currentCell = resolveCurrentCell();
27631
- if (!currentCell) {
28048
+ if (isInteractiveFocusTarget(event.target, event.currentTarget)) {
27632
28049
  return;
27633
28050
  }
27634
- const currentRowIndex = rowIndexByActual.get(currentCell.row) ?? 0;
27635
- const currentColIndex = colIndexByActual.get(currentCell.col) ?? 0;
27636
- if (!readOnly && isPrintableKey(event)) {
27637
- event.preventDefault();
27638
- startEditing(currentCell, event.key);
28051
+ gridKeyboardActiveRef.current = true;
28052
+ focusGridElement(event.currentTarget);
28053
+ },
28054
+ onClickCapture: (event) => {
28055
+ if (isInteractiveFocusTarget(event.target, event.currentTarget)) {
27639
28056
  return;
27640
28057
  }
27641
- switch (event.key) {
27642
- case "ArrowDown":
27643
- event.preventDefault();
27644
- moveSelection(Math.min(currentRowIndex + 1, visibleRows.length - 1), currentColIndex, event.shiftKey);
27645
- break;
27646
- case "ArrowUp":
27647
- event.preventDefault();
27648
- moveSelection(Math.max(currentRowIndex - 1, 0), currentColIndex, event.shiftKey);
27649
- break;
27650
- case "ArrowLeft":
27651
- event.preventDefault();
27652
- moveSelection(currentRowIndex, Math.max(currentColIndex - 1, 0), event.shiftKey);
27653
- break;
27654
- case "ArrowRight":
27655
- event.preventDefault();
27656
- moveSelection(currentRowIndex, Math.min(currentColIndex + 1, visibleCols.length - 1), event.shiftKey);
27657
- break;
27658
- case "Tab":
27659
- event.preventDefault();
27660
- moveSelection(
27661
- currentRowIndex,
27662
- event.shiftKey ? Math.max(currentColIndex - 1, 0) : Math.min(currentColIndex + 1, visibleCols.length - 1),
27663
- false
27664
- );
27665
- break;
27666
- case "Enter":
27667
- event.preventDefault();
27668
- if (event.metaKey || event.ctrlKey || event.altKey) {
27669
- break;
27670
- }
27671
- if (event.shiftKey) {
27672
- moveSelection(Math.max(currentRowIndex - 1, 0), currentColIndex, false);
27673
- break;
27674
- }
27675
- moveSelection(Math.min(currentRowIndex + 1, visibleRows.length - 1), currentColIndex, false);
27676
- break;
27677
- case "Backspace":
27678
- case "Delete":
27679
- if (!readOnly) {
27680
- event.preventDefault();
27681
- clearSelectedCells();
27682
- }
27683
- break;
27684
- case "F2":
27685
- if (!readOnly) {
27686
- event.preventDefault();
27687
- startEditing(currentCell);
27688
- }
27689
- break;
27690
- default:
27691
- break;
27692
- }
28058
+ gridKeyboardActiveRef.current = true;
28059
+ focusGridElement(event.currentTarget);
28060
+ },
28061
+ onFocus: () => {
28062
+ gridKeyboardActiveRef.current = true;
27693
28063
  },
28064
+ onKeyDown: handleGridKeyDown,
27694
28065
  onPaste: (event) => {
27695
28066
  if (editingCell || readOnly) {
27696
28067
  return;
@@ -27940,7 +28311,7 @@ function XlsxGrid({
27940
28311
  {
27941
28312
  ref: editingInputRef,
27942
28313
  autoFocus: true,
27943
- onBlur: commitEditing,
28314
+ onBlur: handleEditingBlur,
27944
28315
  onChange: (event) => setEditingValue(event.target.value),
27945
28316
  onKeyDown: (event) => {
27946
28317
  event.stopPropagation();
@@ -27952,6 +28323,11 @@ function XlsxGrid({
27952
28323
  if (event.key === "Escape") {
27953
28324
  event.preventDefault();
27954
28325
  cancelEditing();
28326
+ return;
28327
+ }
28328
+ if (event.key === "ArrowDown" || event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "ArrowUp") {
28329
+ event.preventDefault();
28330
+ handleEditingNavigate(event.key, event.currentTarget.value);
27955
28331
  }
27956
28332
  },
27957
28333
  style: {
@@ -28106,8 +28482,10 @@ function XlsxGrid({
28106
28482
  onCellClick: handleCellClick,
28107
28483
  onCellDoubleClick: handleCellDoubleClick,
28108
28484
  onCellPointerDown: handleCellPointerDown,
28485
+ onEditingBlur: handleEditingBlur,
28109
28486
  onEditingCancel: cancelEditing,
28110
28487
  onEditingCommit: commitEditing,
28488
+ onEditingNavigate: handleEditingNavigate,
28111
28489
  onEditingValueChange: setEditingValue,
28112
28490
  headerLabelLiveScale,
28113
28491
  onRowHeaderRef: setRowHeaderRef,