@react-spectrum/table 3.14.1 → 3.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/DragPreview.main.js +1 -1
  2. package/dist/DragPreview.mjs +1 -1
  3. package/dist/DragPreview.module.js +1 -1
  4. package/dist/InsertionIndicator.main.js +4 -3
  5. package/dist/InsertionIndicator.main.js.map +1 -1
  6. package/dist/InsertionIndicator.mjs +4 -3
  7. package/dist/InsertionIndicator.module.js +4 -3
  8. package/dist/InsertionIndicator.module.js.map +1 -1
  9. package/dist/Resizer.main.js +7 -7
  10. package/dist/Resizer.main.js.map +1 -1
  11. package/dist/Resizer.mjs +8 -8
  12. package/dist/Resizer.module.js +8 -8
  13. package/dist/Resizer.module.js.map +1 -1
  14. package/dist/RootDropIndicator.main.js +1 -1
  15. package/dist/RootDropIndicator.main.js.map +1 -1
  16. package/dist/RootDropIndicator.mjs +1 -1
  17. package/dist/RootDropIndicator.module.js +1 -1
  18. package/dist/RootDropIndicator.module.js.map +1 -1
  19. package/dist/TableView.main.js +2 -3
  20. package/dist/TableView.main.js.map +1 -1
  21. package/dist/TableView.mjs +2 -3
  22. package/dist/TableView.module.js +2 -3
  23. package/dist/TableView.module.js.map +1 -1
  24. package/dist/TableViewBase.main.js +81 -81
  25. package/dist/TableViewBase.main.js.map +1 -1
  26. package/dist/TableViewBase.mjs +81 -81
  27. package/dist/TableViewBase.module.js +81 -81
  28. package/dist/TableViewBase.module.js.map +1 -1
  29. package/dist/TableViewLayout.main.js +7 -5
  30. package/dist/TableViewLayout.main.js.map +1 -1
  31. package/dist/TableViewLayout.mjs +7 -5
  32. package/dist/TableViewLayout.module.js +7 -5
  33. package/dist/TableViewLayout.module.js.map +1 -1
  34. package/dist/TableViewWrapper.main.js +4 -5
  35. package/dist/TableViewWrapper.main.js.map +1 -1
  36. package/dist/TableViewWrapper.mjs +4 -5
  37. package/dist/TableViewWrapper.module.js +4 -5
  38. package/dist/TableViewWrapper.module.js.map +1 -1
  39. package/dist/TreeGridTableView.main.js +2 -3
  40. package/dist/TreeGridTableView.main.js.map +1 -1
  41. package/dist/TreeGridTableView.mjs +2 -3
  42. package/dist/TreeGridTableView.module.js +2 -3
  43. package/dist/TreeGridTableView.module.js.map +1 -1
  44. package/dist/table_vars_css.main.js.map +1 -1
  45. package/dist/table_vars_css.module.js.map +1 -1
  46. package/dist/types.d.ts.map +1 -1
  47. package/dist/{vars.bd693cb4.css → vars.27f08d5f.css} +2 -2
  48. package/dist/{vars.bd693cb4.css.map → vars.27f08d5f.css.map} +1 -1
  49. package/package.json +29 -29
  50. package/src/InsertionIndicator.tsx +5 -5
  51. package/src/Resizer.tsx +11 -13
  52. package/src/RootDropIndicator.tsx +4 -4
  53. package/src/TableView.tsx +2 -5
  54. package/src/TableViewBase.tsx +136 -126
  55. package/src/TableViewLayout.ts +11 -5
  56. package/src/TableViewWrapper.tsx +6 -9
  57. package/src/TreeGridTableView.tsx +2 -5
@@ -26,9 +26,9 @@ import {ColumnSize, SpectrumColumnProps, TableCollection} from '@react-types/tab
26
26
  import {DOMRef, DropTarget, FocusableElement, FocusableRef, Key, RefObject} from '@react-types/shared';
27
27
  import type {DragAndDropHooks} from '@react-spectrum/dnd';
28
28
  import type {DraggableCollectionState, DroppableCollectionState} from '@react-stately/dnd';
29
- import type {DraggableItemResult, DropIndicatorAria, DroppableCollectionResult, DroppableItemResult} from '@react-aria/dnd';
29
+ import type {DraggableItemResult, DropIndicatorAria, DroppableCollectionResult} from '@react-aria/dnd';
30
30
  import {FocusRing, FocusScope, useFocusRing} from '@react-aria/focus';
31
- import {getInteractionModality, isFocusVisible, useHover, usePress} from '@react-aria/interactions';
31
+ import {getInteractionModality, HoverProps, isFocusVisible, useHover, usePress} from '@react-aria/interactions';
32
32
  import {GridNode} from '@react-types/grid';
33
33
  import {InsertionIndicator} from './InsertionIndicator';
34
34
  // @ts-ignore
