react-hook-tanstack-table 0.0.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.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.org +29 -0
  3. package/dist/TableContext.cjs +6 -0
  4. package/dist/TableContext.d.cts +7 -0
  5. package/dist/TableContext.d.cts.map +1 -0
  6. package/dist/TableContext.d.ts +7 -0
  7. package/dist/TableContext.d.ts.map +1 -0
  8. package/dist/TableContext.js +8 -0
  9. package/dist/TableContext.js.map +1 -0
  10. package/dist/hasTableArg-Bu3FbcSo.js +8 -0
  11. package/dist/hasTableArg-Bu3FbcSo.js.map +1 -0
  12. package/dist/hasTableArg-dMtayKWH.cjs +11 -0
  13. package/dist/index.cjs +40 -0
  14. package/dist/index.d.cts +11 -0
  15. package/dist/index.d.ts +11 -0
  16. package/dist/index.js +11 -0
  17. package/dist/invariant-BgWq7zZS.js +12 -0
  18. package/dist/invariant-BgWq7zZS.js.map +1 -0
  19. package/dist/invariant-D8b385d_.cjs +21 -0
  20. package/dist/isShallowEqual-D6PQ041u.cjs +36 -0
  21. package/dist/isShallowEqual-Kynsoe7a.js +33 -0
  22. package/dist/isShallowEqual-Kynsoe7a.js.map +1 -0
  23. package/dist/runGetters-BfRTE7LZ.js +16 -0
  24. package/dist/runGetters-BfRTE7LZ.js.map +1 -0
  25. package/dist/runGetters-Q-UsPG2j.cjs +19 -0
  26. package/dist/types-DIWB6wdO.d.cts +11 -0
  27. package/dist/types-DIWB6wdO.d.cts.map +1 -0
  28. package/dist/types-DIWB6wdO.d.ts +11 -0
  29. package/dist/types-DIWB6wdO.d.ts.map +1 -0
  30. package/dist/useCell.cjs +53 -0
  31. package/dist/useCell.d.cts +17 -0
  32. package/dist/useCell.d.cts.map +1 -0
  33. package/dist/useCell.d.ts +17 -0
  34. package/dist/useCell.d.ts.map +1 -0
  35. package/dist/useCell.js +53 -0
  36. package/dist/useCell.js.map +1 -0
  37. package/dist/useColumn.cjs +54 -0
  38. package/dist/useColumn.d.cts +19 -0
  39. package/dist/useColumn.d.cts.map +1 -0
  40. package/dist/useColumn.d.ts +19 -0
  41. package/dist/useColumn.d.ts.map +1 -0
  42. package/dist/useColumn.js +54 -0
  43. package/dist/useColumn.js.map +1 -0
  44. package/dist/useHeader.cjs +48 -0
  45. package/dist/useHeader.d.cts +19 -0
  46. package/dist/useHeader.d.cts.map +1 -0
  47. package/dist/useHeader.d.ts +19 -0
  48. package/dist/useHeader.d.ts.map +1 -0
  49. package/dist/useHeader.js +48 -0
  50. package/dist/useHeader.js.map +1 -0
  51. package/dist/useReactTable-Y2z5JrT_.js +70 -0
  52. package/dist/useReactTable-Y2z5JrT_.js.map +1 -0
  53. package/dist/useReactTable-nxQRPiMU.cjs +95 -0
  54. package/dist/useReactTable.cjs +3 -0
  55. package/dist/useReactTable.d.cts +10 -0
  56. package/dist/useReactTable.d.cts.map +1 -0
  57. package/dist/useReactTable.d.ts +10 -0
  58. package/dist/useReactTable.d.ts.map +1 -0
  59. package/dist/useReactTable.js +2 -0
  60. package/dist/useRow.cjs +54 -0
  61. package/dist/useRow.d.cts +19 -0
  62. package/dist/useRow.d.cts.map +1 -0
  63. package/dist/useRow.d.ts +19 -0
  64. package/dist/useRow.d.ts.map +1 -0
  65. package/dist/useRow.js +54 -0
  66. package/dist/useRow.js.map +1 -0
  67. package/dist/useTable.cjs +44 -0
  68. package/dist/useTable.d.cts +11 -0
  69. package/dist/useTable.d.cts.map +1 -0
  70. package/dist/useTable.d.ts +11 -0
  71. package/dist/useTable.d.ts.map +1 -0
  72. package/dist/useTable.js +44 -0
  73. package/dist/useTable.js.map +1 -0
  74. package/dist/useTableWithSelector-Bdsf6Zxk.cjs +79 -0
  75. package/dist/useTableWithSelector-D3f689pF.js +70 -0
  76. package/dist/useTableWithSelector-D3f689pF.js.map +1 -0
  77. package/dist/useTableWithSelector.cjs +3 -0
  78. package/dist/useTableWithSelector.d.cts +8 -0
  79. package/dist/useTableWithSelector.d.cts.map +1 -0
  80. package/dist/useTableWithSelector.d.ts +8 -0
  81. package/dist/useTableWithSelector.d.ts.map +1 -0
  82. package/dist/useTableWithSelector.js +2 -0
  83. package/package.json +99 -0
  84. package/src/contexts/TableContext.ts +7 -0
  85. package/src/hooks/useCell.ts +156 -0
  86. package/src/hooks/useColumn.ts +168 -0
  87. package/src/hooks/useHeader.ts +151 -0
  88. package/src/hooks/useReactTable.ts +88 -0
  89. package/src/hooks/useRow.ts +132 -0
  90. package/src/hooks/useTable.ts +113 -0
  91. package/src/hooks/useTableWithSelector.ts +143 -0
  92. package/src/index.ts +13 -0
  93. package/src/lib/hasTableArg.ts +19 -0
  94. package/src/lib/identity.ts +1 -0
  95. package/src/lib/invariant.ts +12 -0
  96. package/src/lib/isShallowEqual.ts +77 -0
  97. package/src/lib/runGetters.ts +17 -0
  98. package/src/lib/tableRegistry.ts +3 -0
  99. package/src/lib/uncapitalize.ts +2 -0
  100. package/src/lib/useLayoutEffect.ts +3 -0
  101. package/src/lib/useShallowMemo.ts +12 -0
  102. package/src/types.ts +24 -0
