@lensui/lens-table 0.1.83 → 0.1.85

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/README.md CHANGED
@@ -315,6 +315,11 @@ const columns: GridColumn<Row>[] = [
315
315
  | `time-range` | `'09:00 ~ 18:00'` | 时间范围选择器。 |
316
316
  | `date-time-range` | `'2026-01-01 09:00 ~ 2026-01-01 18:00'` | 日期时间范围选择器,包含日期和时间面板。 |
317
317
 
318
+ `select` 可配置 `searchable` 开启输入筛选。需要把输入限制为已有选项时,设置
319
+ `strictOptions: true`:首次打开显示完整列表;开始输入后按输入内容筛选且不产生选中勾;
320
+ 没有匹配项或清空输入时显示完整列表。失焦时只提交精确匹配的选项,不匹配则恢复进入编辑前的值。
321
+ 若 `options` 包含 `{ label: '', value: '' }`,清空输入会在失焦时提交该空选项。
322
+
318
323
  可选 `format` 用于控制提交到数据里的字符串格式,例如:
319
324
 
320
325
  ```tsx
package/dist/index.cjs CHANGED
@@ -345,7 +345,7 @@ function getSearchableChoicePopupHorizontalLayout(anchorLeft, anchorWidth, longe
345
345
  );
346
346
  return { left, width };
347
347
  }
348
- function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownHeight, style, labels, onChange, onCommit, onCancel }) {
348
+ function SearchableChoiceEditor({ value, options, allowCustomValue, strictOptions, maxDropdownHeight, style, labels, onChange, onCommit, onCancel }) {
349
349
  const editorRef = (0, import_react2.useRef)(null);
350
350
  const popupRef = (0, import_react2.useRef)(null);
351
351
  const activeOptionRef = (0, import_react2.useRef)(null);
@@ -355,6 +355,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
355
355
  const listboxId = (0, import_react2.useId)();
356
356
  const originalValue = originalValueRef.current;
357
357
  const [inputValue, setInputValue] = (0, import_react2.useState)(value);
358
+ const [hasTyped, setHasTyped] = (0, import_react2.useState)(false);
358
359
  const [activeIndex, setActiveIndex] = (0, import_react2.useState)(() => {
359
360
  const selectedIndex = options.findIndex((option) => option.value === value);
360
361
  return selectedIndex >= 0 ? selectedIndex : 0;
@@ -364,10 +365,22 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
364
365
  visibility: "hidden"
365
366
  });
366
367
  const filteredOptions = (0, import_react2.useMemo)(() => {
368
+ if (strictOptions) {
369
+ if (!hasTyped) return options;
370
+ const strictQuery = inputValue.trim().toLocaleLowerCase();
371
+ const matches = options.filter((option) => option.label.toLocaleLowerCase().includes(strictQuery) || option.value.toLocaleLowerCase().includes(strictQuery));
372
+ return matches.length > 0 ? matches : options;
373
+ }
367
374
  const query = inputValue.trim().toLocaleLowerCase();
368
375
  if (!query || query === originalValue.toLocaleLowerCase()) return options;
369
376
  return options.filter((option) => option.label.toLocaleLowerCase().includes(query) || option.value.toLocaleLowerCase().includes(query));
370
- }, [inputValue, options, originalValue]);
377
+ }, [hasTyped, inputValue, options, originalValue, strictOptions]);
378
+ const exactInputOption = options.find((option) => option.value === inputValue);
379
+ const selectedValue = hasTyped ? void 0 : exactInputOption?.value;
380
+ const resolveInputValue = (0, import_react2.useCallback)(() => {
381
+ if (strictOptions) return exactInputOption?.value ?? originalValue;
382
+ return allowCustomValue ? inputValue || originalValue : originalValue;
383
+ }, [allowCustomValue, exactInputOption, inputValue, originalValue, strictOptions]);
371
384
  (0, import_react2.useLayoutEffect)(() => {
372
385
  const positionPopup = () => {
373
386
  const rect = editorRef.current?.getBoundingClientRect();
@@ -434,11 +447,11 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
434
447
  const target = event.target;
435
448
  if (!(target instanceof Node)) return;
436
449
  if (editorRef.current?.contains(target) || popupRef.current?.contains(target)) return;
437
- onCommit(allowCustomValue ? inputValue || originalValue : originalValue);
450
+ onCommit(resolveInputValue());
438
451
  };
439
452
  document.addEventListener("pointerdown", handleOutsidePointer, true);
440
453
  return () => document.removeEventListener("pointerdown", handleOutsidePointer, true);
441
- }, [allowCustomValue, inputValue, onCommit, originalValue]);
454
+ }, [onCommit, resolveInputValue]);
442
455
  const selectOption = (option) => {
443
456
  onChange(option.value);
444
457
  onCommit(option.value);
@@ -460,7 +473,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
460
473
  event.preventDefault();
461
474
  const option = filteredOptions[activeIndex];
462
475
  if (option) selectOption(option);
463
- else if (allowCustomValue) onCommit(inputValue || originalValue);
476
+ else if (allowCustomValue || strictOptions) onCommit(resolveInputValue());
464
477
  }
465
478
  };
466
479
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref: editorRef, className: "rvg-choice-editor rvg-searchable-choice-editor", style, children: [
@@ -474,6 +487,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
474
487
  "aria-controls": listboxId,
475
488
  onFocus: (event) => event.currentTarget.select(),
476
489
  onChange: (event) => {
490
+ setHasTyped(true);
477
491
  setInputValue(event.target.value);
478
492
  onChange(event.target.value);
479
493
  navigationSourceRef.current = "filter";
@@ -489,8 +503,8 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
489
503
  ref: index === activeIndex ? activeOptionRef : void 0,
490
504
  type: "button",
491
505
  role: "option",
492
- "aria-selected": option.value === originalValue,
493
- className: `rvg-choice-item${index === activeIndex ? " is-active" : ""}${option.value === originalValue ? " is-selected" : ""}`,
506
+ "aria-selected": option.value === selectedValue,
507
+ className: `rvg-choice-item${index === activeIndex ? " is-active" : ""}${option.value === selectedValue ? " is-selected" : ""}`,
494
508
  onPointerDown: (event) => event.preventDefault(),
495
509
  onMouseEnter: () => {
496
510
  navigationSourceRef.current = "pointer";
@@ -499,7 +513,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
499
513
  onClick: () => selectOption(option),
500
514
  children: [
501
515
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: option.label }),
502
- option.value === originalValue && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChoiceCheckIcon, {})
516
+ option.value === selectedValue && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChoiceCheckIcon, {})
503
517
  ]
504
518
  },
505
519
  option.value
@@ -3722,6 +3736,7 @@ function TableInner({
3722
3736
  options: column.editor.options,
3723
3737
  searchable: column.editor.searchable,
3724
3738
  allowCustomValue: column.editor.allowCustomValue,
3739
+ strictOptions: column.editor.strictOptions,
3725
3740
  maxDropdownHeight: column.editor.maxDropdownHeight,
3726
3741
  style: editorStyle,
3727
3742
  labels,
package/dist/index.d.cts CHANGED
@@ -211,6 +211,8 @@ interface GridColumn<Row> {
211
211
  }>;
212
212
  searchable?: boolean;
213
213
  allowCustomValue?: boolean;
214
+ /** Keep typed input filtered and only commit values that exactly match an option. */
215
+ strictOptions?: boolean;
214
216
  maxDropdownHeight?: number;
215
217
  } | {
216
218
  type: 'textarea';
package/dist/index.d.ts CHANGED
@@ -211,6 +211,8 @@ interface GridColumn<Row> {
211
211
  }>;
212
212
  searchable?: boolean;
213
213
  allowCustomValue?: boolean;
214
+ /** Keep typed input filtered and only commit values that exactly match an option. */
215
+ strictOptions?: boolean;
214
216
  maxDropdownHeight?: number;
215
217
  } | {
216
218
  type: 'textarea';
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,22 @@ 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
+ const strictQuery = inputValue.trim().toLocaleLowerCase();
341
+ const matches = options.filter((option) => option.label.toLocaleLowerCase().includes(strictQuery) || option.value.toLocaleLowerCase().includes(strictQuery));
342
+ return matches.length > 0 ? matches : options;
343
+ }
337
344
  const query = inputValue.trim().toLocaleLowerCase();
338
345
  if (!query || query === originalValue.toLocaleLowerCase()) return options;
339
346
  return options.filter((option) => option.label.toLocaleLowerCase().includes(query) || option.value.toLocaleLowerCase().includes(query));
340
- }, [inputValue, options, originalValue]);
347
+ }, [hasTyped, inputValue, options, originalValue, strictOptions]);
348
+ const exactInputOption = options.find((option) => option.value === inputValue);
349
+ const selectedValue = hasTyped ? void 0 : exactInputOption?.value;
350
+ const resolveInputValue = useCallback(() => {
351
+ if (strictOptions) return exactInputOption?.value ?? originalValue;
352
+ return allowCustomValue ? inputValue || originalValue : originalValue;
353
+ }, [allowCustomValue, exactInputOption, inputValue, originalValue, strictOptions]);
341
354
  useLayoutEffect(() => {
342
355
  const positionPopup = () => {
343
356
  const rect = editorRef.current?.getBoundingClientRect();
@@ -404,11 +417,11 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
404
417
  const target = event.target;
405
418
  if (!(target instanceof Node)) return;
406
419
  if (editorRef.current?.contains(target) || popupRef.current?.contains(target)) return;
407
- onCommit(allowCustomValue ? inputValue || originalValue : originalValue);
420
+ onCommit(resolveInputValue());
408
421
  };
409
422
  document.addEventListener("pointerdown", handleOutsidePointer, true);
410
423
  return () => document.removeEventListener("pointerdown", handleOutsidePointer, true);
411
- }, [allowCustomValue, inputValue, onCommit, originalValue]);
424
+ }, [onCommit, resolveInputValue]);
412
425
  const selectOption = (option) => {
413
426
  onChange(option.value);
414
427
  onCommit(option.value);
@@ -430,7 +443,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
430
443
  event.preventDefault();
431
444
  const option = filteredOptions[activeIndex];
432
445
  if (option) selectOption(option);
433
- else if (allowCustomValue) onCommit(inputValue || originalValue);
446
+ else if (allowCustomValue || strictOptions) onCommit(resolveInputValue());
434
447
  }
435
448
  };
436
449
  return /* @__PURE__ */ jsxs3("div", { ref: editorRef, className: "rvg-choice-editor rvg-searchable-choice-editor", style, children: [
@@ -444,6 +457,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
444
457
  "aria-controls": listboxId,
445
458
  onFocus: (event) => event.currentTarget.select(),
446
459
  onChange: (event) => {
460
+ setHasTyped(true);
447
461
  setInputValue(event.target.value);
448
462
  onChange(event.target.value);
449
463
  navigationSourceRef.current = "filter";
@@ -459,8 +473,8 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
459
473
  ref: index === activeIndex ? activeOptionRef : void 0,
460
474
  type: "button",
461
475
  role: "option",
462
- "aria-selected": option.value === originalValue,
463
- className: `rvg-choice-item${index === activeIndex ? " is-active" : ""}${option.value === originalValue ? " is-selected" : ""}`,
476
+ "aria-selected": option.value === selectedValue,
477
+ className: `rvg-choice-item${index === activeIndex ? " is-active" : ""}${option.value === selectedValue ? " is-selected" : ""}`,
464
478
  onPointerDown: (event) => event.preventDefault(),
465
479
  onMouseEnter: () => {
466
480
  navigationSourceRef.current = "pointer";
@@ -469,7 +483,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
469
483
  onClick: () => selectOption(option),
470
484
  children: [
471
485
  /* @__PURE__ */ jsx3("span", { children: option.label }),
472
- option.value === originalValue && /* @__PURE__ */ jsx3(ChoiceCheckIcon, {})
486
+ option.value === selectedValue && /* @__PURE__ */ jsx3(ChoiceCheckIcon, {})
473
487
  ]
474
488
  },
475
489
  option.value
@@ -1690,11 +1704,11 @@ function paintGrid(options) {
1690
1704
  }
1691
1705
 
1692
1706
  // src/hooks/useControllable.ts
1693
- import { useCallback, useState as useState5 } from "react";
1707
+ import { useCallback as useCallback2, useState as useState5 } from "react";
1694
1708
  function useControllableKeys(value, defaultValue, onChange) {
1695
1709
  const [internal, setInternal] = useState5(defaultValue ?? []);
1696
1710
  const keys = value === void 0 ? internal : value;
1697
- const setKeys = useCallback((next) => {
1711
+ const setKeys = useCallback2((next) => {
1698
1712
  if (value === void 0) setInternal(next);
1699
1713
  onChange?.(next);
1700
1714
  }, [onChange, value]);
@@ -1703,7 +1717,7 @@ function useControllableKeys(value, defaultValue, onChange) {
1703
1717
  function useControllableValue(value, defaultValue, onChange) {
1704
1718
  const [internal, setInternal] = useState5(defaultValue ?? null);
1705
1719
  const selected = value === void 0 ? internal : value;
1706
- const setSelected = useCallback((next) => {
1720
+ const setSelected = useCallback2((next) => {
1707
1721
  if (value === void 0) setInternal(next);
1708
1722
  onChange?.(next);
1709
1723
  }, [onChange, value]);
@@ -2173,7 +2187,7 @@ function TableInner({
2173
2187
  if (headerTooltipTimerRef.current !== null) clearTimeout(headerTooltipTimerRef.current);
2174
2188
  if (cellTooltipTimerRef.current !== null) clearTimeout(cellTooltipTimerRef.current);
2175
2189
  }, []);
2176
- const measureCustomHeaderHeight = useCallback2(() => {
2190
+ const measureCustomHeaderHeight = useCallback3(() => {
2177
2191
  const nextHeights = Array.from({ length: headerDepth }, () => baseHeaderHeight);
2178
2192
  customHeaderContentRefs.current.forEach((node) => {
2179
2193
  const headerCell = node.closest(".rvg-header-title");
@@ -2224,7 +2238,7 @@ function TableInner({
2224
2238
  const [hoveredHeaderAction, setHoveredHeaderAction] = useState6(null);
2225
2239
  const [visibleHeaderTooltip, setVisibleHeaderTooltip] = useState6(null);
2226
2240
  const [hoveredCellTooltip, setHoveredCellTooltip] = useState6(null);
2227
- const hideDragTooltips = useCallback2(() => {
2241
+ const hideDragTooltips = useCallback3(() => {
2228
2242
  if (headerTooltipTimerRef.current !== null) {
2229
2243
  clearTimeout(headerTooltipTimerRef.current);
2230
2244
  headerTooltipTimerRef.current = null;
@@ -2251,10 +2265,10 @@ function TableInner({
2251
2265
  const [insertedRowKeys, setInsertedRowKeys] = useState6(() => /* @__PURE__ */ new Set());
2252
2266
  const [rowOrderKeys, setRowOrderKeys] = useState6(null);
2253
2267
  const settledPendingInsertIdsRef = useRef4(/* @__PURE__ */ new Set());
2254
- const getDataRowKey = useCallback2((row, index) => {
2268
+ const getDataRowKey = useCallback3((row, index) => {
2255
2269
  return typeof rowKey === "function" ? rowKey(row, index) : rowKey ? row[rowKey] : getDefaultRowKey(row, index);
2256
2270
  }, [rowKey]);
2257
- const getSourceRowIndexByKey = useCallback2((key, preferredIndex) => {
2271
+ const getSourceRowIndexByKey = useCallback3((key, preferredIndex) => {
2258
2272
  const preferredRow = sourceRows[preferredIndex];
2259
2273
  if (preferredRow && getDataRowKey(preferredRow, preferredIndex) === key) return preferredIndex;
2260
2274
  const start = Math.max(0, preferredIndex - 8);
@@ -2325,7 +2339,7 @@ function TableInner({
2325
2339
  return result * direction;
2326
2340
  });
2327
2341
  }, [columns, filteredRows, language, onSortChange, sortState]);
2328
- const resolveSelectionTarget = useCallback2((target) => {
2342
+ const resolveSelectionTarget = useCallback3((target) => {
2329
2343
  if (target == null) return target;
2330
2344
  const columnIndex = columns.findIndex((column) => column.key === target.columnKey);
2331
2345
  const rowIndex = target.rowKey !== void 0 ? rows.findIndex((row2, index) => getDataRowKey(row2, index) === target.rowKey) : target.rowIndex ?? -1;
@@ -2340,7 +2354,7 @@ function TableInner({
2340
2354
  }, [columns, getDataRowKey, rows]);
2341
2355
  const resolvedSelectedCell = useMemo2(() => resolveSelectionTarget(selectedCell), [resolveSelectionTarget, selectedCell]);
2342
2356
  const resolvedDefaultSelectedCell = useMemo2(() => resolveSelectionTarget(defaultSelectedCell), [defaultSelectedCell, resolveSelectionTarget]);
2343
- const handleSelectedCellChange = useCallback2((next) => {
2357
+ const handleSelectedCellChange = useCallback3((next) => {
2344
2358
  if (!onSelectedCellChange) return;
2345
2359
  if (!next) {
2346
2360
  onSelectedCellChange(null);
@@ -2369,7 +2383,7 @@ function TableInner({
2369
2383
  document.addEventListener("pointerdown", handleOutsidePointerDown);
2370
2384
  return () => document.removeEventListener("pointerdown", handleOutsidePointerDown);
2371
2385
  }, [selection, setSelection]);
2372
- const applyRowOrder = useCallback2((sourceIndex, targetIndex) => {
2386
+ const applyRowOrder = useCallback3((sourceIndex, targetIndex) => {
2373
2387
  if (sourceIndex === targetIndex || sourceIndex < 0 || targetIndex < 0 || sourceIndex >= rows.length || targetIndex >= rows.length) return;
2374
2388
  const nextEntries = rows.map((row, index) => ({ row, key: getDataRowKey(row, index) }));
2375
2389
  const [entry] = nextEntries.splice(sourceIndex, 1);
@@ -2378,7 +2392,7 @@ function TableInner({
2378
2392
  setRowOrderKeys(nextEntries.map(({ key }) => key));
2379
2393
  onRowsReorder?.(nextRows, { sourceIndex, targetIndex });
2380
2394
  }, [getDataRowKey, onRowsReorder, rows]);
2381
- const applyColumnOrder = useCallback2((sourceIndex, targetIndex, detail) => {
2395
+ const applyColumnOrder = useCallback3((sourceIndex, targetIndex, detail) => {
2382
2396
  const nextColumns = reorderColumns(sourceColumns, detail);
2383
2397
  setSourceColumns(nextColumns);
2384
2398
  onColumnsReorder?.(nextColumns, { sourceIndex, targetIndex, ...detail });
@@ -2451,7 +2465,7 @@ function TableInner({
2451
2465
  }
2452
2466
  return lefts;
2453
2467
  }, [columns, fixedWidth, metrics]);
2454
- const getScrollableColumnLeft = useCallback2((columnIndex) => scrollableColumnLefts[columnIndex] ?? fixedWidth, [fixedWidth, scrollableColumnLefts]);
2468
+ const getScrollableColumnLeft = useCallback3((columnIndex) => scrollableColumnLefts[columnIndex] ?? fixedWidth, [fixedWidth, scrollableColumnLefts]);
2455
2469
  const hasRowSelectionColumn = useMemo2(() => columns.some((column) => column.rowSelection), [columns]);
2456
2470
  const rowSelectionMode = typeof rowSelection === "object" ? rowSelection.mode ?? "multiple" : "multiple";
2457
2471
  const summarySignature = useMemo2(() => getSummarySignature(columns), [columns]);
@@ -2504,7 +2518,7 @@ function TableInner({
2504
2518
  const rowScrollTop = fixedHeader ? currentScroll2.top : Math.max(0, currentScroll2.top - bodyTop);
2505
2519
  return getViewportRange(currentScroll2.left, rowScrollTop, viewport.width, bodyViewportHeight, rows.length, rowHeight, metrics, virtualOverscan);
2506
2520
  }, [bodyTop, bodyViewportHeight, columns.length, fixedHeader, isVirtualized, metrics, rowHeight, rows.length, scrollPosition, viewport.width, virtualOverscan]);
2507
- const getRowKey = useCallback2((row, index) => {
2521
+ const getRowKey = useCallback3((row, index) => {
2508
2522
  const key = getDataRowKey(row, index);
2509
2523
  rowByKeyRef.current.set(key, row);
2510
2524
  rowIndexByKeyRef.current.set(key, index);
@@ -2573,7 +2587,7 @@ function TableInner({
2573
2587
  const selectedRowKeySet = useMemo2(() => new Set(rowKeys), [rowKeys]);
2574
2588
  const selectedColumnKeySet = useMemo2(() => new Set(columnKeys), [columnKeys]);
2575
2589
  const insertedRowKeySet = useMemo2(() => insertedRowKeys, [insertedRowKeys]);
2576
- const measureHeaderTitleWidth = useCallback2((columnIndex) => {
2590
+ const measureHeaderTitleWidth = useCallback3((columnIndex) => {
2577
2591
  const title = columns[columnIndex]?.title ?? "";
2578
2592
  const context = canvasRef.current?.getContext("2d");
2579
2593
  if (!context) return Array.from(title).reduce((width3, character) => width3 + (/^[\x00-\x7F]$/.test(character) ? 7 : 13), 0);
@@ -2583,7 +2597,7 @@ function TableInner({
2583
2597
  context.restore();
2584
2598
  return width2;
2585
2599
  }, [columns]);
2586
- const getCellLabel = useCallback2((rowIndex, columnIndex) => {
2600
+ const getCellLabel = useCallback3((rowIndex, columnIndex) => {
2587
2601
  const row = rows[rowIndex];
2588
2602
  const column = columns[columnIndex];
2589
2603
  if (!row || !column || column.rowSelection || column.rowDragHandle) return "";
@@ -2594,8 +2608,8 @@ function TableInner({
2594
2608
  return "Render error";
2595
2609
  }
2596
2610
  }, [columns, rows]);
2597
- const getCellSpan = useCallback2((rowIndex, columnIndex) => cellSpanLookup.covered.get(getCellCoordKey2(rowIndex, columnIndex)), [cellSpanLookup]);
2598
- const getCellDisplayWidth = useCallback2((columnIndex, colSpan = 1) => {
2611
+ const getCellSpan = useCallback3((rowIndex, columnIndex) => cellSpanLookup.covered.get(getCellCoordKey2(rowIndex, columnIndex)), [cellSpanLookup]);
2612
+ const getCellDisplayWidth = useCallback3((columnIndex, colSpan = 1) => {
2599
2613
  let width2 = 0;
2600
2614
  for (let index = columnIndex; index < Math.min(columns.length, columnIndex + colSpan); index += 1) {
2601
2615
  width2 += metrics[index]?.width ?? 0;
@@ -2610,7 +2624,7 @@ function TableInner({
2610
2624
  if (nextRowIndex === selection.rowIndex && nextColumnIndex === selection.columnIndex) return;
2611
2625
  setSelection({ ...selection, rowIndex: nextRowIndex, columnIndex: nextColumnIndex });
2612
2626
  }, [columns, getRowKey, rows, selection, setSelection]);
2613
- const draw = useCallback2(() => {
2627
+ const draw = useCallback3(() => {
2614
2628
  frameRef.current = null;
2615
2629
  const canvas = canvasRef.current;
2616
2630
  if (!canvas || viewport.width <= 0) return;
@@ -2656,15 +2670,15 @@ function TableInner({
2656
2670
  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 };
2657
2671
  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 });
2658
2672
  }, [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]);
2659
- const scheduleDraw = useCallback2(() => {
2673
+ const scheduleDraw = useCallback3(() => {
2660
2674
  if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
2661
2675
  }, [draw]);
2662
- const drawImmediately = useCallback2(() => {
2676
+ const drawImmediately = useCallback3(() => {
2663
2677
  if (frameRef.current !== null) cancelAnimationFrame(frameRef.current);
2664
2678
  frameRef.current = null;
2665
2679
  draw();
2666
2680
  }, [draw]);
2667
- const getSelectionHorizontalVisibility = useCallback2((scrollLeft) => {
2681
+ const getSelectionHorizontalVisibility = useCallback3((scrollLeft) => {
2668
2682
  if (!selection || selectionRange) return "visible";
2669
2683
  const column = columns[selection.columnIndex];
2670
2684
  if (!column || column.fixed !== void 0) return "visible";
@@ -2675,7 +2689,7 @@ function TableInner({
2675
2689
  if (left >= viewport.width - rightFixedWidth) return "hidden-right";
2676
2690
  return "visible";
2677
2691
  }, [columns, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, rightFixedWidth, selection, selectionRange, viewport.width]);
2678
- const getSelectionEdgeIndicator = useCallback2((scrollLeft, scrollTop) => {
2692
+ const getSelectionEdgeIndicator = useCallback3((scrollLeft, scrollTop) => {
2679
2693
  if (!selection || selectionRange) return null;
2680
2694
  const row = rows[selection.rowIndex];
2681
2695
  const metric = metrics[selection.columnIndex];
@@ -2783,7 +2797,7 @@ function TableInner({
2783
2797
  }
2784
2798
  };
2785
2799
  }, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, leftFixedOffsets, metrics, renderHeight, rightFixedOffsets, rightFixedWidth, rowHeight, rows, selection, selectionRange, viewport.width]);
2786
- const syncSelectionEdgeTarget = useCallback2((scrollLeft, scrollTop) => {
2800
+ const syncSelectionEdgeTarget = useCallback3((scrollLeft, scrollTop) => {
2787
2801
  const target = selectionEdgeTargetRef.current;
2788
2802
  if (!target) return;
2789
2803
  const indicator = getSelectionEdgeIndicator(scrollLeft, scrollTop);
@@ -2905,7 +2919,7 @@ function TableInner({
2905
2919
  scroller.addEventListener("scroll", lockScroll);
2906
2920
  return () => scroller.removeEventListener("scroll", lockScroll);
2907
2921
  }, [insertBusy]);
2908
- const showCustomScrollbar = useCallback2((axis, persist = false) => {
2922
+ const showCustomScrollbar = useCallback3((axis, persist = false) => {
2909
2923
  const showVertical = axis === "vertical" || axis === "both";
2910
2924
  const showHorizontal = axis === "horizontal" || axis === "both";
2911
2925
  if (showVertical) {
@@ -2929,15 +2943,15 @@ function TableInner({
2929
2943
  }
2930
2944
  }
2931
2945
  }, []);
2932
- const keepCustomScrollbarVisible = useCallback2((axis) => {
2946
+ const keepCustomScrollbarVisible = useCallback3((axis) => {
2933
2947
  showCustomScrollbar(axis, true);
2934
2948
  }, [showCustomScrollbar]);
2935
- const releaseCustomScrollbarVisible = useCallback2((axis) => {
2949
+ const releaseCustomScrollbarVisible = useCallback3((axis) => {
2936
2950
  if (axis === "vertical" && verticalScrollbarDragRef.current) return;
2937
2951
  if (axis === "horizontal" && horizontalScrollbarDragRef.current) return;
2938
2952
  showCustomScrollbar(axis);
2939
2953
  }, [showCustomScrollbar]);
2940
- const updateCustomScrollbars = useCallback2(() => {
2954
+ const updateCustomScrollbars = useCallback3(() => {
2941
2955
  const scroller = scrollerRef.current;
2942
2956
  const verticalTrack = verticalScrollbarRef.current;
2943
2957
  const verticalThumb = verticalScrollbarThumbRef.current;
@@ -2990,7 +3004,7 @@ function TableInner({
2990
3004
  useLayoutEffect3(() => {
2991
3005
  updateCustomScrollbars();
2992
3006
  }, [contentHeight, contentWidth, updateCustomScrollbars, viewport.height, viewport.width]);
2993
- const handleVerticalScrollbarPointerDown = useCallback2((event) => {
3007
+ const handleVerticalScrollbarPointerDown = useCallback3((event) => {
2994
3008
  const scroller = scrollerRef.current;
2995
3009
  const track = verticalScrollbarRef.current;
2996
3010
  const thumb = verticalScrollbarThumbRef.current;
@@ -3027,7 +3041,7 @@ function TableInner({
3027
3041
  maxScrollTop
3028
3042
  };
3029
3043
  }, [showCustomScrollbar, updateCustomScrollbars]);
3030
- const handleVerticalScrollbarPointerMove = useCallback2((event) => {
3044
+ const handleVerticalScrollbarPointerMove = useCallback3((event) => {
3031
3045
  const drag = verticalScrollbarDragRef.current;
3032
3046
  const scroller = scrollerRef.current;
3033
3047
  if (!drag || !scroller || drag.pointerId !== event.pointerId) return;
@@ -3037,14 +3051,14 @@ function TableInner({
3037
3051
  scroller.scrollTop = nextThumbTop / maxThumbTop * drag.maxScrollTop;
3038
3052
  updateCustomScrollbars();
3039
3053
  }, [updateCustomScrollbars]);
3040
- const handleVerticalScrollbarPointerUp = useCallback2((event) => {
3054
+ const handleVerticalScrollbarPointerUp = useCallback3((event) => {
3041
3055
  const drag = verticalScrollbarDragRef.current;
3042
3056
  if (!drag || drag.pointerId !== event.pointerId) return;
3043
3057
  if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
3044
3058
  verticalScrollbarDragRef.current = null;
3045
3059
  showCustomScrollbar("vertical");
3046
3060
  }, [showCustomScrollbar]);
3047
- const handleHorizontalScrollbarPointerDown = useCallback2((event) => {
3061
+ const handleHorizontalScrollbarPointerDown = useCallback3((event) => {
3048
3062
  const scroller = scrollerRef.current;
3049
3063
  const track = horizontalScrollbarRef.current;
3050
3064
  const thumb = horizontalScrollbarThumbRef.current;
@@ -3087,7 +3101,7 @@ function TableInner({
3087
3101
  maxScrollLeft
3088
3102
  };
3089
3103
  }, [drawImmediately, getSelectionHorizontalVisibility, showCustomScrollbar, syncSelectionEdgeTarget, updateCustomScrollbars]);
3090
- const handleHorizontalScrollbarPointerMove = useCallback2((event) => {
3104
+ const handleHorizontalScrollbarPointerMove = useCallback3((event) => {
3091
3105
  const drag = horizontalScrollbarDragRef.current;
3092
3106
  const scroller = scrollerRef.current;
3093
3107
  if (!drag || !scroller || drag.pointerId !== event.pointerId) return;
@@ -3103,7 +3117,7 @@ function TableInner({
3103
3117
  if (visibilityChanged) drawImmediately();
3104
3118
  updateCustomScrollbars();
3105
3119
  }, [drawImmediately, getSelectionHorizontalVisibility, syncSelectionEdgeTarget, updateCustomScrollbars]);
3106
- const handleHorizontalScrollbarPointerUp = useCallback2((event) => {
3120
+ const handleHorizontalScrollbarPointerUp = useCallback3((event) => {
3107
3121
  const drag = horizontalScrollbarDragRef.current;
3108
3122
  if (!drag || drag.pointerId !== event.pointerId) return;
3109
3123
  if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
@@ -3117,7 +3131,7 @@ function TableInner({
3117
3131
  clip.style.transform = "";
3118
3132
  });
3119
3133
  }, [scrollPosition.top]);
3120
- const handleScroll = useCallback2(() => {
3134
+ const handleScroll = useCallback3(() => {
3121
3135
  const element = scrollerRef.current;
3122
3136
  if (!element) return;
3123
3137
  const previousScroll = scrollRef.current;
@@ -3194,7 +3208,7 @@ function TableInner({
3194
3208
  setHoveredCellTooltip(null);
3195
3209
  scheduleDraw();
3196
3210
  }, [bodyTop, columns, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, metrics, rightFixedOffsets, rightFixedWidth, rowHeight, rows, scheduleDraw, selection, selectionRange, showCustomScrollbar, syncSelectionEdgeTarget, updateCustomScrollbars, viewport.width]);
3197
- const locateColumn = useCallback2((clientX) => {
3211
+ const locateColumn = useCallback3((clientX) => {
3198
3212
  const canvas = canvasRef.current;
3199
3213
  if (!canvas) return -1;
3200
3214
  const rect = canvas.getBoundingClientRect();
@@ -3222,7 +3236,7 @@ function TableInner({
3222
3236
  }
3223
3237
  return columnIndex;
3224
3238
  }, [columns, fixedWidth, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, rightFixedWidth, viewport.width]);
3225
- const getDisplayedColumnLeft = useCallback2((columnIndex) => {
3239
+ const getDisplayedColumnLeft = useCallback3((columnIndex) => {
3226
3240
  const metric = metrics[columnIndex];
3227
3241
  if (columns[columnIndex].fixed === "left") return leftFixedOffsets.get(columnIndex) ?? 0;
3228
3242
  if (columns[columnIndex].fixed === "right") return viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metric.width;
@@ -3232,7 +3246,7 @@ function TableInner({
3232
3246
  const displayedContentRight = columns.reduce((right, _column, columnIndex) => Math.max(right, getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width), 0);
3233
3247
  return displayedContentRight > 0 && displayedContentRight < viewport.width ? Math.round(displayedContentRight) - 1 : null;
3234
3248
  }, [columns, getDisplayedColumnLeft, metrics, scrollPosition.left, viewport.width]);
3235
- const getHeaderLevelAtY = useCallback2((localY, headerY) => {
3249
+ const getHeaderLevelAtY = useCallback3((localY, headerY) => {
3236
3250
  const y = localY - headerY;
3237
3251
  for (let level = 0; level < headerRowHeights.length; level += 1) {
3238
3252
  const top = headerRowOffsets[level] ?? 0;
@@ -3240,11 +3254,11 @@ function TableInner({
3240
3254
  }
3241
3255
  return headerDepth - 1;
3242
3256
  }, [headerDepth, headerRowHeights, headerRowOffsets]);
3243
- const resizeColumn = useCallback2((columnKey, width2) => {
3257
+ const resizeColumn = useCallback3((columnKey, width2) => {
3244
3258
  setResizedColumnWidths((current) => current[columnKey] === width2 ? current : { ...current, [columnKey]: width2 });
3245
3259
  onColumnResize?.(columnKey, width2);
3246
3260
  }, [onColumnResize]);
3247
- const locateHeaderAction = useCallback2((clientX, clientY, columnIndex) => {
3261
+ const locateHeaderAction = useCallback3((clientX, clientY, columnIndex) => {
3248
3262
  if (columnIndex < 0 || !canvasRef.current) return null;
3249
3263
  const column = columns[columnIndex];
3250
3264
  if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
@@ -3264,7 +3278,7 @@ function TableInner({
3264
3278
  if (visibleActions.filter && localX >= right - headerActionSlotWidth && localX < right) return "filter";
3265
3279
  return null;
3266
3280
  }, [columnDraggable, columns, fixedHeader, getDisplayedColumnLeft, headerActionSize, headerActionSlotWidth, headerLeafHeight, headerLeafTop, measureHeaderTitleWidth, metrics]);
3267
- const isHeaderTitleTruncated = useCallback2((columnIndex) => {
3281
+ const isHeaderTitleTruncated = useCallback3((columnIndex) => {
3268
3282
  const canvas = canvasRef.current;
3269
3283
  if (columnIndex < 0 || !canvas) return false;
3270
3284
  const column = columns[columnIndex];
@@ -3274,7 +3288,7 @@ function TableInner({
3274
3288
  const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
3275
3289
  return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
3276
3290
  }, [columnDraggable, columns, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
3277
- const locateHeaderDragHandle = useCallback2((clientX, clientY, columnIndex) => {
3291
+ const locateHeaderDragHandle = useCallback3((clientX, clientY, columnIndex) => {
3278
3292
  if (!columnDraggable || columnIndex < 0 || !canvasRef.current) return false;
3279
3293
  const column = columns[columnIndex];
3280
3294
  if (column.rowSelection || column.rowDragHandle || column.rowNumber) return false;
@@ -3288,14 +3302,14 @@ function TableInner({
3288
3302
  const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
3289
3303
  return localX >= columnRight - headerActionSlotWidth && localX < columnRight - 2;
3290
3304
  }, [columnDraggable, columns, fixedHeader, getDisplayedColumnLeft, headerActionSize, headerActionSlotWidth, headerLeafHeight, headerLeafTop, measureHeaderTitleWidth, metrics]);
3291
- const getHeaderCellLeft = useCallback2((cell) => {
3305
+ const getHeaderCellLeft = useCallback3((cell) => {
3292
3306
  const startMetric = metrics[cell.startIndex];
3293
3307
  const fixedSide = columns[cell.startIndex]?.fixed;
3294
3308
  if (!startMetric) return 0;
3295
3309
  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;
3296
3310
  }, [columns, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, viewport.width]);
3297
- const getHeaderCellWidth = useCallback2((cell) => cell.leaf ? metrics[cell.startIndex]?.width ?? 0 : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1), [getCellDisplayWidth, metrics]);
3298
- const getHeaderCellEdgeFromMetrics = useCallback2((startIndex, endIndex, edge, nextMetrics) => {
3311
+ const getHeaderCellWidth = useCallback3((cell) => cell.leaf ? metrics[cell.startIndex]?.width ?? 0 : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1), [getCellDisplayWidth, metrics]);
3312
+ const getHeaderCellEdgeFromMetrics = useCallback3((startIndex, endIndex, edge, nextMetrics) => {
3299
3313
  const fixedSide = columns[startIndex]?.fixed;
3300
3314
  const width2 = nextMetrics.slice(startIndex, endIndex + 1).reduce((total, metric) => total + metric.width, 0);
3301
3315
  let left;
@@ -3319,7 +3333,7 @@ function TableInner({
3319
3333
  }
3320
3334
  return left + (edge === "right" ? width2 : 0);
3321
3335
  }, [columns, fixedWidth, viewport.width]);
3322
- const locateHeaderResizeHit = useCallback2((clientX, clientY) => {
3336
+ const locateHeaderResizeHit = useCallback3((clientX, clientY) => {
3323
3337
  if (!columnResizable || !canvasRef.current) return null;
3324
3338
  const rect = canvasRef.current.getBoundingClientRect();
3325
3339
  const localX = clientX - rect.left;
@@ -3346,15 +3360,15 @@ function TableInner({
3346
3360
  }
3347
3361
  return closest;
3348
3362
  }, [columnResizable, columns, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, getHeaderLevelAtY, headerCells, headerHeight]);
3349
- const locateHeaderResizeCell = useCallback2((clientX, clientY) => locateHeaderResizeHit(clientX, clientY)?.cell ?? null, [locateHeaderResizeHit]);
3350
- const locateHeaderCellDragHandle = useCallback2((clientX, clientY, cell) => {
3363
+ const locateHeaderResizeCell = useCallback3((clientX, clientY) => locateHeaderResizeHit(clientX, clientY)?.cell ?? null, [locateHeaderResizeHit]);
3364
+ const locateHeaderCellDragHandle = useCallback3((clientX, clientY, cell) => {
3351
3365
  if (!columnDraggable || !canvasRef.current) return false;
3352
3366
  if (cell.leaf) return locateHeaderDragHandle(clientX, clientY, cell.startIndex);
3353
3367
  const localX = clientX - canvasRef.current.getBoundingClientRect().left;
3354
3368
  const right = getHeaderCellLeft(cell) + getHeaderCellWidth(cell);
3355
3369
  return localX >= right - headerActionSlotWidth && localX < right - 2;
3356
3370
  }, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, locateHeaderDragHandle]);
3357
- const locateHeaderCell = useCallback2((clientX, clientY) => {
3371
+ const locateHeaderCell = useCallback3((clientX, clientY) => {
3358
3372
  const canvas = canvasRef.current;
3359
3373
  if (!canvas) return null;
3360
3374
  const rect = canvas.getBoundingClientRect();
@@ -3371,7 +3385,7 @@ function TableInner({
3371
3385
  }
3372
3386
  return null;
3373
3387
  }, [fixedHeader, getHeaderCellLeft, getHeaderCellWidth, getHeaderLevelAtY, headerCells, headerHeight]);
3374
- const setDragGuide = useCallback2((x, top = 0) => {
3388
+ const setDragGuide = useCallback3((x, top = 0) => {
3375
3389
  const guide = dragGuideRef.current;
3376
3390
  if (!guide) return;
3377
3391
  guide.style.display = x === null ? "none" : "block";
@@ -3380,20 +3394,20 @@ function TableInner({
3380
3394
  guide.style.transform = `translateX(${Math.round(x)}px)`;
3381
3395
  }
3382
3396
  }, []);
3383
- const setRowDragGuide = useCallback2((y) => {
3397
+ const setRowDragGuide = useCallback3((y) => {
3384
3398
  const guide = rowDragGuideRef.current;
3385
3399
  if (!guide) return;
3386
3400
  guide.style.display = y === null ? "none" : "block";
3387
3401
  if (y !== null) guide.style.transform = `translateY(${Math.round(y)}px)`;
3388
3402
  }, []);
3389
- const locateRow = useCallback2((clientY) => {
3403
+ const locateRow = useCallback3((clientY) => {
3390
3404
  const canvas = canvasRef.current;
3391
3405
  if (!canvas) return -1;
3392
3406
  const localY = clientY - canvas.getBoundingClientRect().top;
3393
3407
  const rowIndex = Math.floor((localY - bodyTop + scrollRef.current.top) / rowHeight);
3394
3408
  return rowIndex >= 0 && rowIndex < rows.length ? rowIndex : -1;
3395
3409
  }, [bodyTop, rowHeight, rows.length]);
3396
- const handleRowOrderPointerDown = useCallback2((event) => {
3410
+ const handleRowOrderPointerDown = useCallback3((event) => {
3397
3411
  if (!rowDraggable || event.button !== 0 || rowOrderDragRef.current) return;
3398
3412
  const columnIndex = locateColumn(event.clientX);
3399
3413
  const sourceIndex = locateRow(event.clientY);
@@ -3407,7 +3421,7 @@ function TableInner({
3407
3421
  targetIndex: sourceIndex
3408
3422
  };
3409
3423
  }, [columns, locateColumn, locateRow, rowDraggable]);
3410
- const handleRowOrderPointerMove = useCallback2((event) => {
3424
+ const handleRowOrderPointerMove = useCallback3((event) => {
3411
3425
  const drag = rowOrderDragRef.current;
3412
3426
  if (!drag || drag.pointerId !== event.pointerId) return;
3413
3427
  if (!drag.active) {
@@ -3435,7 +3449,7 @@ function TableInner({
3435
3449
  setRowDragPreview(null);
3436
3450
  setRowDragGuide(rowTop + (edge === "bottom" ? rowHeight : 0));
3437
3451
  }, [bodyTop, hideDragTooltips, locateRow, renderHeight, rowHeight, rows.length, setRowDragGuide]);
3438
- const finishRowOrderPointerDrag = useCallback2((event, apply) => {
3452
+ const finishRowOrderPointerDrag = useCallback3((event, apply) => {
3439
3453
  const drag = rowOrderDragRef.current;
3440
3454
  if (!drag || drag.pointerId !== event.pointerId) return;
3441
3455
  if (event.currentTarget.hasPointerCapture?.(event.pointerId)) event.currentTarget.releasePointerCapture?.(event.pointerId);
@@ -3453,7 +3467,7 @@ function TableInner({
3453
3467
  });
3454
3468
  }
3455
3469
  }, [applyRowOrder, setRowDragGuide]);
3456
- const locateCell = useCallback2((clientX, clientY) => {
3470
+ const locateCell = useCallback3((clientX, clientY) => {
3457
3471
  const canvas = canvasRef.current;
3458
3472
  if (!canvas) return null;
3459
3473
  const rect = canvas.getBoundingClientRect();
@@ -3473,7 +3487,7 @@ function TableInner({
3473
3487
  columnKey: columns[targetColumnIndex].key
3474
3488
  };
3475
3489
  }, [bodyTop, columns, fixedHeader, getCellSpan, getRowKey, locateColumn, rowHeight, rows]);
3476
- const beginRangeDrag = useCallback2((event) => {
3490
+ const beginRangeDrag = useCallback3((event) => {
3477
3491
  if (!rangeSelection) return;
3478
3492
  if (event.button !== 0 || editing || event.target !== event.currentTarget) return;
3479
3493
  const cell = locateCell(event.clientX, event.clientY);
@@ -3482,7 +3496,7 @@ function TableInner({
3482
3496
  setSelectionRange(null);
3483
3497
  event.currentTarget.setPointerCapture(event.pointerId);
3484
3498
  }, [columns, editing, locateCell, rangeSelection]);
3485
- const updateRangeDrag = useCallback2((event) => {
3499
+ const updateRangeDrag = useCallback3((event) => {
3486
3500
  const drag = rangeDragRef.current;
3487
3501
  if (!drag) return;
3488
3502
  const focus = locateCell(event.clientX, event.clientY);
@@ -3492,7 +3506,7 @@ function TableInner({
3492
3506
  event.preventDefault();
3493
3507
  setSelectionRange((current) => current?.focus.rowIndex === focus.rowIndex && current.focus.columnIndex === focus.columnIndex ? current : { anchor: drag.anchor, focus });
3494
3508
  }, [columns, locateCell]);
3495
- const endRangeDrag = useCallback2((event) => {
3509
+ const endRangeDrag = useCallback3((event) => {
3496
3510
  const drag = rangeDragRef.current;
3497
3511
  if (!drag) return;
3498
3512
  rangeDragRef.current = null;
@@ -3502,7 +3516,7 @@ function TableInner({
3502
3516
  setSelection(drag.anchor);
3503
3517
  scrollerRef.current?.focus({ preventScroll: true });
3504
3518
  }, [setSelection]);
3505
- const selectRow = useCallback2((rowIndex, event, forceToggle = false) => {
3519
+ const selectRow = useCallback3((rowIndex, event, forceToggle = false) => {
3506
3520
  if (!rowSelection) return;
3507
3521
  clickedCellRef.current = null;
3508
3522
  setSelectionRange(null);
@@ -3522,7 +3536,7 @@ function TableInner({
3522
3536
  rowAnchorRef.current = rowIndex;
3523
3537
  setRowKeys(next);
3524
3538
  }, [getRowKey, rowKeys, rowSelection, rows, selectedRowKeySet, setRowKeys, setSelection]);
3525
- const selectColumn = useCallback2((columnIndex, event) => {
3539
+ const selectColumn = useCallback3((columnIndex, event) => {
3526
3540
  if (!columnSelection || columnIndex < 0) return;
3527
3541
  clickedCellRef.current = null;
3528
3542
  setSelectionRange(null);
@@ -3542,7 +3556,7 @@ function TableInner({
3542
3556
  columnAnchorRef.current = columnIndex;
3543
3557
  setColumnKeys(next);
3544
3558
  }, [columnKeys, columnSelection, columns, selectedColumnKeySet, setColumnKeys, setSelection]);
3545
- const toggleColumnFromMenu = useCallback2((columnIndex) => {
3559
+ const toggleColumnFromMenu = useCallback3((columnIndex) => {
3546
3560
  if (!columnSelection || columnIndex < 0) return;
3547
3561
  clickedCellRef.current = null;
3548
3562
  setSelectionRange(null);
@@ -3554,7 +3568,7 @@ function TableInner({
3554
3568
  columnAnchorRef.current = columnIndex;
3555
3569
  setColumnKeys(next);
3556
3570
  }, [columnKeys, columnSelection, columns, selectedColumnKeySet, setColumnKeys, setSelection]);
3557
- const revealCell = useCallback2((cell) => {
3571
+ const revealCell = useCallback3((cell) => {
3558
3572
  const scroller = scrollerRef.current;
3559
3573
  const metric = metrics[cell.columnIndex];
3560
3574
  const column = columns[cell.columnIndex];
@@ -3584,13 +3598,13 @@ function TableInner({
3584
3598
  scrollRef.current = { left: scroller.scrollLeft, top: scroller.scrollTop };
3585
3599
  scheduleDraw();
3586
3600
  }, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, scheduleDraw, viewport.width]);
3587
- const isCellEditable = useCallback2((cell) => {
3601
+ const isCellEditable = useCallback3((cell) => {
3588
3602
  const column = columns[cell.columnIndex];
3589
3603
  const row = rows[cell.rowIndex];
3590
3604
  if (!column || !row || column.dataIndex === void 0 || column.rowNumber || column.rowSelection || column.rowDragHandle) return false;
3591
3605
  return typeof column.editable === "function" ? column.editable(row[column.dataIndex], row, cell.rowIndex) : column.editable === true;
3592
3606
  }, [columns, rows]);
3593
- const beginEdit = useCallback2((cell) => {
3607
+ const beginEdit = useCallback3((cell) => {
3594
3608
  const column = columns[cell.columnIndex];
3595
3609
  if (!isCellEditable(cell) || column.dataIndex === void 0) return;
3596
3610
  const value = rows[cell.rowIndex]?.[column.dataIndex];
@@ -3660,7 +3674,7 @@ function TableInner({
3660
3674
  return next;
3661
3675
  });
3662
3676
  };
3663
- const commitEdit = useCallback2((nextDraft, close = true) => {
3677
+ const commitEdit = useCallback3((nextDraft, close = true) => {
3664
3678
  if (!editing) return;
3665
3679
  if (!isCellEditable(editing)) {
3666
3680
  setEditing(null);
@@ -3692,6 +3706,7 @@ function TableInner({
3692
3706
  options: column.editor.options,
3693
3707
  searchable: column.editor.searchable,
3694
3708
  allowCustomValue: column.editor.allowCustomValue,
3709
+ strictOptions: column.editor.strictOptions,
3695
3710
  maxDropdownHeight: column.editor.maxDropdownHeight,
3696
3711
  style: editorStyle,
3697
3712
  labels,
@@ -3764,7 +3779,7 @@ function TableInner({
3764
3779
  }
3765
3780
  );
3766
3781
  };
3767
- const handleKeyDown = useCallback2((event) => {
3782
+ const handleKeyDown = useCallback3((event) => {
3768
3783
  if (editing || !selection) return;
3769
3784
  if (event.key === "Enter") {
3770
3785
  event.preventDefault();
@@ -3837,7 +3852,7 @@ function TableInner({
3837
3852
  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)`
3838
3853
  };
