-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathuseTable.ts
More file actions
122 lines (108 loc) · 4.6 KB
/
useTable.ts
File metadata and controls
122 lines (108 loc) · 4.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import {announce} from '@react-aria/live-announcer';
import {GridAria, GridProps, useGrid} from '@react-aria/grid';
import {gridIds} from './utils';
// @ts-ignore
import intlMessages from '../intl/*.json';
import {Key, LayoutDelegate, Rect, RefObject, Size} from '@react-types/shared';
import {mergeProps, useDescription, useId, useUpdateEffect} from '@react-aria/utils';
import {TableKeyboardDelegate} from './TableKeyboardDelegate';
import {TableState, TreeGridState} from '@react-stately/table';
import {useCollator, useLocale, useLocalizedStringFormatter} from '@react-aria/i18n';
import {useMemo} from 'react';
export interface AriaTableProps extends GridProps {
/** The layout object for the table. Computes what content is visible and how to position and style them. */
layoutDelegate?: LayoutDelegate,
/** @deprecated - Use layoutDelegate instead. */
layout?: DeprecatedLayout
}
interface DeprecatedLayout {
getLayoutInfo(key: Key): DeprecatedLayoutInfo,
getContentSize(): Size,
virtualizer: DeprecatedVirtualizer
}
interface DeprecatedLayoutInfo {
rect: Rect
}
interface DeprecatedVirtualizer {
visibleRect: Rect
}
/**
* Provides the behavior and accessibility implementation for a table component.
* A table displays data in rows and columns and enables a user to navigate its contents via directional navigation keys,
* and optionally supports row selection and sorting.
* @param props - Props for the table.
* @param state - State for the table, as returned by `useTableState`.
* @param ref - The ref attached to the table element.
*/
export function useTable<T>(props: AriaTableProps, state: TableState<T> | TreeGridState<T>, ref: RefObject<HTMLElement | null>): GridAria {
let {
keyboardDelegate,
isVirtualized,
layoutDelegate,
layout
} = props;
// By default, a KeyboardDelegate is provided which uses the DOM to query layout information (e.g. for page up/page down).
// When virtualized, the layout object will be passed in as a prop and override this.
let collator = useCollator({usage: 'search', sensitivity: 'base'});
let {direction} = useLocale();
let disabledBehavior = state.selectionManager.disabledBehavior;
let delegate = useMemo(() => keyboardDelegate || new TableKeyboardDelegate({
collection: state.collection,
disabledKeys: state.disabledKeys,
disabledBehavior,
ref,
direction,
collator,
layoutDelegate,
layout
}), [keyboardDelegate, state.collection, state.disabledKeys, disabledBehavior, ref, direction, collator, layoutDelegate, layout]);
let id = useId(props.id);
gridIds.set(state as TableState<T>, id);
let {gridProps} = useGrid({
...props,
id,
keyboardDelegate: delegate
}, state, ref);
// Override to include header rows
if (isVirtualized) {
gridProps['aria-rowcount'] = state.collection.size + state.collection.headerRows.length;
}
if (state.treeColumn != null) {
gridProps.role = 'treegrid';
}
let {column, direction: sortDirection} = state.sortDescriptor || {};
let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/table');
let sortDescription = useMemo(() => {
let columnName = state.collection.columns.find(c => c.key === column)?.textValue ?? '';
return sortDirection && column ? stringFormatter.format(`${sortDirection}Sort`, {columnName}) : undefined;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sortDirection, column, state.collection.columns]);
let descriptionProps = useDescription(sortDescription);
// Only announce after initial render, tabbing to the table will tell you the initial sort info already
useUpdateEffect(() => {
if (sortDescription) {
announce(sortDescription, 'assertive', 500);
}
}, [sortDescription]);
return {
gridProps: mergeProps(
gridProps,
descriptionProps,
{
// merge sort description with long press information
'aria-describedby': [descriptionProps['aria-describedby'], gridProps['aria-describedby']].filter(Boolean).join(' ')
}
)
};
}