@react-spectrum/table 3.3.2 → 3.3.3-nightly.3472

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/src/TableView.tsx CHANGED
@@ -15,7 +15,7 @@ import {chain, mergeProps, useLayoutEffect} from '@react-aria/utils';
15
15
  import {Checkbox} from '@react-spectrum/checkbox';
16
16
  import {classNames, useDOMRef, useFocusableRef, useStyleProps, useUnwrapDOMRef} from '@react-spectrum/utils';
17
17
  import {DOMRef, FocusableRef} from '@react-types/shared';
18
- import {FocusRing, useFocusRing} from '@react-aria/focus';
18
+ import {FocusRing, FocusScope, useFocusRing} from '@react-aria/focus';
19
19
  import {GridNode} from '@react-types/grid';
20
20
  // @ts-ignore
21
21
  import intlMessages from '../intl/*.json';
@@ -81,7 +81,8 @@ interface TableContextValue<T> {
81
81
  state: TableState<T>,
82
82
  layout: TableLayout<T>,
83
83
  columnState: TableColumnResizeState<T>,
84
- headerRowHovered: boolean
84
+ headerRowHovered: boolean,
85
+ isEmpty: boolean
85
86
  }
86
87
 
87
88
  const TableContext = React.createContext<TableContextValue<unknown>>(null);
@@ -252,6 +253,7 @@ function TableView<T extends object>(props: SpectrumTableProps<T>, ref: DOMRef<H
252
253
  return <TableSelectAllCell column={item} />;
253
254
  }
254
255
 
256
+ // TODO: consider this case, what if we have hidden headers and a empty table
255
257
  if (item.props.hideHeader) {
256
258
  return (
257
259
  <TooltipTrigger placement="top" trigger="focus">
@@ -304,11 +306,13 @@ function TableView<T extends object>(props: SpectrumTableProps<T>, ref: DOMRef<H
304
306
  setHorizontalScollbarVisible(bodyRef.current.clientHeight + 2 < bodyRef.current.offsetHeight);
305
307
  }
306
308
  }, []);
309
+ let {isFocusVisible, focusProps} = useFocusRing();
310
+ let isEmpty = state.collection.size === 0;
307
311
 