3839
3854
  }, [bodyTop, columns, editing, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, leftFixedOffsets, metrics, renderHeight, rightFixedOffsets, rightFixedWidth, rowHeight, rows, rowStyle, viewport.width]);
3840
- const handleColumnPointerDown = useCallback2((event) => {
3855
+ const handleColumnPointerDown = useCallback3((event) => {
3841
3856
  const rect = event.currentTarget.getBoundingClientRect();
3842
3857
  const localY = event.clientY - rect.top;
3843
3858
  const headerY = fixedHeader ? 0 : -scrollRef.current.top;
@@ -3881,7 +3896,7 @@ function TableInner({
3881
3896
  return;
3882
3897
  }
3883
3898
  }, [fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerHeight, headerRowOffsets, locateHeaderResizeHit, metrics]);
3884
- const handleColumnPointerMove = useCallback2((event) => {
3899
+ const handleColumnPointerMove = useCallback3((event) => {
3885
3900
  const drag = columnDragRef.current;
3886
3901
  if (!drag) return;
3887
3902
  const column = columns[drag.columnIndex];
@@ -3917,7 +3932,7 @@ function TableInner({
3917
3932
  resizeColumn(column.key, width2);
3918
3933
  setGuideFromWidths([width2]);
3919
3934
  }, [columnDraggable, columns, getHeaderCellEdgeFromMetrics, resizeColumn, viewport.width]);
3920
- const handleColumnPointerUp = useCallback2((event) => {
3935
+ const handleColumnPointerUp = useCallback3((event) => {
3921
3936
  const drag = columnDragRef.current;
3922
3937
  if (!drag) return;
3923
3938
  if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
@@ -3927,7 +3942,7 @@ function TableInner({
3927
3942
  document.documentElement.classList.remove("rvg-is-dragging");
3928
3943
  event.currentTarget.style.cursor = "default";
3929
3944
  }, []);
3930
- const clearColumnOrderPointerDrag = useCallback2((canvas) => {
3945
+ const clearColumnOrderPointerDrag = useCallback3((canvas) => {
3931
3946
  if (columnOrderLongPressTimerRef.current) {
3932
3947
  clearTimeout(columnOrderLongPressTimerRef.current);
3933
3948
  columnOrderLongPressTimerRef.current = null;
@@ -3940,7 +3955,7 @@ function TableInner({
3940
3955
  document.documentElement.classList.remove("rvg-is-dragging");
3941
3956
  canvas.style.cursor = "default";
3942
3957
  }, [setDragGuide]);
3943
- const updateColumnDragPreview = useCallback2((sourceCell, clientX, canvas) => {
3958
+ const updateColumnDragPreview = useCallback3((sourceCell, clientX, canvas) => {
3944
3959
  const rootRect = rootRef.current?.getBoundingClientRect() ?? canvas.getBoundingClientRect();
3945
3960
  const sourceWidth = metrics[sourceCell.startIndex]?.width ?? 100;
3946
3961
  const previewWidth = sourceWidth;
@@ -3952,7 +3967,7 @@ function TableInner({
3952
3967
  sourceLeft: getDisplayedColumnLeft(sourceCell.startIndex)
3953
3968
  });
3954
3969
  }, [getDisplayedColumnLeft, metrics, viewport.width]);
3955
- const activateColumnOrderPointerDrag = useCallback2((canvas, clientX) => {
3970
+ const activateColumnOrderPointerDrag = useCallback3((canvas, clientX) => {
3956
3971
  const drag = columnOrderDragRef.current;
3957
3972
  if (!drag || drag.active) return;
3958
3973
  if (columnOrderLongPressTimerRef.current) {
@@ -3966,7 +3981,7 @@ function TableInner({
3966
3981
  canvas.style.cursor = "move";
3967
3982
  updateColumnDragPreview(drag.sourceCell, clientX, canvas);
3968
3983
  }, [hideDragTooltips, updateColumnDragPreview]);
3969
- const handleColumnOrderPointerDown = useCallback2((event) => {
3984
+ const handleColumnOrderPointerDown = useCallback3((event) => {
3970
3985
  if (!columnDraggable || event.button !== 0 || columnDragRef.current) return;
3971
3986
  const sourceCell = locateHeaderCell(event.clientX, event.clientY);
3972
3987
  if (!sourceCell || locateHeaderResizeCell(event.clientX, event.clientY)) return;
@@ -3990,7 +4005,7 @@ function TableInner({
3990
4005
  activateColumnOrderPointerDrag(canvas, drag.startX);
3991
4006
  }, 320);
3992
4007
  }, [activateColumnOrderPointerDrag, columnDraggable, columns, locateHeaderAction, locateHeaderCell, locateHeaderResizeCell]);
3993
- const handleColumnOrderPointerMove = useCallback2((event) => {
4008
+ const handleColumnOrderPointerMove = useCallback3((event) => {
3994
4009
  const drag = columnOrderDragRef.current;
3995
4010
  if (!drag || drag.pointerId !== event.pointerId || columnDragRef.current) return;
3996
4011
  if (!drag.active) {
@@ -4061,7 +4076,7 @@ function TableInner({
4061
4076
  columnEdge
4062
4077
  };
4063
4078
  }, [activateColumnOrderPointerDrag, columns, getHeaderCellLeft, getHeaderCellWidth, headerCells, headerRowOffsets, locateColumn, locateHeaderCell, setDragGuide, updateColumnDragPreview]);
4064
- const finishColumnOrderPointerDrag = useCallback2((event, apply) => {
4079
+ const finishColumnOrderPointerDrag = useCallback3((event, apply) => {
4065
4080
  const drag = columnOrderDragRef.current;
4066
4081
  if (!drag || drag.pointerId !== event.pointerId) return;
4067
4082
  if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
@@ -4085,7 +4100,7 @@ function TableInner({
4085
4100
  suppressClickRef.current = false;
4086
4101
  }, 0);
4087
4102
  }, [applyColumnOrder, clearColumnOrderPointerDrag, utilityColumnCount]);
4088
- const queueSortStateChange = useCallback2((next) => {
4103
+ const queueSortStateChange = useCallback3((next) => {
4089
4104
  setSortState(next);
4090
4105
  }, []);
4091
4106
  const renderHeaderIcons = (columnIndex, left) => {
@@ -4120,7 +4135,7 @@ function TableInner({
4120
4135
  }
4121
4136
  return icons;
4122
4137
  };
4123
- const createHeaderTooltip = useCallback2((action, columnIndex, cell) => {
4138
+ const createHeaderTooltip = useCallback3((action, columnIndex, cell) => {
4124
4139
  const column = cell?.column ?? columns[columnIndex];
4125
4140
  if (!column) return null;
4126
4141
  const cellLeft = cell ? getHeaderCellLeft(cell) : getDisplayedColumnLeft(columnIndex);
@@ -4189,7 +4204,7 @@ function TableInner({
4189
4204
  placement
4190
4205
  };
4191
4206
  }, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerActionSize, headerActionSlotWidth, headerDepth, headerLeafHeight, headerLeafTop, headerRowHeights, headerRowOffsets, labels, measureHeaderTitleWidth, metrics, scrollPosition.top, sortState, viewport.width]);
4192
- const isPointerOnHeaderTitle = useCallback2((clientX, clientY, cell) => {
4207
+ const isPointerOnHeaderTitle = useCallback3((clientX, clientY, cell) => {
4193
4208
  const canvas = canvasRef.current;
4194
4209
  if (!canvas) return false;
4195
4210
  const rect = canvas.getBoundingClientRect();
@@ -4210,7 +4225,7 @@ function TableInner({
4210
4225
  const textTop = rowTop + 8;
4211
4226
  return localX >= textLeft - 4 && localX <= textLeft + textWidth + 4 && localY >= textTop - 2 && localY <= textTop + 18;
4212
4227
  }, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, headerRowOffsets]);
4213
- const locateCustomHeaderTooltip = useCallback2((clientX, clientY, columnIndex) => {
4228
+ const locateCustomHeaderTooltip = useCallback3((clientX, clientY, columnIndex) => {
4214
4229
  const root = rootRef.current;
4215
4230
  const canvas = canvasRef.current;
4216
4231
  if (!root || !canvas || columnIndex < 0) return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensui/lens-table",
3
- "version": "0.1.83",
3
+ "version": "0.1.85",
4
4
  "description": "A lightweight, canvas-rendered React table component for LensUI.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",