@react-stately/table 3.15.4 → 3.16.0

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 (76) hide show
  1. package/dist/import.mjs +6 -18
  2. package/dist/main.js +18 -30
  3. package/dist/main.js.map +1 -1
  4. package/dist/module.js +6 -18
  5. package/dist/module.js.map +1 -1
  6. package/dist/types/src/index.d.ts +9 -0
  7. package/package.json +17 -20
  8. package/src/index.ts +9 -16
  9. package/dist/Cell.main.js +0 -38
  10. package/dist/Cell.main.js.map +0 -1
  11. package/dist/Cell.mjs +0 -33
  12. package/dist/Cell.module.js +0 -33
  13. package/dist/Cell.module.js.map +0 -1
  14. package/dist/Column.main.js +0 -75
  15. package/dist/Column.main.js.map +0 -1
  16. package/dist/Column.mjs +0 -66
  17. package/dist/Column.module.js +0 -66
  18. package/dist/Column.module.js.map +0 -1
  19. package/dist/Row.main.js +0 -102
  20. package/dist/Row.main.js.map +0 -1
  21. package/dist/Row.mjs +0 -93
  22. package/dist/Row.module.js +0 -93
  23. package/dist/Row.module.js.map +0 -1
  24. package/dist/TableBody.main.js +0 -61
  25. package/dist/TableBody.main.js.map +0 -1
  26. package/dist/TableBody.mjs +0 -52
  27. package/dist/TableBody.module.js +0 -52
  28. package/dist/TableBody.module.js.map +0 -1
  29. package/dist/TableCollection.main.js +0 -308
  30. package/dist/TableCollection.main.js.map +0 -1
  31. package/dist/TableCollection.mjs +0 -302
  32. package/dist/TableCollection.module.js +0 -302
  33. package/dist/TableCollection.module.js.map +0 -1
  34. package/dist/TableColumnLayout.main.js +0 -113
  35. package/dist/TableColumnLayout.main.js.map +0 -1
  36. package/dist/TableColumnLayout.mjs +0 -108
  37. package/dist/TableColumnLayout.module.js +0 -108
  38. package/dist/TableColumnLayout.module.js.map +0 -1
  39. package/dist/TableHeader.main.js +0 -56
  40. package/dist/TableHeader.main.js.map +0 -1
  41. package/dist/TableHeader.mjs +0 -47
  42. package/dist/TableHeader.module.js +0 -47
  43. package/dist/TableHeader.module.js.map +0 -1
  44. package/dist/TableUtils.main.js +0 -182
  45. package/dist/TableUtils.main.js.map +0 -1
  46. package/dist/TableUtils.mjs +0 -175
  47. package/dist/TableUtils.module.js +0 -175
  48. package/dist/TableUtils.module.js.map +0 -1
  49. package/dist/types.d.ts +0 -194
  50. package/dist/types.d.ts.map +0 -1
  51. package/dist/useTableColumnResizeState.main.js +0 -109
  52. package/dist/useTableColumnResizeState.main.js.map +0 -1
  53. package/dist/useTableColumnResizeState.mjs +0 -104
  54. package/dist/useTableColumnResizeState.module.js +0 -104
  55. package/dist/useTableColumnResizeState.module.js.map +0 -1
  56. package/dist/useTableState.main.js +0 -86
  57. package/dist/useTableState.main.js.map +0 -1
  58. package/dist/useTableState.mjs +0 -80
  59. package/dist/useTableState.module.js +0 -80
  60. package/dist/useTableState.module.js.map +0 -1
  61. package/dist/useTreeGridState.main.js +0 -207
  62. package/dist/useTreeGridState.main.js.map +0 -1
  63. package/dist/useTreeGridState.mjs +0 -202
  64. package/dist/useTreeGridState.module.js +0 -202
  65. package/dist/useTreeGridState.module.js.map +0 -1
  66. package/src/Cell.ts +0 -40
  67. package/src/Column.ts +0 -83
  68. package/src/Row.ts +0 -121
  69. package/src/TableBody.ts +0 -61
  70. package/src/TableCollection.ts +0 -367
  71. package/src/TableColumnLayout.ts +0 -127
  72. package/src/TableHeader.ts +0 -59
  73. package/src/TableUtils.ts +0 -266
  74. package/src/useTableColumnResizeState.ts +0 -147
  75. package/src/useTableState.ts +0 -124
  76. package/src/useTreeGridState.ts +0 -278
