@lensui/lens-table 0.1.82 → 0.1.84

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
@@ -1,5 +1,5 @@
1
1
  // src/Table.tsx
2
- import { forwardRef, useImperativeHandle, Fragment as Fragment2, useCallback as useCallback2, useEffect as useEffect3, useLayoutEffect as useLayoutEffect3, useMemo as useMemo2, useRef as useRef4, useState as useState6 } from "react";
2
+ import { forwardRef, useImperativeHandle, Fragment as Fragment2, useCallback as useCallback3, useEffect as useEffect3, useLayoutEffect as useLayoutEffect3, useMemo as useMemo2, useRef as useRef4, useState as useState6 } from "react";
3
3
  import { flushSync } from "react-dom";
4
4
 
5
5
  // src/components/EmptyState.tsx
@@ -199,7 +199,7 @@ function DefaultEmptyState({ label = ZH_CN_GRID_LABELS.empty }) {
199
199
  // src/components/editors/ChoiceEditor.tsx
200
200
  import { Portal } from "@ark-ui/react/portal";
201
201
  import { Select, createListCollection } from "@ark-ui/react/select";
202
- import { useEffect, useId as useId2, useLayoutEffect, useMemo, useRef, useState } from "react";
202
+ import { useCallback, useEffect, useId as useId2, useLayoutEffect, useMemo, useRef, useState } from "react";
203
203
 
204
204
  // src/icons/gridIcons.tsx
205
205
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -315,7 +315,7 @@ function getSearchableChoicePopupHorizontalLayout(anchorLeft, anchorWidth, longe
315
315
  );
316
316
  return { left, width };
317
317
  }
318
- function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownHeight, style, labels, onChange, onCommit, onCancel }) {
318
+ function SearchableChoiceEditor({ value, options, allowCustomValue, strictOptions, maxDropdownHeight, style, labels, onChange, onCommit, onCancel }) {
319
319
  const editorRef = useRef(null);
320
320
  const popupRef = useRef(null);
321
321
  const activeOptionRef = useRef(null);
@@ -325,6 +325,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
325
325
  const listboxId = useId2();
326
326
  const originalValue = originalValueRef.current;
327
327
  const [inputValue, setInputValue] = useState(value);
328
+ const [hasTyped, setHasTyped] = useState(false);
328
329
  const [activeIndex, setActiveIndex] = useState(() => {
329
330
  const selectedIndex = options.findIndex((option) => option.value === value);
330
331
  return selectedIndex >= 0 ? selectedIndex : 0;
@@ -334,10 +335,23 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
334
335
  visibility: "hidden"
335
336
  });
336
337
  const filteredOptions = useMemo(() => {
338
+ if (strictOptions) {
339
+ if (!hasTyped) return options;
340
+ if (inputValue === "") return options.filter((option) => option.value === "");
341
+ const strictQuery = inputValue.trim().toLocaleLowerCase();
342
+ if (!strictQuery) return [];
343
+ return options.filter((option) => option.label.toLocaleLowerCase().includes(strictQuery) || option.value.toLocaleLowerCase().includes(strictQuery));
344
+ }
337
345
  const query = inputValue.trim().toLocaleLowerCase();
338
346
  if (!query || query === originalValue.toLocaleLowerCase()) return options;
339
347
  return options.filter((option) => option.label.toLocaleLowerCase().includes(query) || option.value.toLocaleLowerCase().includes(query));
340
- }, [inputValue, options, originalValue]);
348
+ }, [hasTyped, inputValue, options, originalValue, strictOptions]);
349
+ const exactInputOption = options.find((option) => option.value === inputValue);
350
+ const selectedValue = exactInputOption?.value;
351
+ const resolveInputValue = useCallback(() => {
352
+ if (strictOptions) return exactInputOption?.value ?? originalValue;
353
+ return allowCustomValue ? inputValue || originalValue : originalValue;
354
+ }, [allowCustomValue, exactInputOption, inputValue, originalValue, strictOptions]);
341
355
  useLayoutEffect(() => {
342
356
  const positionPopup = () => {
343
357
  const rect = editorRef.current?.getBoundingClientRect();
@@ -404,11 +418,11 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
404
418
  const target = event.target;
405
419
  if (!(target instanceof Node)) return;
406
420
  if (editorRef.current?.contains(target) || popupRef.current?.contains(target)) return;
407
- onCommit(allowCustomValue ? inputValue || originalValue : originalValue);
421
+ onCommit(resolveInputValue());
408
422
  };
409
423
  document.addEventListener("pointerdown", handleOutsidePointer, true);
410
424
  return () => document.removeEventListener("pointerdown", handleOutsidePointer, true);
411
- }, [allowCustomValue, inputValue, onCommit, originalValue]);
425
+ }, [onCommit, resolveInputValue]);
412
426
  const selectOption = (option) => {
413
427
  onChange(option.value);
414
428
  onCommit(option.value);
@@ -430,7 +444,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
430
444
  event.preventDefault();
431
445
  const option = filteredOptions[activeIndex];
432
446
  if (option) selectOption(option);
433
- else if (allowCustomValue) onCommit(inputValue || originalValue);
447
+ else if (allowCustomValue || strictOptions) onCommit(resolveInputValue());
434
448
  }
435
449
  };