308
312
  return (
309
- <TableContext.Provider value={{state, layout, columnState, headerRowHovered}}>
313
+ <TableContext.Provider value={{state, layout, columnState, headerRowHovered, isEmpty}}>
310
314
  <TableVirtualizer
311
- {...gridProps}
315
+ {...mergeProps(gridProps, focusProps)}
312
316
  {...styleProps}
313
317
  className={
314
318
  classNames(
@@ -337,13 +341,14 @@ function TableView<T extends object>(props: SpectrumTableProps<T>, ref: DOMRef<H
337
341
  onVisibleRectChange={onVisibleRectChange}
338
342
  domRef={domRef}
339
343
  bodyRef={bodyRef}
344
+ isFocusVisible={isFocusVisible}
340
345
  getColumnWidth={columnState.getColumnWidth} />
341
346
  </TableContext.Provider>
342
347
  );
343
348
  }
344
349
 
345
350
  // This is a custom Virtualizer that also has a header that syncs its scroll position with the body.
346
- function TableVirtualizer({layout, collection, focusedKey, renderView, renderWrapper, domRef, bodyRef, setTableWidth, getColumnWidth, onVisibleRectChange: onVisibleRectChangeProp, ...otherProps}) {
351
+ function TableVirtualizer({layout, collection, focusedKey, renderView, renderWrapper, domRef, bodyRef, setTableWidth, getColumnWidth, onVisibleRectChange: onVisibleRectChangeProp, isFocusVisible, ...otherProps}) {
347
352
  let {direction} = useLocale();
348
353
  let headerRef = useRef<HTMLDivElement>();
349
354
  let loadingState = collection.body.props.loadingState;
@@ -414,37 +419,48 @@ function TableVirtualizer({layout, collection, focusedKey, renderView, renderWra
414
419
  }, [state.contentSize, state.virtualizer, state.isAnimating, onLoadMore, isLoading]);
415
420
 
416
421
  return (
417
- <div
418
- {...mergeProps(otherProps, virtualizerProps)}
419
- ref={domRef}>
422
+ <FocusScope>
420
423
  <div
421
- role="presentation"
422
- className={classNames(styles, 'spectrum-Table-headWrapper')}
423
- style={{
424
- width: visibleRect.width,
425
- height: headerHeight,
426
- overflow: 'hidden',
427
- position: 'relative',
428
- willChange: state.isScrolling ? 'scroll-position' : '',
429
- transition: state.isAnimating ? `none ${state.virtualizer.transitionDuration}ms` : undefined
430
- }}
431
- ref={headerRef}>
432
- {state.visibleViews[0]}
424
+ // Override virtualizer provided tabindex if TableView is empty so it is tabbable.
425
+ {...mergeProps(otherProps, virtualizerProps, collection.size === 0 && {tabIndex: 0})}
426
+ ref={domRef}>
427
+ <div
428
+ role="presentation"
429
+ className={classNames(styles, 'spectrum-Table-headWrapper')}
430
+ style={{
431
+ width: visibleRect.width,
432
+ height: headerHeight,
433
+ overflow: 'hidden',
434
+ position: 'relative',
435
+ willChange: state.isScrolling ? 'scroll-position' : '',
436
+ transition: state.isAnimating ? `none ${state.virtualizer.transitionDuration}ms` : undefined
437
+ }}
438
+ ref={headerRef}>
439
+ {state.visibleViews[0]}
440
+ </div>
441
+ <ScrollView
442
+ role="presentation"
443
+ className={
444
+ classNames(
445
+ styles,
446
+ 'spectrum-Table-body',
447
+ {
448
+ 'focus-ring': isFocusVisible
449
+ }
450
+ )
451
+ }
452
+ style={{flex: 1}}
453
+ innerStyle={{overflow: 'visible', transition: state.isAnimating ? `none ${state.virtualizer.transitionDuration}ms` : undefined}}
454
+ ref={bodyRef}
455
+ contentSize={state.contentSize}
456
+ onVisibleRectChange={chain(onVisibleRectChange, onVisibleRectChangeProp)}
457
+ onScrollStart={state.startScrolling}
458
+ onScrollEnd={state.endScrolling}
459
+ onScroll={onScroll}>
460
+ {state.visibleViews[1]}
461
+ </ScrollView>
433
462
  </div>
434
- <ScrollView
435
- role="presentation"
436
- className={classNames(styles, 'spectrum-Table-body')}
437
- style={{flex: 1}}
438
- innerStyle={{overflow: 'visible', transition: state.isAnimating ? `none ${state.virtualizer.transitionDuration}ms` : undefined}}
439
- ref={bodyRef}
440
- contentSize={state.contentSize}
441
- onVisibleRectChange={chain(onVisibleRectChange, onVisibleRectChangeProp)}
442
- onScrollStart={state.startScrolling}
443
- onScrollEnd={state.endScrolling}
444
- onScroll={onScroll}>
445
- {state.visibleViews[1]}
446
- </ScrollView>
447
- </div>
463
+ </FocusScope>
448
464
  );
449
465
  }
450
466
 
@@ -461,7 +477,8 @@ function TableHeader({children, ...otherProps}) {
461
477
  function TableColumnHeader(props) {
462
478
  let {column} = props;
463
479
  let ref = useRef<HTMLDivElement>(null);
464
- let {state} = useTableContext();
480
+ let {state, isEmpty} = useTableContext();
481
+ let {pressProps, isPressed} = usePress({isDisabled: isEmpty});
465
482
  let {columnHeaderProps} = useTableColumnHeader({
466
483
  node: column,
467
484
  isVirtualized: true
@@ -469,9 +486,9 @@ function TableColumnHeader(props) {
469
486
 
470
487
  let columnProps = column.props as SpectrumColumnProps<unknown>;
471
488
 
472
- let {hoverProps, isHovered} = useHover(props);
489
+ let {hoverProps, isHovered} = useHover({...props, isDisabled: isEmpty});
473
490
 
474
- const allProps = [columnHeaderProps, hoverProps];
491
+ const allProps = [columnHeaderProps, hoverProps, pressProps];
475
492
 
476
493
  return (
477
494
  <FocusRing focusRingClass={classNames(styles, 'focus-ring')}>
@@ -483,6 +500,7 @@ function TableColumnHeader(props) {
483
500
  styles,
484
501
  'spectrum-Table-headCell',
485
502
  {
503
+ 'is-active': isPressed,
486
504
  'is-resizable': columnProps.allowsResizing,
487
505
  'is-sortable': columnProps.allowsSorting,
488
506
  'is-sorted-desc': state.sortDescriptor?.column === column.key && state.sortDescriptor?.direction === 'descending',
@@ -513,8 +531,9 @@ function TableColumnHeader(props) {
513
531
  }
514
532
 
515
533
  let _TableColumnHeaderButton = (props, ref: FocusableRef<HTMLDivElement>) => {
534
+ let {isEmpty} = useTableContext();
516
535
  let domRef = useFocusableRef(ref);
517
- let {buttonProps} = useButton({...props, elementType: 'div'}, domRef);
536
+ let {buttonProps} = useButton({...props, elementType: 'div', isDisabled: isEmpty}, domRef);
518
537
  return (
519
538
  <div className={classNames(styles, 'spectrum-Table-headCellContents')}>
520
539
  <FocusRing focusRingClass={classNames(styles, 'focus-ring')}>
@@ -530,16 +549,17 @@ function ResizableTableColumnHeader(props) {
530
549
  let ref = useRef(null);
531
550
  let triggerRef = useRef(null);
532
551
  let resizingRef = useRef(null);
533
- let {state, columnState, headerRowHovered} = useTableContext();
552
+ let {state, columnState, headerRowHovered, isEmpty} = useTableContext();
534
553
  let stringFormatter = useLocalizedStringFormatter(intlMessages);
554
+ let {pressProps, isPressed} = usePress({isDisabled: isEmpty});
535
555
  let {columnHeaderProps} = useTableColumnHeader({
536
556
  node: column,
537
557
  isVirtualized: true,
538
558
  hasMenu: true
539
559
  }, state, ref);
540
- let {hoverProps, isHovered} = useHover(props);
560
+ let {hoverProps, isHovered} = useHover({...props, isDisabled: isEmpty});
541
561
 
542
- const allProps = [columnHeaderProps, hoverProps];
562
+ const allProps = [columnHeaderProps, hoverProps, pressProps];
543
563
 
544
564
  let columnProps = column.props as SpectrumColumnProps<unknown>;
545
565
 
@@ -589,7 +609,7 @@ function ResizableTableColumnHeader(props) {
589
609
  }
590
610
  }, [columnState.currentlyResizingColumn, column.key]);
591
611
 
592
- let showResizer = headerRowHovered || columnState.currentlyResizingColumn != null;
612
+ let showResizer = !isEmpty && (headerRowHovered || columnState.currentlyResizingColumn != null);
593
613
 
594
614
  return (
595
615
  <FocusRing focusRingClass={classNames(styles, 'focus-ring')}>
@@ -601,6 +621,7 @@ function ResizableTableColumnHeader(props) {
601
621
  styles,
602
622
  'spectrum-Table-headCell',
603
623
  {
624
+ 'is-active': isPressed,
604
625
  'is-resizable': columnProps.allowsResizing,
605
626
  'is-sortable': columnProps.allowsSorting,
606
627
  'is-sorted-desc': state.sortDescriptor?.column === column.key && state.sortDescriptor?.direction === 'descending',
@@ -685,7 +706,6 @@ function TableSelectAllCell({column}) {
685
706
  }
686
707
  <Checkbox
687
708
  {...checkboxProps}
688
- isDisabled={isSingleSelectionMode}
689
709
  isEmphasized
690
710
  UNSAFE_style={isSingleSelectionMode ? {visibility: 'hidden'} : undefined}
691
711
  UNSAFE_className={classNames(styles, 'spectrum-Table-checkbox')} />