@tanstack/angular-table 9.0.0-alpha.10 → 9.0.0-alpha.11
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/fesm2022/tanstack-angular-table.mjs +1363 -247
- package/dist/fesm2022/tanstack-angular-table.mjs.map +1 -1
- package/dist/types/tanstack-angular-table.d.ts +767 -0
- package/package.json +27 -17
- package/src/angularReactivityFeature.ts +210 -0
- package/src/flex-render/context.ts +14 -0
- package/src/flex-render/flags.ts +34 -0
- package/src/flex-render/flexRenderComponent.ts +288 -0
- package/src/flex-render/flexRenderComponentFactory.ts +241 -0
- package/src/flex-render/renderer.ts +376 -0
- package/src/flex-render/view.ts +165 -0
- package/src/flexRender.ts +124 -0
- package/src/helpers/cell.ts +104 -0
- package/src/helpers/createTableHook.ts +480 -0
- package/src/helpers/flexRenderCell.ts +136 -0
- package/src/helpers/header.ts +99 -0
- package/src/helpers/table.ts +87 -0
- package/src/index.ts +17 -70
- package/src/injectTable.ts +123 -0
- package/src/{lazy-signal-initializer.ts → lazySignalInitializer.ts} +2 -2
- package/src/reactivityUtils.ts +232 -0
- package/dist/esm2022/flex-render.mjs +0 -148
- package/dist/esm2022/index.mjs +0 -48
- package/dist/esm2022/lazy-signal-initializer.mjs +0 -43
- package/dist/esm2022/proxy.mjs +0 -83
- package/dist/esm2022/tanstack-angular-table.mjs +0 -5
- package/dist/flex-render.d.ts +0 -30
- package/dist/index.d.ts +0 -5
- package/dist/lazy-signal-initializer.d.ts +0 -5
- package/dist/proxy.d.ts +0 -3
- package/src/flex-render.ts +0 -184
- package/src/proxy.ts +0 -97
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
import { createColumnHelper as coreCreateColumnHelper } from '@tanstack/table-core'
|
|
2
|
+
import { injectTable } from '../injectTable'
|
|
3
|
+
import { injectFlexRenderContext } from '../flexRender'
|
|
4
|
+
import { injectTableHeaderContext as _injectTableHeaderContext } from './header'
|
|
5
|
+
import { injectTableContext as _injectTableContext } from './table'
|
|
6
|
+
import { injectTableCellContext as _injectTableCellContext } from './cell'
|
|
7
|
+
import type { FlexRenderContent } from '../flexRender'
|
|
8
|
+
import type { AngularTable } from '../injectTable'
|
|
9
|
+
import type {
|
|
10
|
+
AccessorFn,
|
|
11
|
+
AccessorFnColumnDef,
|
|
12
|
+
AccessorKeyColumnDef,
|
|
13
|
+
Cell,
|
|
14
|
+
CellContext,
|
|
15
|
+
CellData,
|
|
16
|
+
Column,
|
|
17
|
+
ColumnDef,
|
|
18
|
+
DeepKeys,
|
|
19
|
+
DeepValue,
|
|
20
|
+
DisplayColumnDef,
|
|
21
|
+
GroupColumnDef,
|
|
22
|
+
Header,
|
|
23
|
+
HeaderContext,
|
|
24
|
+
IdentifiedColumnDef,
|
|
25
|
+
Row,
|
|
26
|
+
RowData,
|
|
27
|
+
Table,
|
|
28
|
+
TableFeature,
|
|
29
|
+
TableFeatures,
|
|
30
|
+
TableOptions,
|
|
31
|
+
TableState,
|
|
32
|
+
} from '@tanstack/table-core'
|
|
33
|
+
import type { Signal, Type } from '@angular/core'
|
|
34
|
+
|
|
35
|
+
type RenderableComponent =
|
|
36
|
+
| Type<any>
|
|
37
|
+
| (<T extends NonNullable<unknown>>(props: T) => FlexRenderContent<T>)
|
|
38
|
+
|
|
39
|
+
// =============================================================================
|
|
40
|
+
// Enhanced Context Types with Pre-bound Components
|
|
41
|
+
// =============================================================================
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Enhanced CellContext with pre-bound cell components.
|
|
45
|
+
* The `cell` property includes the registered cellComponents.
|
|
46
|
+
*/
|
|
47
|
+
export type AppCellContext<
|
|
48
|
+
TFeatures extends TableFeatures,
|
|
49
|
+
TData extends RowData,
|
|
50
|
+
TValue extends CellData,
|
|
51
|
+
TCellComponents extends Record<string, RenderableComponent>,
|
|
52
|
+
> = {
|
|
53
|
+
cell: Cell<TFeatures, TData, TValue> &
|
|
54
|
+
TCellComponents & { FlexRender: () => unknown }
|
|
55
|
+
column: Column<TFeatures, TData, TValue>
|
|
56
|
+
getValue: CellContext<TFeatures, TData, TValue>['getValue']
|
|
57
|
+
renderValue: CellContext<TFeatures, TData, TValue>['renderValue']
|
|
58
|
+
row: Row<TFeatures, TData>
|
|
59
|
+
table: Table<TFeatures, TData>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Enhanced HeaderContext with pre-bound header components.
|
|
64
|
+
* The `header` property includes the registered headerComponents.
|
|
65
|
+
*/
|
|
66
|
+
export type AppHeaderContext<
|
|
67
|
+
TFeatures extends TableFeatures,
|
|
68
|
+
TData extends RowData,
|
|
69
|
+
TValue extends CellData,
|
|
70
|
+
THeaderComponents extends Record<string, RenderableComponent>,
|
|
71
|
+
> = {
|
|
72
|
+
column: Column<TFeatures, TData, TValue>
|
|
73
|
+
header: Header<TFeatures, TData, TValue> &
|
|
74
|
+
THeaderComponents & { FlexRender: () => unknown }
|
|
75
|
+
table: Table<TFeatures, TData>
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// =============================================================================
|
|
79
|
+
// Enhanced Column Definition Types
|
|
80
|
+
// =============================================================================
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Template type for column definitions that can be a string or a function.
|
|
84
|
+
*/
|
|
85
|
+
type AppColumnDefTemplate<TProps extends object> =
|
|
86
|
+
| string
|
|
87
|
+
| ((props: TProps) => any)
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Enhanced column definition base with pre-bound components in cell/header/footer contexts.
|
|
91
|
+
*/
|
|
92
|
+
type AppColumnDefBase<
|
|
93
|
+
TFeatures extends TableFeatures,
|
|
94
|
+
TData extends RowData,
|
|
95
|
+
TValue extends CellData,
|
|
96
|
+
TCellComponents extends Record<string, RenderableComponent>,
|
|
97
|
+
THeaderComponents extends Record<string, RenderableComponent>,
|
|
98
|
+
> = Omit<
|
|
99
|
+
IdentifiedColumnDef<TFeatures, TData, TValue>,
|
|
100
|
+
'cell' | 'header' | 'footer'
|
|
101
|
+
> & {
|
|
102
|
+
cell?: AppColumnDefTemplate<
|
|
103
|
+
AppCellContext<TFeatures, TData, TValue, TCellComponents>
|
|
104
|
+
>
|
|
105
|
+
header?: AppColumnDefTemplate<
|
|
106
|
+
AppHeaderContext<TFeatures, TData, TValue, THeaderComponents>
|
|
107
|
+
>
|
|
108
|
+
footer?: AppColumnDefTemplate<
|
|
109
|
+
AppHeaderContext<TFeatures, TData, TValue, THeaderComponents>
|
|
110
|
+
>
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Enhanced display column definition with pre-bound components.
|
|
115
|
+
*/
|
|
116
|
+
type AppDisplayColumnDef<
|
|
117
|
+
TFeatures extends TableFeatures,
|
|
118
|
+
TData extends RowData,
|
|
119
|
+
TCellComponents extends Record<string, RenderableComponent>,
|
|
120
|
+
THeaderComponents extends Record<string, RenderableComponent>,
|
|
121
|
+
> = Omit<
|
|
122
|
+
DisplayColumnDef<TFeatures, TData, unknown>,
|
|
123
|
+
'cell' | 'header' | 'footer'
|
|
124
|
+
> & {
|
|
125
|
+
cell?: AppColumnDefTemplate<
|
|
126
|
+
AppCellContext<TFeatures, TData, unknown, TCellComponents>
|
|
127
|
+
>
|
|
128
|
+
header?: AppColumnDefTemplate<
|
|
129
|
+
AppHeaderContext<TFeatures, TData, unknown, THeaderComponents>
|
|
130
|
+
>
|
|
131
|
+
footer?: AppColumnDefTemplate<
|
|
132
|
+
AppHeaderContext<TFeatures, TData, unknown, THeaderComponents>
|
|
133
|
+
>
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Enhanced group column definition with pre-bound components.
|
|
138
|
+
*/
|
|
139
|
+
type AppGroupColumnDef<
|
|
140
|
+
TFeatures extends TableFeatures,
|
|
141
|
+
TData extends RowData,
|
|
142
|
+
TCellComponents extends Record<string, RenderableComponent>,
|
|
143
|
+
THeaderComponents extends Record<string, RenderableComponent>,
|
|
144
|
+
> = Omit<
|
|
145
|
+
GroupColumnDef<TFeatures, TData, unknown>,
|
|
146
|
+
'cell' | 'header' | 'footer' | 'columns'
|
|
147
|
+
> & {
|
|
148
|
+
cell?: AppColumnDefTemplate<
|
|
149
|
+
AppCellContext<TFeatures, TData, unknown, TCellComponents>
|
|
150
|
+
>
|
|
151
|
+
header?: AppColumnDefTemplate<
|
|
152
|
+
AppHeaderContext<TFeatures, TData, unknown, THeaderComponents>
|
|
153
|
+
>
|
|
154
|
+
footer?: AppColumnDefTemplate<
|
|
155
|
+
AppHeaderContext<TFeatures, TData, unknown, THeaderComponents>
|
|
156
|
+
>
|
|
157
|
+
columns?: Array<ColumnDef<TFeatures, TData, unknown>>
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// =============================================================================
|
|
161
|
+
// Enhanced Column Helper Type
|
|
162
|
+
// =============================================================================
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Enhanced column helper with pre-bound components in cell/header/footer contexts.
|
|
166
|
+
* This enables TypeScript to know about the registered components when defining columns.
|
|
167
|
+
*/
|
|
168
|
+
export type AppColumnHelper<
|
|
169
|
+
TFeatures extends TableFeatures,
|
|
170
|
+
TData extends RowData,
|
|
171
|
+
TCellComponents extends Record<string, RenderableComponent>,
|
|
172
|
+
THeaderComponents extends Record<string, RenderableComponent>,
|
|
173
|
+
> = {
|
|
174
|
+
/**
|
|
175
|
+
* Creates a data column definition with an accessor key or function.
|
|
176
|
+
* The cell, header, and footer contexts include pre-bound components.
|
|
177
|
+
*/
|
|
178
|
+
accessor: <
|
|
179
|
+
TAccessor extends AccessorFn<TData> | DeepKeys<TData>,
|
|
180
|
+
TValue extends TAccessor extends AccessorFn<TData, infer TReturn>
|
|
181
|
+
? TReturn
|
|
182
|
+
: TAccessor extends DeepKeys<TData>
|
|
183
|
+
? DeepValue<TData, TAccessor>
|
|
184
|
+
: never,
|
|
185
|
+
>(
|
|
186
|
+
accessor: TAccessor,
|
|
187
|
+
column: TAccessor extends AccessorFn<TData>
|
|
188
|
+
? AppColumnDefBase<
|
|
189
|
+
TFeatures,
|
|
190
|
+
TData,
|
|
191
|
+
TValue,
|
|
192
|
+
TCellComponents,
|
|
193
|
+
THeaderComponents
|
|
194
|
+
> & { id: string }
|
|
195
|
+
: AppColumnDefBase<
|
|
196
|
+
TFeatures,
|
|
197
|
+
TData,
|
|
198
|
+
TValue,
|
|
199
|
+
TCellComponents,
|
|
200
|
+
THeaderComponents
|
|
201
|
+
>,
|
|
202
|
+
) => TAccessor extends AccessorFn<TData>
|
|
203
|
+
? AccessorFnColumnDef<TFeatures, TData, TValue>
|
|
204
|
+
: AccessorKeyColumnDef<TFeatures, TData, TValue>
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Wraps an array of column definitions to preserve each column's individual TValue type.
|
|
208
|
+
*/
|
|
209
|
+
columns: <TColumns extends ReadonlyArray<ColumnDef<TFeatures, TData, any>>>(
|
|
210
|
+
columns: [...TColumns],
|
|
211
|
+
) => Array<ColumnDef<TFeatures, TData, any>> & [...TColumns]
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Creates a display column definition for non-data columns.
|
|
215
|
+
* The cell, header, and footer contexts include pre-bound components.
|
|
216
|
+
*/
|
|
217
|
+
display: (
|
|
218
|
+
column: AppDisplayColumnDef<
|
|
219
|
+
TFeatures,
|
|
220
|
+
TData,
|
|
221
|
+
TCellComponents,
|
|
222
|
+
THeaderComponents
|
|
223
|
+
>,
|
|
224
|
+
) => DisplayColumnDef<TFeatures, TData, unknown>
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Creates a group column definition with nested child columns.
|
|
228
|
+
* The cell, header, and footer contexts include pre-bound components.
|
|
229
|
+
*/
|
|
230
|
+
group: (
|
|
231
|
+
column: AppGroupColumnDef<
|
|
232
|
+
TFeatures,
|
|
233
|
+
TData,
|
|
234
|
+
TCellComponents,
|
|
235
|
+
THeaderComponents
|
|
236
|
+
>,
|
|
237
|
+
) => GroupColumnDef<TFeatures, TData, unknown>
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Extended table API returned by useAppTable with all App wrapper components
|
|
242
|
+
*/
|
|
243
|
+
export type AppAngularTable<
|
|
244
|
+
TFeatures extends TableFeatures,
|
|
245
|
+
TData extends RowData,
|
|
246
|
+
TSelected,
|
|
247
|
+
TTableComponents extends Record<string, RenderableComponent>,
|
|
248
|
+
TCellComponents extends Record<string, RenderableComponent>,
|
|
249
|
+
THeaderComponents extends Record<string, RenderableComponent>,
|
|
250
|
+
> = AngularTable<TFeatures, TData, TSelected> &
|
|
251
|
+
NoInfer<TTableComponents> & {
|
|
252
|
+
appCell: <TValue>(
|
|
253
|
+
cell: Cell<TFeatures, TData, TValue>,
|
|
254
|
+
) => Cell<TFeatures, TData, TValue> & NoInfer<TCellComponents>
|
|
255
|
+
|
|
256
|
+
appHeader: <TValue>(
|
|
257
|
+
header: Header<TFeatures, TData, TValue>,
|
|
258
|
+
) => Header<TFeatures, TData, TValue> & NoInfer<THeaderComponents>
|
|
259
|
+
|
|
260
|
+
appFooter: <TValue>(
|
|
261
|
+
footer: Header<TFeatures, TData, TValue>,
|
|
262
|
+
) => Header<TFeatures, TData, TValue> & NoInfer<THeaderComponents>
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// =============================================================================
|
|
266
|
+
// CreateTableHook Options and Props
|
|
267
|
+
// =============================================================================
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Options for creating a table hook with pre-bound components and default table options.
|
|
271
|
+
* Extends all TableOptions except 'columns' | 'data' | 'store' | 'state' | 'initialState'.
|
|
272
|
+
*/
|
|
273
|
+
export type CreateTableContextOptions<
|
|
274
|
+
TFeatures extends TableFeatures,
|
|
275
|
+
TTableComponents extends Record<string, RenderableComponent>,
|
|
276
|
+
TCellComponents extends Record<string, RenderableComponent>,
|
|
277
|
+
THeaderComponents extends Record<string, RenderableComponent>,
|
|
278
|
+
> = Omit<
|
|
279
|
+
TableOptions<TFeatures, any>,
|
|
280
|
+
'columns' | 'data' | 'store' | 'state' | 'initialState'
|
|
281
|
+
> & {
|
|
282
|
+
/**
|
|
283
|
+
* Table-level components that need access to the table instance.
|
|
284
|
+
* These are available directly on the table object returned by useAppTable.
|
|
285
|
+
* Use `useTableContext()` inside these components.
|
|
286
|
+
* @example { PaginationControls, GlobalFilter, RowCount }
|
|
287
|
+
*/
|
|
288
|
+
tableComponents?: TTableComponents
|
|
289
|
+
/**
|
|
290
|
+
* Cell-level components that need access to the cell instance.
|
|
291
|
+
* These are available on the cell object passed to AppCell's children.
|
|
292
|
+
* Use `useCellContext()` inside these components.
|
|
293
|
+
* @example { TextCell, NumberCell, DateCell, CurrencyCell }
|
|
294
|
+
*/
|
|
295
|
+
cellComponents?: TCellComponents
|
|
296
|
+
/**
|
|
297
|
+
* Header-level components that need access to the header instance.
|
|
298
|
+
* These are available on the header object passed to AppHeader/AppFooter's children.
|
|
299
|
+
* Use `useHeaderContext()` inside these components.
|
|
300
|
+
* @example { SortIndicator, ColumnFilter, ResizeHandle }
|
|
301
|
+
*/
|
|
302
|
+
headerComponents?: THeaderComponents
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export type CreateTableHookResult<
|
|
306
|
+
TFeatures extends TableFeatures,
|
|
307
|
+
TTableComponents extends Record<string, RenderableComponent>,
|
|
308
|
+
TCellComponents extends Record<string, RenderableComponent>,
|
|
309
|
+
THeaderComponents extends Record<string, RenderableComponent>,
|
|
310
|
+
> = {
|
|
311
|
+
createAppColumnHelper: <TData extends RowData>() => AppColumnHelper<
|
|
312
|
+
TFeatures,
|
|
313
|
+
TData,
|
|
314
|
+
TCellComponents,
|
|
315
|
+
THeaderComponents
|
|
316
|
+
>
|
|
317
|
+
injectTableContext: <TData extends RowData = RowData>() => Signal<
|
|
318
|
+
AngularTable<TFeatures, TData>
|
|
319
|
+
>
|
|
320
|
+
injectTableHeaderContext: <
|
|
321
|
+
TValue extends CellData = CellData,
|
|
322
|
+
TRowData extends RowData = RowData,
|
|
323
|
+
>() => Signal<Header<TFeatures, TRowData, TValue>>
|
|
324
|
+
injectTableCellContext: <
|
|
325
|
+
TValue extends CellData = CellData,
|
|
326
|
+
TRowData extends RowData = RowData,
|
|
327
|
+
>() => Signal<Cell<TFeatures, TRowData, TValue>>
|
|
328
|
+
injectFlexRenderHeaderContext: <
|
|
329
|
+
TData extends RowData,
|
|
330
|
+
TValue extends CellData,
|
|
331
|
+
>() => HeaderContext<TFeatures, TData, TValue>
|
|
332
|
+
injectFlexRenderCellContext: <
|
|
333
|
+
TData extends RowData,
|
|
334
|
+
TValue extends CellData,
|
|
335
|
+
>() => CellContext<TFeatures, TData, TValue>
|
|
336
|
+
injectAppTable: <TData extends RowData, TSelected = TableState<TFeatures>>(
|
|
337
|
+
tableOptions: () => Omit<
|
|
338
|
+
TableOptions<TFeatures, TData>,
|
|
339
|
+
'_features' | '_rowModels'
|
|
340
|
+
>,
|
|
341
|
+
selector?: (state: TableState<TFeatures>) => TSelected,
|
|
342
|
+
) => AppAngularTable<
|
|
343
|
+
TFeatures,
|
|
344
|
+
TData,
|
|
345
|
+
TSelected,
|
|
346
|
+
TTableComponents,
|
|
347
|
+
TCellComponents,
|
|
348
|
+
THeaderComponents
|
|
349
|
+
>
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export function createTableHook<
|
|
353
|
+
TFeatures extends TableFeatures,
|
|
354
|
+
const TTableComponents extends Record<string, RenderableComponent>,
|
|
355
|
+
const TCellComponents extends Record<string, RenderableComponent>,
|
|
356
|
+
const THeaderComponents extends Record<string, RenderableComponent>,
|
|
357
|
+
>({
|
|
358
|
+
tableComponents,
|
|
359
|
+
cellComponents,
|
|
360
|
+
headerComponents,
|
|
361
|
+
...defaultTableOptions
|
|
362
|
+
}: CreateTableContextOptions<
|
|
363
|
+
TFeatures,
|
|
364
|
+
TTableComponents,
|
|
365
|
+
TCellComponents,
|
|
366
|
+
THeaderComponents
|
|
367
|
+
>): CreateTableHookResult<
|
|
368
|
+
TFeatures,
|
|
369
|
+
TTableComponents,
|
|
370
|
+
TCellComponents,
|
|
371
|
+
THeaderComponents
|
|
372
|
+
> {
|
|
373
|
+
function injectTableContext<TData extends RowData = RowData>(): Signal<
|
|
374
|
+
AngularTable<TFeatures, TData>
|
|
375
|
+
> {
|
|
376
|
+
return _injectTableContext<TFeatures, TData>()
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function injectTableHeaderContext<
|
|
380
|
+
TValue extends CellData = CellData,
|
|
381
|
+
TRowData extends RowData = RowData,
|
|
382
|
+
>(): Signal<Header<TFeatures, TRowData, TValue>> {
|
|
383
|
+
return _injectTableHeaderContext<TFeatures, TRowData, TValue>()
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function injectTableCellContext<
|
|
387
|
+
TValue extends CellData = CellData,
|
|
388
|
+
TRowData extends RowData = RowData,
|
|
389
|
+
>(): Signal<Cell<TFeatures, TRowData, TValue>> {
|
|
390
|
+
return _injectTableCellContext<TFeatures, TRowData, TValue>()
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function injectFlexRenderHeaderContext<
|
|
394
|
+
TData extends RowData,
|
|
395
|
+
TValue extends CellData,
|
|
396
|
+
>(): HeaderContext<TFeatures, TData, TValue> {
|
|
397
|
+
return injectFlexRenderContext<HeaderContext<TFeatures, TData, TValue>>()
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function injectFlexRenderCellContext<
|
|
401
|
+
TData extends RowData,
|
|
402
|
+
TValue extends CellData,
|
|
403
|
+
>(): CellContext<TFeatures, TData, TValue> {
|
|
404
|
+
return injectFlexRenderContext<CellContext<TFeatures, TData, TValue>>()
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function injectAppTable<TData extends RowData, TSelected = {}>(
|
|
408
|
+
tableOptions: () => Omit<
|
|
409
|
+
TableOptions<TFeatures, TData>,
|
|
410
|
+
'_features' | '_rowModels'
|
|
411
|
+
>,
|
|
412
|
+
selector?: (state: TableState<TFeatures>) => TSelected,
|
|
413
|
+
): AppAngularTable<
|
|
414
|
+
TFeatures,
|
|
415
|
+
TData,
|
|
416
|
+
TSelected,
|
|
417
|
+
TTableComponents,
|
|
418
|
+
TCellComponents,
|
|
419
|
+
THeaderComponents
|
|
420
|
+
> {
|
|
421
|
+
function appCell(cell: Cell<TFeatures, TData, any>) {
|
|
422
|
+
return cell as Cell<TFeatures, TData, any> & TCellComponents
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function appHeader(header: Header<TFeatures, TData, any>) {
|
|
426
|
+
return header as Header<TFeatures, TData, any> & THeaderComponents
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function appFooter(footer: Header<TFeatures, TData, any>) {
|
|
430
|
+
return footer as Header<TFeatures, TData, any> & THeaderComponents
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const appTableFeatures: TableFeature<{}> = {
|
|
434
|
+
constructTableAPIs: (table) => {
|
|
435
|
+
Object.assign(table, tableComponents, { appCell, appHeader, appFooter })
|
|
436
|
+
},
|
|
437
|
+
assignCellPrototype(prototype) {
|
|
438
|
+
Object.assign(prototype, cellComponents)
|
|
439
|
+
},
|
|
440
|
+
assignHeaderPrototype(prototype) {
|
|
441
|
+
Object.assign(prototype, headerComponents)
|
|
442
|
+
},
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return injectTable<TFeatures, TData, TSelected>(() => {
|
|
446
|
+
const options = {
|
|
447
|
+
...defaultTableOptions,
|
|
448
|
+
...tableOptions(),
|
|
449
|
+
} as TableOptions<TFeatures, TData>
|
|
450
|
+
options._features = { ...options._features, appTableFeatures }
|
|
451
|
+
return options
|
|
452
|
+
}, selector) as AngularTable<any, any>
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function createAppColumnHelper<TData extends RowData>(): AppColumnHelper<
|
|
456
|
+
TFeatures,
|
|
457
|
+
TData,
|
|
458
|
+
TCellComponents,
|
|
459
|
+
THeaderComponents
|
|
460
|
+
> {
|
|
461
|
+
// The runtime implementation is the same - components are attached at render time
|
|
462
|
+
// This cast provides the enhanced types for column definitions
|
|
463
|
+
return coreCreateColumnHelper<TFeatures, TData>() as AppColumnHelper<
|
|
464
|
+
TFeatures,
|
|
465
|
+
TData,
|
|
466
|
+
TCellComponents,
|
|
467
|
+
THeaderComponents
|
|
468
|
+
>
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return {
|
|
472
|
+
createAppColumnHelper,
|
|
473
|
+
injectTableContext,
|
|
474
|
+
injectTableHeaderContext,
|
|
475
|
+
injectTableCellContext,
|
|
476
|
+
injectFlexRenderHeaderContext,
|
|
477
|
+
injectFlexRenderCellContext,
|
|
478
|
+
injectAppTable,
|
|
479
|
+
}
|
|
480
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DestroyRef,
|
|
3
|
+
Directive,
|
|
4
|
+
Injector,
|
|
5
|
+
TemplateRef,
|
|
6
|
+
ViewContainerRef,
|
|
7
|
+
computed,
|
|
8
|
+
inject,
|
|
9
|
+
input,
|
|
10
|
+
} from '@angular/core'
|
|
11
|
+
import {
|
|
12
|
+
Cell,
|
|
13
|
+
CellData,
|
|
14
|
+
Header,
|
|
15
|
+
RowData,
|
|
16
|
+
TableFeatures,
|
|
17
|
+
} from '@tanstack/table-core'
|
|
18
|
+
import { FlexViewRenderer } from '../flex-render/renderer'
|
|
19
|
+
import type { FlexRenderInputContent } from '../flex-render/renderer'
|
|
20
|
+
import type { CellContext, HeaderContext } from '@tanstack/table-core'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Simplified directive wrapper of `*flexRender`.
|
|
24
|
+
*
|
|
25
|
+
* Use this utility component to render headers, cells, or footers with custom markup.
|
|
26
|
+
*
|
|
27
|
+
* Only one prop (`cell`, `header`, or `footer`) may be passed based on the used selector.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```html
|
|
31
|
+
* <td *flexRenderCell="cell; let cell">{{cell}}</td>
|
|
32
|
+
* <th *flexRenderHeader="header; let header">{{header}}</th>
|
|
33
|
+
* <th *flexRenderFooter="footer; let footer">{{footer}}</th>
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* This replaces calling `*flexRender` directly like this:
|
|
37
|
+
* ```html
|
|
38
|
+
* <td *flexRender="cell.column.columnDef.cell; props: cell.getContext(); let cell">{{cell}}</td>
|
|
39
|
+
* <td *flexRender="header.column.columnDef.header; props: header.getContext(); let header">{{header}}</td>
|
|
40
|
+
* <td *flexRender="footer.column.columnDef.footer; props: footer.getContext(); let footer">{{footer}}</td>
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* Can be imported through {@link FlexRenderCell} or {@link FlexRender} import,
|
|
44
|
+
* which the latter is preferred.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import {FlexRender} from '@tanstack/angular-table
|
|
49
|
+
*
|
|
50
|
+
* @Component({
|
|
51
|
+
* // ...
|
|
52
|
+
* imports: [
|
|
53
|
+
* FlexRender
|
|
54
|
+
* ]
|
|
55
|
+
* })
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
@Directive({
|
|
59
|
+
selector:
|
|
60
|
+
'ng-template[flexRenderCell], ng-template[flexRenderFooter], ng-template[flexRenderHeader]',
|
|
61
|
+
})
|
|
62
|
+
export class FlexRenderCell<
|
|
63
|
+
TFeatures extends TableFeatures,
|
|
64
|
+
TData extends RowData,
|
|
65
|
+
TValue extends CellData,
|
|
66
|
+
> {
|
|
67
|
+
readonly cell = input<Cell<TFeatures, TData, TValue>>(undefined, {
|
|
68
|
+
alias: 'flexRenderCell',
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
readonly header = input<Header<TFeatures, TData, TValue>>(undefined, {
|
|
72
|
+
alias: 'flexRenderHeader',
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
readonly footer = input<Header<TFeatures, TData, TValue>>(undefined, {
|
|
76
|
+
alias: 'flexRenderFooter',
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
readonly #renderData = computed<
|
|
80
|
+
| [
|
|
81
|
+
content: FlexRenderInputContent<CellContext<TFeatures, TData, TValue>>,
|
|
82
|
+
props: CellContext<TFeatures, TData, TValue>,
|
|
83
|
+
]
|
|
84
|
+
| [
|
|
85
|
+
content: FlexRenderInputContent<
|
|
86
|
+
HeaderContext<TFeatures, TData, TValue>
|
|
87
|
+
>,
|
|
88
|
+
props: HeaderContext<TFeatures, TData, TValue>,
|
|
89
|
+
]
|
|
90
|
+
| [content: null, props: null]
|
|
91
|
+
>(
|
|
92
|
+
() => {
|
|
93
|
+
const cell = this.cell()
|
|
94
|
+
const header = this.header()
|
|
95
|
+
const footer = this.footer()
|
|
96
|
+
if (cell) {
|
|
97
|
+
return [cell.column.columnDef.cell, cell.getContext()]
|
|
98
|
+
}
|
|
99
|
+
if (header) {
|
|
100
|
+
return [header.column.columnDef.header, header.getContext()]
|
|
101
|
+
}
|
|
102
|
+
if (footer) {
|
|
103
|
+
return [footer.column.columnDef.footer, footer.getContext()]
|
|
104
|
+
}
|
|
105
|
+
return [null, null]
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
equal: (a, b) => {
|
|
109
|
+
return a[0] === b[0] && a[1] === b[1]
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
readonly #injector = inject(Injector)
|
|
115
|
+
readonly #templateRef = inject(TemplateRef)
|
|
116
|
+
readonly #viewContainerRef = inject(ViewContainerRef)
|
|
117
|
+
|
|
118
|
+
constructor() {
|
|
119
|
+
const content = computed(() => this.#renderData()[0])
|
|
120
|
+
const props = computed(() => this.#renderData()[1])
|
|
121
|
+
|
|
122
|
+
const renderer = new FlexViewRenderer<TFeatures, TData, TValue, any>({
|
|
123
|
+
content: content,
|
|
124
|
+
props: props,
|
|
125
|
+
injector: () => this.#injector,
|
|
126
|
+
templateRef: this.#templateRef,
|
|
127
|
+
viewContainerRef: this.#viewContainerRef,
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
renderer.mount()
|
|
131
|
+
|
|
132
|
+
inject(DestroyRef).onDestroy(() => {
|
|
133
|
+
renderer.destroy()
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Directive, InjectionToken, inject, input } from '@angular/core'
|
|
2
|
+
import { CellData, Header, RowData, TableFeatures } from '@tanstack/table-core'
|
|
3
|
+
import type { Signal } from '@angular/core'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* DI context shape for a TanStack Table header.
|
|
7
|
+
*
|
|
8
|
+
* This exists to make the current `Header` injectable by any nested component/directive
|
|
9
|
+
* without passing it through inputs/props.
|
|
10
|
+
*/
|
|
11
|
+
export interface TanStackTableHeaderContext<
|
|
12
|
+
TFeatures extends TableFeatures,
|
|
13
|
+
TData extends RowData,
|
|
14
|
+
TValue extends CellData,
|
|
15
|
+
> {
|
|
16
|
+
/** Signal that returns the current header instance. */
|
|
17
|
+
header: Signal<Header<TFeatures, TData, TValue>>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Injection token that provides access to the current header.
|
|
22
|
+
*
|
|
23
|
+
* This token is provided by the {@link TanStackTableHeader} directive.
|
|
24
|
+
*/
|
|
25
|
+
export const TanStackTableHeaderToken = new InjectionToken<
|
|
26
|
+
TanStackTableHeaderContext<any, any, any>['header']
|
|
27
|
+
>('[TanStack Table] HeaderContext')
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Provides a TanStack Table `Header` instance in Angular DI.
|
|
31
|
+
*
|
|
32
|
+
* The header can be injected by:
|
|
33
|
+
* - any descendant of an element using `[tanStackTableHeader]="..."`
|
|
34
|
+
* - any component instantiated by `*flexRender` when the render props contains `header`
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```html
|
|
38
|
+
* <th [tanStackTableHeader]="header">
|
|
39
|
+
* <app-sort-indicator />
|
|
40
|
+
* </th>
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* @Component({
|
|
45
|
+
* selector: 'app-sort-indicator',
|
|
46
|
+
* template: `
|
|
47
|
+
* <button (click)="toggle()">
|
|
48
|
+
* {{ header().column.id }}
|
|
49
|
+
* </button>
|
|
50
|
+
* `,
|
|
51
|
+
* })
|
|
52
|
+
* export class SortIndicatorComponent {
|
|
53
|
+
* readonly header = injectTableHeaderContext()
|
|
54
|
+
*
|
|
55
|
+
* toggle() {
|
|
56
|
+
* this.header().column.toggleSorting()
|
|
57
|
+
* }
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
@Directive({
|
|
62
|
+
selector: '[tanStackTableHeader]',
|
|
63
|
+
exportAs: 'header',
|
|
64
|
+
providers: [
|
|
65
|
+
{
|
|
66
|
+
provide: TanStackTableHeaderToken,
|
|
67
|
+
useFactory: () => inject(TanStackTableHeader).header,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
})
|
|
71
|
+
export class TanStackTableHeader<
|
|
72
|
+
TFeatures extends TableFeatures,
|
|
73
|
+
TData extends RowData,
|
|
74
|
+
TValue extends CellData,
|
|
75
|
+
> implements TanStackTableHeaderContext<TFeatures, TData, TValue> {
|
|
76
|
+
/**
|
|
77
|
+
* The current TanStack Table header.
|
|
78
|
+
*
|
|
79
|
+
* Provided as a required signal input so DI consumers always read the latest value.
|
|
80
|
+
*/
|
|
81
|
+
readonly header = input.required<Header<TFeatures, TData, TValue>>({
|
|
82
|
+
alias: 'tanStackTableHeader',
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Injects the current TanStack Table header signal.
|
|
88
|
+
*
|
|
89
|
+
* Available when:
|
|
90
|
+
* - there is a nearest `[tanStackTableHeader]` directive in the DI tree, or
|
|
91
|
+
* - the caller is rendered via `*flexRender` with render props containing `header`
|
|
92
|
+
*/
|
|
93
|
+
export function injectTableHeaderContext<
|
|
94
|
+
TFeatures extends TableFeatures,
|
|
95
|
+
TData extends RowData,
|
|
96
|
+
TValue extends CellData,
|
|
97
|
+
>(): TanStackTableHeaderContext<TFeatures, TData, TValue>['header'] {
|
|
98
|
+
return inject(TanStackTableHeaderToken)
|
|
99
|
+
}
|