package/src/TableUtils.ts DELETED
@@ -1,266 +0,0 @@
1
- /*
2
- * Copyright 2022 Adobe. All rights reserved.
3
- * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License. You may obtain a copy
5
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- *
7
- * Unless required by applicable law or agreed to in writing, software distributed under
8
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
- * OF ANY KIND, either express or implied. See the License for the specific language
10
- * governing permissions and limitations under the License.
11
- */
12
-
13
- import {ColumnSize} from '@react-types/table';
14
- import {Key} from '@react-types/shared';
15
-
16
- // numbers and percents are considered static. *fr units or a lack of units are considered dynamic.
17
- export function isStatic(width?: ColumnSize | null): boolean {
18
- return width != null && (!isNaN(width as number) || (String(width)).match(/^(\d+)(?=%$)/) !== null);
19
- }
20
-
21
- export function parseFractionalUnit(width?: ColumnSize | null): number {
22
- if (!width || typeof width === 'number') {
23
- return 1;
24
- }
25
- let match = width.match(/^(.+)(?=fr$)/);
26
- // if width is the incorrect format, just default it to a 1fr
27
- if (!match) {
28
- if (process.env.NODE_ENV !== 'production') {
29
- console.warn(`width: ${width} is not a supported format, width should be a number (ex. 150), percentage (ex. '50%') or fr unit (ex. '2fr')`,
30
- 'defaulting to \'1fr\'');
31
- }
32
- return 1;
33
- }
34
- return parseFloat(match[0]);
35
- }
36
-
37
- export function parseStaticWidth(width: number | string, tableWidth: number): number {
38
- if (typeof width === 'string') {
39
- let match = width.match(/^(\d+)(?=%$)/);
40
- if (!match) {
41
- throw new Error('Only percentages or numbers are supported for static column widths');
42
- }
43
- return tableWidth * (parseFloat(match[0]) / 100);
44
- }
45
- return width;
46
- }
47
-
48
-
49
- export function getMaxWidth(maxWidth: number | string | null | undefined, tableWidth: number): number {
50
- return maxWidth != null
51
- ? parseStaticWidth(maxWidth, tableWidth)
52
- : Number.MAX_SAFE_INTEGER;
53
- }
54
-
55
- // cannot support FR units, we'd need to know everything else in the table to do that
56
- export function getMinWidth(minWidth: number | string, tableWidth: number): number {
57
- return minWidth != null
58
- ? parseStaticWidth(minWidth, tableWidth)
59
- : 0;
60
- }
61
-
62
-
63
- export interface IColumn {
64
- minWidth?: number | string,
65
- maxWidth?: number | string,
66
- width?: number | string,
67
- defaultWidth?: number | string,
68
- key: Key
69
- }
70
-
71
- interface FlexItem {
72
- frozen: boolean,
73
- baseSize: number,
74
- hypotheticalMainSize: number,
75
- min: number,
76
- max: number,
77
- flex: number,
78
- targetMainSize: number,
79
- violation: number
80
- }
81
-
82
- /**
83
- * Implements the flex algorithm described in https://www.w3.org/TR/css-flexbox-1/#layout-algorithm
84
- * It makes a few constraint/assumptions:
85
- * 1. All basis values are 0 unless it is a static width, then the basis is the static width
86
- * 2. All flex grow and shrink values are equal to the FR specified on the column, grow and shrink for the same column are equal
87
- * 3. We only have one row
88
- * An example of the setup can be seen here https://jsfiddle.net/snowystinger/wv0ymjaf/61/ where I let the browser figure out the
89
- * flex of the columns.
90
- * Note: We differ in one key aspect, all of our column widths must be whole numbers, so we avoid browser
91
- * sub pixel rounding errors. To do this, we use a cascading rounding algorithm to ensure that the sum of the widths is maintained
92
- * while distributing the rounding remainder across the columns.
93
- *
94
- * As noted in the chrome source code, this algorithm is very accurate, but has the potential to be quadratic.
95
- * They have deemed this to be acceptable because the number of elements is usually small and the flex factors
96
- * are usually not high variance. I believe we can make the same assumptions. Particularly once resizing is
97
- * started, it will convert all columns to the left to static widths, so it will cut down on the number of FR columns.
98
- *
99
- * There are likely faster ways to do this, I've chosen to stick to the spec as closely as possible for readability, accuracy, and for the
100
- * note that this behaving quadratically is unlikely to be a problem.
101
- * @param availableWidth - The visible width of the table.
102
- * @param columns - The table defined columns.
103
- * @param changedColumns - Any columns we want to override, for example, during resizing.
104
- * @param getDefaultWidth - A function that returns the default width of a column by its index.
105
- * @param getDefaultMinWidth - A function that returns the default min width of a column by its index.
106
- */
107
- export function calculateColumnSizes(availableWidth: number, columns: IColumn[], changedColumns: Map<Key, ColumnSize>, getDefaultWidth?: (index: number) => ColumnSize | null | undefined, getDefaultMinWidth?: (index: number) => ColumnSize | null | undefined): number[] {
108
- let hasNonFrozenItems = false;
109
- let flexItems: FlexItem[] = columns.map((column, index) => {
110
- let width: ColumnSize = (changedColumns.get(column.key) != null ? changedColumns.get(column.key) ?? '1fr' : column.width ?? column.defaultWidth ?? getDefaultWidth?.(index) ?? '1fr') as ColumnSize;
111
- let frozen = false;
112
- let baseSize = 0;
113
- let flex = 0;
114
- let targetMainSize = 0;
115
- if (isStatic(width)) {
116
- baseSize = parseStaticWidth(width, availableWidth);
117
- frozen = true;
118
- } else {
119
- flex = parseFractionalUnit(width);
120
- if (flex <= 0) {
121
- frozen = true;
122
- }
123
- }
124
-
125
- let min = getMinWidth(column.minWidth ?? getDefaultMinWidth?.(index) ?? 0, availableWidth);
126
- let max = getMaxWidth(column.maxWidth, availableWidth);
127
- let hypotheticalMainSize = Math.max(min, Math.min(baseSize, max));
128
-
129
- // 9.7.1
130
- // We don't make use of flex basis, it's always 0, so we are always in 'grow' mode.
131
- // 9.7.2
132
- if (frozen) {
133
- targetMainSize = hypotheticalMainSize;
134
- } else if (baseSize > hypotheticalMainSize) {
135
- frozen = true;
136
- targetMainSize = hypotheticalMainSize;
137
- }
138
-
139
- // 9.7.3
140
- if (!frozen) {
141
- hasNonFrozenItems = true;
142
- }
143
- return {
144
- frozen,
145
- baseSize,
146
- hypotheticalMainSize,
147
- min,
148
- max,
149
- flex,
150
- targetMainSize,
151
- violation: 0
152
- };
153
- });
154
-
155
- // 9.7.4
156
- // 9.7.4.a
157
- while (hasNonFrozenItems) {
158
- // 9.7.4.b
159
- /**
160
- * Calculate the remaining free space as for initial free space,
161
- * above (9.7.3). If the sum of the unfrozen flex items’ flex factors is
162
- * less than one, multiply the initial free space by this sum (of flex factors).
163
- * If the magnitude of this value is less than the magnitude of
164
- * the remaining free space, use this as the remaining free space.
165
- */
166
- let usedWidth = 0;
167
- let flexFactors = 0;
168
- flexItems.forEach(item => {
169
- if (item.frozen) {
170
- usedWidth += item.targetMainSize;
171
- } else {
172
- usedWidth += item.baseSize;
173
- flexFactors += item.flex;
174
- }
175
- });
176
-
177
- let remainingFreeSpace = availableWidth - usedWidth;
178
- // we only support integer FR's, and because of hasNonFrozenItems, we know that flexFactors > 0
179
- // so no need to check for flexFactors < 1
180
- // 9.7.4.c
181
- /**
182
- * If the remaining free space is zero
183
- * - Do nothing.
184
- * Else // remember, we're always in grow mode
185
- * - Find the ratio of the item’s flex grow factor to the
186
- * sum of the flex grow factors of all unfrozen items on
187
- * the line. Set the item’s target main size to its flex
188
- * base size plus a fraction of the remaining free space
189
- * proportional to the ratio.
190
- */
191
- if (remainingFreeSpace > 0) {
192
- flexItems.forEach((item) => {
193
- if (!item.frozen) {
194
- let ratio = item.flex / flexFactors;
195
- item.targetMainSize = item.baseSize + (ratio * remainingFreeSpace);
196
- }
197
- });
198
- }
199
-
200
- // 9.7.4.d
201
- /**
202
- * Fix min/max violations. Clamp each non-frozen item’s
203
- * target main size by its used min and max main sizes
204
- * and floor its content-box size at zero. If the item’s
205
- * target main size was made smaller by this, it’s a max
206
- * violation. If the item’s target main size was made
207
- * larger by this, it’s a min violation.
208
- */
209
- let totalViolation = 0;
210
- flexItems.forEach(item => {
211
- item.violation = 0;
212
- if (!item.frozen) {
213
- let {min, max, targetMainSize} = item;
214
- item.targetMainSize = Math.max(min, Math.min(targetMainSize, max));
215
-
216
- item.violation = item.targetMainSize - targetMainSize;
217
- totalViolation += item.violation;
218
- }
219
- });
220
-
221
- // 9.7.4.e
222
- /**
223
- * Freeze over-flexed items. The total violation is the
224
- * sum of the adjustments from the previous step
225
- * ∑(clamped size - unclamped size). If the total violation is:
226
- * Zero
227
- * - Freeze all items.
228
- *
229
- * Positive
230
- * - Freeze all the items with min violations.
231
- *
232
- * Negative
233
- * - Freeze all the items with max violations.
234
- */
235
- hasNonFrozenItems = false;
236
- flexItems.forEach(item => {
237
- if (totalViolation === 0 || Math.sign(totalViolation) === Math.sign(item.violation)) {
238
- item.frozen = true;
239
- } else if (!item.frozen) {
240
- hasNonFrozenItems = true;
241
- }
242
- });
243
- }
244
-
245
- return cascadeRounding(flexItems);
246
- }
247
-
248
- function cascadeRounding(flexItems: FlexItem[]): number[] {
249
- /*
250
- Given an array of floats that sum to an integer, this rounds the floats
251
- and returns an array of integers with the same sum.
252
- */
253
-
254
- let fpTotal = 0;
255
- let intTotal = 0;
256
- let roundedArray: number[] = [];
257
- flexItems.forEach(function (item) {
258
- let float = item.targetMainSize;
259
- let integer = Math.round(float + fpTotal) - intTotal;
260
- fpTotal += float;
261
- intTotal += integer;
262
- roundedArray.push(integer);
263
- });
264
-
265
- return roundedArray;
266
- }
@@ -1,147 +0,0 @@
1
- /*
2
- * Copyright 2022 Adobe. All rights reserved.
3
- * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License. You may obtain a copy
5
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- *
7
- * Unless required by applicable law or agreed to in writing, software distributed under
8
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
- * OF ANY KIND, either express or implied. See the License for the specific language
10
- * governing permissions and limitations under the License.
11
- */
12
-
13
- import {ColumnSize} from '@react-types/table';
14
- import {GridNode} from '@react-types/grid';
15
- import {Key} from '@react-types/shared';
16
- import {TableColumnLayout} from './TableColumnLayout';
17
- import {TableState} from './useTableState';
18
- import {useCallback, useMemo, useState} from 'react';
19
-
20
- export interface TableColumnResizeStateProps<T> {
21
- /**
22
- * Current width of the table or table viewport that the columns
23
- * should be calculated against.
24
- */
25
- tableWidth: number,
26
- /** A function that is called to find the default width for a given column. */
27
- getDefaultWidth?: (node: GridNode<T>) => ColumnSize | null | undefined,
28
- /** A function that is called to find the default minWidth for a given column. */
29
- getDefaultMinWidth?: (node: GridNode<T>) => ColumnSize | null | undefined
30
- }
31
- export interface TableColumnResizeState<T> {
32
- /**
33
- * Called to update the state that a resize event has occurred.
34
- * Returns the new widths for all columns based on the resized column.
35
- */
36
- updateResizedColumns: (key: Key, width: number) => Map<Key, ColumnSize>,
37
- /** Callback for when onColumnResize has started. */
38
- startResize: (key: Key) => void,
39
- /** Callback for when onColumnResize has ended. */
40
- endResize: () => void,
41
- /** Gets the current width for the specified column. */
42
- getColumnWidth: (key: Key) => number,
43
- /** Gets the current minWidth for the specified column. */
44
- getColumnMinWidth: (key: Key) => number,
45
- /** Gets the current maxWidth for the specified column. */
46
- getColumnMaxWidth: (key: Key) => number,
47
- /** Key of the currently resizing column. */
48
- resizingColumn: Key | null,
49
- /** A reference to the table state. */
50
- tableState: TableState<T>,
51
- /** A map of the current column widths. */
52
- columnWidths: Map<Key, number>
53
- }
54
-
55
- /**
56
- * Provides column width state management for a table component with column resizing support. Handles building
57
- * a map of column widths calculated from the table's width and any provided column width information from the collection.
58
- * In addition, it tracks the currently resizing column and provides callbacks for updating the widths upon resize operations.
59
- * @param props - Props for the table.
60
- * @param state - State for the table, as returned by `useTableState`.
61
- */
62
- export function useTableColumnResizeState<T>(props: TableColumnResizeStateProps<T>, state: TableState<T>): TableColumnResizeState<T> {
63
- let {
64
- getDefaultWidth,
65
- getDefaultMinWidth,
66
- tableWidth = 0
67
- } = props;
68
-
69
- let [resizingColumn, setResizingColumn] = useState<Key | null>(null);
70
- let columnLayout = useMemo(
71
- () => new TableColumnLayout({
72
- getDefaultWidth,
73
- getDefaultMinWidth
74
- }),
75
- [getDefaultWidth, getDefaultMinWidth]
76
- );
77
-
78
- let [controlledColumns, uncontrolledColumns] = useMemo(() =>
79
- columnLayout.splitColumnsIntoControlledAndUncontrolled(state.collection.columns)
80
- , [state.collection.columns, columnLayout]);
81
-
82
- // uncontrolled column widths
83
- let [uncontrolledWidths, setUncontrolledWidths] = useState(() =>
84
- columnLayout.getInitialUncontrolledWidths(uncontrolledColumns)
85
- );
86
-
87
- // Update uncontrolled widths if the columns changed.
88
- let [lastColumns, setLastColumns] = useState(state.collection.columns);
89
- if (state.collection.columns !== lastColumns) {
90
- if (
91
- state.collection.columns.length !== lastColumns.length ||
92
- state.collection.columns.some((c, i) => c.key !== lastColumns[i].key)
93
- ) {
94
- let newUncontrolledWidths = columnLayout.getInitialUncontrolledWidths(uncontrolledColumns);
95
- setUncontrolledWidths(newUncontrolledWidths);
96
- }
97
- setLastColumns(state.collection.columns);
98
- }
99
-
100
- // combine columns back into one map that maintains same order as the columns
101
- let colWidths = useMemo(() =>
102
- columnLayout.recombineColumns(state.collection.columns, uncontrolledWidths, uncontrolledColumns, controlledColumns)
103
- , [state.collection.columns, uncontrolledWidths, uncontrolledColumns, controlledColumns, columnLayout]);
104
-
105
- let startResize = useCallback((key: Key) => {
106
- setResizingColumn(key);
107
- }, [setResizingColumn]);
108
-
109
- let updateResizedColumns = useCallback((key: Key, width: number): Map<Key, ColumnSize> => {
110
- let newSizes = columnLayout.resizeColumnWidth(state.collection, uncontrolledWidths, key, width);
111
- let map = new Map(Array.from(uncontrolledColumns).map(([key]) => [key, newSizes.get(key)!]));
112
- map.set(key, width);
113
- setUncontrolledWidths(map);
114
- return newSizes;
115
- }, [uncontrolledColumns, setUncontrolledWidths, columnLayout, state.collection, uncontrolledWidths]);
116
-
117
- let endResize = useCallback(() => {
118
- setResizingColumn(null);
119
- }, [setResizingColumn]);
120
-
121
- let columnWidths = useMemo(() =>
122
- columnLayout.buildColumnWidths(tableWidth, state.collection, colWidths)
123
- , [tableWidth, state.collection, colWidths, columnLayout]);
124
-
125
- return useMemo(() => ({
126
- resizingColumn,
127
- updateResizedColumns,
128
- startResize,
129
- endResize,
130
- getColumnWidth: (key: Key) =>
131
- columnLayout.getColumnWidth(key),
132
- getColumnMinWidth: (key: Key) =>
133
- columnLayout.getColumnMinWidth(key),
134
- getColumnMaxWidth: (key: Key) =>
135
- columnLayout.getColumnMaxWidth(key),
136
- tableState: state,
137
- columnWidths
138
- }), [
139
- columnLayout,
140
- columnWidths,
141
- resizingColumn,
142
- updateResizedColumns,
143
- startResize,
144
- endResize,
145
- state
146
- ]);
147
- }
@@ -1,124 +0,0 @@
1
- /*
2
- * Copyright 2020 Adobe. All rights reserved.
3
- * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License. You may obtain a copy
5
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- *
7
- * Unless required by applicable law or agreed to in writing, software distributed under
8
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
- * OF ANY KIND, either express or implied. See the License for the specific language
10
- * governing permissions and limitations under the License.
11
- */
12
-
13
- import {GridState, useGridState} from '@react-stately/grid';
14
- import {TableCollection as ITableCollection, TableBodyProps, TableHeaderProps} from '@react-types/table';
15
- import {Key, Node, SelectionMode, Sortable, SortDescriptor, SortDirection} from '@react-types/shared';
16
- import {MultipleSelectionState, MultipleSelectionStateProps} from '@react-stately/selection';
17
- import {ReactElement, useCallback, useMemo, useState} from 'react';
18
- import {TableCollection} from './TableCollection';
19
- import {useCollection} from '@react-stately/collections';
20
-
21
- export interface TableState<T> extends GridState<T, ITableCollection<T>> {
22
- /** A collection of rows and columns in the table. */
23
- collection: ITableCollection<T>,
24
- /** Whether the row selection checkboxes should be displayed. */
25
- showSelectionCheckboxes: boolean,
26
- /** The current sorted column and direction. */
27
- sortDescriptor: SortDescriptor | null,
28
- /** Calls the provided onSortChange handler with the provided column key and sort direction. */
29
- sort(columnKey: Key, direction?: 'ascending' | 'descending'): void,
30
- /** Whether keyboard navigation is disabled, such as when the arrow keys should be handled by a component within a cell. */
31
- isKeyboardNavigationDisabled: boolean,
32
- /** Set whether keyboard navigation is disabled, such as when the arrow keys should be handled by a component within a cell. */
33
- setKeyboardNavigationDisabled: (val: boolean) => void
34
- }
35
-
36
- export interface CollectionBuilderContext<T> {
37
- showSelectionCheckboxes: boolean,
38
- showDragButtons: boolean,
39
- selectionMode: SelectionMode,
40
- columns: Node<T>[]
41
- }
42
-
43
- export interface TableStateProps<T> extends MultipleSelectionStateProps, Sortable {
44
- /** The elements that make up the table. Includes the TableHeader, TableBody, Columns, and Rows. */
45
- children?: [ReactElement<TableHeaderProps<T>>, ReactElement<TableBodyProps<T>>],
46
- /** A list of row keys to disable. */
47
- disabledKeys?: Iterable<Key>,
48
- /** A pre-constructed collection to use instead of building one from items and children. */
49
- collection?: ITableCollection<T>,
50
- /** Whether the row selection checkboxes should be displayed. */
51
- showSelectionCheckboxes?: boolean,
52
- /** Whether the row drag button should be displayed.
53
- * @private
54
- */
55
- showDragButtons?: boolean,
56
- /** @private - do not use unless you know what you're doing. */
57
- UNSAFE_selectionState?: MultipleSelectionState
58
- }
59
-
60
- const OPPOSITE_SORT_DIRECTION = {
61
- ascending: 'descending' as SortDirection,
62
- descending: 'ascending' as SortDirection
63
- };
64
-
65
- /**
66
- * Provides state management for a table component. Handles building a collection
67
- * of columns and rows from props. In addition, it tracks row selection and manages sort order changes.
68
- */
69
- export function useTableState<T extends object>(props: TableStateProps<T>): TableState<T> {
70
- let [isKeyboardNavigationDisabled, setKeyboardNavigationDisabled] = useState(false);
71
- let {selectionMode = 'none', showSelectionCheckboxes, showDragButtons} = props;
72
-
73
- let context = useMemo(() => ({
74
- showSelectionCheckboxes: showSelectionCheckboxes && selectionMode !== 'none',
75
- showDragButtons: showDragButtons,
76
- selectionMode,
77
- columns: []
78
- // eslint-disable-next-line react-hooks/exhaustive-deps
79
- }), [props.children, showSelectionCheckboxes, selectionMode, showDragButtons]);
80
-
81
- let collection = useCollection<T, ITableCollection<T>>(
82
- props,
83
- useCallback((nodes) => new TableCollection(nodes, null, context), [context]),
84
- context
85
- );
86
- let {disabledKeys, selectionManager} = useGridState({
87
- ...props,
88
- collection,
89
- disabledBehavior: props.disabledBehavior || 'selection'
90
- });
91
-
92
- return {
93
- collection,
94
- disabledKeys,
95
- selectionManager,
96
- showSelectionCheckboxes: props.showSelectionCheckboxes || false,
97
- sortDescriptor: props.sortDescriptor ?? null,
98
- isKeyboardNavigationDisabled: collection.size === 0 || isKeyboardNavigationDisabled,
99
- setKeyboardNavigationDisabled,
100
- sort(columnKey: Key, direction?: 'ascending' | 'descending') {
101
- props.onSortChange?.({
102
- column: columnKey,
103
- direction: direction ?? (props.sortDescriptor?.column === columnKey
104
- ? OPPOSITE_SORT_DIRECTION[props.sortDescriptor.direction]
105
- : 'ascending')
106
- });
107
- }
108
- };
109
- }
110
-
111
- /**
112
- * Filters a collection using the provided filter function and returns a new TableState.
113
- */
114
- export function UNSTABLE_useFilteredTableState<T extends object>(state: TableState<T>, filterFn: ((nodeValue: string, node: Node<T>) => boolean) | null | undefined): TableState<T> {
115
- let collection = useMemo(() => filterFn ? state.collection.filter!(filterFn) : state.collection, [state.collection, filterFn]) as ITableCollection<T>;
116
- let selectionManager = state.selectionManager.withCollection(collection);
117
- // TODO: handle focus key reset? That logic is in useGridState
118
-
119
- return {
120
- ...state,
121
- collection,
122
- selectionManager
123
- };
124
- }