@tanstack/angular-table 9.0.0-alpha.5 → 9.0.0-alpha.52

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 (59) hide show
  1. package/README.md +127 -0
  2. package/dist/README.md +127 -0
  3. package/dist/fesm2022/tanstack-angular-table-static-functions.mjs +6 -0
  4. package/dist/fesm2022/tanstack-angular-table-static-functions.mjs.map +1 -0
  5. package/dist/fesm2022/tanstack-angular-table.mjs +1357 -242
  6. package/dist/fesm2022/tanstack-angular-table.mjs.map +1 -1
  7. package/dist/types/tanstack-angular-table-static-functions.d.ts +1 -0
  8. package/dist/types/tanstack-angular-table.d.ts +793 -0
  9. package/package.json +39 -19
  10. package/skills/angular/angular-rendering-directives/SKILL.md +415 -0
  11. package/skills/angular/angular-rendering-directives/references/content-shapes.md +142 -0
  12. package/skills/angular/angular-rendering-directives/references/create-table-hook-registries.md +89 -0
  13. package/skills/angular/angular-rendering-directives/references/di-tokens.md +171 -0
  14. package/skills/angular/angular-rendering-directives/references/flex-render-component-options.md +64 -0
  15. package/skills/angular/client-to-server/SKILL.md +467 -0
  16. package/skills/angular/compose-with-tanstack-query/SKILL.md +482 -0
  17. package/skills/angular/compose-with-tanstack-store/SKILL.md +397 -0
  18. package/skills/angular/compose-with-tanstack-virtual/SKILL.md +400 -0
  19. package/skills/angular/getting-started/SKILL.md +496 -0
  20. package/skills/angular/getting-started/references/feature-row-model-mapping.md +48 -0
  21. package/skills/angular/migrate-v8-to-v9/SKILL.md +419 -0
  22. package/skills/angular/migrate-v8-to-v9/references/v8-to-v9-mapping.md +261 -0
  23. package/skills/angular/production-readiness/SKILL.md +469 -0
  24. package/skills/angular/table-state/SKILL.md +429 -0
  25. package/skills/angular/table-state/references/external-atoms-and-app-hook.md +152 -0
  26. package/src/flex-render/context.ts +14 -0
  27. package/src/flex-render/flags.ts +34 -0
  28. package/src/flex-render/flexRenderComponent.ts +288 -0
  29. package/src/flex-render/flexRenderComponentFactory.ts +251 -0
  30. package/src/flex-render/renderer.ts +393 -0
  31. package/src/flex-render/view.ts +226 -0
  32. package/src/flexRender.ts +124 -0
  33. package/src/helpers/cell.ts +104 -0
  34. package/src/helpers/createTableHook.ts +499 -0
  35. package/src/helpers/flexRenderCell.ts +136 -0
  36. package/src/helpers/header.ts +99 -0
  37. package/src/helpers/table.ts +85 -0
  38. package/src/index.ts +23 -70
  39. package/src/injectTable.ts +206 -0
  40. package/src/{lazy-signal-initializer.ts → lazySignalInitializer.ts} +2 -2
  41. package/src/reactivity.ts +147 -0
  42. package/static-functions/index.ts +1 -0
  43. package/static-functions/ng-package.json +6 -0
  44. package/dist/esm2022/flex-render.mjs +0 -150
  45. package/dist/esm2022/index.mjs +0 -48
  46. package/dist/esm2022/lazy-signal-initializer.mjs +0 -43
  47. package/dist/esm2022/proxy.mjs +0 -83
  48. package/dist/esm2022/tanstack-angular-table.mjs +0 -5
  49. package/dist/flex-render.d.ts +0 -31
  50. package/dist/index.d.ts +0 -5
  51. package/dist/lazy-signal-initializer.d.ts +0 -5
  52. package/dist/proxy.d.ts +0 -3
  53. package/src/__tests__/createAngularTable.test.ts +0 -95
  54. package/src/__tests__/flex-render.test.ts +0 -178
  55. package/src/__tests__/lazy-init.test.ts +0 -124
  56. package/src/__tests__/test-setup.ts +0 -12
  57. package/src/__tests__/test-utils.ts +0 -62
  58. package/src/flex-render.ts +0 -187
  59. package/src/proxy.ts +0 -97