436
450
  return /* @__PURE__ */ jsxs3("div", { ref: editorRef, className: "rvg-choice-editor rvg-searchable-choice-editor", style, children: [
@@ -444,6 +458,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
444
458
  "aria-controls": listboxId,
445
459
  onFocus: (event) => event.currentTarget.select(),
446
460
  onChange: (event) => {
461
+ setHasTyped(true);
447
462
  setInputValue(event.target.value);
448
463
  onChange(event.target.value);
449
464
  navigationSourceRef.current = "filter";
@@ -459,8 +474,8 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
459
474
  ref: index === activeIndex ? activeOptionRef : void 0,
460
475
  type: "button",
461
476
  role: "option",
462
- "aria-selected": option.value === originalValue,
463
- className: `rvg-choice-item${index === activeIndex ? " is-active" : ""}${option.value === originalValue ? " is-selected" : ""}`,
477
+ "aria-selected": option.value === selectedValue,
478
+ className: `rvg-choice-item${index === activeIndex ? " is-active" : ""}${option.value === selectedValue ? " is-selected" : ""}`,
464
479
  onPointerDown: (event) => event.preventDefault(),
465
480
  onMouseEnter: () => {
466
481
  navigationSourceRef.current = "pointer";
@@ -469,7 +484,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
469
484
  onClick: () => selectOption(option),
470
485
  children: [
471
486
  /* @__PURE__ */ jsx3("span", { children: option.label }),
472
- option.value === originalValue && /* @__PURE__ */ jsx3(ChoiceCheckIcon, {})
487
+ option.value === selectedValue && /* @__PURE__ */ jsx3(ChoiceCheckIcon, {})
473
488
  ]
474
489
  },
475
490
  option.value
@@ -1114,6 +1129,24 @@ function ellipsizeText(context, text, maxWidth) {
1114
1129
  }
1115
1130
  return `${text.slice(0, start)}${ellipsis}`;
1116
1131
  }
1132
+ function getSelectionOutlineBounds({
1133
+ left,
1134
+ right,
1135
+ top,
1136
+ bottom,
1137
+ horizontalStart,
1138
+ horizontalEnd,
1139
+ verticalStart,
1140
+ verticalEnd,
1141
+ borderWidth = 2
1142
+ }) {
1143
+ return {
1144
+ left: Math.max(left - borderWidth, horizontalStart - borderWidth),
1145
+ right: Math.min(right + 1, horizontalEnd + 1),
1146
+ top: Math.max(top - borderWidth, verticalStart - borderWidth),
1147
+ bottom: Math.min(bottom + borderWidth, verticalEnd + borderWidth)
1148
+ };
1149
+ }
1117
1150
  function paintGrid(options) {
1118
1151
  const { context: ctx, width, height, pixelRatio, scrollLeft, scrollTop, rowHeight, bodyFontSize, headerActionSlotWidth, headerHeight, fixedHeader, verticalBorderless, horizontalBorderless, frameBorderless, extendVerticalGridLines, striped, columnDraggable, sortState, filterValues, hoveredHeaderAction, rows, columns, metrics, range, selection, editing, hoveredRowIndex, selectionRange, selectedRowKeys, rowSelectionMode, selectedColumnKeys, highlightEditedCells, highlightInsertedRows, insertedRowKeys, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget } = options;
1119
1152
  const headerLeafTop = options.headerLeafTop ?? 0;
@@ -1602,51 +1635,65 @@ function paintGrid(options) {
1602
1635
  const visibleRight = x + selectionWidth;
1603
1636
  const visibleBottom = y + selectionHeight;
1604
1637
  const selectionTop = fixedHeader ? bodyTop : 0;
1605
- const selectionClipTop = selectionTop;
1606
1638
  const hiddenAboveHeader = visibleBottom <= selectionTop;
1607
1639
  const hiddenBelowViewport = y >= height;
1608
1640
  const hiddenBehindLeft = !isFixed && visibleRight <= visibleLeft;
1609
1641
  const hiddenBehindRight = !isFixed && x >= selectionAreaRight;
1610
- const leftMarkerX = Math.max(0, leftFixedWidth);
1642
+ const leftMarkerX = leftFixedWidth - borderWidth;
1643
+ const rightMarkerX = selectionAreaRight - 1;
1644
+ const topMarkerY = selectionTop - borderWidth;
1645
+ const bottomMarkerY = height;
1611
1646
  if ((hiddenAboveHeader || hiddenBelowViewport) && (hiddenBehindLeft || hiddenBehindRight)) {
1612
1647
  const markerSize = 2;
1613
- const markerX = hiddenBehindLeft ? leftMarkerX : selectionAreaRight - borderWidth - rightFixedBoundaryInset;
1614
- const markerY = hiddenAboveHeader ? selectionClipTop : height - markerSize;
1648
+ const markerX = hiddenBehindLeft ? leftMarkerX : rightMarkerX;
1649
+ const markerY = hiddenAboveHeader ? topMarkerY : bottomMarkerY;
1615
1650
  ctx.fillStyle = colors.selection;
1616
1651
  ctx.fillRect(markerX, markerY, markerSize, markerSize);
1617
1652
  return;
1618
1653
  }
1654
+ const outline = getSelectionOutlineBounds({
1655
+ left: x,
1656
+ right: visibleRight,
1657
+ top: y,
1658
+ bottom: visibleBottom,
1659
+ horizontalStart: visibleLeft,
1660
+ horizontalEnd: selectionAreaRight,
1661
+ verticalStart: selectionTop,
1662
+ verticalEnd: height,
1663
+ borderWidth
1664
+ });
1619
1665
  ctx.save();
1620
1666
  ctx.beginPath();
1621
- const clipLeft = fixedSide === "left" ? 0 : Math.max(0, leftFixedWidth);
1667
+ const clipLeft = Math.max(0, outline.left);
1622
1668
  const clipRight = Math.min(width, selectionAreaRight + 1);
1623
- ctx.rect(clipLeft, selectionClipTop, clipRight - clipLeft, height - selectionClipTop);
1669
+ const clipTop = Math.max(0, outline.top);
1670
+ ctx.rect(clipLeft, clipTop, clipRight - clipLeft, height - clipTop);
1624
1671
  ctx.clip();
1625
1672
  ctx.fillStyle = colors.selection;
1626
1673
  if (hiddenAboveHeader) {
1627
- const markerLeft = Math.max(x - borderWidth, visibleLeft - 1);
1628
- const markerRight = Math.min(visibleRight + 1, selectionAreaRight);
1629
- if (markerRight > markerLeft) ctx.fillRect(markerLeft, selectionClipTop, markerRight - markerLeft, borderWidth);
1674
+ const markerLeft = Math.max(x - borderWidth, visibleLeft - borderWidth);
1675
+ const markerRight = Math.min(visibleRight + 1, selectionAreaRight + 1);
1676
+ if (markerRight > markerLeft) ctx.fillRect(markerLeft, topMarkerY, markerRight - markerLeft, borderWidth);
1630
1677
  }
1631
1678
  if (hiddenBelowViewport) {
1632
- const markerLeft = Math.max(x - borderWidth, visibleLeft - 1);
1633
- const markerRight = Math.min(visibleRight + 1, selectionAreaRight);
1634
- if (markerRight > markerLeft) ctx.fillRect(markerLeft, height - borderWidth, markerRight - markerLeft, borderWidth);
1679
+ const markerLeft = Math.max(x - borderWidth, visibleLeft - borderWidth);
1680
+ const markerRight = Math.min(visibleRight + 1, selectionAreaRight + 1);
1681
+ if (markerRight > markerLeft) ctx.fillRect(markerLeft, bottomMarkerY, markerRight - markerLeft, borderWidth);
1635
1682
  }
1636
1683
  if (hiddenBehindLeft || hiddenBehindRight) {
1637
- const markerTop = Math.max(y - borderWidth, selectionTop);
1638
- const markerBottom = Math.min(y + selectionHeight + 1, height);
1639
- const markerX = hiddenBehindLeft ? leftMarkerX : selectionAreaRight - borderWidth - rightFixedBoundaryInset;
1684
+ const markerTop = Math.max(y - borderWidth, selectionTop - borderWidth);
1685
+ const markerBottom = Math.min(y + selectionHeight + borderWidth, height + borderWidth);
1686
+ const markerX = hiddenBehindLeft ? leftMarkerX : rightMarkerX;
1640
1687
  ctx.fillRect(markerX, markerTop, borderWidth, Math.max(0, markerBottom - markerTop));
1641
1688
  }
1642
1689
  if (hiddenAboveHeader || hiddenBelowViewport || hiddenBehindLeft || hiddenBehindRight) {
1643
1690
  ctx.restore();
1644
1691
  return;
1645
1692
  }
1646
- const borderLeft = x <= 0 ? 0 : Math.max(x - borderWidth, visibleLeft);
1647
- const borderRight = Math.min(x + selectionWidth - 1, selectionAreaRight - borderWidth, width - borderWidth);
1648
- const borderTop = Math.max(y - borderWidth, selectionClipTop);
1649
- const borderBottom = Math.min(y + selectionHeight, height - borderWidth);
1693
+ const borderLeft = outline.left;
1694
+ const borderRight = outline.right - borderWidth;
1695
+ const borderTop = outline.top;
1696
+ const borderBottom = outline.bottom - borderWidth;
1650
1697
  const borderOuterWidth = borderRight + borderWidth - borderLeft;
1651
1698
  ctx.fillRect(borderLeft, borderTop, borderOuterWidth, borderWidth);
1652
1699
  ctx.fillRect(borderLeft, borderBottom, borderOuterWidth, borderWidth);
@@ -1658,11 +1705,11 @@ function paintGrid(options) {
1658
1705
  }
1659
1706
 
1660
1707
  // src/hooks/useControllable.ts
1661
- import { useCallback, useState as useState5 } from "react";
1708
+ import { useCallback as useCallback2, useState as useState5 } from "react";
1662
1709
  function useControllableKeys(value, defaultValue, onChange) {
1663
1710
  const [internal, setInternal] = useState5(defaultValue ?? []);
1664
1711
  const keys = value === void 0 ? internal : value;
1665
- const setKeys = useCallback((next) => {
1712
+ const setKeys = useCallback2((next) => {
1666
1713
  if (value === void 0) setInternal(next);
1667
1714
  onChange?.(next);
1668
1715
  }, [onChange, value]);
@@ -1671,7 +1718,7 @@ function useControllableKeys(value, defaultValue, onChange) {
1671
1718
  function useControllableValue(value, defaultValue, onChange) {
1672
1719
  const [internal, setInternal] = useState5(defaultValue ?? null);
1673
1720
  const selected = value === void 0 ? internal : value;
1674
- const setSelected = useCallback((next) => {
1721
+ const setSelected = useCallback2((next) => {
1675
1722
  if (value === void 0) setInternal(next);
1676
1723
  onChange?.(next);
1677
1724
  }, [onChange, value]);
@@ -2141,7 +2188,7 @@ function TableInner({
2141
2188
  if (headerTooltipTimerRef.current !== null) clearTimeout(headerTooltipTimerRef.current);
2142
2189
  if (cellTooltipTimerRef.current !== null) clearTimeout(cellTooltipTimerRef.current);
2143
2190
  }, []);
2144
- const measureCustomHeaderHeight = useCallback2(() => {
2191
+ const measureCustomHeaderHeight = useCallback3(() => {
2145
2192
  const nextHeights = Array.from({ length: headerDepth }, () => baseHeaderHeight);
2146
2193
  customHeaderContentRefs.current.forEach((node) => {
2147
2194
  const headerCell = node.closest(".rvg-header-title");
@@ -2192,7 +2239,7 @@ function TableInner({
2192
2239
  const [hoveredHeaderAction, setHoveredHeaderAction] = useState6(null);
2193
2240
  const [visibleHeaderTooltip, setVisibleHeaderTooltip] = useState6(null);
2194
2241
  const [hoveredCellTooltip, setHoveredCellTooltip] = useState6(null);
2195
- const hideDragTooltips = useCallback2(() => {
2242
+ const hideDragTooltips = useCallback3(() => {
2196
2243
  if (headerTooltipTimerRef.current !== null) {
2197
2244
  clearTimeout(headerTooltipTimerRef.current);
2198
2245
  headerTooltipTimerRef.current = null;
@@ -2219,10 +2266,10 @@ function TableInner({
2219
2266
  const [insertedRowKeys, setInsertedRowKeys] = useState6(() => /* @__PURE__ */ new Set());
2220
2267
  const [rowOrderKeys, setRowOrderKeys] = useState6(null);
2221
2268
  const settledPendingInsertIdsRef = useRef4(/* @__PURE__ */ new Set());
2222
- const getDataRowKey = useCallback2((row, index) => {
2269
+ const getDataRowKey = useCallback3((row, index) => {
2223
2270
  return typeof rowKey === "function" ? rowKey(row, index) : rowKey ? row[rowKey] : getDefaultRowKey(row, index);
2224
2271
  }, [rowKey]);
2225
- const getSourceRowIndexByKey = useCallback2((key, preferredIndex) => {
2272
+ const getSourceRowIndexByKey = useCallback3((key, preferredIndex) => {
2226
2273
  const preferredRow = sourceRows[preferredIndex];
2227
2274
  if (preferredRow && getDataRowKey(preferredRow, preferredIndex) === key) return preferredIndex;
2228
2275
  const start = Math.max(0, preferredIndex - 8);
@@ -2293,7 +2340,7 @@ function TableInner({
2293
2340
  return result * direction;
2294
2341
  });
2295
2342
  }, [columns, filteredRows, language, onSortChange, sortState]);
2296
- const resolveSelectionTarget = useCallback2((target) => {
2343
+ const resolveSelectionTarget = useCallback3((target) => {
2297
2344
  if (target == null) return target;
2298
2345
  const columnIndex = columns.findIndex((column) => column.key === target.columnKey);
2299
2346
  const rowIndex = target.rowKey !== void 0 ? rows.findIndex((row2, index) => getDataRowKey(row2, index) === target.rowKey) : target.rowIndex ?? -1;
@@ -2308,7 +2355,7 @@ function TableInner({
2308
2355
  }, [columns, getDataRowKey, rows]);
2309
2356
  const resolvedSelectedCell = useMemo2(() => resolveSelectionTarget(selectedCell), [resolveSelectionTarget, selectedCell]);
2310
2357
  const resolvedDefaultSelectedCell = useMemo2(() => resolveSelectionTarget(defaultSelectedCell), [defaultSelectedCell, resolveSelectionTarget]);
2311
- const handleSelectedCellChange = useCallback2((next) => {
2358
+ const handleSelectedCellChange = useCallback3((next) => {
2312
2359
  if (!onSelectedCellChange) return;
2313
2360
  if (!next) {
2314
2361
  onSelectedCellChange(null);
@@ -2337,7 +2384,7 @@ function TableInner({
2337
2384
  document.addEventListener("pointerdown", handleOutsidePointerDown);
2338
2385
  return () => document.removeEventListener("pointerdown", handleOutsidePointerDown);
2339
2386
  }, [selection, setSelection]);
2340
- const applyRowOrder = useCallback2((sourceIndex, targetIndex) => {
2387
+ const applyRowOrder = useCallback3((sourceIndex, targetIndex) => {
2341
2388
  if (sourceIndex === targetIndex || sourceIndex < 0 || targetIndex < 0 || sourceIndex >= rows.length || targetIndex >= rows.length) return;
2342
2389
  const nextEntries = rows.map((row, index) => ({ row, key: getDataRowKey(row, index) }));
2343
2390
  const [entry] = nextEntries.splice(sourceIndex, 1);
@@ -2346,7 +2393,7 @@ function TableInner({
2346
2393
  setRowOrderKeys(nextEntries.map(({ key }) => key));
2347
2394
  onRowsReorder?.(nextRows, { sourceIndex, targetIndex });
2348
2395
  }, [getDataRowKey, onRowsReorder, rows]);
2349
- const applyColumnOrder = useCallback2((sourceIndex, targetIndex, detail) => {
2396
+ const applyColumnOrder = useCallback3((sourceIndex, targetIndex, detail) => {
2350
2397
  const nextColumns = reorderColumns(sourceColumns, detail);
2351
2398
  setSourceColumns(nextColumns);
2352
2399
  onColumnsReorder?.(nextColumns, { sourceIndex, targetIndex, ...detail });
@@ -2419,7 +2466,7 @@ function TableInner({
2419
2466
  }
2420
2467
  return lefts;
2421
2468
  }, [columns, fixedWidth, metrics]);
2422
- const getScrollableColumnLeft = useCallback2((columnIndex) => scrollableColumnLefts[columnIndex] ?? fixedWidth, [fixedWidth, scrollableColumnLefts]);
2469
+ const getScrollableColumnLeft = useCallback3((columnIndex) => scrollableColumnLefts[columnIndex] ?? fixedWidth, [fixedWidth, scrollableColumnLefts]);
2423
2470
  const hasRowSelectionColumn = useMemo2(() => columns.some((column) => column.rowSelection), [columns]);
2424
2471
  const rowSelectionMode = typeof rowSelection === "object" ? rowSelection.mode ?? "multiple" : "multiple";
2425
2472
  const summarySignature = useMemo2(() => getSummarySignature(columns), [columns]);
@@ -2472,7 +2519,7 @@ function TableInner({
2472
2519
  const rowScrollTop = fixedHeader ? currentScroll2.top : Math.max(0, currentScroll2.top - bodyTop);
2473
2520
  return getViewportRange(currentScroll2.left, rowScrollTop, viewport.width, bodyViewportHeight, rows.length, rowHeight, metrics, virtualOverscan);
2474
2521
  }, [bodyTop, bodyViewportHeight, columns.length, fixedHeader, isVirtualized, metrics, rowHeight, rows.length, scrollPosition, viewport.width, virtualOverscan]);
2475
- const getRowKey = useCallback2((row, index) => {
2522
+ const getRowKey = useCallback3((row, index) => {
2476
2523
  const key = getDataRowKey(row, index);
2477
2524
  rowByKeyRef.current.set(key, row);
2478
2525
  rowIndexByKeyRef.current.set(key, index);
@@ -2541,7 +2588,7 @@ function TableInner({
2541
2588
  const selectedRowKeySet = useMemo2(() => new Set(rowKeys), [rowKeys]);
2542
2589
  const selectedColumnKeySet = useMemo2(() => new Set(columnKeys), [columnKeys]);
2543
2590
  const insertedRowKeySet = useMemo2(() => insertedRowKeys, [insertedRowKeys]);
2544
- const measureHeaderTitleWidth = useCallback2((columnIndex) => {
2591
+ const measureHeaderTitleWidth = useCallback3((columnIndex) => {
2545
2592
  const title = columns[columnIndex]?.title ?? "";
2546
2593
  const context = canvasRef.current?.getContext("2d");
2547
2594
  if (!context) return Array.from(title).reduce((width3, character) => width3 + (/^[\x00-\x7F]$/.test(character) ? 7 : 13), 0);
@@ -2551,7 +2598,7 @@ function TableInner({
2551
2598
  context.restore();
2552
2599
  return width2;
2553
2600
  }, [columns]);
2554
- const getCellLabel = useCallback2((rowIndex, columnIndex) => {
2601
+ const getCellLabel = useCallback3((rowIndex, columnIndex) => {
2555
2602
  const row = rows[rowIndex];
2556
2603
  const column = columns[columnIndex];
2557
2604
  if (!row || !column || column.rowSelection || column.rowDragHandle) return "";
@@ -2562,8 +2609,8 @@ function TableInner({
2562
2609
  return "Render error";
2563
2610
  }
2564
2611
  }, [columns, rows]);
2565
- const getCellSpan = useCallback2((rowIndex, columnIndex) => cellSpanLookup.covered.get(getCellCoordKey2(rowIndex, columnIndex)), [cellSpanLookup]);
2566
- const getCellDisplayWidth = useCallback2((columnIndex, colSpan = 1) => {
2612
+ const getCellSpan = useCallback3((rowIndex, columnIndex) => cellSpanLookup.covered.get(getCellCoordKey2(rowIndex, columnIndex)), [cellSpanLookup]);
2613
+ const getCellDisplayWidth = useCallback3((columnIndex, colSpan = 1) => {
2567
2614
  let width2 = 0;
2568
2615
  for (let index = columnIndex; index < Math.min(columns.length, columnIndex + colSpan); index += 1) {
2569
2616
  width2 += metrics[index]?.width ?? 0;
@@ -2578,7 +2625,7 @@ function TableInner({
2578
2625
  if (nextRowIndex === selection.rowIndex && nextColumnIndex === selection.columnIndex) return;
2579
2626
  setSelection({ ...selection, rowIndex: nextRowIndex, columnIndex: nextColumnIndex });
2580
2627
  }, [columns, getRowKey, rows, selection, setSelection]);
2581
- const draw = useCallback2(() => {
2628
+ const draw = useCallback3(() => {
2582
2629
  frameRef.current = null;
2583
2630
  const canvas = canvasRef.current;
2584
2631
  if (!canvas || viewport.width <= 0) return;
@@ -2624,15 +2671,15 @@ function TableInner({
2624
2671
  const range = isVirtualized ? getViewportRange(scroll.left, rowScrollTop, viewport.width, bodyViewportHeight, rows.length, rowHeight, metrics, virtualOverscan) : { rowStart: 0, rowEnd: rows.length, columnStart: 0, columnEnd: columns.length };
2625
2672
  paintGrid({ context, width: viewport.width, height: renderHeight, pixelRatio: ratio, scrollLeft: scroll.left, scrollTop: scroll.top, rowHeight, bodyFontSize, headerActionSlotWidth, headerHeight, headerLeafTop, headerLeafHeight, bodyTop, suppressLastRowBottomBorder: bottomSummaryHeight > 0, suppressFrameBottomBorder: bottomSummaryHeight > 0, fixedHeader, verticalBorderless: !hasVerticalBorders, horizontalBorderless, frameBorderless, extendVerticalGridLines: !autoHeight, striped: hasStripedRows, columnDraggable, sortState, filterValues, hoveredHeaderAction: hoveredHeaderActionRef.current, rows, rowStyle, columns, metrics, range, selection, editing, hoveredRowIndex: hoveredRowIndexRef.current, selectionRange, selectedRowKeys: selectedRowKeySet, rowSelectionMode, selectedColumnKeys: selectedColumnKeySet, cellSpans: cellSpanLookup.covered, maxRowSpan: cellSpanLookup.maxRowSpan, highlightEditedCells: highlightsEditedCells, highlightInsertedRows: highlightsInsertedRows, insertedRowKeys: insertedRowKeySet, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget, resolveColor: (color) => resolveCanvasColor(themeStyles, color), colors: themeColors });
2626
2673
  }, [autoHeight, bodyTop, bodyViewportHeight, bottomSummaryHeight, cellAnnotations, cellSpanLookup, columnDragPreview, columnDraggable, columnDropTarget, columns, editedCellHighlightColor, editedCellKeys, editing, renderHeight, filterValues, fixedHeader, frameBorderless, getRowKey, hasStripedRows, hasVerticalBorders, headerActionSlotWidth, headerDepth, headerHeight, headerLeafHeight, headerLeafTop, horizontalBorderless, highlightsEditedCells, highlightsInsertedRows, insertedRowHighlightColor, insertedRowKeySet, isVirtualized, metrics, rowDragPreview, rowHeight, rowSelectionMode, rowStyle, rows, selectedColumnKeySet, selectedRowKeySet, selection, selectionRange, sortState, stripedColor, viewport.width, virtualOverscan]);
2627
- const scheduleDraw = useCallback2(() => {
2674
+ const scheduleDraw = useCallback3(() => {
2628
2675
  if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
2629
2676
  }, [draw]);
2630
- const drawImmediately = useCallback2(() => {
2677
+ const drawImmediately = useCallback3(() => {
2631
2678
  if (frameRef.current !== null) cancelAnimationFrame(frameRef.current);
2632
2679
  frameRef.current = null;
2633
2680
  draw();
2634
2681
  }, [draw]);
2635
- const getSelectionHorizontalVisibility = useCallback2((scrollLeft) => {
2682
+ const getSelectionHorizontalVisibility = useCallback3((scrollLeft) => {
2636
2683
  if (!selection || selectionRange) return "visible";
2637
2684
  const column = columns[selection.columnIndex];
2638
2685
  if (!column || column.fixed !== void 0) return "visible";
@@ -2643,7 +2690,7 @@ function TableInner({
2643
2690
  if (left >= viewport.width - rightFixedWidth) return "hidden-right";
2644
2691
  return "visible";
2645
2692
  }, [columns, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, rightFixedWidth, selection, selectionRange, viewport.width]);
2646
- const getSelectionEdgeIndicator = useCallback2((scrollLeft, scrollTop) => {
2693
+ const getSelectionEdgeIndicator = useCallback3((scrollLeft, scrollTop) => {
2647
2694
  if (!selection || selectionRange) return null;
2648
2695
  const row = rows[selection.rowIndex];
2649
2696
  const metric = metrics[selection.columnIndex];
@@ -2666,14 +2713,17 @@ function TableInner({
2666
2713
  const cornerLength = 10;
2667
2714
  const hitSlop = 6;
2668
2715
  const targetSize = borderWidth + hitSlop * 2;
2669
- const rightBoundaryInset = rightFixedWidth > 0 && hasVerticalBorders ? 1 : 0;
2670
- const markerX = hiddenLeft ? horizontalStart : horizontalEnd - borderWidth - rightBoundaryInset;
2671
- const markerY = hiddenTop ? verticalStart : renderHeight - borderWidth;
2716
+ const leftBoundary = horizontalStart - borderWidth;
2717
+ const rightBoundary = horizontalEnd - 1;
2718
+ const topBoundary = verticalStart - borderWidth;
2719
+ const bottomBoundary = renderHeight;
2720
+ const markerX = hiddenLeft ? leftBoundary : rightBoundary;
2721
+ const markerY = hiddenTop ? topBoundary : bottomBoundary;
2672
2722
  if (hiddenLeft || hiddenRight) {
2673
- let markerTop = Math.max(rawTop - borderWidth, verticalStart);
2674
- let markerBottom = Math.min(rawBottom + 1, renderHeight);
2675
- const topClip = Math.max(0, verticalStart - (rawTop - borderWidth));
2676
- const bottomClip = Math.max(0, rawBottom + 1 - renderHeight);
2723
+ const markerTop = Math.max(rawTop - borderWidth, topBoundary);
2724
+ const markerBottom = Math.min(rawBottom + borderWidth, renderHeight + borderWidth);
2725
+ const topClip = Math.max(0, verticalStart - rawTop);
2726
+ const bottomClip = Math.max(0, rawBottom - renderHeight);
2677
2727
  if (topClip > 0 || bottomClip > 0) {
2678
2728
  const foldAtTop = topClip > 0;
2679
2729
  const fold = Math.min(cornerLength, foldAtTop ? topClip : bottomClip);
@@ -2682,7 +2732,7 @@ function TableInner({
2682
2732
  const cornerHeight = Math.max(cornerLength, markerBottom - markerTop);
2683
2733
  const cornerOnLeft = hiddenLeft;
2684
2734
  const shapeLeft = cornerOnLeft ? markerX : markerX + borderWidth - cornerWidth;
2685
- const shapeTop = foldAtTop ? verticalStart : renderHeight - cornerHeight;
2735
+ const shapeTop = foldAtTop ? topBoundary : renderHeight + borderWidth - cornerHeight;
2686
2736
  return {
2687
2737
  side: `${foldAtTop ? "top" : "bottom"}-${cornerOnLeft ? "left" : "right"}`,
2688
2738
  orientation: "corner",
@@ -2709,19 +2759,19 @@ function TableInner({
2709
2759
  }
2710
2760
  };
2711
2761
  }
2712
- const horizontalMarkerEnd = horizontalEnd - rightBoundaryInset;
2713
- let markerLeft = Math.max(rawLeft - borderWidth, horizontalStart);
2714
- let markerRight = Math.min(rawRight + 1, horizontalMarkerEnd);
2715
- const leftClip = Math.max(0, horizontalStart - (rawLeft - borderWidth));
2716
- const rightClip = Math.max(0, rawRight + 1 - horizontalMarkerEnd);
2762
+ const horizontalMarkerEnd = horizontalEnd + 1;
2763
+ const markerLeft = Math.max(rawLeft - borderWidth, leftBoundary);
2764
+ const markerRight = Math.min(rawRight + 1, horizontalMarkerEnd);
2765
+ const leftClip = Math.max(0, horizontalStart - rawLeft);
2766
+ const rightClip = Math.max(0, rawRight - horizontalEnd);
2717
2767
  if (leftClip > 0 || rightClip > 0) {
2718
2768
  const foldAtLeft = leftClip > 0;
2719
2769
  const fold = Math.min(cornerLength, foldAtLeft ? leftClip : rightClip);
2720
2770
  if (fold > borderWidth) {
2721
2771
  const cornerWidth = Math.max(cornerLength, markerRight - markerLeft);
2722
2772
  const cornerHeight = fold;
2723
- const shapeLeft = foldAtLeft ? horizontalStart : horizontalMarkerEnd - cornerWidth;
2724
- const shapeTop = hiddenTop ? verticalStart : renderHeight - cornerHeight;
2773
+ const shapeLeft = foldAtLeft ? leftBoundary : horizontalMarkerEnd - cornerWidth;
2774
+ const shapeTop = hiddenTop ? topBoundary : renderHeight + borderWidth - cornerHeight;
2725
2775
  return {
2726
2776
  side: `${hiddenTop ? "top" : "bottom"}-${foldAtLeft ? "left" : "right"}`,
2727
2777
  orientation: "corner",
@@ -2747,8 +2797,8 @@ function TableInner({
2747
2797
  height: targetSize
2748
2798
  }
2749
2799
  };
2750
- }, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, hasVerticalBorders, leftFixedOffsets, metrics, renderHeight, rightFixedOffsets, rightFixedWidth, rowHeight, rows, selection, selectionRange, viewport.width]);
2751
- const syncSelectionEdgeTarget = useCallback2((scrollLeft, scrollTop) => {
2800
+ }, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, leftFixedOffsets, metrics, renderHeight, rightFixedOffsets, rightFixedWidth, rowHeight, rows, selection, selectionRange, viewport.width]);
2801
+ const syncSelectionEdgeTarget = useCallback3((scrollLeft, scrollTop) => {
2752
2802
  const target = selectionEdgeTargetRef.current;
2753
2803
  if (!target) return;
2754
2804
  const indicator = getSelectionEdgeIndicator(scrollLeft, scrollTop);
@@ -2870,7 +2920,7 @@ function TableInner({
2870
2920
  scroller.addEventListener("scroll", lockScroll);
2871
2921
  return () => scroller.removeEventListener("scroll", lockScroll);
2872
2922
  }, [insertBusy]);
2873
- const showCustomScrollbar = useCallback2((axis, persist = false) => {
2923
+ const showCustomScrollbar = useCallback3((axis, persist = false) => {
2874
2924
  const showVertical = axis === "vertical" || axis === "both";
2875
2925
  const showHorizontal = axis === "horizontal" || axis === "both";
2876
2926
  if (showVertical) {
@@ -2894,15 +2944,15 @@ function TableInner({
2894
2944
  }
2895
2945
  }
2896
2946
  }, []);
2897
- const keepCustomScrollbarVisible = useCallback2((axis) => {
2947
+ const keepCustomScrollbarVisible = useCallback3((axis) => {
2898
2948
  showCustomScrollbar(axis, true);
2899
2949
  }, [showCustomScrollbar]);
2900
- const releaseCustomScrollbarVisible = useCallback2((axis) => {
2950
+ const releaseCustomScrollbarVisible = useCallback3((axis) => {
2901
2951
  if (axis === "vertical" && verticalScrollbarDragRef.current) return;
2902
2952
  if (axis === "horizontal" && horizontalScrollbarDragRef.current) return;
2903
2953
  showCustomScrollbar(axis);
2904
2954
  }, [showCustomScrollbar]);
2905
- const updateCustomScrollbars = useCallback2(() => {
2955
+ const updateCustomScrollbars = useCallback3(() => {
2906
2956
  const scroller = scrollerRef.current;
2907
2957
  const verticalTrack = verticalScrollbarRef.current;
2908
2958
  const verticalThumb = verticalScrollbarThumbRef.current;
@@ -2955,7 +3005,7 @@ function TableInner({
2955
3005
  useLayoutEffect3(() => {
2956
3006
  updateCustomScrollbars();
2957
3007
  }, [contentHeight, contentWidth, updateCustomScrollbars, viewport.height, viewport.width]);
2958
- const handleVerticalScrollbarPointerDown = useCallback2((event) => {
3008
+ const handleVerticalScrollbarPointerDown = useCallback3((event) => {
2959
3009
  const scroller = scrollerRef.current;
2960
3010
  const track = verticalScrollbarRef.current;
2961
3011
  const thumb = verticalScrollbarThumbRef.current;
@@ -2992,7 +3042,7 @@ function TableInner({
2992
3042
  maxScrollTop
2993
3043
  };
2994
3044
  }, [showCustomScrollbar, updateCustomScrollbars]);
2995
- const handleVerticalScrollbarPointerMove = useCallback2((event) => {
3045
+ const handleVerticalScrollbarPointerMove = useCallback3((event) => {
2996
3046
  const drag = verticalScrollbarDragRef.current;
2997
3047
  const scroller = scrollerRef.current;
2998
3048
  if (!drag || !scroller || drag.pointerId !== event.pointerId) return;
@@ -3002,14 +3052,14 @@ function TableInner({
3002
3052
  scroller.scrollTop = nextThumbTop / maxThumbTop * drag.maxScrollTop;
3003
3053
  updateCustomScrollbars();
3004
3054
  }, [updateCustomScrollbars]);
3005
- const handleVerticalScrollbarPointerUp = useCallback2((event) => {
3055
+ const handleVerticalScrollbarPointerUp = useCallback3((event) => {
3006
3056
  const drag = verticalScrollbarDragRef.current;
3007
3057
  if (!drag || drag.pointerId !== event.pointerId) return;
3008
3058
  if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
3009
3059
  verticalScrollbarDragRef.current = null;
3010
3060
  showCustomScrollbar("vertical");
3011
3061
  }, [showCustomScrollbar]);
3012
- const handleHorizontalScrollbarPointerDown = useCallback2((event) => {
3062
+ const handleHorizontalScrollbarPointerDown = useCallback3((event) => {
3013
3063
  const scroller = scrollerRef.current;
3014
3064
  const track = horizontalScrollbarRef.current;
3015
3065
  const thumb = horizontalScrollbarThumbRef.current;
@@ -3052,7 +3102,7 @@ function TableInner({
3052
3102
  maxScrollLeft
3053
3103
  };
3054
3104
  }, [drawImmediately, getSelectionHorizontalVisibility, showCustomScrollbar, syncSelectionEdgeTarget, updateCustomScrollbars]);
3055
- const handleHorizontalScrollbarPointerMove = useCallback2((event) => {
3105
+ const handleHorizontalScrollbarPointerMove = useCallback3((event) => {
3056
3106
  const drag = horizontalScrollbarDragRef.current;
3057
3107
  const scroller = scrollerRef.current;
3058
3108
  if (!drag || !scroller || drag.pointerId !== event.pointerId) return;
@@ -3068,7 +3118,7 @@ function TableInner({
3068
3118
  if (visibilityChanged) drawImmediately();
3069
3119
  updateCustomScrollbars();
3070
3120
  }, [drawImmediately, getSelectionHorizontalVisibility, syncSelectionEdgeTarget, updateCustomScrollbars]);
3071
- const handleHorizontalScrollbarPointerUp = useCallback2((event) => {
3121
+ const handleHorizontalScrollbarPointerUp = useCallback3((event) => {
3072
3122
  const drag = horizontalScrollbarDragRef.current;
3073
3123
  if (!drag || drag.pointerId !== event.pointerId) return;
3074
3124
  if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
@@ -3082,7 +3132,7 @@ function TableInner({
3082
3132
  clip.style.transform = "";
3083
3133
  });
3084
3134
  }, [scrollPosition.top]);
3085
- const handleScroll = useCallback2(() => {
3135
+ const handleScroll = useCallback3(() => {
3086
3136
  const element = scrollerRef.current;
3087
3137
  if (!element) return;
3088
3138
  const previousScroll = scrollRef.current;
@@ -3117,11 +3167,20 @@ function TableInner({
3117
3167
  if (rawRight <= horizontalStart || rawLeft >= horizontalEnd || rawBottom <= verticalStart || rawTop >= renderHeight) {
3118
3168
  focus.style.display = "none";
3119
3169
  } else {
3120
- const borderWidth = 2;
3121
- const left = Math.round(Math.max(rawLeft - borderWidth, horizontalStart));
3122
- const right = Math.round(Math.min(rawRight + 1, horizontalEnd, viewport.width));
3123
- const top = Math.round(Math.max(rawTop - borderWidth, verticalStart));
3124
- const bottom = Math.round(Math.min(rawBottom + borderWidth, renderHeight));
3170
+ const bounds = getSelectionOutlineBounds({
3171
+ left: rawLeft,
3172
+ right: rawRight,
3173
+ top: rawTop,
3174
+ bottom: rawBottom,
3175
+ horizontalStart,
3176
+ horizontalEnd,
3177
+ verticalStart,
3178
+ verticalEnd: renderHeight
3179
+ });
3180
+ const left = Math.round(bounds.left);
3181
+ const right = Math.round(bounds.right);
3182
+ const top = Math.round(bounds.top);
3183
+ const bottom = Math.round(bounds.bottom);
3125
3184
  focus.style.display = "block";
3126
3185
  focus.style.left = `${left}px`;
3127
3186
  focus.style.top = `${top}px`;
@@ -3150,7 +3209,7 @@ function TableInner({
3150
3209
  setHoveredCellTooltip(null);
3151
3210
  scheduleDraw();
3152
3211
  }, [bodyTop, columns, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, metrics, rightFixedOffsets, rightFixedWidth, rowHeight, rows, scheduleDraw, selection, selectionRange, showCustomScrollbar, syncSelectionEdgeTarget, updateCustomScrollbars, viewport.width]);
3153
- const locateColumn = useCallback2((clientX) => {
3212
+ const locateColumn = useCallback3((clientX) => {
3154
3213
  const canvas = canvasRef.current;
3155
3214
  if (!canvas) return -1;
3156
3215
  const rect = canvas.getBoundingClientRect();
@@ -3178,7 +3237,7 @@ function TableInner({
3178
3237
  }
3179
3238
  return columnIndex;
3180
3239
  }, [columns, fixedWidth, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, rightFixedWidth, viewport.width]);
3181
- const getDisplayedColumnLeft = useCallback2((columnIndex) => {
3240
+ const getDisplayedColumnLeft = useCallback3((columnIndex) => {
3182
3241
  const metric = metrics[columnIndex];
3183
3242
  if (columns[columnIndex].fixed === "left") return leftFixedOffsets.get(columnIndex) ?? 0;
3184
3243
  if (columns[columnIndex].fixed === "right") return viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metric.width;
@@ -3188,7 +3247,7 @@ function TableInner({
3188
3247
  const displayedContentRight = columns.reduce((right, _column, columnIndex) => Math.max(right, getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width), 0);
3189
3248
  return displayedContentRight > 0 && displayedContentRight < viewport.width ? Math.round(displayedContentRight) - 1 : null;
3190
3249
  }, [columns, getDisplayedColumnLeft, metrics, scrollPosition.left, viewport.width]);
3191
- const getHeaderLevelAtY = useCallback2((localY, headerY) => {
3250
+ const getHeaderLevelAtY = useCallback3((localY, headerY) => {
3192
3251
  const y = localY - headerY;
3193
3252
  for (let level = 0; level < headerRowHeights.length; level += 1) {
3194
3253
  const top = headerRowOffsets[level] ?? 0;
@@ -3196,11 +3255,11 @@ function TableInner({
3196
3255
  }
3197
3256
  return headerDepth - 1;
3198
3257
  }, [headerDepth, headerRowHeights, headerRowOffsets]);
3199
- const resizeColumn = useCallback2((columnKey, width2) => {
3258
+ const resizeColumn = useCallback3((columnKey, width2) => {
3200
3259
  setResizedColumnWidths((current) => current[columnKey] === width2 ? current : { ...current, [columnKey]: width2 });
3201
3260
  onColumnResize?.(columnKey, width2);
3202
3261
  }, [onColumnResize]);
3203
- const locateHeaderAction = useCallback2((clientX, clientY, columnIndex) => {
3262
+ const locateHeaderAction = useCallback3((clientX, clientY, columnIndex) => {
3204
3263
  if (columnIndex < 0 || !canvasRef.current) return null;
3205
3264
  const column = columns[columnIndex];
3206
3265
  if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
@@ -3220,7 +3279,7 @@ function TableInner({
3220
3279
  if (visibleActions.filter && localX >= right - headerActionSlotWidth && localX < right) return "filter";
3221
3280
  return null;
3222
3281
  }, [columnDraggable, columns, fixedHeader, getDisplayedColumnLeft, headerActionSize, headerActionSlotWidth, headerLeafHeight, headerLeafTop, measureHeaderTitleWidth, metrics]);
3223
- const isHeaderTitleTruncated = useCallback2((columnIndex) => {
3282
+ const isHeaderTitleTruncated = useCallback3((columnIndex) => {
3224
3283
  const canvas = canvasRef.current;
3225
3284
  if (columnIndex < 0 || !canvas) return false;
3226
3285
  const column = columns[columnIndex];
@@ -3230,7 +3289,7 @@ function TableInner({
3230
3289
  const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
3231
3290
  return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
3232
3291
  }, [columnDraggable, columns, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
3233
- const locateHeaderDragHandle = useCallback2((clientX, clientY, columnIndex) => {
3292
+ const locateHeaderDragHandle = useCallback3((clientX, clientY, columnIndex) => {
3234
3293
  if (!columnDraggable || columnIndex < 0 || !canvasRef.current) return false;
3235
3294
  const column = columns[columnIndex];
3236
3295
  if (column.rowSelection || column.rowDragHandle || column.rowNumber) return false;
@@ -3244,14 +3303,14 @@ function TableInner({
3244
3303
  const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
3245
3304
  return localX >= columnRight - headerActionSlotWidth && localX < columnRight - 2;
3246
3305
  }, [columnDraggable, columns, fixedHeader, getDisplayedColumnLeft, headerActionSize, headerActionSlotWidth, headerLeafHeight, headerLeafTop, measureHeaderTitleWidth, metrics]);
3247
- const getHeaderCellLeft = useCallback2((cell) => {
3306
+ const getHeaderCellLeft = useCallback3((cell) => {
3248
3307
  const startMetric = metrics[cell.startIndex];
3249
3308
  const fixedSide = columns[cell.startIndex]?.fixed;
3250
3309
  if (!startMetric) return 0;
3251
3310
  return fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex) - scrollRef.current.left;
3252
3311
  }, [columns, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, viewport.width]);
3253
- const getHeaderCellWidth = useCallback2((cell) => cell.leaf ? metrics[cell.startIndex]?.width ?? 0 : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1), [getCellDisplayWidth, metrics]);
3254
- const getHeaderCellEdgeFromMetrics = useCallback2((startIndex, endIndex, edge, nextMetrics) => {
3312
+ const getHeaderCellWidth = useCallback3((cell) => cell.leaf ? metrics[cell.startIndex]?.width ?? 0 : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1), [getCellDisplayWidth, metrics]);
3313
+ const getHeaderCellEdgeFromMetrics = useCallback3((startIndex, endIndex, edge, nextMetrics) => {
3255
3314
  const fixedSide = columns[startIndex]?.fixed;
3256
3315
  const width2 = nextMetrics.slice(startIndex, endIndex + 1).reduce((total, metric) => total + metric.width, 0);
3257
3316
  let left;
@@ -3275,7 +3334,7 @@ function TableInner({
3275
3334
  }
3276
3335
  return left + (edge === "right" ? width2 : 0);
3277
3336
  }, [columns, fixedWidth, viewport.width]);
3278
- const locateHeaderResizeHit = useCallback2((clientX, clientY) => {
3337
+ const locateHeaderResizeHit = useCallback3((clientX, clientY) => {
3279
3338
  if (!columnResizable || !canvasRef.current) return null;
3280
3339
  const rect = canvasRef.current.getBoundingClientRect();
3281
3340
  const localX = clientX - rect.left;
@@ -3302,15 +3361,15 @@ function TableInner({
3302
3361
  }
3303
3362
  return closest;
3304
3363
  }, [columnResizable, columns, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, getHeaderLevelAtY, headerCells, headerHeight]);
3305
- const locateHeaderResizeCell = useCallback2((clientX, clientY) => locateHeaderResizeHit(clientX, clientY)?.cell ?? null, [locateHeaderResizeHit]);
3306
- const locateHeaderCellDragHandle = useCallback2((clientX, clientY, cell) => {
3364
+ const locateHeaderResizeCell = useCallback3((clientX, clientY) => locateHeaderResizeHit(clientX, clientY)?.cell ?? null, [locateHeaderResizeHit]);
3365
+ const locateHeaderCellDragHandle = useCallback3((clientX, clientY, cell) => {
3307
3366
  if (!columnDraggable || !canvasRef.current) return false;
3308
3367
  if (cell.leaf) return locateHeaderDragHandle(clientX, clientY, cell.startIndex);
3309
3368
  const localX = clientX - canvasRef.current.getBoundingClientRect().left;
3310
3369
  const right = getHeaderCellLeft(cell) + getHeaderCellWidth(cell);
3311
3370
  return localX >= right - headerActionSlotWidth && localX < right - 2;
3312
3371
  }, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, locateHeaderDragHandle]);
3313
- const locateHeaderCell = useCallback2((clientX, clientY) => {
3372
+ const locateHeaderCell = useCallback3((clientX, clientY) => {
3314
3373
  const canvas = canvasRef.current;
3315
3374
  if (!canvas) return null;
3316
3375
  const rect = canvas.getBoundingClientRect();
@@ -3327,7 +3386,7 @@ function TableInner({
3327
3386
  }
3328
3387
  return null;
3329
3388
  }, [fixedHeader, getHeaderCellLeft, getHeaderCellWidth, getHeaderLevelAtY, headerCells, headerHeight]);
3330
- const setDragGuide = useCallback2((x, top = 0) => {
3389
+ const setDragGuide = useCallback3((x, top = 0) => {
3331
3390
  const guide = dragGuideRef.current;
3332
3391
  if (!guide) return;
3333
3392
  guide.style.display = x === null ? "none" : "block";
@@ -3336,20 +3395,20 @@ function TableInner({
3336
3395
  guide.style.transform = `translateX(${Math.round(x)}px)`;
3337
3396
  }
3338
3397
  }, []);
3339
- const setRowDragGuide = useCallback2((y) => {
3398
+ const setRowDragGuide = useCallback3((y) => {
3340
3399
  const guide = rowDragGuideRef.current;
3341
3400
  if (!guide) return;
3342
3401
  guide.style.display = y === null ? "none" : "block";
3343
3402
  if (y !== null) guide.style.transform = `translateY(${Math.round(y)}px)`;
3344
3403
  }, []);
3345
- const locateRow = useCallback2((clientY) => {
3404
+ const locateRow = useCallback3((clientY) => {
3346
3405
  const canvas = canvasRef.current;
3347
3406
  if (!canvas) return -1;
3348
3407
  const localY = clientY - canvas.getBoundingClientRect().top;
3349
3408
  const rowIndex = Math.floor((localY - bodyTop + scrollRef.current.top) / rowHeight);
3350
3409
  return rowIndex >= 0 && rowIndex < rows.length ? rowIndex : -1;
3351
3410
  }, [bodyTop, rowHeight, rows.length]);
3352
- const handleRowOrderPointerDown = useCallback2((event) => {
3411
+ const handleRowOrderPointerDown = useCallback3((event) => {
3353
3412
  if (!rowDraggable || event.button !== 0 || rowOrderDragRef.current) return;
3354
3413
  const columnIndex = locateColumn(event.clientX);
3355
3414
  const sourceIndex = locateRow(event.clientY);
@@ -3363,7 +3422,7 @@ function TableInner({
3363
3422
  targetIndex: sourceIndex
3364
3423
  };
3365
3424
  }, [columns, locateColumn, locateRow, rowDraggable]);
3366
- const handleRowOrderPointerMove = useCallback2((event) => {
3425
+ const handleRowOrderPointerMove = useCallback3((event) => {
3367
3426
  const drag = rowOrderDragRef.current;
3368
3427
  if (!drag || drag.pointerId !== event.pointerId) return;
3369
3428
  if (!drag.active) {
@@ -3391,7 +3450,7 @@ function TableInner({
3391
3450
  setRowDragPreview(null);
3392
3451
  setRowDragGuide(rowTop + (edge === "bottom" ? rowHeight : 0));
3393
3452
  }, [bodyTop, hideDragTooltips, locateRow, renderHeight, rowHeight, rows.length, setRowDragGuide]);
3394
- const finishRowOrderPointerDrag = useCallback2((event, apply) => {
3453
+ const finishRowOrderPointerDrag = useCallback3((event, apply) => {
3395
3454
  const drag = rowOrderDragRef.current;
3396
3455
  if (!drag || drag.pointerId !== event.pointerId) return;
3397
3456
  if (event.currentTarget.hasPointerCapture?.(event.pointerId)) event.currentTarget.releasePointerCapture?.(event.pointerId);
@@ -3409,7 +3468,7 @@ function TableInner({
3409
3468
  });
3410
3469
  }
3411
3470
  }, [applyRowOrder, setRowDragGuide]);
3412
- const locateCell = useCallback2((clientX, clientY) => {
3471
+ const locateCell = useCallback3((clientX, clientY) => {
3413
3472
  const canvas = canvasRef.current;
3414
3473
  if (!canvas) return null;
3415
3474
  const rect = canvas.getBoundingClientRect();
@@ -3429,7 +3488,7 @@ function TableInner({
3429
3488
  columnKey: columns[targetColumnIndex].key
3430
3489
  };
3431
3490
  }, [bodyTop, columns, fixedHeader, getCellSpan, getRowKey, locateColumn, rowHeight, rows]);
3432
- const beginRangeDrag = useCallback2((event) => {
3491
+ const beginRangeDrag = useCallback3((event) => {
3433
3492
  if (!rangeSelection) return;
3434
3493
  if (event.button !== 0 || editing || event.target !== event.currentTarget) return;
3435
3494
  const cell = locateCell(event.clientX, event.clientY);
@@ -3438,7 +3497,7 @@ function TableInner({
3438
3497
  setSelectionRange(null);
3439
3498
  event.currentTarget.setPointerCapture(event.pointerId);
3440
3499
  }, [columns, editing, locateCell, rangeSelection]);
3441
- const updateRangeDrag = useCallback2((event) => {
3500
+ const updateRangeDrag = useCallback3((event) => {
3442
3501
  const drag = rangeDragRef.current;
3443
3502
  if (!drag) return;
3444
3503
  const focus = locateCell(event.clientX, event.clientY);
@@ -3448,7 +3507,7 @@ function TableInner({
3448
3507
  event.preventDefault();
3449
3508
  setSelectionRange((current) => current?.focus.rowIndex === focus.rowIndex && current.focus.columnIndex === focus.columnIndex ? current : { anchor: drag.anchor, focus });
3450
3509
  }, [columns, locateCell]);
3451
- const endRangeDrag = useCallback2((event) => {
3510
+ const endRangeDrag = useCallback3((event) => {
3452
3511
  const drag = rangeDragRef.current;
3453
3512
  if (!drag) return;
3454
3513
  rangeDragRef.current = null;
@@ -3458,7 +3517,7 @@ function TableInner({
3458
3517
  setSelection(drag.anchor);
3459
3518
  scrollerRef.current?.focus({ preventScroll: true });
3460
3519
  }, [setSelection]);
3461
- const selectRow = useCallback2((rowIndex, event, forceToggle = false) => {
3520
+ const selectRow = useCallback3((rowIndex, event, forceToggle = false) => {
3462
3521
  if (!rowSelection) return;
3463
3522
  clickedCellRef.current = null;
3464
3523
  setSelectionRange(null);
@@ -3478,7 +3537,7 @@ function TableInner({
3478
3537
  rowAnchorRef.current = rowIndex;
3479
3538
  setRowKeys(next);
3480
3539
  }, [getRowKey, rowKeys, rowSelection, rows, selectedRowKeySet, setRowKeys, setSelection]);
3481
- const selectColumn = useCallback2((columnIndex, event) => {
3540
+ const selectColumn = useCallback3((columnIndex, event) => {
3482
3541
  if (!columnSelection || columnIndex < 0) return;
3483
3542
  clickedCellRef.current = null;
3484
3543
  setSelectionRange(null);
@@ -3498,7 +3557,7 @@ function TableInner({
3498
3557
  columnAnchorRef.current = columnIndex;
3499
3558
  setColumnKeys(next);
3500
3559
  }, [columnKeys, columnSelection, columns, selectedColumnKeySet, setColumnKeys, setSelection]);
3501
- const toggleColumnFromMenu = useCallback2((columnIndex) => {
3560
+ const toggleColumnFromMenu = useCallback3((columnIndex) => {
3502
3561
  if (!columnSelection || columnIndex < 0) return;
3503
3562
  clickedCellRef.current = null;
3504
3563
  setSelectionRange(null);
@@ -3510,7 +3569,7 @@ function TableInner({
3510
3569
  columnAnchorRef.current = columnIndex;
3511
3570
  setColumnKeys(next);
3512
3571
  }, [columnKeys, columnSelection, columns, selectedColumnKeySet, setColumnKeys, setSelection]);
3513
- const revealCell = useCallback2((cell) => {
3572
+ const revealCell = useCallback3((cell) => {
3514
3573
  const scroller = scrollerRef.current;
3515
3574
  const metric = metrics[cell.columnIndex];
3516
3575
  const column = columns[cell.columnIndex];
@@ -3540,13 +3599,13 @@ function TableInner({
3540
3599
  scrollRef.current = { left: scroller.scrollLeft, top: scroller.scrollTop };
3541
3600
  scheduleDraw();
3542
3601
  }, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, scheduleDraw, viewport.width]);
3543
- const isCellEditable = useCallback2((cell) => {
3602
+ const isCellEditable = useCallback3((cell) => {
3544
3603
  const column = columns[cell.columnIndex];
3545
3604
  const row = rows[cell.rowIndex];
3546
3605
  if (!column || !row || column.dataIndex === void 0 || column.rowNumber || column.rowSelection || column.rowDragHandle) return false;
3547
3606
  return typeof column.editable === "function" ? column.editable(row[column.dataIndex], row, cell.rowIndex) : column.editable === true;
3548
3607
  }, [columns, rows]);
3549
- const beginEdit = useCallback2((cell) => {
3608
+ const beginEdit = useCallback3((cell) => {
3550
3609
  const column = columns[cell.columnIndex];
3551
3610
  if (!isCellEditable(cell) || column.dataIndex === void 0) return;
3552
3611
  const value = rows[cell.rowIndex]?.[column.dataIndex];
@@ -3616,7 +3675,7 @@ function TableInner({
3616
3675
  return next;
3617
3676
  });
3618
3677
  };
3619
- const commitEdit = useCallback2((nextDraft, close = true) => {
3678
+ const commitEdit = useCallback3((nextDraft, close = true) => {
3620
3679
  if (!editing) return;
3621
3680
  if (!isCellEditable(editing)) {
3622
3681
  setEditing(null);
@@ -3648,6 +3707,7 @@ function TableInner({
3648
3707
  options: column.editor.options,
3649
3708
  searchable: column.editor.searchable,
3650
3709
  allowCustomValue: column.editor.allowCustomValue,
3710
+ strictOptions: column.editor.strictOptions,
3651
3711
  maxDropdownHeight: column.editor.maxDropdownHeight,
3652
3712
  style: editorStyle,
3653
3713
  labels,
@@ -3720,7 +3780,7 @@ function TableInner({
3720
3780
  }
3721
3781
  );
3722
3782
  };
3723
- const handleKeyDown = useCallback2((event) => {
3783
+ const handleKeyDown = useCallback3((event) => {
3724
3784
  if (editing || !selection) return;
3725
3785
  if (event.key === "Enter") {
3726
3786
  event.preventDefault();
@@ -3793,7 +3853,7 @@ function TableInner({
3793
3853
  clipPath: `inset(${Math.max(0, visibleTop - cellTop)}px ${Math.max(0, cellLeft + cellWidth - visibleRight)}px ${Math.max(0, cellTop + cellHeight - visibleBottom)}px ${Math.max(0, visibleLeft - cellLeft)}px)`
3794
3854
  };
3795
3855
  }, [bodyTop, columns, editing, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, leftFixedOffsets, metrics, renderHeight, rightFixedOffsets, rightFixedWidth, rowHeight, rows, rowStyle, viewport.width]);
3796
- const handleColumnPointerDown = useCallback2((event) => {
3856
+ const handleColumnPointerDown = useCallback3((event) => {
3797
3857
  const rect = event.currentTarget.getBoundingClientRect();
3798
3858
  const localY = event.clientY - rect.top;
3799
3859
  const headerY = fixedHeader ? 0 : -scrollRef.current.top;
@@ -3837,7 +3897,7 @@ function TableInner({
3837
3897
  return;
3838
3898
  }
3839
3899
  }, [fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerHeight, headerRowOffsets, locateHeaderResizeHit, metrics]);
3840
- const handleColumnPointerMove = useCallback2((event) => {
3900
+ const handleColumnPointerMove = useCallback3((event) => {
3841
3901
  const drag = columnDragRef.current;
3842
3902
  if (!drag) return;
3843
3903
  const column = columns[drag.columnIndex];
@@ -3873,7 +3933,7 @@ function TableInner({
3873
3933
  resizeColumn(column.key, width2);
3874
3934
  setGuideFromWidths([width2]);
3875
3935
  }, [columnDraggable, columns, getHeaderCellEdgeFromMetrics, resizeColumn, viewport.width]);
3876
- const handleColumnPointerUp = useCallback2((event) => {
3936
+ const handleColumnPointerUp = useCallback3((event) => {
3877
3937
  const drag = columnDragRef.current;
3878
3938
  if (!drag) return;
3879
3939
  if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
@@ -3883,7 +3943,7 @@ function TableInner({
3883
3943
  document.documentElement.classList.remove("rvg-is-dragging");
3884
3944
  event.currentTarget.style.cursor = "default";
3885
3945
  }, []);
3886
- const clearColumnOrderPointerDrag = useCallback2((canvas) => {
3946
+ const clearColumnOrderPointerDrag = useCallback3((canvas) => {
3887
3947
  if (columnOrderLongPressTimerRef.current) {
3888
3948
  clearTimeout(columnOrderLongPressTimerRef.current);
3889
3949
  columnOrderLongPressTimerRef.current = null;
@@ -3896,7 +3956,7 @@ function TableInner({
3896
3956
  document.documentElement.classList.remove("rvg-is-dragging");
3897
3957
  canvas.style.cursor = "default";
3898
3958
  }, [setDragGuide]);
3899
- const updateColumnDragPreview = useCallback2((sourceCell, clientX, canvas) => {
3959
+ const updateColumnDragPreview = useCallback3((sourceCell, clientX, canvas) => {
3900
3960
  const rootRect = rootRef.current?.getBoundingClientRect() ?? canvas.getBoundingClientRect();
3901
3961
  const sourceWidth = metrics[sourceCell.startIndex]?.width ?? 100;
3902
3962
  const previewWidth = sourceWidth;
@@ -3908,7 +3968,7 @@ function TableInner({
3908
3968
  sourceLeft: getDisplayedColumnLeft(sourceCell.startIndex)
3909
3969
  });
3910
3970
  }, [getDisplayedColumnLeft, metrics, viewport.width]);
3911
- const activateColumnOrderPointerDrag = useCallback2((canvas, clientX) => {
3971
+ const activateColumnOrderPointerDrag = useCallback3((canvas, clientX) => {
3912
3972
  const drag = columnOrderDragRef.current;
3913
3973
  if (!drag || drag.active) return;
3914
3974
  if (columnOrderLongPressTimerRef.current) {
@@ -3922,7 +3982,7 @@ function TableInner({
3922
3982
  canvas.style.cursor = "move";
3923
3983
  updateColumnDragPreview(drag.sourceCell, clientX, canvas);
3924
3984
  }, [hideDragTooltips, updateColumnDragPreview]);
3925
- const handleColumnOrderPointerDown = useCallback2((event) => {
3985
+ const handleColumnOrderPointerDown = useCallback3((event) => {
3926
3986
  if (!columnDraggable || event.button !== 0 || columnDragRef.current) return;
3927
3987
  const sourceCell = locateHeaderCell(event.clientX, event.clientY);
3928
3988
  if (!sourceCell || locateHeaderResizeCell(event.clientX, event.clientY)) return;
@@ -3946,7 +4006,7 @@ function TableInner({
3946
4006
  activateColumnOrderPointerDrag(canvas, drag.startX);
3947
4007
  }, 320);
3948
4008
  }, [activateColumnOrderPointerDrag, columnDraggable, columns, locateHeaderAction, locateHeaderCell, locateHeaderResizeCell]);
3949
- const handleColumnOrderPointerMove = useCallback2((event) => {
4009
+ const handleColumnOrderPointerMove = useCallback3((event) => {
3950
4010
  const drag = columnOrderDragRef.current;
3951
4011
  if (!drag || drag.pointerId !== event.pointerId || columnDragRef.current) return;
3952
4012
  if (!drag.active) {
@@ -4017,7 +4077,7 @@ function TableInner({
4017
4077
  columnEdge
4018
4078
  };
4019
4079
  }, [activateColumnOrderPointerDrag, columns, getHeaderCellLeft, getHeaderCellWidth, headerCells, headerRowOffsets, locateColumn, locateHeaderCell, setDragGuide, updateColumnDragPreview]);
4020
- const finishColumnOrderPointerDrag = useCallback2((event, apply) => {
4080
+ const finishColumnOrderPointerDrag = useCallback3((event, apply) => {
4021
4081
  const drag = columnOrderDragRef.current;
4022
4082
  if (!drag || drag.pointerId !== event.pointerId) return;
4023
4083
  if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
@@ -4041,7 +4101,7 @@ function TableInner({
4041
4101
  suppressClickRef.current = false;
4042
4102
  }, 0);
4043
4103
  }, [applyColumnOrder, clearColumnOrderPointerDrag, utilityColumnCount]);
4044
- const queueSortStateChange = useCallback2((next) => {
4104
+ const queueSortStateChange = useCallback3((next) => {
4045
4105
  setSortState(next);
4046
4106
  }, []);
4047
4107
  const renderHeaderIcons = (columnIndex, left) => {
@@ -4076,7 +4136,7 @@ function TableInner({
4076
4136
  }
4077
4137
  return icons;
4078
4138
  };
4079
- const createHeaderTooltip = useCallback2((action, columnIndex, cell) => {
4139
+ const createHeaderTooltip = useCallback3((action, columnIndex, cell) => {
4080
4140
  const column = cell?.column ?? columns[columnIndex];
4081
4141
  if (!column) return null;
4082
4142
  const cellLeft = cell ? getHeaderCellLeft(cell) : getDisplayedColumnLeft(columnIndex);
@@ -4145,7 +4205,7 @@ function TableInner({
4145
4205
  placement
4146
4206
  };
4147
4207
  }, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerActionSize, headerActionSlotWidth, headerDepth, headerLeafHeight, headerLeafTop, headerRowHeights, headerRowOffsets, labels, measureHeaderTitleWidth, metrics, scrollPosition.top, sortState, viewport.width]);
4148
- const isPointerOnHeaderTitle = useCallback2((clientX, clientY, cell) => {
4208
+ const isPointerOnHeaderTitle = useCallback3((clientX, clientY, cell) => {
4149
4209
  const canvas = canvasRef.current;
4150
4210
  if (!canvas) return false;
4151
4211
  const rect = canvas.getBoundingClientRect();
@@ -4166,7 +4226,7 @@ function TableInner({
4166
4226
  const textTop = rowTop + 8;
4167
4227
  return localX >= textLeft - 4 && localX <= textLeft + textWidth + 4 && localY >= textTop - 2 && localY <= textTop + 18;
4168
4228
  }, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, headerRowOffsets]);
4169
- const locateCustomHeaderTooltip = useCallback2((clientX, clientY, columnIndex) => {
4229
+ const locateCustomHeaderTooltip = useCallback3((clientX, clientY, columnIndex) => {
4170
4230
  const root = rootRef.current;
4171
4231
  const canvas = canvasRef.current;
4172
4232
  if (!root || !canvas || columnIndex < 0) return null;
@@ -4657,11 +4717,20 @@ function TableInner({
4657
4717
  const horizontalEnd = column.fixed === void 0 ? viewport.width - rightFixedWidth : viewport.width;
4658
4718
  const verticalStart = fixedHeader ? bodyTop : 0;
4659
4719
  if (rawRight <= horizontalStart || rawLeft >= horizontalEnd || rawBottom + dragOffset <= verticalStart || rawTop + dragOffset >= renderHeight) return null;
4660
- const borderWidth = 2;
4661
- const left = Math.round(Math.max(rawLeft - borderWidth, horizontalStart));
4662
- const right = Math.round(Math.min(rawRight + 1, horizontalEnd, viewport.width));
4663
- const top = Math.round(Math.max(rawTop - borderWidth, verticalStart));
4664
- const bottom = Math.round(Math.min(rawBottom + borderWidth, renderHeight));
4720
+ const bounds = getSelectionOutlineBounds({
4721
+ left: rawLeft,
4722
+ right: rawRight,
4723
+ top: rawTop,
4724
+ bottom: rawBottom,
4725
+ horizontalStart,
4726
+ horizontalEnd,
4727
+ verticalStart,
4728
+ verticalEnd: renderHeight
4729
+ });
4730
+ const left = Math.round(bounds.left);
4731
+ const right = Math.round(bounds.right);
4732
+ const top = Math.round(bounds.top);
4733
+ const bottom = Math.round(bounds.bottom);
4665
4734
  return {
4666
4735
  left,
4667
4736
  top,