@@ -108,9 +108,9 @@ const LEVEL_OFFSET_WIDTH = {
108
108
 
109
109
  export interface TableContextValue<T> {
110
110
  state: TableState<T> | TreeGridState<T>,
111
- dragState: DraggableCollectionState,
112
- dropState: DroppableCollectionState,
113
- dragAndDropHooks: DragAndDropHooks['dragAndDropHooks'],
111
+ dragState: DraggableCollectionState | null,
112
+ dropState: DroppableCollectionState | null,
113
+ dragAndDropHooks?: DragAndDropHooks['dragAndDropHooks'],
114
114
  isTableDraggable: boolean,
115
115
  isTableDroppable: boolean,
116
116
  layout: TableViewLayout<T>,
@@ -119,20 +119,20 @@ export interface TableContextValue<T> {
119
119
  setIsInResizeMode: (val: boolean) => void,
120
120
  isEmpty: boolean,
121
121
  onFocusedResizer: () => void,
122
- onResizeStart: (widths: Map<Key, ColumnSize>) => void,
123
- onResize: (widths: Map<Key, ColumnSize>) => void,
124
- onResizeEnd: (widths: Map<Key, ColumnSize>) => void,
122
+ onResizeStart?: (widths: Map<Key, ColumnSize>) => void,
123
+ onResize?: (widths: Map<Key, ColumnSize>) => void,
124
+ onResizeEnd?: (widths: Map<Key, ColumnSize>) => void,
125
125
  headerMenuOpen: boolean,
126
126
  setHeaderMenuOpen: (val: boolean) => void,
127
127
  renderEmptyState?: () => ReactElement
128
128
  }
129
129
 
130
- export const TableContext = React.createContext<TableContextValue<unknown>>(null);
130
+ export const TableContext = React.createContext<TableContextValue<unknown> | null>(null);
131
131
  export function useTableContext() {
132
- return useContext(TableContext);
132
+ return useContext(TableContext)!;
133
133
  }
134
134
 
135
- export const VirtualizerContext = React.createContext(null);
135
+ export const VirtualizerContext = React.createContext<{width: number, key: Key | null} | null>(null);
136
136
  export function useVirtualizerContext() {
137
137
  return useContext(VirtualizerContext);
138
138
  }
@@ -181,51 +181,51 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
181
181
  let [, setIsResizing] = useState(false);
182
182
 
183
183
  let domRef = useDOMRef(ref);
184
- let headerRef = useRef<HTMLDivElement>(undefined);
185
- let bodyRef = useRef<HTMLDivElement>(undefined);
184
+ let headerRef = useRef<HTMLDivElement | null>(null);
185
+ let bodyRef = useRef<HTMLDivElement | null>(null);
186
186
 
187
187
  let density = props.density || 'regular';
188
- let layout = useMemo(() => new TableViewLayout({
188
+ let layout = useMemo(() => new TableViewLayout<T>({
189
189
  // If props.rowHeight is auto, then use estimated heights based on scale, otherwise use fixed heights.
190
190
  rowHeight: props.overflowMode === 'wrap'
191
- ? null
191
+ ? undefined
192
192
  : ROW_HEIGHTS[density][scale],
193
193
  estimatedRowHeight: props.overflowMode === 'wrap'
194
194
  ? ROW_HEIGHTS[density][scale]
195
- : null,
195
+ : undefined,
196
196
  headingHeight: props.overflowMode === 'wrap'
197
- ? null
197
+ ? undefined
198
198
  : DEFAULT_HEADER_HEIGHT[scale],
199
199
  estimatedHeadingHeight: props.overflowMode === 'wrap'
200
200
  ? DEFAULT_HEADER_HEIGHT[scale]
201
- : null
201
+ : undefined
202
202
  }),
203
203
  // don't recompute when state.collection changes, only used for initial value
204
- // eslint-disable-next-line react-hooks/exhaustive-deps
204
+
205
205
  [props.overflowMode, scale, density]
206
206
  );
207
207
 
208
- let dragState: DraggableCollectionState;
208
+ let dragState: DraggableCollectionState | null = null;
209
209
  let preview = useRef(null);
210
- if (isTableDraggable) {
211
- dragState = dragAndDropHooks.useDraggableCollectionState({
210
+ if (isTableDraggable && dragAndDropHooks) {
211
+ dragState = dragAndDropHooks.useDraggableCollectionState!({
212
212
  collection: state.collection,
213
213
  selectionManager: state.selectionManager,
214
214
  preview
215
215
  });
216
- dragAndDropHooks.useDraggableCollection({}, dragState, domRef);
216
+ dragAndDropHooks.useDraggableCollection!({}, dragState, domRef);
217
217
  }
218
218
 
219
219
  let DragPreview = dragAndDropHooks?.DragPreview;
220
- let dropState: DroppableCollectionState;
221
- let droppableCollection: DroppableCollectionResult;
222
- let isRootDropTarget: boolean;
223
- if (isTableDroppable) {
224
- dropState = dragAndDropHooks.useDroppableCollectionState({
220
+ let dropState: DroppableCollectionState | null = null;
221
+ let droppableCollection: DroppableCollectionResult | null = null;
222
+ let isRootDropTarget = false;
223
+ if (isTableDroppable && dragAndDropHooks) {
224
+ dropState = dragAndDropHooks.useDroppableCollectionState!({
225
225
  collection: state.collection,
226
226
  selectionManager: state.selectionManager
227
227
  });
228
- droppableCollection = dragAndDropHooks.useDroppableCollection({
228
+ droppableCollection = dragAndDropHooks.useDroppableCollection!({
229
229
  keyboardDelegate: new ListKeyboardDelegate({
230
230
  collection: state.collection,
231
231
  disabledKeys: state.selectionManager.disabledKeys,
@@ -249,13 +249,13 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
249
249
  let [headerRowHovered, setHeaderRowHovered] = useState(false);
250
250
 
251
251
  // This overrides collection view's renderWrapper to support DOM hierarchy.
252
- let renderWrapper = useCallback((parent: View, reusableView: View, children: View[], renderChildren: (views: View[]) => ReactElement[]) => {
252
+ let renderWrapper = useCallback((parent: View | null, reusableView: View, children: View[], renderChildren: (views: View[]) => ReactElement[]): ReactElement => {
253
253
  if (reusableView.viewType === 'rowgroup') {
254
254
  return (
255
255
  <TableRowGroup
256
256
  key={reusableView.key}
257
- layoutInfo={reusableView.layoutInfo}
258
- parent={parent?.layoutInfo}
257
+ layoutInfo={reusableView.layoutInfo!}
258
+ parent={parent?.layoutInfo ?? null}
259
259
  // Override the default role="rowgroup" with role="presentation",
260
260
  // in favor or adding role="rowgroup" to the ScrollView with
261
261
  // ref={bodyRef} in the TableVirtualizer below.
@@ -269,8 +269,8 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
269
269
  return (
270
270
  <TableHeader
271
271
  key={reusableView.key}
272
- layoutInfo={reusableView.layoutInfo}
273
- parent={parent?.layoutInfo}>
272
+ layoutInfo={reusableView.layoutInfo!}
273
+ parent={parent?.layoutInfo ?? null}>
274
274
  {renderChildren(children)}
275
275
  </TableHeader>
276
276
  );
@@ -280,9 +280,9 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
280
280
  return (
281
281
  <TableRow
282
282
  key={reusableView.key}
283
- item={reusableView.content}
284
- layoutInfo={reusableView.layoutInfo}
285
- parent={parent?.layoutInfo}>
283
+ item={reusableView.content!}
284
+ layoutInfo={reusableView.layoutInfo!}
285
+ parent={parent?.layoutInfo ?? null}>
286
286
  {renderChildren(children)}
287
287
  </TableRow>
288
288
  );
@@ -293,9 +293,9 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
293
293
  <TableHeaderRow
294
294
  onHoverChange={setHeaderRowHovered}
295
295
  key={reusableView.key}
296
- layoutInfo={reusableView.layoutInfo}
297
- parent={parent?.layoutInfo}
298
- item={reusableView.content}>
296
+ layoutInfo={reusableView.layoutInfo!}
297
+ parent={parent?.layoutInfo ?? null}
298
+ item={reusableView.content!}>
299
299
  {renderChildren(children)}
300
300
  </TableHeaderRow>
301
301
  );
@@ -304,9 +304,9 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
304
304
  return (
305
305
  <TableCellWrapper
306
306
  key={reusableView.key}
307
- layoutInfo={reusableView.layoutInfo}
307
+ layoutInfo={reusableView.layoutInfo!}
308
308
  virtualizer={reusableView.virtualizer}
309
- parent={parent}>
309
+ parent={parent!}>
310
310
  {reusableView.rendered}
311
311
  </TableCellWrapper>
312
312
  );
@@ -337,7 +337,7 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
337
337
  <div
338
338
  role="gridcell"
339
339
  aria-colindex={item.index + 1}
340
- aria-colspan={item.colspan > 1 ? item.colspan : null} />
340
+ aria-colspan={item.colspan != null && item.colspan > 1 ? item.colspan : undefined} />
341
341
  );
342
342
  case 'column':
343
343
  if (item.props.isSelectionCell) {
@@ -371,6 +371,7 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
371
371
  return <EmptyState />;
372
372
  }
373
373
  }
374
+ return null;
374
375
  }, []);
375
376
 
376
377
  let [isVerticalScrollbarVisible, setVerticalScollbarVisible] = useState(false);
@@ -390,7 +391,9 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
390
391
  let isEmpty = state.collection.size === 0;
391
392
 
392
393
  let onFocusedResizer = () => {
393
- bodyRef.current.scrollLeft = headerRef.current.scrollLeft;
394
+ if (bodyRef.current && headerRef.current) {
395
+ bodyRef.current.scrollLeft = headerRef.current.scrollLeft;
396
+ }
394
397
  };
395
398
 
396
399
  let onResizeStart = useCallback((widths) => {
@@ -419,12 +422,15 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
419
422
  }, [focusedKey, dropTargetKey]);
420
423
 
421
424
  let mergedProps = mergeProps(
422
- isTableDroppable && droppableCollection?.collectionProps,
425
+ isTableDroppable ? droppableCollection?.collectionProps : null,
423
426
  gridProps,
424
- focusProps,
425
- dragAndDropHooks?.isVirtualDragging() && {tabIndex: null}
427
+ focusProps
426
428
  );
427
429
 
430
+ if (dragAndDropHooks?.isVirtualDragging?.()) {
431
+ mergedProps.tabIndex = undefined;
432
+ }
433
+
428
434
  return (
429
435
  <TableContext.Provider
430
436
  value={{
@@ -480,18 +486,21 @@ function TableViewBase<T extends object>(props: TableBaseProps<T>, ref: DOMRef<H
480
486
  headerRef={headerRef}
481
487
  bodyRef={bodyRef}
482
488
  isFocusVisible={isFocusVisible}
483
- isVirtualDragging={dragAndDropHooks?.isVirtualDragging()}
489
+ isVirtualDragging={dragAndDropHooks?.isVirtualDragging?.() || false}
484
490
  isRootDropTarget={isRootDropTarget} />
485
- {DragPreview && isTableDraggable &&
491
+ {DragPreview && isTableDraggable && dragAndDropHooks && dragState &&
486
492
  <DragPreview ref={preview}>
487
493
  {() => {
494
+ if (dragState.draggedKey == null) {
495
+ return null;
496
+ }
488
497
  if (dragAndDropHooks.renderPreview) {
489
498
  return dragAndDropHooks.renderPreview(dragState.draggingKeys, dragState.draggedKey);
490
499
  }
491
500
  let itemCount = dragState.draggingKeys.size;
492
- let maxWidth = bodyRef.current.getBoundingClientRect().width;
501
+ let maxWidth = bodyRef.current!.getBoundingClientRect().width;
493
502
  let height = ROW_HEIGHTS[density][scale];
494
- let itemText = state.collection.getTextValue(dragState.draggedKey);
503
+ let itemText = state.collection.getTextValue!(dragState.draggedKey);
495
504
  return <SpectrumDragPreview itemText={itemText} itemCount={itemCount} height={height} maxWidth={maxWidth} />;
496
505
  }}
497
506
  </DragPreview>
@@ -505,16 +514,16 @@ interface TableVirtualizerProps<T> extends HTMLAttributes<HTMLElement> {
505
514
  layout: TableViewLayout<T>,
506
515
  collection: TableCollection<T>,
507
516
  persistedKeys: Set<Key> | null,
508
- renderView: (type: string, content: GridNode<T>) => ReactElement,
509
- renderWrapper?: (
517
+ renderView: (type: string, content: GridNode<T>) => ReactElement | null,
518
+ renderWrapper: (
510
519
  parent: View | null,
511
520
  reusableView: View,
512
521
  children: View[],
513
522
  renderChildren: (views: View[]) => ReactElement[]
514
- ) => ReactElement,
515
- domRef: RefObject<HTMLDivElement>,
516
- bodyRef: RefObject<HTMLDivElement>,
517
- headerRef: RefObject<HTMLDivElement>,
523
+ ) => ReactElement | null,
524
+ domRef: RefObject<HTMLDivElement | null>,
525
+ bodyRef: RefObject<HTMLDivElement | null>,
526
+ headerRef: RefObject<HTMLDivElement | null>,
518
527
  onVisibleRectChange: (rect: Rect) => void,
519
528
  isFocusVisible: boolean,
520
529
  isVirtualDragging: boolean,
@@ -565,8 +574,10 @@ function TableVirtualizer<T>(props: TableVirtualizerProps<T>) {
565
574
  collection,
566
575
  renderView,
567
576
  onVisibleRectChange(rect) {
568
- bodyRef.current.scrollTop = rect.y;
569
- setScrollLeft(bodyRef.current, direction, rect.x);
577
+ if (bodyRef.current) {
578
+ bodyRef.current.scrollTop = rect.y;
579
+ setScrollLeft(bodyRef.current, direction, rect.x);
580
+ }
570
581
  },
571
582
  persistedKeys,
572
583
  layoutOptions: useMemo(() => ({
@@ -589,7 +600,7 @@ function TableVirtualizer<T>(props: TableVirtualizerProps<T>) {
589
600
  // only that it changes in a resize, and when that happens, we want to sync the body to the
590
601
  // header scroll position
591
602
  useEffect(() => {
592
- if (getInteractionModality() === 'keyboard' && headerRef.current.contains(document.activeElement)) {
603
+ if (getInteractionModality() === 'keyboard' && headerRef.current?.contains(document.activeElement) && bodyRef.current) {
593
604
  scrollIntoView(headerRef.current, document.activeElement as HTMLElement);
594
605
  scrollIntoViewport(document.activeElement, {containingElement: domRef.current});
595
606
  bodyRef.current.scrollLeft = headerRef.current.scrollLeft;
@@ -600,10 +611,12 @@ function TableVirtualizer<T>(props: TableVirtualizerProps<T>) {
600
611
 
601
612
  // Sync the scroll position from the table body to the header container.
602
613
  let onScroll = useCallback(() => {
603
- headerRef.current.scrollLeft = bodyRef.current.scrollLeft;
614
+ if (headerRef.current && bodyRef.current) {
615
+ headerRef.current.scrollLeft = bodyRef.current.scrollLeft;
616
+ }
604
617
  }, [bodyRef, headerRef]);
605
618
 
606
- let resizerPosition = columnResizeState.resizingColumn != null ? layout.getLayoutInfo(columnResizeState.resizingColumn).rect.maxX - 2 : 0;
619
+ let resizerPosition = columnResizeState.resizingColumn != null ? layout.getLayoutInfo(columnResizeState.resizingColumn)!.rect.maxX - 2 : 0;
607
620
 
608
621
  let resizerAtEdge = resizerPosition > Math.max(state.virtualizer.contentSize.width, state.virtualizer.visibleRect.width) - 3;
609
622
  // this should be fine, every movement of the resizer causes a rerender
@@ -617,10 +630,10 @@ function TableVirtualizer<T>(props: TableVirtualizerProps<T>) {
617
630
  width: resizingColumnWidth,
618
631
  key: columnResizeState.resizingColumn
619
632
  }), [resizingColumnWidth, columnResizeState.resizingColumn]);
620
- let mergedProps = mergeProps(
621
- otherProps,
622
- isVirtualDragging && {tabIndex: null}
623
- );
633
+
634
+ if (isVirtualDragging) {
635
+ otherProps.tabIndex = undefined;
636
+ }
624
637
 
625
638
  let firstColumn = collection.columns[0];
626
639
  let scrollPadding = 0;
@@ -634,7 +647,7 @@ function TableVirtualizer<T>(props: TableVirtualizerProps<T>) {
634
647
  <VirtualizerContext.Provider value={resizingColumn}>
635
648
  <FocusScope>
636
649
  <div
637
- {...mergedProps}
650
+ {...otherProps}
638
651
  ref={domRef}>
639
652
  <div
640
653
  role="presentation"
@@ -674,7 +687,7 @@ function TableVirtualizer<T>(props: TableVirtualizerProps<T>) {
674
687
  // Using tabIndex={-1} prevents the ScrollView from being tabbable, and using role="rowgroup"
675
688
  // here and role="presentation" on the table body content fixes the table structure.
676
689
  role="rowgroup"
677
- tabIndex={isVirtualDragging ? null : -1}
690
+ tabIndex={isVirtualDragging ? undefined : -1}
678
691
  style={{
679
692
  flex: 1,
680
693
  scrollPaddingInlineStart: scrollPadding
@@ -697,7 +710,7 @@ function TableVirtualizer<T>(props: TableVirtualizerProps<T>) {
697
710
  );
698
711
  }
699
712
 
700
- function renderChildren<T extends object>(parent: View | null, views: View[], renderWrapper: TableVirtualizerProps<T>['renderWrapper']) {
713
+ function renderChildren<T extends object>(parent: View | null, views: View[], renderWrapper: NonNullable<TableVirtualizerProps<T>['renderWrapper']>) {
701
714
  return views.map(view => {
702
715
  return renderWrapper(
703
716
  parent,
@@ -717,7 +730,7 @@ function useStyle(layoutInfo: LayoutInfo, parent: LayoutInfo | null) {
717
730
  return style;
718
731
  }
719
732
 
720
- function TableHeader({children, layoutInfo, parent, ...otherProps}) {
733
+ function TableHeader({children, layoutInfo, parent, ...otherProps}: {children: ReactNode, layoutInfo: LayoutInfo, parent: LayoutInfo | null}) {
721
734
  let {rowGroupProps} = useTableRowGroup();
722
735
  let style = useStyle(layoutInfo, parent);
723
736
 
@@ -788,7 +801,7 @@ function TableColumnHeader(props) {
788
801
  );
789
802
  }
790
803
 
791
- let _TableColumnHeaderButton = (props, ref: FocusableRef<HTMLDivElement>) => {
804
+ let ForwardTableColumnHeaderButton = (props, ref: FocusableRef<HTMLDivElement>) => {
792
805
  let {focusProps, alignment, ...otherProps} = props;
793
806
  let {isEmpty} = useTableContext();
794
807
  let domRef = useFocusableRef(ref);
@@ -826,7 +839,7 @@ let _TableColumnHeaderButton = (props, ref: FocusableRef<HTMLDivElement>) => {
826
839
  </div>
827
840
  );
828
841
  };
829
- let TableColumnHeaderButton = React.forwardRef(_TableColumnHeaderButton);
842
+ let TableColumnHeaderButton = React.forwardRef(ForwardTableColumnHeaderButton);
830
843
 
831
844
  function ResizableTableColumnHeader(props) {
832
845
  let {column} = props;
@@ -845,7 +858,7 @@ function ResizableTableColumnHeader(props) {
845
858
  headerMenuOpen,
846
859
  setHeaderMenuOpen
847
860
  } = useTableContext();
848
- let columnResizeState = useContext(ResizeStateContext);
861
+ let columnResizeState = useContext(ResizeStateContext)!;
849
862
  let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/table');
850
863
  let {pressProps, isPressed} = usePress({isDisabled: isEmpty});
851
864
  let {columnHeaderProps} = useTableColumnHeader({
@@ -878,20 +891,21 @@ function ResizableTableColumnHeader(props) {
878
891
  };
879
892
  let allowsSorting = column.props?.allowsSorting;
880
893
  let items = useMemo(() => {
881
- let options = [
882
- allowsSorting ? {
894
+ let options: {label: string, id: string}[] = [];
895
+ if (allowsSorting) {
896
+ options.push({
883
897
  label: stringFormatter.format('sortAscending'),
884
898
  id: 'sort-asc'
885
- } : undefined,
886
- allowsSorting ? {
899
+ });
900
+ options.push({
887
901
  label: stringFormatter.format('sortDescending'),
888
902
  id: 'sort-desc'
889
- } : undefined,
890
- {
891
- label: stringFormatter.format('resizeColumn'),
892
- id: 'resize'
893
- }
894
- ];
903
+ });
904
+ }
905
+ options.push({
906
+ label: stringFormatter.format('resizeColumn'),
907
+ id: 'resize'
908
+ });
895
909
  return options;
896
910
  // eslint-disable-next-line react-hooks/exhaustive-deps
897
911
  }, [allowsSorting]);
@@ -992,7 +1006,7 @@ function ResizableTableColumnHeader(props) {
992
1006
  }
993
1007
 
994
1008
  function TableSelectAllCell({column}) {
995
- let ref = useRef(undefined);
1009
+ let ref = useRef<HTMLDivElement | null>(null);
996
1010
  let {state} = useTableContext();
997
1011
  let isSingleSelectionMode = state.selectionManager.selectionMode === 'single';
998
1012
  let {columnHeaderProps} = useTableColumnHeader({
@@ -1039,7 +1053,7 @@ function TableSelectAllCell({column}) {
1039
1053
  }
1040
1054
 
1041
1055
  function TableDragHeaderCell({column}) {
1042
- let ref = useRef(undefined);
1056
+ let ref = useRef<HTMLDivElement | null>(null);
1043
1057
  let {state} = useTableContext();
1044
1058
  let {columnHeaderProps} = useTableColumnHeader({
1045
1059
  node: column,
@@ -1069,9 +1083,9 @@ function TableDragHeaderCell({column}) {
1069
1083
  );
1070
1084
  }
1071
1085
 
1072
- function TableRowGroup({children, layoutInfo, parent, ...otherProps}) {
1086
+ function TableRowGroup({children, layoutInfo, parent, ...otherProps}: {children: ReactNode, layoutInfo: LayoutInfo, parent: LayoutInfo | null, role: string}) {
1073
1087
  let {rowGroupProps} = useTableRowGroup();
1074
- let {isTableDroppable} = useContext(TableContext);
1088
+ let {isTableDroppable} = useContext(TableContext)!;
1075
1089
  let style = useStyle(layoutInfo, parent);
1076
1090
 
1077
1091
  return (
@@ -1108,18 +1122,18 @@ function DragButton() {
1108
1122
 
1109
1123
  interface TableRowContextValue {
1110
1124
  dragButtonProps: React.HTMLAttributes<HTMLDivElement>,
1111
- dragButtonRef: React.MutableRefObject<undefined>,
1125
+ dragButtonRef: React.RefObject<HTMLDivElement | null>,
1112
1126
  isFocusVisibleWithin: boolean
1113
1127
  }
1114
1128
 
1115
1129
 
1116
- const TableRowContext = React.createContext<TableRowContextValue>(null);
1130
+ const TableRowContext = React.createContext<TableRowContextValue | null>(null);
1117
1131
  export function useTableRowContext() {
1118
- return useContext(TableRowContext);
1132
+ return useContext(TableRowContext)!;
1119
1133
  }
1120
1134
 
1121
- function TableRow({item, children, layoutInfo, parent, ...otherProps}) {
1122
- let ref = useRef(undefined);
1135
+ function TableRow({item, children, layoutInfo, parent, ...otherProps}: {item: GridNode<unknown>, children: ReactNode, layoutInfo: LayoutInfo, parent: LayoutInfo | null}) {
1136
+ let ref = useRef<HTMLDivElement | null>(null);
1123
1137
  let {state, layout, dragAndDropHooks, isTableDraggable, isTableDroppable, dragState, dropState} = useTableContext();
1124
1138
  let isSelected = state.selectionManager.isSelected(item.key);
1125
1139
  let {rowProps, hasAction, allowsSelection} = useTableRow({
@@ -1130,7 +1144,6 @@ function TableRow({item, children, layoutInfo, parent, ...otherProps}) {
1130
1144
 
1131
1145
  let isDisabled = state.selectionManager.isDisabled(item.key);
1132
1146
  let isInteractive = !isDisabled && (hasAction || allowsSelection || isTableDraggable);
1133
- let isDroppable = isTableDroppable && !isDisabled;
1134
1147
  let {pressProps, isPressed} = usePress({isDisabled: !isInteractive});
1135
1148
 
1136
1149
  // The row should show the focus background style when any cell inside it is focused.
@@ -1147,31 +1160,29 @@ function TableRow({item, children, layoutInfo, parent, ...otherProps}) {
1147
1160
  // border corners of the last row when selected.
1148
1161
  let isFlushWithContainerBottom = false;
1149
1162
  if (isLastRow) {
1150
- if (layout.getContentSize()?.height >= layout.virtualizer?.visibleRect.height) {
1163
+ if (layout.getContentSize()?.height >= (layout.virtualizer?.visibleRect.height ?? 0)) {
1151
1164
  isFlushWithContainerBottom = true;
1152
1165
  }
1153
1166
  }
1154
1167
 
1155
- let draggableItem: DraggableItemResult;
1156
- if (isTableDraggable) {
1157
- // eslint-disable-next-line react-hooks/rules-of-hooks
1158
- draggableItem = dragAndDropHooks.useDraggableItem({key: item.key, hasDragButton: true}, dragState);
1168
+ let draggableItem: DraggableItemResult | null = null;
1169
+ if (isTableDraggable && dragAndDropHooks && dragState) {
1170
+ draggableItem = dragAndDropHooks.useDraggableItem!({key: item.key, hasDragButton: true}, dragState);
1159
1171
  if (isDisabled) {
1160
1172
  draggableItem = null;
1161
1173
  }
1162
1174
  }
1163
- let droppableItem: DroppableItemResult;
1164
- let isDropTarget: boolean;
1165
- let dropIndicator: DropIndicatorAria;
1166
- let dropIndicatorRef = useRef(undefined);
1167
- if (isTableDroppable) {
1175
+ let isDropTarget = false;
1176
+ let dropIndicator: DropIndicatorAria | null = null;
1177
+ let dropIndicatorRef = useRef<HTMLDivElement | null>(null);
1178
+ if (isTableDroppable && dragAndDropHooks && dropState) {
1168
1179
  let target = {type: 'item', key: item.key, dropPosition: 'on'} as DropTarget;
1169
1180
  isDropTarget = dropState.isDropTarget(target);
1170
- // eslint-disable-next-line react-hooks/rules-of-hooks
1171
- dropIndicator = dragAndDropHooks.useDropIndicator({target}, dropState, dropIndicatorRef);
1181
+
1182
+ dropIndicator = dragAndDropHooks.useDropIndicator!({target}, dropState, dropIndicatorRef);
1172
1183
  }
1173
1184
 
1174
- let dragButtonRef = React.useRef(undefined);
1185
+ let dragButtonRef = React.useRef<HTMLDivElement | null>(null);
1175
1186
  let {buttonProps: dragButtonProps} = useButton({
1176
1187
  ...draggableItem?.dragButtonProps,
1177
1188
  elementType: 'div'
@@ -1190,10 +1201,9 @@ function TableRow({item, children, layoutInfo, parent, ...otherProps}) {
1190
1201
  draggableItem?.dragProps,
1191
1202
  // Remove tab index from list row if performing a screenreader drag. This prevents TalkBack from focusing the row,
1192
1203
  // allowing for single swipe navigation between row drop indicator
1193
- dragAndDropHooks?.isVirtualDragging() && {tabIndex: null}
1204
+ dragAndDropHooks?.isVirtualDragging?.() ? {tabIndex: null} : null
1194
1205
  ) as HTMLAttributes<HTMLElement> & DOMAttributes<FocusableElement>;
1195
1206
 
1196
- let dropProps = isDroppable ? droppableItem?.dropProps : {'aria-hidden': droppableItem?.dropProps['aria-hidden']};
1197
1207
  let {visuallyHiddenProps} = useVisuallyHidden();
1198
1208
 
1199
1209
  return (
@@ -1212,7 +1222,7 @@ function TableRow({item, children, layoutInfo, parent, ...otherProps}) {
1212
1222
  </div>
1213
1223
  }
1214
1224
  <div
1215
- {...mergeProps(props, dropProps)}
1225
+ {...props}
1216
1226
  ref={ref}
1217
1227
  className={
1218
1228
  classNames(
@@ -1222,7 +1232,7 @@ function TableRow({item, children, layoutInfo, parent, ...otherProps}) {
1222
1232
  'is-active': isPressed,
1223
1233
  'is-selected': isSelected,
1224
1234
  'spectrum-Table-row--highlightSelection': state.selectionManager.selectionBehavior === 'replace',
1225
- 'is-next-selected': state.selectionManager.isSelected(item.nextKey),
1235
+ 'is-next-selected': item.nextKey != null && state.selectionManager.isSelected(item.nextKey),
1226
1236
  'is-focused': isFocusVisibleWithin,
1227
1237
  'focus-ring': isFocusVisible,
1228
1238
  'is-hovered': isHovered,
@@ -1250,9 +1260,9 @@ function TableRow({item, children, layoutInfo, parent, ...otherProps}) {
1250
1260
  );
1251
1261
  }
1252
1262
 
1253
- function TableHeaderRow({item, children, layoutInfo, parent, ...props}) {
1263
+ function TableHeaderRow({item, children, layoutInfo, parent, ...props}: {item: GridNode<unknown>, children: ReactNode, layoutInfo: LayoutInfo, parent: LayoutInfo | null} & HoverProps) {
1254
1264
  let {state, headerMenuOpen} = useTableContext();
1255
- let ref = useRef(undefined);
1265
+ let ref = useRef<HTMLDivElement | null>(null);
1256
1266
  let {rowProps} = useTableHeaderRow({node: item, isVirtualized: true}, state, ref);
1257
1267
  let {hoverProps} = useHover({...props, isDisabled: headerMenuOpen});
1258
1268
  let style = useStyle(layoutInfo, parent);
@@ -1265,7 +1275,7 @@ function TableHeaderRow({item, children, layoutInfo, parent, ...props}) {
1265
1275
  }
1266
1276
 
1267
1277
  function TableDragCell({cell}) {
1268
- let ref = useRef(undefined);
1278
+ let ref = useRef<HTMLDivElement | null>(null);
1269
1279
  let {state, isTableDraggable} = useTableContext();
1270
1280
  let isDisabled = state.selectionManager.isDisabled(cell.parentKey);
1271
1281
  let {gridCellProps} = useTableCell({
@@ -1300,7 +1310,7 @@ function TableDragCell({cell}) {
1300
1310
  }
1301
1311
 
1302
1312
  function TableCheckboxCell({cell}) {
1303
- let ref = useRef(undefined);
1313
+ let ref = useRef<HTMLDivElement | null>(null);
1304
1314
  let {state} = useTableContext();
1305
1315
  // The TableCheckbox should always render its disabled status if the row is disabled, regardless of disabledBehavior,
1306
1316
  // but the cell itself should not render its disabled styles if disabledBehavior="selection" because the row might have actions on it.
@@ -1348,7 +1358,7 @@ function TableCell({cell}) {
1348
1358
  let {scale} = useProvider();
1349
1359
  let {state} = useTableContext();
1350
1360
  let isExpandableTable = 'expandedKeys' in state;
1351
- let ref = useRef(undefined);
1361
+ let ref = useRef<HTMLDivElement | null>(null);
1352
1362
  let columnProps = cell.column.props as SpectrumColumnProps<unknown>;
1353
1363
  let isDisabled = state.selectionManager.isDisabled(cell.parentKey);
1354
1364
  let {gridCellProps} = useTableCell({
@@ -1412,11 +1422,11 @@ function TableCell({cell}) {
1412
1422
  );
1413
1423
  }
1414
1424
 
1415
- function TableCellWrapper({layoutInfo, virtualizer, parent, children}) {
1416
- let {isTableDroppable, dropState} = useContext(TableContext);
1417
- let isDropTarget: boolean;
1418
- let isRootDroptarget: boolean;
1419
- if (isTableDroppable) {
1425
+ function TableCellWrapper({layoutInfo, virtualizer, parent, children}: {layoutInfo: LayoutInfo, virtualizer: any, parent: ReusableView<any, any>, children: ReactNode}) {
1426
+ let {isTableDroppable, dropState} = useContext(TableContext)!;
1427
+ let isDropTarget = false;
1428
+ let isRootDroptarget = false;
1429
+ if (isTableDroppable && dropState) {
1420
1430
  if (parent.content) {
1421
1431
  isDropTarget = dropState.isDropTarget({type: 'item', dropPosition: 'on', key: parent.content.key});
1422
1432
  }
@@ -1450,7 +1460,7 @@ function ExpandableRowChevron({cell}) {
1450
1460
  // TODO: move some/all of the chevron button setup into a separate hook?
1451
1461
  let {direction} = useLocale();
1452
1462
  let {state} = useTableContext();
1453
- let expandButtonRef = useRef(undefined);
1463
+ let expandButtonRef = useRef<HTMLSpanElement | null>(null);
1454
1464
  let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/table');
1455
1465
  let isExpanded;
1456
1466
 
@@ -1493,7 +1503,7 @@ function ExpandableRowChevron({cell}) {
1493
1503
  }
1494
1504
 
1495
1505
  function LoadingState() {
1496
- let {state} = useContext(TableContext);
1506
+ let {state} = useContext(TableContext)!;
1497
1507
  let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/table');
1498
1508
  return (
1499
1509
  <CenteredWrapper>
@@ -1505,7 +1515,7 @@ function LoadingState() {
1505
1515
  }
1506
1516
 
1507
1517
  function EmptyState() {
1508
- let {renderEmptyState} = useContext(TableContext);
1518
+ let {renderEmptyState} = useContext(TableContext)!;
1509
1519
  let emptyState = renderEmptyState ? renderEmptyState() : null;
1510
1520
  if (emptyState == null) {
1511
1521
  return null;
@@ -1523,7 +1533,7 @@ function CenteredWrapper({children}) {
1523
1533
  let rowProps;
1524
1534
 
1525
1535
  if ('expandedKeys' in state) {
1526
- let topLevelRowCount = [...state.keyMap.get(state.collection.body.key).childNodes].length;
1536
+ let topLevelRowCount = [...state.collection.body.childNodes].length;
1527
1537
  rowProps = {
1528
1538
  'aria-level': 1,
1529
1539
  'aria-posinset': topLevelRowCount + 1,
@@ -1547,6 +1557,6 @@ function CenteredWrapper({children}) {
1547
1557
  );
1548
1558
  }
1549
1559
 
1550
- const _TableViewBase = React.forwardRef(TableViewBase) as <T>(props: TableBaseProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReactElement;
1560
+ const ForwardTableViewBase = React.forwardRef(TableViewBase) as <T>(props: TableBaseProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReactElement;
1551
1561
 
1552
- export {_TableViewBase as TableViewBase};
1562
+ export {ForwardTableViewBase as TableViewBase};