@@ -0,0 +1,89 @@
1
+ # `createTableHook` — Component Registries Reference
2
+
3
+ `createTableHook(...)` returns Angular helpers with three optional component
4
+ registries:
5
+
6
+ | Registry | Lives on | Inject inside it with |
7
+ | ------------------ | --------------------------------------------------------------------------------- | ----------------------------------------------------------- |
8
+ | `tableComponents` | `table.<ComponentName>` (the table object) | `injectTableContext()` |
9
+ | `cellComponents` | the `Cell` prototype (`cell.<ComponentName>` after `table.appCell(cell)`) | `injectTableCellContext()` (or `injectFlexRenderContext()`) |
10
+ | `headerComponents` | the `Header` prototype (`header.<ComponentName>` after `table.appHeader(header)`) | `injectTableHeaderContext()` |
11
+
12
+ ```ts
13
+ import {
14
+ createTableHook,
15
+ tableFeatures,
16
+ rowSortingFeature,
17
+ } from '@tanstack/angular-table'
18
+ import { PaginationControls, RowCount } from './components/table-components'
19
+ import { TextCell, NumberCell, StatusCell } from './components/cell-components'
20
+ import { SortIndicator, ColumnFilter } from './components/header-components'
21
+
22
+ export const {
23
+ injectAppTable,
24
+ createAppColumnHelper,
25
+ injectTableContext,
26
+ injectTableCellContext,
27
+ injectTableHeaderContext,
28
+ } = createTableHook({
29
+ _features: tableFeatures({ rowSortingFeature }),
30
+ _rowModels: {
31
+ /* … */
32
+ },
33
+ tableComponents: { PaginationControls, RowCount },
34
+ cellComponents: { TextCell, NumberCell, StatusCell },
35
+ headerComponents: { SortIndicator, ColumnFilter },
36
+ })
37
+ ```
38
+
39
+ Use `NgComponentOutlet` to render table components:
40
+
41
+ ```html
42
+ <ng-container *ngComponentOutlet="table.PaginationControls" />
43
+ <ng-container *ngComponentOutlet="table.RowCount" />
44
+ ```
45
+
46
+ Reference cell components from column defs (type-safe through
47
+ `createAppColumnHelper<Person>()`):
48
+
49
+ ```ts
50
+ const columnHelper = createAppColumnHelper<Person>()
51
+
52
+ const columns = columnHelper.columns([
53
+ columnHelper.accessor('firstName', {
54
+ cell: ({ cell }) => cell.TextCell, // ✅ TS autocompletes registered components
55
+ }),
56
+ columnHelper.accessor('age', {
57
+ cell: ({ cell }) => cell.NumberCell,
58
+ }),
59
+ ])
60
+ ```
61
+
62
+ Headers via `table.appHeader(header)`:
63
+
64
+ ```html
65
+ @for (_h of headerGroup.headers; track _h.id) { @let header =
66
+ table.appHeader(_h);
67
+ <th>
68
+ <ng-container *flexRenderHeader="header; let value">
69
+ {{ value }}
70
+ </ng-container>
71
+ <ng-container
72
+ *flexRender="header.SortIndicator; props: header.getContext(); let v"
73
+ >
74
+ <div [innerHTML]="v"></div>
75
+ </ng-container>
76
+ </th>
77
+ }
78
+ ```
79
+
80
+ A header component is just an injection-context function or component:
81
+
82
+ ```ts
83
+ export function SortIndicator(): string | null {
84
+ const header = injectTableHeaderContext()
85
+ const sorted = header().column.getIsSorted()
86
+ if (!sorted) return null
87
+ return sorted === 'asc' ? '🔼' : '🔽'
88
+ }
89
+ ```
@@ -0,0 +1,171 @@
1
+ # DI Tokens & Context Injection — Full Reference
2
+
3
+ `FlexRender` automatically provides DI tokens for the render context to any
4
+ component rendered through `*flexRender` / `*flexRenderCell` / etc. The renderer
5
+ inspects the props object — if it has `table`, `header`, or `cell`, it
6
+ provides the matching token in the child injector.
7
+
8
+ | Helper | Returns | Available inside |
9
+ | ------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------ |
10
+ | `injectFlexRenderContext<T>()` | `T` (full props proxy) | a component rendered via `*flexRender` / `*flexRenderCell` / `*flexRenderHeader` / `*flexRenderFooter` |
11
+ | `injectTableContext<TData>()` | `Signal<Table<TFeatures, TData>>` | anything under `[tanStackTable]` or rendered via `*flexRender` whose context has `table` |
12
+ | `injectTableHeaderContext<TValue, TData>()` | `Signal<Header<...>>` | anything under `[tanStackTableHeader]` or rendered via `*flexRenderHeader` |
13
+ | `injectTableCellContext<TValue, TData>()` | `Signal<Cell<...>>` | anything under `[tanStackTableCell]` or rendered via `*flexRenderCell` |
14
+
15
+ The full props passed via `*flexRender`'s `props:` (or auto-derived by the
16
+ shorthand directives) is wrapped in a `Proxy` so property access always reads
17
+ the _latest_ value across re-renders.
18
+
19
+ ---
20
+
21
+ ## Pattern A — inject inside the rendered component itself
22
+
23
+ If your component **is** the cell, header, or footer (rendered through
24
+ `*flexRender*`), you don't need any extra directive — the token is auto-provided.
25
+
26
+ ```ts
27
+ @Component({
28
+ template: `
29
+ <span>{{ context.getValue() }}</span>
30
+ <button (click)="context.row.toggleSelected()">Toggle</button>
31
+ `,
32
+ })
33
+ export class InteractiveCell {
34
+ readonly context = injectFlexRenderContext<CellContext<any, any, any>>()
35
+ }
36
+ ```
37
+
38
+ Or, for just the cell signal:
39
+
40
+ ```ts
41
+ @Component({ template: `{{ cell().getValue() }}` })
42
+ export class TextCell {
43
+ readonly cell = injectTableCellContext<string>()
44
+ }
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Pattern B — context for _descendants outside the FlexRender tree_
50
+
51
+ When you have a component that lives next to the `*flexRenderCell` block, or
52
+ when you want any nested element to inject the table/header/cell, use the
53
+ context **host directives**:
54
+
55
+ ```ts
56
+ import {
57
+ FlexRender,
58
+ TanStackTable,
59
+ TanStackTableHeader,
60
+ TanStackTableCell,
61
+ } from '@tanstack/angular-table'
62
+
63
+ @Component({
64
+ imports: [FlexRender, TanStackTable, TanStackTableHeader, TanStackTableCell],
65
+ templateUrl: './app.html',
66
+ })
67
+ export class App {}
68
+ ```
69
+
70
+ ```html
71
+ <table [tanStackTable]="table">
72
+ @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) {
73
+ <tr>
74
+ @for (header of headerGroup.headers; track header.id) {
75
+ <th [tanStackTableHeader]="header">
76
+ <ng-container *flexRenderHeader="header; let value">
77
+ {{ value }}
78
+ </ng-container>
79
+ <!-- Any component here can call injectTableHeaderContext() -->
80
+ </th>
81
+ }
82
+ </tr>
83
+ } @for (row of table.getRowModel().rows; track row.id) {
84
+ <tr>
85
+ @for (cell of row.getVisibleCells(); track cell.id) {
86
+ <td [tanStackTableCell]="cell">
87
+ <ng-container *flexRenderCell="cell; let value">{{ value }}</ng-container>
88
+ <app-cell-actions />
89
+ <!-- ↑ cell-actions calls injectTableCellContext() — no input drilling -->
90
+ </td>
91
+ }
92
+ </tr>
93
+ }
94
+ </table>
95
+ ```
96
+
97
+ ```ts
98
+ @Component({
99
+ selector: 'app-cell-actions',
100
+ template: `<button (click)="cell().row.toggleSelected()">Toggle</button>`,
101
+ })
102
+ export class CellActionsComponent {
103
+ readonly cell = injectTableCellContext()
104
+ }
105
+ ```
106
+
107
+ Each directive uses Angular's `providers` array to register a per-host factory,
108
+ so contexts are correctly scoped — multiple `[tanStackTableCell]` directives on
109
+ sibling cells provide independent values.
110
+
111
+ ---
112
+
113
+ ## `*flexRender` directly (custom props)
114
+
115
+ Reach for the long form `*flexRender` when:
116
+
117
+ - You're rendering something that isn't `columnDef.cell` / `header` / `footer`
118
+ (e.g. a registered `headerComponents` member, see `createTableHook`).
119
+ - You want to override the props passed to the render function.
120
+
121
+ ```html
122
+ <ng-container
123
+ *flexRender="
124
+ cell.column.columnDef.cell;
125
+ props: cell.getContext();
126
+ let rendered
127
+ "
128
+ >
129
+ {{ rendered }}
130
+ </ng-container>
131
+ ```
132
+
133
+ Custom props (e.g. extending the default context):
134
+
135
+ ```html
136
+ <ng-container
137
+ *flexRender="
138
+ cell.column.columnDef.cell;
139
+ props: {
140
+ ...cell.getContext(),
141
+ extra: someValue(),
142
+ };
143
+ let rendered
144
+ "
145
+ >
146
+ {{ rendered }}
147
+ </ng-container>
148
+ ```
149
+
150
+ Inside the rendered component, `injectFlexRenderContext()` returns this full
151
+ props object.
152
+
153
+ You can also pass `flexRenderInjector:` to override the injector used for
154
+ `createComponent`.
155
+
156
+ ---
157
+
158
+ ## Render-function injection context
159
+
160
+ Because column-def `cell` / `header` / `footer` functions run inside
161
+ `runInInjectionContext`, this **works** at the top of those functions:
162
+
163
+ ```ts
164
+ cell: ({ getValue }) => {
165
+ const router = inject(Router) // ✅ legal
166
+ return router.url.endsWith('/admin') ? `[admin] ${getValue()}` : getValue()
167
+ }
168
+ ```
169
+
170
+ Be deliberate: this runs every time the cell renders. For per-app values that
171
+ don't change, prefer `inject(...)` at the component level and close over.
@@ -0,0 +1,64 @@
1
+ # `flexRenderComponent` — Full Options Reference
2
+
3
+ When you need custom inputs not derived from the render context, output
4
+ callbacks, a custom injector, or Angular v20+ `bindings` / `directives`,
5
+ **wrap the component**:
6
+
7
+ ```ts
8
+ import { flexRenderComponent, type ColumnDef } from '@tanstack/angular-table'
9
+ import { EditableCell } from './editable-cell'
10
+
11
+ const columns: Array<ColumnDef<typeof _features, Person>> = [
12
+ {
13
+ accessorKey: 'firstName',
14
+ cell: ({ getValue, row, column, table }) =>
15
+ flexRenderComponent(EditableCell, {
16
+ inputs: {
17
+ value: getValue(),
18
+ },
19
+ outputs: {
20
+ change: (value) => {
21
+ table.options.meta?.updateData(row.index, column.id, value)
22
+ },
23
+ },
24
+ }),
25
+ },
26
+ ]
27
+ ```
28
+
29
+ ## How inputs/outputs are wired
30
+
31
+ - **`inputs`** → applied via `ComponentRef.setInput(key, value)` (works with
32
+ both `input()` signals and legacy `@Input()`). Diffed per change-detection
33
+ cycle with `KeyValueDiffers` — unchanged values are _not_ re-set, so object
34
+ inputs are reference-checked. Keep input objects referentially stable when
35
+ you can.
36
+ - **`outputs`** → resolved at component-instance level. The wrapper reads the
37
+ property by name, checks it is an `OutputEmitterRef`, and subscribes. The
38
+ subscription is cleaned up when the component is destroyed.
39
+ - **`injector`** → use when the rendered component needs to inject from a
40
+ specific scope (e.g. a feature module / sub-injector).
41
+ - **`bindings`** (Angular v20+) → forwarded directly to
42
+ `ViewContainerRef.createComponent` at creation time. Use this with
43
+ `inputBinding`, `outputBinding`, `twoWayBinding` for native programmatic
44
+ rendering semantics.
45
+ - **`directives`** (Angular v20+) → host directives forwarded the same way.
46
+
47
+ ```ts
48
+ import { inputBinding, outputBinding, twoWayBinding, signal } from '@angular/core'
49
+
50
+ readonly name = signal('Ada')
51
+
52
+ cell: () =>
53
+ flexRenderComponent(EditableNameCell, {
54
+ bindings: [
55
+ inputBinding('value', this.name),
56
+ twoWayBinding('value', this.name),
57
+ outputBinding('valueChange', (v) => console.log('changed', v)),
58
+ ],
59
+ })
60
+ ```
61
+
62
+ > **Do not mix `bindings` with `inputs`/`outputs`** on the same component.
63
+ > `bindings` apply at creation time and participate in the initial CD cycle;
64
+ > `inputs`/`outputs` apply after. Mixing them risks double-initialization.