@tanstack/react-table 8.0.0-alpha.1 → 8.0.0-alpha.2

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.
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  Cell,
3
3
  Column,
4
+ CoreHeader,
4
5
  FooterGroupProps,
5
6
  FooterProps,
6
7
  Getter,
@@ -14,6 +15,8 @@ import {
14
15
  } from '../types'
15
16
  import { propGetter, memo, flexRender } from '../utils'
16
17
 
18
+ import * as ColumnSizing from './ColumnSizing'
19
+
17
20
  export type HeadersRow<
18
21
  TData,
19
22
  TValue,
@@ -319,7 +322,7 @@ export function getInstance<
319
322
  ) => {
320
323
  const id = options.id ?? column.id
321
324
 
322
- let header: Header<
325
+ let header: CoreHeader<
323
326
  TData,
324
327
  TValue,
325
328
  TFilterFns,
@@ -338,7 +341,7 @@ export function getInstance<
338
341
  let sum = 0
339
342
 
340
343
  const recurse = (
341
- header: Header<
344
+ header: CoreHeader<
342
345
  TData,
343
346
  TValue,
344
347
  TFilterFns,
@@ -364,7 +367,7 @@ export function getInstance<
364
367
  TSortingFns,
365
368
  TAggregationFns
366
369
  >[] => {
367
- const leafHeaders: Header<
370
+ const leafHeaders: CoreHeader<
368
371
  TData,
369
372
  TValue,
370
373
  TFilterFns,
@@ -373,7 +376,13 @@ export function getInstance<
373
376
  >[] = []
374
377
 
375
378
  const recurseHeader = (
376
- h: Header<TData, TValue, TFilterFns, TSortingFns, TAggregationFns>
379
+ h: CoreHeader<
380
+ TData,
381
+ TValue,
382
+ TFilterFns,
383
+ TSortingFns,
384
+ TAggregationFns
385
+ >
377
386
  ) => {
378
387
  if (h.subHeaders && h.subHeaders.length) {
379
388
  h.subHeaders.map(recurseHeader)
@@ -382,7 +391,14 @@ export function getInstance<
382
391
  }
383
392
 
384
393
  recurseHeader(header)
385
- return leafHeaders
394
+
395
+ return leafHeaders as Header<
396
+ TData,
397
+ TValue,
398
+ TFilterFns,
399
+ TSortingFns,
400
+ TAggregationFns
401
+ >[]
386
402
  },
387
403
  getHeaderProps: userProps =>
388
404
  instance.getHeaderProps(header.id, userProps)!,
@@ -392,7 +408,28 @@ export function getInstance<
392
408
  renderFooter: () => flexRender(column.footer, { header, column }),
393
409
  }
394
410
 
395
- return header
411
+ header = Object.assign(
412
+ header,
413
+ ColumnSizing.createHeader(
414
+ header as Header<
415
+ TData,
416
+ TValue,
417
+ TFilterFns,
418
+ TSortingFns,
419
+ TAggregationFns
420
+ >,
421
+ instance
422
+ )
423
+ )
424
+
425
+ // Yes, we have to convert instance to uknown, because we know more than the compiler here.
426
+ return header as Header<
427
+ TData,
428
+ TValue,
429
+ TFilterFns,
430
+ TSortingFns,
431
+ TAggregationFns
432
+ >
396
433
  },
397
434
 
398
435
  // Header Groups
package/src/types.ts CHANGED
@@ -56,6 +56,14 @@ import {
56
56
  ExpandedTableState,
57
57
  } from './features/Expanding'
58
58
  import { Overwrite } from './utils'
59
+ import {
60
+ ColumnSizingColumn,
61
+ ColumnSizingColumnDef,
62
+ ColumnSizingHeader,
63
+ ColumnSizingInstance,
64
+ ColumnSizingOptions,
65
+ ColumnSizingTableState,
66
+ } from './features/ColumnSizing'
59
67
 
60
68
  // declare global {
61
69
  // const process.env.NODE_ENV !== 'production': boolean
@@ -81,6 +89,13 @@ export type ReactTable<
81
89
  FiltersInstance<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
82
90
  SortingInstance<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
83
91
  GroupingInstance<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
92
+ ColumnSizingInstance<
93
+ TData,
94
+ TValue,
95
+ TFilterFns,
96
+ TSortingFns,
97
+ TAggregationFns
98
+ > &
84
99
  ExpandedInstance<TData, TValue, TFilterFns, TSortingFns, TAggregationFns>
85
100
 
86
101
  export type Renderable<TProps> =
@@ -98,9 +113,10 @@ export type Options<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> =
98
113
  FiltersOptions<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
99
114
  SortingOptions<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
100
115
  GroupingOptions<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
101
- ExpandedOptions<TData, TValue, TFilterFns, TSortingFns, TAggregationFns>
116
+ ExpandedOptions<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
117
+ ColumnSizingOptions
102
118
 
103
- export type Updater<T> = T | ((old?: T) => T)
119
+ export type Updater<T> = T | ((old: T) => T)
104
120
  export type OnChangeFn<T> = (updaterOrValue: Updater<T>, value: T) => void
105
121
 
106
122
  export type TableState = VisibilityTableState &
@@ -109,7 +125,8 @@ export type TableState = VisibilityTableState &
109
125
  FiltersTableState &
110
126
  SortingTableState &
111
127
  ExpandedTableState &
112
- GroupingTableState
128
+ GroupingTableState &
129
+ ColumnSizingTableState
113
130
 
114
131
  export type Row<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> =
115
132
  CoreRow<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
@@ -139,7 +156,8 @@ export type ColumnDef<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> =
139
156
  ColumnPinningColumnDef &
140
157
  FiltersColumnDef<TFilterFns> &
141
158
  SortingColumnDef<TSortingFns> &
142
- GroupingColumnDef<TAggregationFns>
159
+ GroupingColumnDef<TAggregationFns> &
160
+ ColumnSizingColumnDef
143
161
 
144
162
  export type Column<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> =
145
163
  ColumnDef<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
@@ -148,7 +166,8 @@ export type Column<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> =
148
166
  ColumnPinningColumn &
149
167
  FiltersColumn<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
150
168
  SortingColumn<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
151
- GroupingColumn<TData, TValue, TFilterFns, TSortingFns, TAggregationFns>
169
+ GroupingColumn<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
170
+ ColumnSizingColumn<TData, TValue, TFilterFns, TSortingFns, TAggregationFns>
152
171
 
153
172
  export type Cell<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> = {
154
173
  id: string
@@ -161,7 +180,17 @@ export type Cell<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> = {
161
180
  renderCell: () => React.ReactNode
162
181
  }
163
182
 
164
- export type Header<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> = {
183
+ export type Header<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> =
184
+ CoreHeader<TData, TValue, TFilterFns, TSortingFns, TAggregationFns> &
185
+ ColumnSizingHeader<TData, TValue, TFilterFns, TSortingFns, TAggregationFns>
186
+
187
+ export type CoreHeader<
188
+ TData,
189
+ TValue,
190
+ TFilterFns,
191
+ TSortingFns,
192
+ TAggregationFns
193
+ > = {
165
194
  id: string
166
195
  depth: number
167
196
  column: Column<TData, TValue, TFilterFns, TSortingFns, TAggregationFns>
package/src/utils.tsx CHANGED
@@ -1,5 +1,11 @@
1
1
  import React from 'react'
2
- import { Getter, NoInfer, PropGetterValue, Renderable } from './types'
2
+ import {
3
+ Getter,
4
+ NoInfer,
5
+ PropGetterValue,
6
+ Renderable,
7
+ TableState,
8
+ } from './types'
3
9
 
4
10
  export type IsAny<T> = 0 extends 1 & T ? true : false
5
11
  export type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
@@ -26,7 +32,7 @@ export function noop() {
26
32
  //
27
33
  }
28
34
 
29
- export function makeStateUpdater(key: string, instance: unknown) {
35
+ export function makeStateUpdater(key: keyof TableState, instance: unknown) {
30
36
  return (updater: Updater<any, any>) => {
31
37
  ;(instance as any).setState(<TTableState,>(old: TTableState) => {
32
38
  return {
@@ -1,281 +0,0 @@
1
- import React, {
2
- ComponentProps,
3
- MouseEvent as ReactMouseEvent,
4
- PropsWithoutRef,
5
- PropsWithRef,
6
- TouchEvent as ReactTouchEvent,
7
- } from 'react'
8
-
9
- import { getLeafHeaders, makeStateUpdater } from '../utils'
10
-
11
- import { withColumnResizing as name, withColumnVisibility } from '../Constants'
12
- import {
13
- ColumnId,
14
- ColumnResizing,
15
- ReduceColumn,
16
- ReduceHeader,
17
- Header,
18
- MakeInstance,
19
- GetDefaultOptions,
20
- } from '../types'
21
-
22
- let passiveSupported: boolean | null = null
23
-
24
- export function passiveEventSupported() {
25
- // memoize support to avoid adding multiple test events
26
- if (typeof passiveSupported === 'boolean') return passiveSupported
27
-
28
- let supported = false
29
- try {
30
- const options = {
31
- get passive() {
32
- supported = true
33
- return false
34
- },
35
- }
36
-
37
- window.addEventListener('test', noop, options)
38
- window.removeEventListener('test', noop)
39
- } catch (err) {
40
- supported = false
41
- }
42
- passiveSupported = supported
43
- return passiveSupported
44
- }
45
-
46
- const getDefaultOptions: GetDefaultOptions = options => {
47
- return {
48
- onColumnResizingChange: React.useCallback(
49
- makeStateUpdater('columnResizing'),
50
- []
51
- ),
52
- ...options,
53
- initialState: {
54
- columnResizing: {
55
- columnWidths: {},
56
- },
57
- ...options.initialState,
58
- },
59
- }
60
- }
61
-
62
- const extendInstance: MakeInstance = instance => {
63
- instance.setColumnResizing = React.useCallback(
64
- updater => instance.options.onColumnResizingChange?.(updater, instance),
65
- [instance]
66
- )
67
-
68
- instance.getColumnCanResize = React.useCallback(
69
- columnId => {
70
- const column = instance.allColumns.find(d => d.id === columnId)
71
-
72
- if (!column) return false
73
-
74
- return (
75
- (column.disableResizing ? false : undefined) ??
76
- (instance.options?.disableResizing ? false : undefined) ??
77
- column.defaultCanResize ??
78
- true
79
- )
80
- },
81
- [instance.allColumns, instance.options.disableResizing]
82
- )
83
-
84
- instance.getColumnWidth = React.useCallback(
85
- columnId => {
86
- if (!columnId) return 0
87
- const { allColumns } = instance
88
- const column = allColumns.find(d => d.id === columnId)
89
- const columnWidths = instance.state.columnResizing?.columnWidths
90
-
91
- if (!column) return 0
92
-
93
- return Math.min(
94
- Math.max(
95
- column?.minWidth ?? 0,
96
- (columnWidths?.[columnId] ?? 0) || (column.width ?? 0)
97
- ),
98
- column.maxWidth ?? 0
99
- )
100
- },
101
- [instance]
102
- )
103
-
104
- const isResizingColumn = instance.state.columnResizing?.isResizingColumn
105
- instance.getColumnIsResizing = React.useCallback(
106
- columnId => {
107
- return isResizingColumn === columnId
108
- },
109
- [isResizingColumn]
110
- )
111
-
112
- return instance
113
- }
114
-
115
- const reduceColumn: ReduceColumn = (column, { instance }) => {
116
- column.getIsResizing = () => instance.getColumnIsResizing(column.id)
117
- column.getCanResize = () => instance.getColumnCanResize(column.id)
118
-
119
- return column
120
- }
121
-
122
- const reduceHeader: ReduceHeader = (header, { instance }) => {
123
- header.getIsResizing = () =>
124
- header?.column?.getIsResizing ? header.column.getIsResizing() : true
125
- header.getCanResize = () =>
126
- header?.column?.getCanResize ? header.column.getCanResize() : true
127
-
128
- function isTouchStartEvent(
129
- e: ReactTouchEvent | ReactMouseEvent
130
- ): e is ReactTouchEvent {
131
- return e.type === 'touchstart'
132
- }
133
-
134
- header.getResizerProps = (props = {}) => {
135
- const onResizeStart = (
136
- e: ReactMouseEvent | ReactTouchEvent,
137
- header: Header
138
- ) => {
139
- if (isTouchStartEvent(e)) {
140
- // lets not respond to multiple touches (e.g. 2 or 3 fingers)
141
- if (e.touches && e.touches.length > 1) {
142
- return
143
- }
144
- }
145
- const headersToResize = getLeafHeaders(header)
146
- const headerIdWidths: [ColumnId, number][] = headersToResize.map(d => [
147
- d.id,
148
- d.getWidth(),
149
- ])
150
-
151
- const clientX = isTouchStartEvent(e)
152
- ? Math.round(e.touches[0].clientX)
153
- : e.clientX
154
-
155
- const onMove = (clientXPos?: number) => {
156
- if (typeof clientXPos !== 'number') {
157
- return
158
- }
159
-
160
- return instance.setColumnResizing(old => {
161
- const deltaX = clientXPos - (old?.startX ?? 0)
162
- const percentageDeltaX = Math.max(
163
- deltaX / (old?.columnWidth ?? 0),
164
- -0.999999
165
- )
166
-
167
- const newColumnWidths: ColumnResizing['columnWidths'] = {}
168
- ;(old?.headerIdWidths ?? []).forEach(([headerId, headerWidth]) => {
169
- newColumnWidths[headerId] = Math.max(
170
- headerWidth + headerWidth * percentageDeltaX,
171
- 0
172
- )
173
- })
174
-
175
- return {
176
- ...old,
177
- columnWidths: {
178
- ...(old?.columnWidths ?? {}),
179
- ...newColumnWidths,
180
- },
181
- }
182
- })
183
- }
184
-
185
- const onEnd = () =>
186
- instance.setColumnResizing(old => ({
187
- ...old,
188
- startX: null,
189
- isResizingColumn: false,
190
- }))
191
-
192
- const mouseEvents = {
193
- moveHandler: (e: MouseEvent) => onMove(e.clientX),
194
- upHandler: () => {
195
- document.removeEventListener('mousemove', mouseEvents.moveHandler)
196
- document.removeEventListener('mouseup', mouseEvents.upHandler)
197
- onEnd()
198
- },
199
- }
200
-
201
- const touchEvents = {
202
- moveHandler: (e: TouchEvent) => {
203
- if (e.cancelable) {
204
- e.preventDefault()
205
- e.stopPropagation()
206
- }
207
- onMove(e.touches[0].clientX)
208
- return false
209
- },
210
- upHandler: () => {
211
- document.removeEventListener('touchmove', touchEvents.moveHandler)
212
- document.removeEventListener('touchend', touchEvents.upHandler)
213
- onEnd()
214
- },
215
- }
216
-
217
- const passiveIfSupported = passiveEventSupported()
218
- ? { passive: false }
219
- : false
220
-
221
- if (isTouchStartEvent(e)) {
222
- document.addEventListener(
223
- 'touchmove',
224
- touchEvents.moveHandler,
225
- passiveIfSupported
226
- )
227
- document.addEventListener(
228
- 'touchend',
229
- touchEvents.upHandler,
230
- passiveIfSupported
231
- )
232
- } else {
233
- document.addEventListener(
234
- 'mousemove',
235
- mouseEvents.moveHandler,
236
- passiveIfSupported
237
- )
238
- document.addEventListener(
239
- 'mouseup',
240
- mouseEvents.upHandler,
241
- passiveIfSupported
242
- )
243
- }
244
-
245
- instance.setColumnResizing(old => ({
246
- ...old,
247
- startX: clientX,
248
- headerIdWidths,
249
- columnWidth: header.getWidth(),
250
- isResizingColumn: header.id,
251
- }))
252
- }
253
-
254
- return {
255
- onMouseDown: (e: ReactMouseEvent) => {
256
- e.persist()
257
- onResizeStart(e, header)
258
- },
259
- onTouchStart: (e: ReactTouchEvent) => {
260
- e.persist()
261
- onResizeStart(e, header)
262
- },
263
- draggable: false,
264
- role: 'separator',
265
- ...props,
266
- }
267
- }
268
-
269
- return header
270
- }
271
-
272
- export const withColumnResizing = {
273
- name,
274
- after: [withColumnVisibility],
275
- plugs: {
276
- getDefaultOptions,
277
- extendInstance,
278
- reduceColumn,
279
- reduceHeader,
280
- },
281
- }