@@ -0,0 +1,156 @@
1
+ import { useCallback } from "react"
2
+
3
+ import type {
4
+ Cell,
5
+ Column,
6
+ RequiredKeys,
7
+ Row,
8
+ RowData,
9
+ Table,
10
+ TableOptionsResolved,
11
+ } from "@tanstack/table-core"
12
+
13
+ import { identity } from "../lib/identity"
14
+ import { hasTableArg } from "../lib/hasTableArg"
15
+ import { runGetters } from "../lib/runGetters"
16
+ import { isShallowEqual } from "../lib/isShallowEqual"
17
+ import { invariant } from "../lib/invariant"
18
+
19
+ import type { IsEqual, RunGetters } from "../types"
20
+
21
+ import type { ColumnValues } from "./useColumn"
22
+ import type { RowValues } from "./useRow"
23
+ import { useTableWithSelector } from "./useTableWithSelector"
24
+
25
+ export interface CellValues<TData extends RowData, TValue> extends RunGetters<
26
+ Cell<TData, TValue>
27
+ > {}
28
+
29
+ const cellValuesCache = new WeakMap<
30
+ RequiredKeys<TableOptionsResolved<any>, "state">,
31
+ Map<string, Map<string, CellValues<any, any>>>
32
+ >()
33
+
34
+ const getCellValues = <TData extends RowData, TValue>(
35
+ table: Table<TData>,
36
+ rowId: string,
37
+ columnId: string,
38
+ ): CellValues<TData, TValue> => {
39
+ let cellCache = cellValuesCache.get(table.options)
40
+ if (!cellCache) {
41
+ cellCache = new Map()
42
+ cellValuesCache.set(table.options, cellCache)
43
+ }
44
+
45
+ let rowCache = cellCache.get(rowId)
46
+ if (!rowCache) {
47
+ rowCache = new Map()
48
+ cellCache.set(rowId, rowCache)
49
+ }
50
+
51
+ let cached = rowCache.get(columnId)
52
+
53
+ if (!cached) {
54
+ const cell = table
55
+ .getRow(rowId)
56
+ ?.getAllCells()
57
+ .find((c) => c.column.id === columnId) as Cell<TData, TValue> | undefined
58
+
59
+ invariant(cell)
60
+
61
+ cached = runGetters(cell)
62
+
63
+ rowCache.set(columnId, cached)
64
+ }
65
+
66
+ return cached
67
+ }
68
+
69
+ type Selector<TData extends RowData, TValue, Selection> = (
70
+ cellValues: CellValues<TData, TValue>,
71
+ ) => Selection
72
+
73
+ interface CellCoords<TData extends RowData, TValue> {
74
+ column: Column<TData, TValue> | ColumnValues<TData> | string
75
+ row: Row<TData> | RowValues<TData> | string
76
+ }
77
+
78
+ export const useCell = <
79
+ TData extends RowData,
80
+ TValue,
81
+ Selection = CellValues<TData, TValue>,
82
+ >(
83
+ ...args:
84
+ | [
85
+ table: Table<TData> | undefined,
86
+ cell:
87
+ | Cell<TData, TValue>
88
+ | CellValues<TData, TValue>
89
+ | CellCoords<TData, TValue>,
90
+ selector?: Selector<TData, TValue, Selection> | undefined,
91
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
92
+ ]
93
+ | [
94
+ cell:
95
+ | Cell<TData, TValue>
96
+ | CellValues<TData, TValue>
97
+ | CellCoords<TData, TValue>,
98
+ selector?: Selector<TData, TValue, Selection> | undefined,
99
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
100
+ ]
101
+ ): Selection => {
102
+ const [
103
+ table,
104
+ cellOrCoords,
105
+ selector = identity as never,
106
+ isEqual = isShallowEqual,
107
+ ] = hasTableArg(args) ? args : [undefined, ...args]
108
+
109
+ const { columnId, rowId } =
110
+ "id" in cellOrCoords ?
111
+ { columnId: cellOrCoords.column.id, rowId: cellOrCoords.row.id }
112
+ : {
113
+ columnId:
114
+ typeof cellOrCoords.column === "string" ?
115
+ cellOrCoords.column
116
+ : cellOrCoords.column.id,
117
+ rowId:
118
+ typeof cellOrCoords.row === "string" ?
119
+ cellOrCoords.row
120
+ : cellOrCoords.row.id,
121
+ }
122
+
123
+ const getSelection = useCallback(
124
+ (table: Table<TData>) => selector(getCellValues(table, rowId, columnId)),
125
+ [columnId, rowId, selector],
126
+ )
127
+
128
+ return useTableWithSelector(table, getSelection, isEqual)
129
+ }
130
+
131
+ const cellHook = useCell
132
+
133
+ const cellHookʹ =
134
+ <TData extends RowData, TValue>(
135
+ ...args:
136
+ | [
137
+ table: Table<TData> | undefined,
138
+ cell:
139
+ | Cell<TData, TValue>
140
+ | CellValues<TData, TValue>
141
+ | CellCoords<TData, TValue>,
142
+ ]
143
+ | [
144
+ cell:
145
+ | Cell<TData, TValue>
146
+ | CellValues<TData, TValue>
147
+ | CellCoords<TData, TValue>,
148
+ ]
149
+ ) =>
150
+ <Selection = CellValues<TData, TValue>>(
151
+ selector?: Selector<TData, TValue, Selection> | undefined,
152
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
153
+ ): Selection =>
154
+ cellHook(...[...args, selector, isEqual])
155
+
156
+ export { cellHookʹ as useCellʹ }
@@ -0,0 +1,168 @@
1
+ import { useCallback } from "react"
2
+
3
+ import type {
4
+ Column,
5
+ RequiredKeys,
6
+ RowData,
7
+ Table,
8
+ TableOptionsResolved,
9
+ } from "@tanstack/table-core"
10
+
11
+ import { identity } from "../lib/identity"
12
+ import { hasTableArg } from "../lib/hasTableArg"
13
+ import { runGetters } from "../lib/runGetters"
14
+ import { isShallowEqual } from "../lib/isShallowEqual"
15
+ import { invariant } from "../lib/invariant"
16
+
17
+ import type { IsEqual, RunGetters } from "../types"
18
+
19
+ import { useTableWithSelector } from "./useTableWithSelector"
20
+
21
+ export interface ColumnValues<
22
+ TData extends RowData,
23
+ TValue = unknown,
24
+ > extends RunGetters<Column<TData, TValue>> {}
25
+
26
+ const columnValuesCache = new WeakMap<
27
+ RequiredKeys<TableOptionsResolved<any>, "state">,
28
+ Map<string, ColumnValues<any, any>>
29
+ >()
30
+
31
+ const columnHandlersCache = new WeakMap<
32
+ Column<any, any>,
33
+ {
34
+ toggleGroupingHandler: ReturnType<
35
+ Column<any, any>["getToggleGroupingHandler"]
36
+ >
37
+ toggleSortingHandler: ReturnType<
38
+ Column<any, any>["getToggleSortingHandler"]
39
+ >
40
+ toggleVisibilityHandler: ReturnType<
41
+ Column<any, any>["getToggleVisibilityHandler"]
42
+ >
43
+ }
44
+ >()
45
+
46
+ const getColumnValues = <TData extends RowData, TValue = unknown>(
47
+ table: Table<TData>,
48
+ columnId: string,
49
+ ): ColumnValues<TData, TValue> => {
50
+ let columnCache = columnValuesCache.get(table.options)
51
+ if (!columnCache) {
52
+ columnCache = new Map()
53
+ columnValuesCache.set(table.options, columnCache)
54
+ }
55
+
56
+ let cached = columnCache.get(columnId)
57
+
58
+ if (!cached) {
59
+ const column = table.getColumn(columnId) as
60
+ | Column<TData, TValue>
61
+ | undefined
62
+
63
+ invariant(column)
64
+
65
+ let cachedHandlers = columnHandlersCache.get(column)
66
+ if (!cachedHandlers) {
67
+ cachedHandlers = {
68
+ toggleGroupingHandler: column.getToggleGroupingHandler(),
69
+ toggleSortingHandler: column.getToggleSortingHandler(),
70
+ toggleVisibilityHandler: column.getToggleVisibilityHandler(),
71
+ }
72
+ columnHandlersCache.set(column, cachedHandlers)
73
+ }
74
+
75
+ const {
76
+ toggleGroupingHandler,
77
+ toggleSortingHandler,
78
+ toggleVisibilityHandler,
79
+ } = cachedHandlers
80
+
81
+ cached = {
82
+ ...runGetters(column),
83
+ toggleGroupingHandler,
84
+ toggleSortingHandler,
85
+ toggleVisibilityHandler,
86
+ }
87
+
88
+ columnCache.set(columnId, cached)
89
+ }
90
+
91
+ return cached
92
+ }
93
+
94
+ type Selector<TData extends RowData, TValue, Selection> = (
95
+ table: ColumnValues<TData, TValue>,
96
+ ) => Selection
97
+
98
+ export const useColumn = <
99
+ TData extends RowData,
100
+ TValue = unknown,
101
+ Selection = ColumnValues<TData, TValue>,
102
+ >(
103
+ ...args:
104
+ | [
105
+ table: Table<TData> | undefined,
106
+ column:
107
+ | Column<TData, TValue>
108
+ | ColumnValues<TData, TValue>
109
+ | { id: string }
110
+ | string,
111
+ selector?: Selector<TData, TValue, Selection> | undefined,
112
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
113
+ ]
114
+ | [
115
+ column:
116
+ | Column<TData, TValue>
117
+ | ColumnValues<TData, TValue>
118
+ | { id: string }
119
+ | string,
120
+ selector?: Selector<TData, TValue, Selection> | undefined,
121
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
122
+ ]
123
+ ): Selection => {
124
+ const [
125
+ table,
126
+ columnOrId,
127
+ selector = identity as never,
128
+ isEqual = isShallowEqual,
129
+ ] = hasTableArg(args) ? args : [undefined, ...args]
130
+
131
+ const columnId = typeof columnOrId === "string" ? columnOrId : columnOrId.id
132
+
133
+ const getSelection = useCallback(
134
+ (table: Table<TData>) => selector(getColumnValues(table, columnId)),
135
+ [columnId, selector],
136
+ )
137
+
138
+ return useTableWithSelector(table, getSelection, isEqual)
139
+ }
140
+
141
+ const columnHook = useColumn
142
+
143
+ const columnHookʹ =
144
+ <TData extends RowData, TValue = unknown>(
145
+ ...args:
146
+ | [
147
+ table: Table<TData> | undefined,
148
+ column:
149
+ | Column<TData, TValue>
150
+ | ColumnValues<TData, TValue>
151
+ | { id: string }
152
+ | string,
153
+ ]
154
+ | [
155
+ column:
156
+ | Column<TData, TValue>
157
+ | ColumnValues<TData, TValue>
158
+ | { id: string }
159
+ | string,
160
+ ]
161
+ ) =>
162
+ <Selection = ColumnValues<TData, TValue>>(
163
+ selector?: Selector<TData, TValue, Selection> | undefined,
164
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
165
+ ): Selection =>
166
+ columnHook(...[...args, selector, isEqual])
167
+
168
+ export { columnHookʹ as useColumnʹ }
@@ -0,0 +1,151 @@
1
+ import { useCallback } from "react"
2
+
3
+ import type {
4
+ Header,
5
+ RequiredKeys,
6
+ RowData,
7
+ Table,
8
+ TableOptionsResolved,
9
+ } from "@tanstack/table-core"
10
+
11
+ import { identity } from "../lib/identity"
12
+ import { hasTableArg } from "../lib/hasTableArg"
13
+ import { runGetters } from "../lib/runGetters"
14
+ import { isShallowEqual } from "../lib/isShallowEqual"
15
+ import { invariant } from "../lib/invariant"
16
+
17
+ import type { IsEqual, RunGetters } from "../types"
18
+
19
+ import { useTableWithSelector } from "./useTableWithSelector"
20
+
21
+ export interface HeaderValues<TData extends RowData, TValue> extends RunGetters<
22
+ Header<TData, TValue>
23
+ > {}
24
+
25
+ const headerValuesCache = new WeakMap<
26
+ RequiredKeys<TableOptionsResolved<any>, "state">,
27
+ Map<string, HeaderValues<any, any>>
28
+ >()
29
+
30
+ const headerHandlersCache = new WeakMap<
31
+ Header<any, any>,
32
+ {
33
+ resizeHandler: ReturnType<Header<any, any>["getResizeHandler"]>
34
+ }
35
+ >()
36
+
37
+ const getHeaderValues = <TData extends RowData, TValue>(
38
+ table: Table<TData>,
39
+ headerId: string,
40
+ ): HeaderValues<TData, TValue> => {
41
+ let headerCache = headerValuesCache.get(table.options)
42
+ if (!headerCache) {
43
+ headerCache = new Map()
44
+ headerValuesCache.set(table.options, headerCache)
45
+ }
46
+
47
+ let cached = headerCache.get(headerId)
48
+
49
+ if (!cached) {
50
+ const header = table.getFlatHeaders().find((h) => h.id === headerId) as
51
+ | Header<TData, TValue>
52
+ | undefined
53
+
54
+ invariant(header)
55
+
56
+ let cachedHandlers = headerHandlersCache.get(header)
57
+ if (!cachedHandlers) {
58
+ cachedHandlers = {
59
+ resizeHandler: header.getResizeHandler(),
60
+ }
61
+ headerHandlersCache.set(header, cachedHandlers)
62
+ }
63
+
64
+ const { resizeHandler } = cachedHandlers
65
+
66
+ cached = {
67
+ ...runGetters(header),
68
+ resizeHandler,
69
+ }
70
+
71
+ headerCache.set(headerId, cached)
72
+ }
73
+
74
+ return cached
75
+ }
76
+
77
+ type Selector<TData extends RowData, TValue, Selection> = (
78
+ headerValues: HeaderValues<TData, TValue>,
79
+ ) => Selection
80
+
81
+ export const useHeader = <
82
+ TData extends RowData,
83
+ TValue,
84
+ Selection = HeaderValues<TData, TValue>,
85
+ >(
86
+ ...args:
87
+ | [
88
+ table: Table<TData> | undefined,
89
+ header:
90
+ | Header<TData, TValue>
91
+ | HeaderValues<TData, TValue>
92
+ | { id: string }
93
+ | string,
94
+ selector?: Selector<TData, TValue, Selection> | undefined,
95
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
96
+ ]
97
+ | [
98
+ header:
99
+ | Header<TData, TValue>
100
+ | HeaderValues<TData, TValue>
101
+ | { id: string }
102
+ | string,
103
+ selector?: Selector<TData, TValue, Selection> | undefined,
104
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
105
+ ]
106
+ ): Selection => {
107
+ const [
108
+ table,
109
+ headerOrId,
110
+ selector = identity as never,
111
+ isEqual = isShallowEqual,
112
+ ] = hasTableArg(args) ? args : [undefined, ...args]
113
+
114
+ const headerId = typeof headerOrId === "string" ? headerOrId : headerOrId.id
115
+
116
+ const getSelection = useCallback(
117
+ (table: Table<TData>) => selector(getHeaderValues(table, headerId)),
118
+ [headerId, selector],
119
+ )
120
+
121
+ return useTableWithSelector(table, getSelection, isEqual)
122
+ }
123
+
124
+ const headerHook = useHeader
125
+
126
+ const headerHookʹ =
127
+ <TData extends RowData, TValue>(
128
+ ...args:
129
+ | [
130
+ table: Table<TData> | undefined,
131
+ header:
132
+ | Header<TData, TValue>
133
+ | HeaderValues<TData, TValue>
134
+ | { id: string }
135
+ | string,
136
+ ]
137
+ | [
138
+ header:
139
+ | Header<TData, TValue>
140
+ | HeaderValues<TData, TValue>
141
+ | { id: string }
142
+ | string,
143
+ ]
144
+ ) =>
145
+ <Selection = HeaderValues<TData, TValue>>(
146
+ selector?: Selector<TData, TValue, Selection> | undefined,
147
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
148
+ ): Selection =>
149
+ headerHook(...[...args, selector, isEqual])
150
+
151
+ export { headerHookʹ as useHeaderʹ }
@@ -0,0 +1,88 @@
1
+ import { useCallback, useState } from "react"
2
+
3
+ import {
4
+ type OnChangeFn,
5
+ type RowData,
6
+ type Table,
7
+ type TableOptions,
8
+ type TableState,
9
+ createTable,
10
+ } from "@tanstack/table-core"
11
+
12
+ import { useShallowMemo } from "../lib/useShallowMemo"
13
+ import { tableRegistry } from "../lib/tableRegistry"
14
+ import { invariant } from "../lib/invariant"
15
+ import { useLayoutEffect } from "../lib/useLayoutEffect"
16
+
17
+ export const useReactTable = <TData extends RowData>({
18
+ state,
19
+ ...options
20
+ }: TableOptions<TData>): Table<TData> => {
21
+ const memoOptions = useShallowMemo(options)
22
+ const memoState = useShallowMemo(state)
23
+
24
+ // We'll maintain both our internal state and any user-provided
25
+ // state.
26
+ const [internalState, setInternalState] = useState<TableState>(null!)
27
+
28
+ const onStateChange = useCallback<OnChangeFn<TableState>>(
29
+ (updater) => {
30
+ setInternalState(updater)
31
+ memoOptions.onStateChange?.call(undefined, updater)
32
+ },
33
+ [memoOptions.onStateChange],
34
+ )
35
+
36
+ // Create a new table and store it in state
37
+ const [table] = useState(() => {
38
+ // Compose in the generic memoOptions to the user memoOptions
39
+ const resolvedOptions = {
40
+ state: {}, // Dummy state
41
+ onStateChange: () => {}, // noop
42
+ renderFallbackValue: null,
43
+ ...memoOptions,
44
+ }
45
+
46
+ const table = createTable<TData>(resolvedOptions)
47
+
48
+ table.setOptions((prev) => ({
49
+ ...prev,
50
+ ...memoOptions,
51
+ state: {
52
+ ...table.initialState,
53
+ ...memoState,
54
+ },
55
+ onStateChange,
56
+ }))
57
+
58
+ tableRegistry.set(table, { listeners: new Set() })
59
+
60
+ return table
61
+ })
62
+
63
+ if (!internalState) {
64
+ setInternalState(table.initialState)
65
+ }
66
+
67
+ useLayoutEffect(() => {
68
+ // Compose the default state above with any user state. This will allow the user
69
+ // to only control a subset of the state if desired.
70
+ table.setOptions((prev) => ({
71
+ ...prev,
72
+ ...memoOptions,
73
+ state: {
74
+ ...internalState,
75
+ ...memoState,
76
+ },
77
+ onStateChange,
78
+ }))
79
+
80
+ const { listeners } = tableRegistry.get(table) ?? {}
81
+ invariant(listeners)
82
+ for (const listener of listeners) {
83
+ listener()
84
+ }
85
+ }, [memoOptions, memoState, onStateChange, table, internalState])
86
+
87
+ return table
88
+ }
@@ -0,0 +1,132 @@
1
+ import { useCallback } from "react"
2
+
3
+ import type {
4
+ RequiredKeys,
5
+ Row,
6
+ RowData,
7
+ Table,
8
+ TableOptionsResolved,
9
+ } from "@tanstack/table-core"
10
+
11
+ import { identity } from "../lib/identity"
12
+ import { hasTableArg } from "../lib/hasTableArg"
13
+ import { runGetters } from "../lib/runGetters"
14
+ import { isShallowEqual } from "../lib/isShallowEqual"
15
+
16
+ import type { IsEqual, RunGetters } from "../types"
17
+
18
+ import { useTableWithSelector } from "./useTableWithSelector"
19
+
20
+ export interface RowValues<TData extends RowData> extends RunGetters<
21
+ Row<TData>
22
+ > {}
23
+
24
+ const hookRowCache = new WeakMap<
25
+ RequiredKeys<TableOptionsResolved<any>, "state">,
26
+ Map<string, RowValues<any>>
27
+ >()
28
+
29
+ const rowHandlersCache = new WeakMap<
30
+ Row<any>,
31
+ {
32
+ toggleExpandedHandler: ReturnType<Row<any>["getToggleExpandedHandler"]>
33
+ toggleSelectedHandler: ReturnType<Row<any>["getToggleSelectedHandler"]>
34
+ }
35
+ >()
36
+
37
+ const getRowValues = <TData extends RowData>(
38
+ table: Table<TData>,
39
+ rowId: string,
40
+ ): RowValues<TData> => {
41
+ let rowCache = hookRowCache.get(table.options)
42
+ if (!rowCache) {
43
+ rowCache = new Map()
44
+ hookRowCache.set(table.options, rowCache)
45
+ }
46
+
47
+ let cached = rowCache.get(rowId)
48
+
49
+ if (!cached) {
50
+ const row = table.getRow(rowId)
51
+
52
+ let cachedHandlers = rowHandlersCache.get(row)
53
+ if (!cachedHandlers) {
54
+ cachedHandlers = {
55
+ toggleExpandedHandler: row.getToggleExpandedHandler(),
56
+ toggleSelectedHandler: row.getToggleSelectedHandler(),
57
+ }
58
+ rowHandlersCache.set(row, cachedHandlers)
59
+ }
60
+
61
+ const { toggleExpandedHandler, toggleSelectedHandler } = cachedHandlers
62
+
63
+ const { getGroupingValue, getUniqueValues, getValue, ...rest } = row
64
+
65
+ cached = {
66
+ ...runGetters(rest),
67
+ getGroupingValue,
68
+ getUniqueValues,
69
+ getValue,
70
+ toggleExpandedHandler,
71
+ toggleSelectedHandler,
72
+ }
73
+
74
+ rowCache.set(rowId, cached)
75
+ }
76
+
77
+ return cached
78
+ }
79
+
80
+ type Selector<TData extends RowData, Selection> = (
81
+ rowValues: RowValues<TData>,
82
+ ) => Selection
83
+
84
+ export const useRow = <TData extends RowData, Selection = RowValues<TData>>(
85
+ ...args:
86
+ | [
87
+ table: Table<TData> | undefined,
88
+ row: Row<TData> | RowValues<TData> | { id: string } | string,
89
+ selector?: Selector<TData, Selection> | undefined,
90
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
91
+ ]
92
+ | [
93
+ row: Row<TData> | RowValues<TData> | { id: string } | string,
94
+ selector?: Selector<TData, Selection> | undefined,
95
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
96
+ ]
97
+ ): Selection => {
98
+ const [
99
+ table,
100
+ rowOrId,
101
+ selector = identity as never,
102
+ isEqual = isShallowEqual,
103
+ ] = hasTableArg(args) ? args : [undefined, ...args]
104
+
105
+ const rowId = typeof rowOrId === "string" ? rowOrId : rowOrId.id
106
+
107
+ const getSelection = useCallback(
108
+ (table: Table<TData>) => selector(getRowValues(table, rowId)),
109
+ [rowId, selector],
110
+ )
111
+
112
+ return useTableWithSelector(table, getSelection, isEqual)
113
+ }
114
+
115
+ const rowHook = useRow
116
+
117
+ const rowHookʹ =
118
+ <TData extends RowData>(
119
+ ...args:
120
+ | [
121
+ table: Table<TData> | undefined,
122
+ row: Row<TData> | RowValues<TData> | { id: string } | string,
123
+ ]
124
+ | [row: Row<TData> | RowValues<TData> | { id: string } | string]
125
+ ) =>
126
+ <Selection = RowValues<TData>>(
127
+ selector?: Selector<TData, Selection> | undefined,
128
+ isEqual?: IsEqual<NoInfer<Selection>> | undefined,
129
+ ): Selection =>
130
+ rowHook(...[...args, selector, isEqual])
131
+
132
+ export { rowHookʹ as useRowʹ }