diff --git a/docs/config.json b/docs/config.json
index 506f16ab8f..e0da28e51b 100644
--- a/docs/config.json
+++ b/docs/config.json
@@ -438,6 +438,18 @@
{
"to": "framework/angular/examples/signal-input",
"label": "Signal Input"
+ },
+ {
+ "to": "framework/angular/examples/editable",
+ "label": "Editable data"
+ },
+ {
+ "to": "framework/angular/examples/row-dnd",
+ "label": "Row DnD"
+ },
+ {
+ "to": "framework/angular/examples/column-resizing-performant",
+ "label": "Performant Column Resizing"
}
]
},
diff --git a/examples/angular/column-resizing-performant/.devcontainer/devcontainer.json b/examples/angular/column-resizing-performant/.devcontainer/devcontainer.json
new file mode 100644
index 0000000000..36f47d8762
--- /dev/null
+++ b/examples/angular/column-resizing-performant/.devcontainer/devcontainer.json
@@ -0,0 +1,4 @@
+{
+ "name": "Node.js",
+ "image": "mcr.microsoft.com/devcontainers/javascript-node:18"
+}
diff --git a/examples/angular/column-resizing-performant/.editorconfig b/examples/angular/column-resizing-performant/.editorconfig
new file mode 100644
index 0000000000..59d9a3a3e7
--- /dev/null
+++ b/examples/angular/column-resizing-performant/.editorconfig
@@ -0,0 +1,16 @@
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.ts]
+quote_type = single
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/examples/angular/column-resizing-performant/.gitignore b/examples/angular/column-resizing-performant/.gitignore
new file mode 100644
index 0000000000..0711527ef9
--- /dev/null
+++ b/examples/angular/column-resizing-performant/.gitignore
@@ -0,0 +1,42 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# Compiled output
+/dist
+/tmp
+/out-tsc
+/bazel-out
+
+# Node
+/node_modules
+npm-debug.log
+yarn-error.log
+
+# IDEs and editors
+.idea/
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# Visual Studio Code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history/*
+
+# Miscellaneous
+/.angular/cache
+.sass-cache/
+/connect.lock
+/coverage
+/libpeerconnection.log
+testem.log
+/typings
+
+# System files
+.DS_Store
+Thumbs.db
diff --git a/examples/angular/column-resizing-performant/README.md b/examples/angular/column-resizing-performant/README.md
new file mode 100644
index 0000000000..5da97a87d1
--- /dev/null
+++ b/examples/angular/column-resizing-performant/README.md
@@ -0,0 +1,27 @@
+# Basic
+
+This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.1.2.
+
+## Development server
+
+Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
+
+## Code scaffolding
+
+Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
+
+## Build
+
+Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
+
+## Running unit tests
+
+Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
+
+## Running end-to-end tests
+
+Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
+
+## Further help
+
+To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
diff --git a/examples/angular/column-resizing-performant/angular.json b/examples/angular/column-resizing-performant/angular.json
new file mode 100644
index 0000000000..f74e8d69b9
--- /dev/null
+++ b/examples/angular/column-resizing-performant/angular.json
@@ -0,0 +1,83 @@
+{
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "version": 1,
+ "newProjectRoot": "projects",
+ "projects": {
+ "column-resizing-performant": {
+ "cli": {
+ "cache": {
+ "enabled": false
+ }
+ },
+ "projectType": "application",
+ "schematics": {
+ "@schematics/angular:component": {
+ "style": "scss"
+ }
+ },
+ "root": "",
+ "sourceRoot": "src",
+ "prefix": "app",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:application",
+ "options": {
+ "outputPath": "dist/column-resizing-performant",
+ "index": "src/index.html",
+ "browser": "src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": ["src/favicon.ico", "src/assets"],
+ "styles": ["src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "column-resizing-performant:build:production"
+ },
+ "development": {
+ "buildTarget": "column-resizing-performant:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "column-resizing-performant:build"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "polyfills": ["zone.js", "zone.js/testing"],
+ "tsConfig": "tsconfig.spec.json",
+ "inlineStyleLanguage": "scss",
+ "assets": ["src/favicon.ico", "src/assets"],
+ "styles": ["src/styles.scss"],
+ "scripts": []
+ }
+ }
+ }
+ }
+ },
+ "cli": {
+ "analytics": false
+ }
+}
diff --git a/examples/angular/column-resizing-performant/package.json b/examples/angular/column-resizing-performant/package.json
new file mode 100644
index 0000000000..a61a62b8a3
--- /dev/null
+++ b/examples/angular/column-resizing-performant/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "tanstack-table-example-angular-column-resizing-performant",
+ "version": "0.0.0",
+ "scripts": {
+ "ng": "ng",
+ "start": "ng serve",
+ "build": "ng build",
+ "watch": "ng build --watch --configuration development",
+ "test": "ng test"
+ },
+ "private": true,
+ "dependencies": {
+ "@angular/animations": "^17.3.9",
+ "@angular/common": "^17.3.9",
+ "@angular/compiler": "^17.3.9",
+ "@angular/core": "^17.3.9",
+ "@angular/forms": "^17.3.9",
+ "@angular/platform-browser": "^17.3.9",
+ "@angular/platform-browser-dynamic": "^17.3.9",
+ "@angular/router": "^17.3.9",
+ "@tanstack/angular-table": "^8.21.0",
+ "rxjs": "~7.8.1",
+ "zone.js": "~0.14.4"
+ },
+ "devDependencies": {
+ "@angular-devkit/build-angular": "^17.3.8",
+ "@angular/cli": "^17.3.8",
+ "@angular/compiler-cli": "^17.3.9",
+ "@types/jasmine": "~5.1.4",
+ "jasmine-core": "~5.1.2",
+ "karma": "~6.4.3",
+ "karma-chrome-launcher": "~3.2.0",
+ "karma-coverage": "~2.2.1",
+ "karma-jasmine": "~5.1.0",
+ "karma-jasmine-html-reporter": "~2.1.0",
+ "tslib": "^2.6.2",
+ "typescript": "5.4.5"
+ }
+}
diff --git a/examples/angular/column-resizing-performant/src/app/app.component.html b/examples/angular/column-resizing-performant/src/app/app.component.html
new file mode 100644
index 0000000000..e18f52be95
--- /dev/null
+++ b/examples/angular/column-resizing-performant/src/app/app.component.html
@@ -0,0 +1,66 @@
+
+
+
+ {{ columnSizingDebugInfo() }}
+
+
+
+ ({{ data().length }} rows)
+
+
+
+
+ @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) {
+
+ @for (header of headerGroup.headers; track header.id) {
+
+ @if (!header.isPlaceholder) {
+
+
+
+ }
+
+
+
+ }
+
+ }
+
+
+ @for (row of table.getRowModel().rows; track row.id) {
+
+ @for (cell of row.getVisibleCells(); track cell.id) {
+
+
+
+
+ |
+ }
+
+ }
+
+
+
+
diff --git a/examples/angular/column-resizing-performant/src/app/app.component.ts b/examples/angular/column-resizing-performant/src/app/app.component.ts
new file mode 100644
index 0000000000..43efd47de2
--- /dev/null
+++ b/examples/angular/column-resizing-performant/src/app/app.component.ts
@@ -0,0 +1,122 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ computed,
+ signal,
+ untracked,
+} from '@angular/core'
+import {
+ ColumnDef,
+ createAngularTable,
+ FlexRenderDirective,
+ getCoreRowModel,
+} from '@tanstack/angular-table'
+import { makeData, type Person } from './makeData'
+import { TableResizableCell, TableResizableHeader } from './resizable-cell'
+
+const defaultColumns: ColumnDef[] = [
+ {
+ header: 'Name',
+ footer: props => props.column.id,
+ columns: [
+ {
+ accessorKey: 'firstName',
+ cell: info => info.getValue(),
+ footer: props => props.column.id,
+ },
+ {
+ accessorFn: row => row.lastName,
+ id: 'lastName',
+ cell: info => info.getValue(),
+ header: () => 'Last Name',
+ footer: props => props.column.id,
+ },
+ ],
+ },
+ {
+ header: 'Info',
+ footer: props => props.column.id,
+ columns: [
+ {
+ accessorKey: 'age',
+ header: () => 'Age',
+ footer: props => props.column.id,
+ },
+ {
+ accessorKey: 'visits',
+ header: () => 'Visits',
+ footer: props => props.column.id,
+ },
+ {
+ accessorKey: 'status',
+ header: 'Status',
+ footer: props => props.column.id,
+ },
+ {
+ accessorKey: 'progress',
+ header: 'Profile Progress',
+ footer: props => props.column.id,
+ },
+ ],
+ },
+]
+
+@Component({
+ selector: 'app-root',
+ standalone: true,
+ imports: [FlexRenderDirective, TableResizableCell, TableResizableHeader],
+ templateUrl: './app.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AppComponent {
+ readonly data = signal(makeData(200))
+
+ readonly columnSizingInfo = computed(
+ () => this.table.getState().columnSizingInfo
+ )
+ readonly columnSizing = computed(() => this.table.getState().columnSizing)
+
+ /**
+ * Instead of calling `column.getSize()` on every render for every header
+ * and especially every data cell (very expensive),
+ * we will calculate all column sizes at once at the root table level in a useMemo
+ * and pass the column sizes down as CSS variables to the element.
+ */
+ readonly columnSizeVars = computed(() => {
+ void this.columnSizing()
+ void this.columnSizingInfo()
+ const headers = untracked(() => this.table.getFlatHeaders())
+ const colSizes: { [key: string]: number } = {}
+ let i = headers.length
+ while (--i >= 0) {
+ const header = headers[i]!
+ colSizes[`--header-${header.id}-size`] = header.getSize()
+ colSizes[`--col-${header.column.id}-size`] = header.column.getSize()
+ }
+ return colSizes
+ })
+
+ readonly table = createAngularTable(() => ({
+ data: this.data(),
+ columns: defaultColumns,
+ columnResizeMode: 'onChange',
+ getCoreRowModel: getCoreRowModel(),
+ defaultColumn: {
+ minSize: 60,
+ maxSize: 800,
+ },
+ debugTable: true,
+ debugHeaders: true,
+ debugColumns: true,
+ }))
+
+ readonly columnSizingDebugInfo = computed(() =>
+ JSON.stringify(
+ {
+ columnSizing: this.table.getState().columnSizing,
+ },
+ null,
+ 2
+ )
+ )
+}
diff --git a/examples/angular/column-resizing-performant/src/app/app.config.ts b/examples/angular/column-resizing-performant/src/app/app.config.ts
new file mode 100644
index 0000000000..f27099f33c
--- /dev/null
+++ b/examples/angular/column-resizing-performant/src/app/app.config.ts
@@ -0,0 +1,5 @@
+import { ApplicationConfig } from '@angular/core'
+
+export const appConfig: ApplicationConfig = {
+ providers: [],
+}
diff --git a/examples/angular/column-resizing-performant/src/app/makeData.ts b/examples/angular/column-resizing-performant/src/app/makeData.ts
new file mode 100644
index 0000000000..331dd1eb19
--- /dev/null
+++ b/examples/angular/column-resizing-performant/src/app/makeData.ts
@@ -0,0 +1,48 @@
+import { faker } from '@faker-js/faker'
+
+export type Person = {
+ firstName: string
+ lastName: string
+ age: number
+ visits: number
+ progress: number
+ status: 'relationship' | 'complicated' | 'single'
+ subRows?: Person[]
+}
+
+const range = (len: number) => {
+ const arr: number[] = []
+ for (let i = 0; i < len; i++) {
+ arr.push(i)
+ }
+ return arr
+}
+
+const newPerson = (): Person => {
+ return {
+ firstName: faker.person.firstName(),
+ lastName: faker.person.lastName(),
+ age: faker.number.int(40),
+ visits: faker.number.int(1000),
+ progress: faker.number.int(100),
+ status: faker.helpers.shuffle([
+ 'relationship',
+ 'complicated',
+ 'single',
+ ])[0]!,
+ }
+}
+
+export function makeData(...lens: number[]) {
+ const makeDataLevel = (depth = 0): Person[] => {
+ const len = lens[depth]!
+ return range(len).map((d): Person => {
+ return {
+ ...newPerson(),
+ subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
+ }
+ })
+ }
+
+ return makeDataLevel()
+}
diff --git a/examples/angular/column-resizing-performant/src/app/resizable-cell.ts b/examples/angular/column-resizing-performant/src/app/resizable-cell.ts
new file mode 100644
index 0000000000..2338bbc8c4
--- /dev/null
+++ b/examples/angular/column-resizing-performant/src/app/resizable-cell.ts
@@ -0,0 +1,35 @@
+import { computed, Directive, input } from '@angular/core'
+
+@Directive({
+ selector: '[tableResizableHeader]',
+ host: {
+ '[style.width]': 'width()',
+ },
+ standalone: true,
+})
+export class TableResizableHeader {
+ readonly cellId = input.required({
+ alias: 'tableResizableHeader',
+ })
+
+ readonly width = computed(
+ () => `calc(var(--header-${this.cellId()}-size) * 1px)`
+ )
+}
+
+@Directive({
+ selector: '[tableResizableCell]',
+ host: {
+ '[style.width]': 'width()',
+ },
+ standalone: true,
+})
+export class TableResizableCell {
+ readonly cellId = input.required({
+ alias: 'tableResizableCell',
+ })
+
+ readonly width = computed(
+ () => `calc(var(--col-${this.cellId()}-size) * 1px)`
+ )
+}
diff --git a/examples/angular/column-resizing-performant/src/assets/.gitkeep b/examples/angular/column-resizing-performant/src/assets/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/examples/angular/column-resizing-performant/src/favicon.ico b/examples/angular/column-resizing-performant/src/favicon.ico
new file mode 100644
index 0000000000..57614f9c96
Binary files /dev/null and b/examples/angular/column-resizing-performant/src/favicon.ico differ
diff --git a/examples/angular/column-resizing-performant/src/index.html b/examples/angular/column-resizing-performant/src/index.html
new file mode 100644
index 0000000000..0132a98242
--- /dev/null
+++ b/examples/angular/column-resizing-performant/src/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Performant Column Resizing
+
+
+
+
+
+
+
+
+
diff --git a/examples/angular/column-resizing-performant/src/main.ts b/examples/angular/column-resizing-performant/src/main.ts
new file mode 100644
index 0000000000..0c3b92057c
--- /dev/null
+++ b/examples/angular/column-resizing-performant/src/main.ts
@@ -0,0 +1,5 @@
+import { bootstrapApplication } from '@angular/platform-browser'
+import { appConfig } from './app/app.config'
+import { AppComponent } from './app/app.component'
+
+bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err))
diff --git a/examples/angular/column-resizing-performant/src/styles.scss b/examples/angular/column-resizing-performant/src/styles.scss
new file mode 100644
index 0000000000..b829b6ca09
--- /dev/null
+++ b/examples/angular/column-resizing-performant/src/styles.scss
@@ -0,0 +1,74 @@
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: sans-serif;
+ font-size: 14px;
+}
+
+table,
+.divTable {
+ display: block;
+ border: 1px solid lightgray;
+ width: fit-content;
+}
+
+.tr {
+ display: flex;
+}
+
+tr,
+.tr {
+ width: fit-content;
+ height: 30px;
+}
+
+th,
+.th,
+td,
+.td {
+ box-shadow: inset 0 0 0 1px lightgray;
+ padding: 0.25rem;
+}
+
+th,
+.th {
+ padding: 2px 4px;
+ position: relative;
+ font-weight: bold;
+ text-align: center;
+ height: 30px;
+}
+
+td,
+.td {
+ height: 30px;
+}
+
+.resizer {
+ position: absolute;
+ top: 0;
+ height: 100%;
+ right: 0;
+ width: 5px;
+ background: rgba(0, 0, 0, 0.5);
+ cursor: col-resize;
+ user-select: none;
+ touch-action: none;
+}
+
+.resizer.isResizing {
+ background: blue;
+ opacity: 1;
+}
+
+@media (hover: hover) {
+ .resizer {
+ opacity: 0;
+ }
+
+ *:hover > .resizer {
+ opacity: 1;
+ }
+}
diff --git a/examples/angular/column-resizing-performant/tsconfig.app.json b/examples/angular/column-resizing-performant/tsconfig.app.json
new file mode 100644
index 0000000000..84f1f992d2
--- /dev/null
+++ b/examples/angular/column-resizing-performant/tsconfig.app.json
@@ -0,0 +1,10 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./out-tsc/app",
+ "types": []
+ },
+ "files": ["src/main.ts"],
+ "include": ["src/**/*.d.ts"]
+}
diff --git a/examples/angular/column-resizing-performant/tsconfig.json b/examples/angular/column-resizing-performant/tsconfig.json
new file mode 100644
index 0000000000..b58d3efc71
--- /dev/null
+++ b/examples/angular/column-resizing-performant/tsconfig.json
@@ -0,0 +1,31 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "compileOnSave": false,
+ "compilerOptions": {
+ "baseUrl": "src",
+ "outDir": "./dist/out-tsc",
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "sourceMap": true,
+ "declaration": false,
+ "experimentalDecorators": true,
+ "moduleResolution": "node",
+ "importHelpers": true,
+ "target": "ES2022",
+ "module": "ES2022",
+ "useDefineForClassFields": false,
+ "lib": ["ES2022", "dom"]
+ },
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/examples/angular/column-resizing-performant/tsconfig.spec.json b/examples/angular/column-resizing-performant/tsconfig.spec.json
new file mode 100644
index 0000000000..47e3dd7551
--- /dev/null
+++ b/examples/angular/column-resizing-performant/tsconfig.spec.json
@@ -0,0 +1,9 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./out-tsc/spec",
+ "types": ["jasmine"]
+ },
+ "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
+}
diff --git a/examples/angular/editable/.devcontainer/devcontainer.json b/examples/angular/editable/.devcontainer/devcontainer.json
new file mode 100644
index 0000000000..36f47d8762
--- /dev/null
+++ b/examples/angular/editable/.devcontainer/devcontainer.json
@@ -0,0 +1,4 @@
+{
+ "name": "Node.js",
+ "image": "mcr.microsoft.com/devcontainers/javascript-node:18"
+}
diff --git a/examples/angular/editable/.editorconfig b/examples/angular/editable/.editorconfig
new file mode 100644
index 0000000000..59d9a3a3e7
--- /dev/null
+++ b/examples/angular/editable/.editorconfig
@@ -0,0 +1,16 @@
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.ts]
+quote_type = single
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/examples/angular/editable/.gitignore b/examples/angular/editable/.gitignore
new file mode 100644
index 0000000000..0711527ef9
--- /dev/null
+++ b/examples/angular/editable/.gitignore
@@ -0,0 +1,42 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# Compiled output
+/dist
+/tmp
+/out-tsc
+/bazel-out
+
+# Node
+/node_modules
+npm-debug.log
+yarn-error.log
+
+# IDEs and editors
+.idea/
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# Visual Studio Code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history/*
+
+# Miscellaneous
+/.angular/cache
+.sass-cache/
+/connect.lock
+/coverage
+/libpeerconnection.log
+testem.log
+/typings
+
+# System files
+.DS_Store
+Thumbs.db
diff --git a/examples/angular/editable/README.md b/examples/angular/editable/README.md
new file mode 100644
index 0000000000..5da97a87d1
--- /dev/null
+++ b/examples/angular/editable/README.md
@@ -0,0 +1,27 @@
+# Basic
+
+This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.1.2.
+
+## Development server
+
+Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
+
+## Code scaffolding
+
+Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
+
+## Build
+
+Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
+
+## Running unit tests
+
+Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
+
+## Running end-to-end tests
+
+Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
+
+## Further help
+
+To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
diff --git a/examples/angular/editable/angular.json b/examples/angular/editable/angular.json
new file mode 100644
index 0000000000..0a6c896860
--- /dev/null
+++ b/examples/angular/editable/angular.json
@@ -0,0 +1,83 @@
+{
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "version": 1,
+ "newProjectRoot": "projects",
+ "projects": {
+ "editable": {
+ "cli": {
+ "cache": {
+ "enabled": false
+ }
+ },
+ "projectType": "application",
+ "schematics": {
+ "@schematics/angular:component": {
+ "style": "scss"
+ }
+ },
+ "root": "",
+ "sourceRoot": "src",
+ "prefix": "app",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:application",
+ "options": {
+ "outputPath": "dist/editable",
+ "index": "src/index.html",
+ "browser": "src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": ["src/favicon.ico", "src/assets"],
+ "styles": ["src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "editable:build:production"
+ },
+ "development": {
+ "buildTarget": "editable:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "editable:build"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "polyfills": ["zone.js", "zone.js/testing"],
+ "tsConfig": "tsconfig.spec.json",
+ "inlineStyleLanguage": "scss",
+ "assets": ["src/favicon.ico", "src/assets"],
+ "styles": ["src/styles.scss"],
+ "scripts": []
+ }
+ }
+ }
+ }
+ },
+ "cli": {
+ "analytics": false
+ }
+}
diff --git a/examples/angular/editable/package.json b/examples/angular/editable/package.json
new file mode 100644
index 0000000000..b01d3ffe33
--- /dev/null
+++ b/examples/angular/editable/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "tanstack-table-example-angular-editable",
+ "version": "0.0.0",
+ "scripts": {
+ "ng": "ng",
+ "start": "ng serve",
+ "build": "ng build",
+ "watch": "ng build --watch --configuration development",
+ "test": "ng test"
+ },
+ "private": true,
+ "dependencies": {
+ "@angular/animations": "^17.3.9",
+ "@angular/common": "^17.3.9",
+ "@angular/compiler": "^17.3.9",
+ "@angular/core": "^17.3.9",
+ "@angular/forms": "^17.3.9",
+ "@angular/platform-browser": "^17.3.9",
+ "@angular/platform-browser-dynamic": "^17.3.9",
+ "@angular/router": "^17.3.9",
+ "@tanstack/angular-table": "^8.21.0",
+ "rxjs": "~7.8.1",
+ "zone.js": "~0.14.4"
+ },
+ "devDependencies": {
+ "@angular-devkit/build-angular": "^17.3.8",
+ "@angular/cli": "^17.3.8",
+ "@angular/compiler-cli": "^17.3.9",
+ "@types/jasmine": "~5.1.4",
+ "jasmine-core": "~5.1.2",
+ "karma": "~6.4.3",
+ "karma-chrome-launcher": "~3.2.0",
+ "karma-coverage": "~2.2.1",
+ "karma-jasmine": "~5.1.0",
+ "karma-jasmine-html-reporter": "~2.1.0",
+ "tslib": "^2.6.2",
+ "typescript": "5.4.5"
+ }
+}
diff --git a/examples/angular/editable/src/app/app.component.html b/examples/angular/editable/src/app/app.component.html
new file mode 100644
index 0000000000..d960bcf324
--- /dev/null
+++ b/examples/angular/editable/src/app/app.component.html
@@ -0,0 +1,106 @@
+
+
+
+ @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) {
+
+ @for (header of headerGroup.headers; track header.id) {
+ @if (!header.isPlaceholder) {
+
+
+
+
+ |
+ }
+ }
+
+ }
+
+
+ @for (row of table.getRowModel().rows; track row.id) {
+
+ @for (cell of row.getVisibleCells(); track cell.id) {
+
+
+
+
+ |
+ }
+
+ }
+
+
+ @for (footerGroup of table.getFooterGroups(); track footerGroup.id) {
+
+ @for (footer of footerGroup.headers; track footer.id) {
+
+
+ {{ footer }}
+
+ |
+ }
+
+ }
+
+
+
+
+
+
+
+
+
+
+ Page
+
+ {{ table.getState().pagination.pageIndex + 1 }} of
+ {{ table.getPageCount() }}
+
+
+
+
+
+
diff --git a/examples/angular/editable/src/app/app.component.ts b/examples/angular/editable/src/app/app.component.ts
new file mode 100644
index 0000000000..54956725a4
--- /dev/null
+++ b/examples/angular/editable/src/app/app.component.ts
@@ -0,0 +1,130 @@
+import {
+ afterNextRender,
+ ChangeDetectionStrategy,
+ Component,
+ inject,
+ Injector,
+ signal,
+} from '@angular/core'
+import {
+ ColumnDef,
+ createAngularTable,
+ flexRenderComponent,
+ FlexRenderDirective,
+ getCoreRowModel,
+ getFilteredRowModel,
+ getPaginationRowModel,
+ type RowData,
+} from '@tanstack/angular-table'
+import { EditableCell } from './editable-cell'
+import { makeData, type Person } from './makeData'
+
+declare module '@tanstack/angular-table' {
+ interface TableMeta {
+ updateData: (rowIndex: number, columnId: string, value: unknown) => void
+ }
+}
+
+const defaultColumn: Partial> = {
+ cell: ({ getValue, row, column, table }) => {
+ const initialValue = getValue()
+
+ return flexRenderComponent(EditableCell, {
+ inputs: {
+ value: initialValue,
+ },
+ outputs: {
+ blur: value => {
+ if (table.options.meta?.updateData) {
+ table.options.meta.updateData(row.index, column.id, value)
+ }
+ },
+ },
+ })
+ },
+}
+
+const defaultColumns: ColumnDef[] = [
+ {
+ accessorKey: 'firstName',
+ footer: info => info.column.id,
+ },
+ {
+ accessorFn: row => row.lastName,
+ id: 'lastName',
+ header: () => `Last Name`,
+ footer: info => info.column.id,
+ },
+ {
+ accessorKey: 'age',
+ header: () => 'Age',
+ footer: info => info.column.id,
+ },
+ {
+ accessorKey: 'visits',
+ header: () => `Visits`,
+ footer: info => info.column.id,
+ },
+ {
+ accessorKey: 'status',
+ header: 'Status',
+ footer: info => info.column.id,
+ },
+ {
+ accessorKey: 'progress',
+ header: 'Profile Progress',
+ footer: info => info.column.id,
+ },
+]
+
+@Component({
+ selector: 'app-root',
+ standalone: true,
+ imports: [FlexRenderDirective],
+ templateUrl: './app.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AppComponent {
+ readonly data = signal(makeData(10_000))
+ readonly injector = inject(Injector)
+
+ readonly autoResetPageIndex = signal(true)
+
+ readonly table = createAngularTable(() => ({
+ data: this.data(),
+ columns: defaultColumns,
+ defaultColumn: defaultColumn,
+ getCoreRowModel: getCoreRowModel(),
+ getFilteredRowModel: getFilteredRowModel(),
+ getPaginationRowModel: getPaginationRowModel(),
+ debugTable: true,
+ autoResetPageIndex: this.autoResetPageIndex(),
+ // Provide our updateData function to our table meta
+ meta: {
+ updateData: (rowIndex, columnId, value) => {
+ // Skip page index reset until after next rerender
+ this.autoResetPageIndex.set(false)
+
+ this.data.update(old =>
+ old.map((row, index) => {
+ if (index === rowIndex) {
+ return {
+ ...old[rowIndex],
+ [columnId]: value,
+ }
+ }
+ return row
+ })
+ )
+
+ afterNextRender(() => this.autoResetPageIndex.set(true), {
+ injector: this.injector,
+ })
+ },
+ },
+ }))
+
+ refresh() {
+ this.data.set(makeData(10_000))
+ }
+}
diff --git a/examples/angular/editable/src/app/app.config.ts b/examples/angular/editable/src/app/app.config.ts
new file mode 100644
index 0000000000..f27099f33c
--- /dev/null
+++ b/examples/angular/editable/src/app/app.config.ts
@@ -0,0 +1,5 @@
+import { ApplicationConfig } from '@angular/core'
+
+export const appConfig: ApplicationConfig = {
+ providers: [],
+}
diff --git a/examples/angular/editable/src/app/editable-cell.ts b/examples/angular/editable/src/app/editable-cell.ts
new file mode 100644
index 0000000000..db5980334c
--- /dev/null
+++ b/examples/angular/editable/src/app/editable-cell.ts
@@ -0,0 +1,30 @@
+import {
+ Component,
+ effect,
+ input,
+ output,
+ signal,
+ untracked,
+} from '@angular/core'
+import { FormsModule } from '@angular/forms'
+
+@Component({
+ selector: 'editable-cell',
+ template: ` `,
+ standalone: true,
+ imports: [FormsModule],
+})
+export class EditableCell {
+ readonly modelValue = signal(undefined)
+
+ readonly value = input()
+
+ readonly blur = output()
+
+ constructor() {
+ effect(() => {
+ const value = this.value()
+ untracked(() => this.modelValue.set(value))
+ })
+ }
+}
diff --git a/examples/angular/editable/src/app/makeData.ts b/examples/angular/editable/src/app/makeData.ts
new file mode 100644
index 0000000000..331dd1eb19
--- /dev/null
+++ b/examples/angular/editable/src/app/makeData.ts
@@ -0,0 +1,48 @@
+import { faker } from '@faker-js/faker'
+
+export type Person = {
+ firstName: string
+ lastName: string
+ age: number
+ visits: number
+ progress: number
+ status: 'relationship' | 'complicated' | 'single'
+ subRows?: Person[]
+}
+
+const range = (len: number) => {
+ const arr: number[] = []
+ for (let i = 0; i < len; i++) {
+ arr.push(i)
+ }
+ return arr
+}
+
+const newPerson = (): Person => {
+ return {
+ firstName: faker.person.firstName(),
+ lastName: faker.person.lastName(),
+ age: faker.number.int(40),
+ visits: faker.number.int(1000),
+ progress: faker.number.int(100),
+ status: faker.helpers.shuffle([
+ 'relationship',
+ 'complicated',
+ 'single',
+ ])[0]!,
+ }
+}
+
+export function makeData(...lens: number[]) {
+ const makeDataLevel = (depth = 0): Person[] => {
+ const len = lens[depth]!
+ return range(len).map((d): Person => {
+ return {
+ ...newPerson(),
+ subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
+ }
+ })
+ }
+
+ return makeDataLevel()
+}
diff --git a/examples/angular/editable/src/assets/.gitkeep b/examples/angular/editable/src/assets/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/examples/angular/editable/src/favicon.ico b/examples/angular/editable/src/favicon.ico
new file mode 100644
index 0000000000..57614f9c96
Binary files /dev/null and b/examples/angular/editable/src/favicon.ico differ
diff --git a/examples/angular/editable/src/index.html b/examples/angular/editable/src/index.html
new file mode 100644
index 0000000000..d24da42550
--- /dev/null
+++ b/examples/angular/editable/src/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Editable data
+
+
+
+
+
+
+
+
+
diff --git a/examples/angular/editable/src/main.ts b/examples/angular/editable/src/main.ts
new file mode 100644
index 0000000000..0c3b92057c
--- /dev/null
+++ b/examples/angular/editable/src/main.ts
@@ -0,0 +1,5 @@
+import { bootstrapApplication } from '@angular/platform-browser'
+import { appConfig } from './app/app.config'
+import { AppComponent } from './app/app.component'
+
+bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err))
diff --git a/examples/angular/editable/src/styles.scss b/examples/angular/editable/src/styles.scss
new file mode 100644
index 0000000000..cda3113f7d
--- /dev/null
+++ b/examples/angular/editable/src/styles.scss
@@ -0,0 +1,32 @@
+html {
+ font-family: sans-serif;
+ font-size: 14px;
+}
+
+table {
+ border: 1px solid lightgray;
+}
+
+tbody {
+ border-bottom: 1px solid lightgray;
+}
+
+th {
+ border-bottom: 1px solid lightgray;
+ border-right: 1px solid lightgray;
+ padding: 2px 4px;
+}
+
+tfoot {
+ color: gray;
+}
+
+tfoot th {
+ font-weight: normal;
+}
+
+.pagination-actions {
+ margin: 10px;
+ display: flex;
+ gap: 10px;
+}
diff --git a/examples/angular/editable/tsconfig.app.json b/examples/angular/editable/tsconfig.app.json
new file mode 100644
index 0000000000..84f1f992d2
--- /dev/null
+++ b/examples/angular/editable/tsconfig.app.json
@@ -0,0 +1,10 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./out-tsc/app",
+ "types": []
+ },
+ "files": ["src/main.ts"],
+ "include": ["src/**/*.d.ts"]
+}
diff --git a/examples/angular/editable/tsconfig.json b/examples/angular/editable/tsconfig.json
new file mode 100644
index 0000000000..b58d3efc71
--- /dev/null
+++ b/examples/angular/editable/tsconfig.json
@@ -0,0 +1,31 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "compileOnSave": false,
+ "compilerOptions": {
+ "baseUrl": "src",
+ "outDir": "./dist/out-tsc",
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "sourceMap": true,
+ "declaration": false,
+ "experimentalDecorators": true,
+ "moduleResolution": "node",
+ "importHelpers": true,
+ "target": "ES2022",
+ "module": "ES2022",
+ "useDefineForClassFields": false,
+ "lib": ["ES2022", "dom"]
+ },
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/examples/angular/editable/tsconfig.spec.json b/examples/angular/editable/tsconfig.spec.json
new file mode 100644
index 0000000000..47e3dd7551
--- /dev/null
+++ b/examples/angular/editable/tsconfig.spec.json
@@ -0,0 +1,9 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./out-tsc/spec",
+ "types": ["jasmine"]
+ },
+ "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
+}
diff --git a/examples/angular/row-dnd/.devcontainer/devcontainer.json b/examples/angular/row-dnd/.devcontainer/devcontainer.json
new file mode 100644
index 0000000000..36f47d8762
--- /dev/null
+++ b/examples/angular/row-dnd/.devcontainer/devcontainer.json
@@ -0,0 +1,4 @@
+{
+ "name": "Node.js",
+ "image": "mcr.microsoft.com/devcontainers/javascript-node:18"
+}
diff --git a/examples/angular/row-dnd/.editorconfig b/examples/angular/row-dnd/.editorconfig
new file mode 100644
index 0000000000..59d9a3a3e7
--- /dev/null
+++ b/examples/angular/row-dnd/.editorconfig
@@ -0,0 +1,16 @@
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.ts]
+quote_type = single
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/examples/angular/row-dnd/.gitignore b/examples/angular/row-dnd/.gitignore
new file mode 100644
index 0000000000..0711527ef9
--- /dev/null
+++ b/examples/angular/row-dnd/.gitignore
@@ -0,0 +1,42 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# Compiled output
+/dist
+/tmp
+/out-tsc
+/bazel-out
+
+# Node
+/node_modules
+npm-debug.log
+yarn-error.log
+
+# IDEs and editors
+.idea/
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# Visual Studio Code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history/*
+
+# Miscellaneous
+/.angular/cache
+.sass-cache/
+/connect.lock
+/coverage
+/libpeerconnection.log
+testem.log
+/typings
+
+# System files
+.DS_Store
+Thumbs.db
diff --git a/examples/angular/row-dnd/README.md b/examples/angular/row-dnd/README.md
new file mode 100644
index 0000000000..8494f725e3
--- /dev/null
+++ b/examples/angular/row-dnd/README.md
@@ -0,0 +1,27 @@
+# Row Dnd
+
+This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.1.2.
+
+## Development server
+
+Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
+
+## Code scaffolding
+
+Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
+
+## Build
+
+Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
+
+## Running unit tests
+
+Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
+
+## Running end-to-end tests
+
+Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
+
+## Further help
+
+To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
diff --git a/examples/angular/row-dnd/angular.json b/examples/angular/row-dnd/angular.json
new file mode 100644
index 0000000000..0a6c896860
--- /dev/null
+++ b/examples/angular/row-dnd/angular.json
@@ -0,0 +1,83 @@
+{
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "version": 1,
+ "newProjectRoot": "projects",
+ "projects": {
+ "editable": {
+ "cli": {
+ "cache": {
+ "enabled": false
+ }
+ },
+ "projectType": "application",
+ "schematics": {
+ "@schematics/angular:component": {
+ "style": "scss"
+ }
+ },
+ "root": "",
+ "sourceRoot": "src",
+ "prefix": "app",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:application",
+ "options": {
+ "outputPath": "dist/editable",
+ "index": "src/index.html",
+ "browser": "src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": ["src/favicon.ico", "src/assets"],
+ "styles": ["src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "editable:build:production"
+ },
+ "development": {
+ "buildTarget": "editable:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "editable:build"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "polyfills": ["zone.js", "zone.js/testing"],
+ "tsConfig": "tsconfig.spec.json",
+ "inlineStyleLanguage": "scss",
+ "assets": ["src/favicon.ico", "src/assets"],
+ "styles": ["src/styles.scss"],
+ "scripts": []
+ }
+ }
+ }
+ }
+ },
+ "cli": {
+ "analytics": false
+ }
+}
diff --git a/examples/angular/row-dnd/package.json b/examples/angular/row-dnd/package.json
new file mode 100644
index 0000000000..af045e7d7a
--- /dev/null
+++ b/examples/angular/row-dnd/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "tanstack-table-example-angular-row-dnd",
+ "version": "0.0.0",
+ "scripts": {
+ "ng": "ng",
+ "start": "ng serve",
+ "build": "ng build",
+ "watch": "ng build --watch --configuration development",
+ "test": "ng test"
+ },
+ "private": true,
+ "dependencies": {
+ "@angular/animations": "^17.3.9",
+ "@angular/common": "^17.3.9",
+ "@angular/compiler": "^17.3.9",
+ "@angular/cdk": "^17.3.10",
+ "@angular/core": "^17.3.9",
+ "@angular/forms": "^17.3.9",
+ "@angular/platform-browser": "^17.3.9",
+ "@angular/platform-browser-dynamic": "^17.3.9",
+ "@angular/router": "^17.3.9",
+ "@tanstack/angular-table": "^8.21.0",
+ "rxjs": "~7.8.1",
+ "zone.js": "~0.14.4"
+ },
+ "devDependencies": {
+ "@angular-devkit/build-angular": "^17.3.8",
+ "@angular/cli": "^17.3.8",
+ "@angular/compiler-cli": "^17.3.9",
+ "@types/jasmine": "~5.1.4",
+ "jasmine-core": "~5.1.2",
+ "karma": "~6.4.3",
+ "karma-chrome-launcher": "~3.2.0",
+ "karma-coverage": "~2.2.1",
+ "karma-jasmine": "~5.1.0",
+ "karma-jasmine-html-reporter": "~2.1.0",
+ "tslib": "^2.6.2",
+ "typescript": "5.4.5"
+ }
+}
diff --git a/examples/angular/row-dnd/src/app/app.component.css b/examples/angular/row-dnd/src/app/app.component.css
new file mode 100644
index 0000000000..9c94476209
--- /dev/null
+++ b/examples/angular/row-dnd/src/app/app.component.css
@@ -0,0 +1,23 @@
+.cdk-drag-preview {
+ box-sizing: border-box;
+ box-shadow:
+ 0 5px 5px -3px rgba(0, 0, 0, 0.2),
+ 0 8px 10px 1px rgba(0, 0, 0, 0.14),
+ 0 3px 14px 2px rgba(0, 0, 0, 0.12);
+}
+
+.cdk-drag-placeholder {
+ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.cdk-drag-placeholder > td {
+ background: #ccc;
+}
+
+.cdk-drag-animating {
+ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.cdk-drop-list-dragging tr[cdkdrag]:not(.cdk-drag-placeholder) {
+ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+}
diff --git a/examples/angular/row-dnd/src/app/app.component.html b/examples/angular/row-dnd/src/app/app.component.html
new file mode 100644
index 0000000000..b680eaf212
--- /dev/null
+++ b/examples/angular/row-dnd/src/app/app.component.html
@@ -0,0 +1,55 @@
+
+
+
+ @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) {
+
+ @for (header of headerGroup.headers; track header.id) {
+ @if (!header.isPlaceholder) {
+
+
+
+
+ |
+ }
+ }
+
+ }
+
+
+ @for (row of table.getRowModel().rows; track row.id) {
+
+ @for (cell of row.getVisibleCells(); track cell.id) {
+
+
+
+
+ |
+ }
+
+ }
+
+
+
+
{{ sortedIds() | json }}
+
diff --git a/examples/angular/row-dnd/src/app/app.component.ts b/examples/angular/row-dnd/src/app/app.component.ts
new file mode 100644
index 0000000000..e28c236f08
--- /dev/null
+++ b/examples/angular/row-dnd/src/app/app.component.ts
@@ -0,0 +1,93 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ computed,
+ signal,
+} from '@angular/core'
+import {
+ ColumnDef,
+ createAngularTable,
+ flexRenderComponent,
+ FlexRenderDirective,
+ getCoreRowModel,
+ getFilteredRowModel,
+ getPaginationRowModel,
+} from '@tanstack/angular-table'
+import { DragHandleCell } from './drag-handle-cell'
+import { makeData, type Person } from './makeData'
+import {
+ CdkDrag,
+ type CdkDragDrop,
+ CdkDropList,
+ moveItemInArray,
+} from '@angular/cdk/drag-drop'
+import { JsonPipe } from '@angular/common'
+
+const defaultColumns: ColumnDef[] = [
+ {
+ id: 'drag-handle',
+ header: 'Move',
+ cell: () => flexRenderComponent(DragHandleCell),
+ size: 60,
+ },
+ {
+ accessorKey: 'firstName',
+ cell: info => info.getValue(),
+ },
+ {
+ accessorFn: row => row.lastName,
+ id: 'lastName',
+ cell: info => info.getValue(),
+ header: () => `Last Name`,
+ },
+ {
+ accessorKey: 'age',
+ header: () => 'Age',
+ },
+ {
+ accessorKey: 'visits',
+ header: () => `Visits`,
+ },
+ {
+ accessorKey: 'status',
+ header: 'Status',
+ },
+ {
+ accessorKey: 'progress',
+ header: 'Profile Progress',
+ },
+]
+
+@Component({
+ selector: 'app-root',
+ standalone: true,
+ imports: [FlexRenderDirective, CdkDropList, CdkDrag, JsonPipe],
+ templateUrl: './app.component.html',
+ styleUrl: './app.component.css',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AppComponent {
+ readonly data = signal(makeData(20))
+
+ readonly table = createAngularTable(() => {
+ return {
+ data: this.data(),
+ columns: defaultColumns,
+ getRowId: row => row.userId, //required because row indexes will change
+ debugTable: true,
+ debugHeaders: true,
+ debugColumns: true,
+ getCoreRowModel: getCoreRowModel(),
+ getFilteredRowModel: getFilteredRowModel(),
+ getPaginationRowModel: getPaginationRowModel(),
+ }
+ })
+
+ readonly sortedIds = computed(() => this.data().map(data => data.userId))
+
+ drop(event: CdkDragDrop) {
+ const data = [...this.data()]
+ moveItemInArray(data, event.previousIndex, event.currentIndex)
+ this.data.set(data)
+ }
+}
diff --git a/examples/angular/row-dnd/src/app/app.config.ts b/examples/angular/row-dnd/src/app/app.config.ts
new file mode 100644
index 0000000000..f27099f33c
--- /dev/null
+++ b/examples/angular/row-dnd/src/app/app.config.ts
@@ -0,0 +1,5 @@
+import { ApplicationConfig } from '@angular/core'
+
+export const appConfig: ApplicationConfig = {
+ providers: [],
+}
diff --git a/examples/angular/row-dnd/src/app/drag-handle-cell.ts b/examples/angular/row-dnd/src/app/drag-handle-cell.ts
new file mode 100644
index 0000000000..00320e706e
--- /dev/null
+++ b/examples/angular/row-dnd/src/app/drag-handle-cell.ts
@@ -0,0 +1,20 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ effect,
+ input,
+ output,
+ signal,
+ untracked,
+} from '@angular/core'
+import { FormsModule } from '@angular/forms'
+import { CdkDragHandle } from '@angular/cdk/drag-drop'
+
+@Component({
+ selector: 'editable-cell',
+ template: ` `,
+ standalone: true,
+ imports: [CdkDragHandle],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DragHandleCell {}
diff --git a/examples/angular/row-dnd/src/app/makeData.ts b/examples/angular/row-dnd/src/app/makeData.ts
new file mode 100644
index 0000000000..26b666d2ae
--- /dev/null
+++ b/examples/angular/row-dnd/src/app/makeData.ts
@@ -0,0 +1,50 @@
+import { faker } from '@faker-js/faker'
+
+export type Person = {
+ userId: string
+ firstName: string
+ lastName: string
+ age: number
+ visits: number
+ progress: number
+ status: 'relationship' | 'complicated' | 'single'
+ subRows?: Person[]
+}
+
+const range = (len: number) => {
+ const arr: number[] = []
+ for (let i = 0; i < len; i++) {
+ arr.push(i)
+ }
+ return arr
+}
+
+const newPerson = (): Person => {
+ return {
+ userId: faker.string.uuid(),
+ firstName: faker.person.firstName(),
+ lastName: faker.person.lastName(),
+ age: faker.number.int(40),
+ visits: faker.number.int(1000),
+ progress: faker.number.int(100),
+ status: faker.helpers.shuffle([
+ 'relationship',
+ 'complicated',
+ 'single',
+ ])[0]!,
+ }
+}
+
+export function makeData(...lens: number[]) {
+ const makeDataLevel = (depth = 0): Person[] => {
+ const len = lens[depth]!
+ return range(len).map((_d): Person => {
+ return {
+ ...newPerson(),
+ subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
+ }
+ })
+ }
+
+ return makeDataLevel()
+}
diff --git a/examples/angular/row-dnd/src/assets/.gitkeep b/examples/angular/row-dnd/src/assets/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/examples/angular/row-dnd/src/favicon.ico b/examples/angular/row-dnd/src/favicon.ico
new file mode 100644
index 0000000000..57614f9c96
Binary files /dev/null and b/examples/angular/row-dnd/src/favicon.ico differ
diff --git a/examples/angular/row-dnd/src/index.html b/examples/angular/row-dnd/src/index.html
new file mode 100644
index 0000000000..adc28921f9
--- /dev/null
+++ b/examples/angular/row-dnd/src/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Row Drag and drop
+
+
+
+
+
+
+
+
+
diff --git a/examples/angular/row-dnd/src/main.ts b/examples/angular/row-dnd/src/main.ts
new file mode 100644
index 0000000000..0c3b92057c
--- /dev/null
+++ b/examples/angular/row-dnd/src/main.ts
@@ -0,0 +1,5 @@
+import { bootstrapApplication } from '@angular/platform-browser'
+import { appConfig } from './app/app.config'
+import { AppComponent } from './app/app.component'
+
+bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err))
diff --git a/examples/angular/row-dnd/src/styles.scss b/examples/angular/row-dnd/src/styles.scss
new file mode 100644
index 0000000000..bcafc9601e
--- /dev/null
+++ b/examples/angular/row-dnd/src/styles.scss
@@ -0,0 +1,41 @@
+html {
+ font-family: sans-serif;
+ font-size: 14px;
+}
+
+table {
+ border: 1px solid lightgray;
+}
+
+tbody {
+ border-bottom: 1px solid lightgray;
+}
+
+th {
+ border-bottom: 1px solid lightgray;
+ border-right: 1px solid lightgray;
+ padding: 2px 4px;
+}
+
+td {
+ border-right: 1px solid lightgray;
+ padding: 4px 4px;
+ background-color: white;
+}
+
+td button {
+ padding: 1px 1rem;
+ cursor: grab;
+}
+
+td:last-child {
+ border-right: 0;
+}
+
+tfoot {
+ color: gray;
+}
+
+tfoot th {
+ font-weight: normal;
+}
diff --git a/examples/angular/row-dnd/tsconfig.app.json b/examples/angular/row-dnd/tsconfig.app.json
new file mode 100644
index 0000000000..84f1f992d2
--- /dev/null
+++ b/examples/angular/row-dnd/tsconfig.app.json
@@ -0,0 +1,10 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./out-tsc/app",
+ "types": []
+ },
+ "files": ["src/main.ts"],
+ "include": ["src/**/*.d.ts"]
+}
diff --git a/examples/angular/row-dnd/tsconfig.json b/examples/angular/row-dnd/tsconfig.json
new file mode 100644
index 0000000000..b58d3efc71
--- /dev/null
+++ b/examples/angular/row-dnd/tsconfig.json
@@ -0,0 +1,31 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "compileOnSave": false,
+ "compilerOptions": {
+ "baseUrl": "src",
+ "outDir": "./dist/out-tsc",
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "sourceMap": true,
+ "declaration": false,
+ "experimentalDecorators": true,
+ "moduleResolution": "node",
+ "importHelpers": true,
+ "target": "ES2022",
+ "module": "ES2022",
+ "useDefineForClassFields": false,
+ "lib": ["ES2022", "dom"]
+ },
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/examples/angular/row-dnd/tsconfig.spec.json b/examples/angular/row-dnd/tsconfig.spec.json
new file mode 100644
index 0000000000..47e3dd7551
--- /dev/null
+++ b/examples/angular/row-dnd/tsconfig.spec.json
@@ -0,0 +1,9 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./out-tsc/spec",
+ "types": ["jasmine"]
+ },
+ "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 80bcb75124..6b3a532b2c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -391,6 +391,79 @@ importers:
specifier: 5.4.5
version: 5.4.5
+ examples/angular/column-resizing-performant:
+ dependencies:
+ '@angular/animations':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))
+ '@angular/common':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1)
+ '@angular/compiler':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))
+ '@angular/core':
+ specifier: ^17.3.9
+ version: 17.3.11(rxjs@7.8.1)(zone.js@0.14.7)
+ '@angular/forms':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(@angular/platform-browser@17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(rxjs@7.8.1)
+ '@angular/platform-browser':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))
+ '@angular/platform-browser-dynamic':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(@angular/platform-browser@17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))
+ '@angular/router':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(@angular/platform-browser@17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(rxjs@7.8.1)
+ '@tanstack/angular-table':
+ specifier: ^8.21.0
+ version: link:../../../packages/angular-table
+ rxjs:
+ specifier: ~7.8.1
+ version: 7.8.1
+ zone.js:
+ specifier: ~0.14.4
+ version: 0.14.7
+ devDependencies:
+ '@angular-devkit/build-angular':
+ specifier: ^17.3.8
+ version: 17.3.8(@angular/compiler-cli@17.3.11(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.4.5))(@types/express@4.17.21)(@types/node@20.14.9)(chokidar@3.6.0)(karma@6.4.3)(ng-packagr@17.3.0(@angular/compiler-cli@17.3.11(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.4.5))(tslib@2.6.3)(typescript@5.4.5))(typescript@5.4.5)
+ '@angular/cli':
+ specifier: ^17.3.8
+ version: 17.3.8(chokidar@3.6.0)
+ '@angular/compiler-cli':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.4.5)
+ '@types/jasmine':
+ specifier: ~5.1.4
+ version: 5.1.4
+ jasmine-core:
+ specifier: ~5.1.2
+ version: 5.1.2
+ karma:
+ specifier: ~6.4.3
+ version: 6.4.3
+ karma-chrome-launcher:
+ specifier: ~3.2.0
+ version: 3.2.0
+ karma-coverage:
+ specifier: ~2.2.1
+ version: 2.2.1
+ karma-jasmine:
+ specifier: ~5.1.0
+ version: 5.1.0(karma@6.4.3)
+ karma-jasmine-html-reporter:
+ specifier: ~2.1.0
+ version: 2.1.0(jasmine-core@5.1.2)(karma-jasmine@5.1.0(karma@6.4.3))(karma@6.4.3)
+ tslib:
+ specifier: ^2.6.2
+ version: 2.6.3
+ typescript:
+ specifier: 5.4.5
+ version: 5.4.5
+
examples/angular/column-visibility:
dependencies:
'@angular/animations':
@@ -461,6 +534,79 @@ importers:
specifier: 5.4.5
version: 5.4.5
+ examples/angular/editable:
+ dependencies:
+ '@angular/animations':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))
+ '@angular/common':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1)
+ '@angular/compiler':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))
+ '@angular/core':
+ specifier: ^17.3.9
+ version: 17.3.11(rxjs@7.8.1)(zone.js@0.14.7)
+ '@angular/forms':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(@angular/platform-browser@17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(rxjs@7.8.1)
+ '@angular/platform-browser':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))
+ '@angular/platform-browser-dynamic':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(@angular/platform-browser@17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))
+ '@angular/router':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(@angular/platform-browser@17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(rxjs@7.8.1)
+ '@tanstack/angular-table':
+ specifier: ^8.21.0
+ version: link:../../../packages/angular-table
+ rxjs:
+ specifier: ~7.8.1
+ version: 7.8.1
+ zone.js:
+ specifier: ~0.14.4
+ version: 0.14.7
+ devDependencies:
+ '@angular-devkit/build-angular':
+ specifier: ^17.3.8
+ version: 17.3.8(@angular/compiler-cli@17.3.11(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.4.5))(@types/express@4.17.21)(@types/node@20.14.9)(chokidar@3.6.0)(karma@6.4.3)(ng-packagr@17.3.0(@angular/compiler-cli@17.3.11(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.4.5))(tslib@2.6.3)(typescript@5.4.5))(typescript@5.4.5)
+ '@angular/cli':
+ specifier: ^17.3.8
+ version: 17.3.8(chokidar@3.6.0)
+ '@angular/compiler-cli':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.4.5)
+ '@types/jasmine':
+ specifier: ~5.1.4
+ version: 5.1.4
+ jasmine-core:
+ specifier: ~5.1.2
+ version: 5.1.2
+ karma:
+ specifier: ~6.4.3
+ version: 6.4.3
+ karma-chrome-launcher:
+ specifier: ~3.2.0
+ version: 3.2.0
+ karma-coverage:
+ specifier: ~2.2.1
+ version: 2.2.1
+ karma-jasmine:
+ specifier: ~5.1.0
+ version: 5.1.0(karma@6.4.3)
+ karma-jasmine-html-reporter:
+ specifier: ~2.1.0
+ version: 2.1.0(jasmine-core@5.1.2)(karma-jasmine@5.1.0(karma@6.4.3))(karma@6.4.3)
+ tslib:
+ specifier: ^2.6.2
+ version: 2.6.3
+ typescript:
+ specifier: 5.4.5
+ version: 5.4.5
+
examples/angular/filters:
dependencies:
'@angular/animations':
@@ -607,6 +753,82 @@ importers:
specifier: 5.4.5
version: 5.4.5
+ examples/angular/row-dnd:
+ dependencies:
+ '@angular/animations':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))
+ '@angular/cdk':
+ specifier: ^17.3.10
+ version: 17.3.10(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1)
+ '@angular/common':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1)
+ '@angular/compiler':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))
+ '@angular/core':
+ specifier: ^17.3.9
+ version: 17.3.11(rxjs@7.8.1)(zone.js@0.14.7)
+ '@angular/forms':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(@angular/platform-browser@17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(rxjs@7.8.1)
+ '@angular/platform-browser':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))
+ '@angular/platform-browser-dynamic':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(@angular/platform-browser@17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))
+ '@angular/router':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(@angular/platform-browser@17.3.11(@angular/animations@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(rxjs@7.8.1)
+ '@tanstack/angular-table':
+ specifier: ^8.21.0
+ version: link:../../../packages/angular-table
+ rxjs:
+ specifier: ~7.8.1
+ version: 7.8.1
+ zone.js:
+ specifier: ~0.14.4
+ version: 0.14.7
+ devDependencies:
+ '@angular-devkit/build-angular':
+ specifier: ^17.3.8
+ version: 17.3.8(@angular/compiler-cli@17.3.11(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.4.5))(@types/express@4.17.21)(@types/node@20.14.9)(chokidar@3.6.0)(karma@6.4.3)(ng-packagr@17.3.0(@angular/compiler-cli@17.3.11(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.4.5))(tslib@2.6.3)(typescript@5.4.5))(typescript@5.4.5)
+ '@angular/cli':
+ specifier: ^17.3.8
+ version: 17.3.8(chokidar@3.6.0)
+ '@angular/compiler-cli':
+ specifier: ^17.3.9
+ version: 17.3.11(@angular/compiler@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.4.5)
+ '@types/jasmine':
+ specifier: ~5.1.4
+ version: 5.1.4
+ jasmine-core:
+ specifier: ~5.1.2
+ version: 5.1.2
+ karma:
+ specifier: ~6.4.3
+ version: 6.4.3
+ karma-chrome-launcher:
+ specifier: ~3.2.0
+ version: 3.2.0
+ karma-coverage:
+ specifier: ~2.2.1
+ version: 2.2.1
+ karma-jasmine:
+ specifier: ~5.1.0
+ version: 5.1.0(karma@6.4.3)
+ karma-jasmine-html-reporter:
+ specifier: ~2.1.0
+ version: 2.1.0(jasmine-core@5.1.2)(karma-jasmine@5.1.0(karma@6.4.3))(karma@6.4.3)
+ tslib:
+ specifier: ^2.6.2
+ version: 2.6.3
+ typescript:
+ specifier: 5.4.5
+ version: 5.4.5
+
examples/angular/row-selection:
dependencies:
'@angular/animations':
@@ -3187,6 +3409,13 @@ packages:
peerDependencies:
'@angular/core': 17.3.11
+ '@angular/cdk@17.3.10':
+ resolution: {integrity: sha512-b1qktT2c1TTTe5nTji/kFAVW92fULK0YhYAvJ+BjZTPKu2FniZNe8o4qqQ0pUuvtMu+ZQxp/QqFYoidIVCjScg==}
+ peerDependencies:
+ '@angular/common': ^17.0.0 || ^18.0.0
+ '@angular/core': ^17.0.0 || ^18.0.0
+ rxjs: ^6.5.3 || ^7.4.0
+
'@angular/cli@17.3.8':
resolution: {integrity: sha512-X5ZOQ6ZTKVHjhIsfl32ZRqbs+FUoeHLbT7x4fh2Os/8ObDDwrUcCJPqxe2b2RB5E2d0vepYigknHeLE7gwzlNQ==}
engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
@@ -6017,6 +6246,7 @@ packages:
acorn-import-assertions@1.9.0:
resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==}
+ deprecated: package has been renamed to acorn-import-attributes
peerDependencies:
acorn: ^8
@@ -10570,6 +10800,15 @@ snapshots:
'@angular/core': 17.3.11(rxjs@7.8.1)(zone.js@0.14.7)
tslib: 2.6.3
+ '@angular/cdk@17.3.10(@angular/common@17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1))(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1)':
+ dependencies:
+ '@angular/common': 17.3.11(@angular/core@17.3.11(rxjs@7.8.1)(zone.js@0.14.7))(rxjs@7.8.1)
+ '@angular/core': 17.3.11(rxjs@7.8.1)(zone.js@0.14.7)
+ rxjs: 7.8.1
+ tslib: 2.6.3
+ optionalDependencies:
+ parse5: 7.1.2
+
'@angular/cli@17.3.8(chokidar@3.6.0)':
dependencies:
'@angular-devkit/architect': 0.1703.8(chokidar@3.6.0)
@@ -10663,7 +10902,7 @@ snapshots:
'@babel/code-frame@7.24.7':
dependencies:
'@babel/highlight': 7.24.7
- picocolors: 1.0.1
+ picocolors: 1.1.1
'@babel/compat-data@7.24.7': {}
@@ -10675,10 +10914,10 @@ snapshots:
'@babel/helper-compilation-targets': 7.24.7
'@babel/helper-module-transforms': 7.24.7(@babel/core@7.23.9)
'@babel/helpers': 7.24.7
- '@babel/parser': 7.24.7
+ '@babel/parser': 7.26.3
'@babel/template': 7.24.7
'@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
convert-source-map: 2.0.0
debug: 4.3.6
gensync: 1.0.0-beta.2
@@ -10695,10 +10934,10 @@ snapshots:
'@babel/helper-compilation-targets': 7.24.7
'@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.0)
'@babel/helpers': 7.24.7
- '@babel/parser': 7.24.7
+ '@babel/parser': 7.26.3
'@babel/template': 7.24.7
'@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
convert-source-map: 2.0.0
debug: 4.3.6
gensync: 1.0.0-beta.2
@@ -10729,21 +10968,21 @@ snapshots:
'@babel/generator@7.23.6':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
jsesc: 2.5.2
'@babel/generator@7.24.7':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
jsesc: 2.5.2
'@babel/helper-annotate-as-pure@7.22.5':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@babel/helper-annotate-as-pure@7.24.7':
dependencies:
@@ -10752,7 +10991,7 @@ snapshots:
'@babel/helper-builder-binary-assignment-operator-visitor@7.24.7':
dependencies:
'@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
transitivePeerDependencies:
- supports-color
@@ -10843,16 +11082,16 @@ snapshots:
'@babel/helper-environment-visitor@7.24.7':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@babel/helper-function-name@7.24.7':
dependencies:
'@babel/template': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@babel/helper-hoist-variables@7.24.7':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@babel/helper-member-expression-to-functions@7.24.7':
dependencies:
@@ -10867,7 +11106,7 @@ snapshots:
'@babel/helper-module-imports@7.22.15':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@babel/helper-module-imports@7.24.7':
dependencies:
@@ -10954,24 +11193,24 @@ snapshots:
'@babel/helper-simple-access@7.24.7':
dependencies:
'@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
transitivePeerDependencies:
- supports-color
'@babel/helper-skip-transparent-expression-wrappers@7.24.7':
dependencies:
'@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
transitivePeerDependencies:
- supports-color
'@babel/helper-split-export-declaration@7.22.6':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@babel/helper-split-export-declaration@7.24.7':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@babel/helper-string-parser@7.24.7': {}
@@ -10995,18 +11234,18 @@ snapshots:
'@babel/helpers@7.24.7':
dependencies:
'@babel/template': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@babel/highlight@7.24.7':
dependencies:
'@babel/helper-validator-identifier': 7.24.7
chalk: 2.4.2
js-tokens: 4.0.0
- picocolors: 1.0.1
+ picocolors: 1.1.1
'@babel/parser@7.24.7':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
'@babel/parser@7.26.3':
dependencies:
@@ -12161,14 +12400,14 @@ snapshots:
dependencies:
'@babel/core': 7.24.0
'@babel/helper-plugin-utils': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
esutils: 2.0.3
'@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
esutils: 2.0.3
'@babel/preset-react@7.24.7(@babel/core@7.24.7)':
@@ -12207,8 +12446,8 @@ snapshots:
'@babel/template@7.24.7':
dependencies:
'@babel/code-frame': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/parser': 7.26.3
+ '@babel/types': 7.26.3
'@babel/traverse@7.24.7':
dependencies:
@@ -12218,8 +12457,8 @@ snapshots:
'@babel/helper-function-name': 7.24.7
'@babel/helper-hoist-variables': 7.24.7
'@babel/helper-split-export-declaration': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/parser': 7.26.3
+ '@babel/types': 7.26.3
debug: 4.3.6
globals: 11.12.0
transitivePeerDependencies:
@@ -13687,11 +13926,11 @@ snapshots:
'@types/eslint-scope@3.7.7':
dependencies:
'@types/eslint': 9.6.1
- '@types/estree': 1.0.5
+ '@types/estree': 1.0.6
'@types/eslint@9.6.1':
dependencies:
- '@types/estree': 1.0.5
+ '@types/estree': 1.0.6
'@types/json-schema': 7.0.15
'@types/estree@1.0.5': {}
@@ -14396,7 +14635,7 @@ snapshots:
caniuse-lite: 1.0.30001638
fraction.js: 4.3.7
normalize-range: 0.1.2
- picocolors: 1.0.1
+ picocolors: 1.1.1
postcss: 8.4.35
postcss-value-parser: 4.2.0
@@ -14417,7 +14656,7 @@ snapshots:
'@babel/core': 7.24.7
'@babel/parser': 7.26.3
'@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/types': 7.26.3
transitivePeerDependencies:
- supports-color
@@ -14746,7 +14985,7 @@ snapshots:
code-red@1.0.4:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
- '@types/estree': 1.0.5
+ '@types/estree': 1.0.6
acorn: 8.12.1
estree-walker: 3.0.3
periscopic: 3.1.0
@@ -14901,7 +15140,7 @@ snapshots:
dom-serializer: 2.0.0
domhandler: 5.0.3
htmlparser2: 8.0.2
- postcss: 8.4.39
+ postcss: 8.4.49
postcss-media-query-parser: 0.2.3
cross-spawn@5.1.0:
@@ -14918,12 +15157,12 @@ snapshots:
css-loader@6.10.0(webpack@5.90.3(esbuild@0.20.1)):
dependencies:
- icss-utils: 5.1.0(postcss@8.4.39)
- postcss: 8.4.39
- postcss-modules-extract-imports: 3.1.0(postcss@8.4.39)
- postcss-modules-local-by-default: 4.0.5(postcss@8.4.39)
- postcss-modules-scope: 3.2.0(postcss@8.4.39)
- postcss-modules-values: 4.0.0(postcss@8.4.39)
+ icss-utils: 5.1.0(postcss@8.4.49)
+ postcss: 8.4.49
+ postcss-modules-extract-imports: 3.1.0(postcss@8.4.49)
+ postcss-modules-local-by-default: 4.0.5(postcss@8.4.49)
+ postcss-modules-scope: 3.2.0(postcss@8.4.49)
+ postcss-modules-values: 4.0.0(postcss@8.4.49)
postcss-value-parser: 4.2.0
semver: 7.6.3
optionalDependencies:
@@ -14940,7 +15179,7 @@ snapshots:
css-tree@2.3.1:
dependencies:
mdn-data: 2.0.30
- source-map-js: 1.2.0
+ source-map-js: 1.2.1
css-what@6.1.0: {}
@@ -15439,7 +15678,7 @@ snapshots:
estree-walker@3.0.3:
dependencies:
- '@types/estree': 1.0.5
+ '@types/estree': 1.0.6
esutils@2.0.3: {}
@@ -15963,9 +16202,9 @@ snapshots:
dependencies:
safer-buffer: 2.1.2
- icss-utils@5.1.0(postcss@8.4.39):
+ icss-utils@5.1.0(postcss@8.4.49):
dependencies:
- postcss: 8.4.39
+ postcss: 8.4.49
identity-function@1.0.0: {}
@@ -16111,7 +16350,7 @@ snapshots:
is-reference@3.0.2:
dependencies:
- '@types/estree': 1.0.5
+ '@types/estree': 1.0.6
is-relative@1.0.0:
dependencies:
@@ -16158,7 +16397,7 @@ snapshots:
istanbul-lib-instrument@5.2.1:
dependencies:
'@babel/core': 7.24.7
- '@babel/parser': 7.24.7
+ '@babel/parser': 7.26.3
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
semver: 6.3.1
@@ -16393,7 +16632,7 @@ snapshots:
launch-editor@2.8.0:
dependencies:
- picocolors: 1.0.1
+ picocolors: 1.1.1
shell-quote: 1.8.1
less-loader@11.1.0(less@4.2.0)(webpack@5.90.3(esbuild@0.20.1)):
@@ -16761,7 +17000,7 @@ snapshots:
nanospinner@1.1.0:
dependencies:
- picocolors: 1.0.1
+ picocolors: 1.1.1
nanostores@0.11.3: {}
@@ -17196,7 +17435,7 @@ snapshots:
periscopic@3.1.0:
dependencies:
- '@types/estree': 1.0.5
+ '@types/estree': 1.0.6
estree-walker: 3.0.3
is-reference: 3.0.2
@@ -17248,26 +17487,26 @@ snapshots:
postcss-media-query-parser@0.2.3: {}
- postcss-modules-extract-imports@3.1.0(postcss@8.4.39):
+ postcss-modules-extract-imports@3.1.0(postcss@8.4.49):
dependencies:
- postcss: 8.4.39
+ postcss: 8.4.49
- postcss-modules-local-by-default@4.0.5(postcss@8.4.39):
+ postcss-modules-local-by-default@4.0.5(postcss@8.4.49):
dependencies:
- icss-utils: 5.1.0(postcss@8.4.39)
- postcss: 8.4.39
+ icss-utils: 5.1.0(postcss@8.4.49)
+ postcss: 8.4.49
postcss-selector-parser: 6.1.0
postcss-value-parser: 4.2.0
- postcss-modules-scope@3.2.0(postcss@8.4.39):
+ postcss-modules-scope@3.2.0(postcss@8.4.49):
dependencies:
- postcss: 8.4.39
+ postcss: 8.4.49
postcss-selector-parser: 6.1.0
- postcss-modules-values@4.0.0(postcss@8.4.39):
+ postcss-modules-values@4.0.0(postcss@8.4.49):
dependencies:
- icss-utils: 5.1.0(postcss@8.4.39)
- postcss: 8.4.39
+ icss-utils: 5.1.0(postcss@8.4.49)
+ postcss: 8.4.49
postcss-selector-parser@6.1.0:
dependencies:
@@ -17279,8 +17518,8 @@ snapshots:
postcss@8.4.35:
dependencies:
nanoid: 3.3.7
- picocolors: 1.0.1
- source-map-js: 1.2.0
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
postcss@8.4.39:
dependencies:
@@ -17553,7 +17792,7 @@ snapshots:
adjust-sourcemap-loader: 4.0.0
convert-source-map: 1.9.0
loader-utils: 2.0.4
- postcss: 8.4.39
+ postcss: 8.4.49
source-map: 0.6.1
resolve.exports@2.0.2: {}
@@ -17715,13 +17954,13 @@ snapshots:
dependencies:
chokidar: 3.6.0
immutable: 4.3.6
- source-map-js: 1.2.0
+ source-map-js: 1.2.1
sass@1.77.6:
dependencies:
chokidar: 3.6.0
immutable: 4.3.6
- source-map-js: 1.2.0
+ source-map-js: 1.2.1
sax@1.4.1:
optional: true
@@ -18058,7 +18297,7 @@ snapshots:
source-map-loader@5.0.0(webpack@5.90.3(esbuild@0.20.1)):
dependencies:
iconv-lite: 0.6.3
- source-map-js: 1.2.0
+ source-map-js: 1.2.1
webpack: 5.90.3(esbuild@0.21.5)
source-map-support@0.5.21:
@@ -18539,7 +18778,7 @@ snapshots:
dependencies:
browserslist: 4.23.1
escalade: 3.1.2
- picocolors: 1.0.1
+ picocolors: 1.1.1
update-check@1.5.4:
dependencies:
@@ -18659,8 +18898,8 @@ snapshots:
vite@5.1.7(@types/node@20.14.9)(less@4.2.0)(sass@1.71.1)(terser@5.29.1):
dependencies:
esbuild: 0.19.12
- postcss: 8.4.39
- rollup: 4.18.0
+ postcss: 8.4.49
+ rollup: 4.29.1
optionalDependencies:
'@types/node': 20.14.9
fsevents: 2.3.3
@@ -18870,7 +19109,7 @@ snapshots:
webpack@5.90.3(esbuild@0.21.5):
dependencies:
'@types/eslint-scope': 3.7.7
- '@types/estree': 1.0.5
+ '@types/estree': 1.0.6
'@webassemblyjs/ast': 1.12.1
'@webassemblyjs/wasm-edit': 1.12.1
'@webassemblyjs/wasm-parser': 1.12.1