@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.
- package/dist/DragPreview.main.js +1 -1
- package/dist/DragPreview.mjs +1 -1
- package/dist/DragPreview.module.js +1 -1
- package/dist/InsertionIndicator.main.js +4 -3
- package/dist/InsertionIndicator.main.js.map +1 -1
- package/dist/InsertionIndicator.mjs +4 -3
- package/dist/InsertionIndicator.module.js +4 -3
- package/dist/InsertionIndicator.module.js.map +1 -1
- package/dist/Resizer.main.js +7 -7
- package/dist/Resizer.main.js.map +1 -1
- package/dist/Resizer.mjs +8 -8
- package/dist/Resizer.module.js +8 -8
- package/dist/Resizer.module.js.map +1 -1
- package/dist/RootDropIndicator.main.js +1 -1
- package/dist/RootDropIndicator.main.js.map +1 -1
- package/dist/RootDropIndicator.mjs +1 -1
- package/dist/RootDropIndicator.module.js +1 -1
- package/dist/RootDropIndicator.module.js.map +1 -1
- package/dist/TableView.main.js +2 -3
- package/dist/TableView.main.js.map +1 -1
- package/dist/TableView.mjs +2 -3
- package/dist/TableView.module.js +2 -3
- package/dist/TableView.module.js.map +1 -1
- package/dist/TableViewBase.main.js +81 -81
- package/dist/TableViewBase.main.js.map +1 -1
- package/dist/TableViewBase.mjs +81 -81
- package/dist/TableViewBase.module.js +81 -81
- package/dist/TableViewBase.module.js.map +1 -1
- package/dist/TableViewLayout.main.js +7 -5
- package/dist/TableViewLayout.main.js.map +1 -1
- package/dist/TableViewLayout.mjs +7 -5
- package/dist/TableViewLayout.module.js +7 -5
- package/dist/TableViewLayout.module.js.map +1 -1
- package/dist/TableViewWrapper.main.js +4 -5
- package/dist/TableViewWrapper.main.js.map +1 -1
- package/dist/TableViewWrapper.mjs +4 -5
- package/dist/TableViewWrapper.module.js +4 -5
- package/dist/TableViewWrapper.module.js.map +1 -1
- package/dist/TreeGridTableView.main.js +2 -3
- package/dist/TreeGridTableView.main.js.map +1 -1
- package/dist/TreeGridTableView.mjs +2 -3
- package/dist/TreeGridTableView.module.js +2 -3
- package/dist/TreeGridTableView.module.js.map +1 -1
- package/dist/table_vars_css.main.js.map +1 -1
- package/dist/table_vars_css.module.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/{vars.bd693cb4.css → vars.27f08d5f.css} +2 -2
- package/dist/{vars.bd693cb4.css.map → vars.27f08d5f.css.map} +1 -1
- package/package.json +29 -29
- package/src/InsertionIndicator.tsx +5 -5
- package/src/Resizer.tsx +11 -13
- package/src/RootDropIndicator.tsx +4 -4
- package/src/TableView.tsx +2 -5
- package/src/TableViewBase.tsx +136 -126
- package/src/TableViewLayout.ts +11 -5
- package/src/TableViewWrapper.tsx +6 -9
- package/src/TreeGridTableView.tsx +2 -5
package/src/TableViewBase.tsx
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
123
|
-
onResize
|
|
124
|
-
onResizeEnd
|
|
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
|
|
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>(
|
|
185
|
-
let bodyRef = useRef<HTMLDivElement>(
|
|
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
|
-
?
|
|
191
|
+
? undefined
|
|
192
192
|
: ROW_HEIGHTS[density][scale],
|
|
193
193
|
estimatedRowHeight: props.overflowMode === 'wrap'
|
|
194
194
|
? ROW_HEIGHTS[density][scale]
|
|
195
|
-
:
|
|
195
|
+
: undefined,
|
|
196
196
|
headingHeight: props.overflowMode === 'wrap'
|
|
197
|
-
?
|
|
197
|
+
? undefined
|
|
198
198
|
: DEFAULT_HEADER_HEIGHT[scale],
|
|
199
199
|
estimatedHeadingHeight: props.overflowMode === 'wrap'
|
|
200
200
|
? DEFAULT_HEADER_HEIGHT[scale]
|
|
201
|
-
:
|
|
201
|
+
: undefined
|
|
202
202
|
}),
|
|
203
203
|
// don't recompute when state.collection changes, only used for initial value
|
|
204
|
-
|
|
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
|
|
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 :
|
|
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
|
|
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
|
|
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
|
|
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
|
|
569
|
-
|
|
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
|
|
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
|
|
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)
|
|
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
|
-
|
|
621
|
-
|
|
622
|
-
|
|
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
|
-
{...
|
|
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 ?
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
}
|
|
886
|
-
|
|
899
|
+
});
|
|
900
|
+
options.push({
|
|
887
901
|
label: stringFormatter.format('sortDescending'),
|
|
888
902
|
id: 'sort-desc'
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
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(
|
|
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(
|
|
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.
|
|
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(
|
|
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
|
-
|
|
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
|
|
1164
|
-
let
|
|
1165
|
-
let
|
|
1166
|
-
|
|
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
|
-
|
|
1171
|
-
dropIndicator = dragAndDropHooks.useDropIndicator({target}, dropState, dropIndicatorRef);
|
|
1181
|
+
|
|
1182
|
+
dropIndicator = dragAndDropHooks.useDropIndicator!({target}, dropState, dropIndicatorRef);
|
|
1172
1183
|
}
|
|
1173
1184
|
|
|
1174
|
-
let dragButtonRef = React.useRef(
|
|
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()
|
|
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
|
-
{...
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
1418
|
-
let isRootDroptarget
|
|
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(
|
|
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.
|
|
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
|
|
1560
|
+
const ForwardTableViewBase = React.forwardRef(TableViewBase) as <T>(props: TableBaseProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReactElement;
|
|
1551
1561
|
|
|
1552
|
-
export {
|
|
1562
|
+
export {ForwardTableViewBase as TableViewBase};
|