From 0baabdd292ed38fa0af4224b7a460b0fc46d2474 Mon Sep 17 00:00:00 2001 From: Riccardo Perra Date: Tue, 21 Jan 2025 17:53:09 +0100 Subject: [PATCH] docs(angular): add editable, row-dnd and performant column resizing example (#5881) * add editable cell example * add editable cell example * row dnd exmaple * revert basic * ci: apply automated fixes * column resizing performant example * fix * fix budgets * ci: apply automated fixes * typo --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- docs/config.json | 12 + .../.devcontainer/devcontainer.json | 4 + .../column-resizing-performant/.editorconfig | 16 + .../column-resizing-performant/.gitignore | 42 ++ .../column-resizing-performant/README.md | 27 ++ .../column-resizing-performant/angular.json | 83 ++++ .../column-resizing-performant/package.json | 39 ++ .../src/app/app.component.html | 66 ++++ .../src/app/app.component.ts | 122 ++++++ .../src/app/app.config.ts | 5 + .../src/app/makeData.ts | 48 +++ .../src/app/resizable-cell.ts | 35 ++ .../src/assets/.gitkeep | 0 .../src/favicon.ico | Bin 0 -> 15086 bytes .../column-resizing-performant/src/index.html | 14 + .../column-resizing-performant/src/main.ts | 5 + .../src/styles.scss | 74 ++++ .../tsconfig.app.json | 10 + .../column-resizing-performant/tsconfig.json | 31 ++ .../tsconfig.spec.json | 9 + .../editable/.devcontainer/devcontainer.json | 4 + examples/angular/editable/.editorconfig | 16 + examples/angular/editable/.gitignore | 42 ++ examples/angular/editable/README.md | 27 ++ examples/angular/editable/angular.json | 83 ++++ examples/angular/editable/package.json | 39 ++ .../editable/src/app/app.component.html | 106 +++++ .../angular/editable/src/app/app.component.ts | 130 ++++++ .../angular/editable/src/app/app.config.ts | 5 + .../angular/editable/src/app/editable-cell.ts | 30 ++ examples/angular/editable/src/app/makeData.ts | 48 +++ examples/angular/editable/src/assets/.gitkeep | 0 examples/angular/editable/src/favicon.ico | Bin 0 -> 15086 bytes examples/angular/editable/src/index.html | 14 + examples/angular/editable/src/main.ts | 5 + examples/angular/editable/src/styles.scss | 32 ++ examples/angular/editable/tsconfig.app.json | 10 + examples/angular/editable/tsconfig.json | 31 ++ examples/angular/editable/tsconfig.spec.json | 9 + .../row-dnd/.devcontainer/devcontainer.json | 4 + examples/angular/row-dnd/.editorconfig | 16 + examples/angular/row-dnd/.gitignore | 42 ++ examples/angular/row-dnd/README.md | 27 ++ examples/angular/row-dnd/angular.json | 83 ++++ examples/angular/row-dnd/package.json | 40 ++ .../angular/row-dnd/src/app/app.component.css | 23 ++ .../row-dnd/src/app/app.component.html | 55 +++ .../angular/row-dnd/src/app/app.component.ts | 93 +++++ .../angular/row-dnd/src/app/app.config.ts | 5 + .../row-dnd/src/app/drag-handle-cell.ts | 20 + examples/angular/row-dnd/src/app/makeData.ts | 50 +++ examples/angular/row-dnd/src/assets/.gitkeep | 0 examples/angular/row-dnd/src/favicon.ico | Bin 0 -> 15086 bytes examples/angular/row-dnd/src/index.html | 14 + examples/angular/row-dnd/src/main.ts | 5 + examples/angular/row-dnd/src/styles.scss | 41 ++ examples/angular/row-dnd/tsconfig.app.json | 10 + examples/angular/row-dnd/tsconfig.json | 31 ++ examples/angular/row-dnd/tsconfig.spec.json | 9 + pnpm-lock.yaml | 373 ++++++++++++++---- 60 files changed, 2147 insertions(+), 67 deletions(-) create mode 100644 examples/angular/column-resizing-performant/.devcontainer/devcontainer.json create mode 100644 examples/angular/column-resizing-performant/.editorconfig create mode 100644 examples/angular/column-resizing-performant/.gitignore create mode 100644 examples/angular/column-resizing-performant/README.md create mode 100644 examples/angular/column-resizing-performant/angular.json create mode 100644 examples/angular/column-resizing-performant/package.json create mode 100644 examples/angular/column-resizing-performant/src/app/app.component.html create mode 100644 examples/angular/column-resizing-performant/src/app/app.component.ts create mode 100644 examples/angular/column-resizing-performant/src/app/app.config.ts create mode 100644 examples/angular/column-resizing-performant/src/app/makeData.ts create mode 100644 examples/angular/column-resizing-performant/src/app/resizable-cell.ts create mode 100644 examples/angular/column-resizing-performant/src/assets/.gitkeep create mode 100644 examples/angular/column-resizing-performant/src/favicon.ico create mode 100644 examples/angular/column-resizing-performant/src/index.html create mode 100644 examples/angular/column-resizing-performant/src/main.ts create mode 100644 examples/angular/column-resizing-performant/src/styles.scss create mode 100644 examples/angular/column-resizing-performant/tsconfig.app.json create mode 100644 examples/angular/column-resizing-performant/tsconfig.json create mode 100644 examples/angular/column-resizing-performant/tsconfig.spec.json create mode 100644 examples/angular/editable/.devcontainer/devcontainer.json create mode 100644 examples/angular/editable/.editorconfig create mode 100644 examples/angular/editable/.gitignore create mode 100644 examples/angular/editable/README.md create mode 100644 examples/angular/editable/angular.json create mode 100644 examples/angular/editable/package.json create mode 100644 examples/angular/editable/src/app/app.component.html create mode 100644 examples/angular/editable/src/app/app.component.ts create mode 100644 examples/angular/editable/src/app/app.config.ts create mode 100644 examples/angular/editable/src/app/editable-cell.ts create mode 100644 examples/angular/editable/src/app/makeData.ts create mode 100644 examples/angular/editable/src/assets/.gitkeep create mode 100644 examples/angular/editable/src/favicon.ico create mode 100644 examples/angular/editable/src/index.html create mode 100644 examples/angular/editable/src/main.ts create mode 100644 examples/angular/editable/src/styles.scss create mode 100644 examples/angular/editable/tsconfig.app.json create mode 100644 examples/angular/editable/tsconfig.json create mode 100644 examples/angular/editable/tsconfig.spec.json create mode 100644 examples/angular/row-dnd/.devcontainer/devcontainer.json create mode 100644 examples/angular/row-dnd/.editorconfig create mode 100644 examples/angular/row-dnd/.gitignore create mode 100644 examples/angular/row-dnd/README.md create mode 100644 examples/angular/row-dnd/angular.json create mode 100644 examples/angular/row-dnd/package.json create mode 100644 examples/angular/row-dnd/src/app/app.component.css create mode 100644 examples/angular/row-dnd/src/app/app.component.html create mode 100644 examples/angular/row-dnd/src/app/app.component.ts create mode 100644 examples/angular/row-dnd/src/app/app.config.ts create mode 100644 examples/angular/row-dnd/src/app/drag-handle-cell.ts create mode 100644 examples/angular/row-dnd/src/app/makeData.ts create mode 100644 examples/angular/row-dnd/src/assets/.gitkeep create mode 100644 examples/angular/row-dnd/src/favicon.ico create mode 100644 examples/angular/row-dnd/src/index.html create mode 100644 examples/angular/row-dnd/src/main.ts create mode 100644 examples/angular/row-dnd/src/styles.scss create mode 100644 examples/angular/row-dnd/tsconfig.app.json create mode 100644 examples/angular/row-dnd/tsconfig.json create mode 100644 examples/angular/row-dnd/tsconfig.spec.json 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 0000000000000000000000000000000000000000..57614f9c967596fad0a3989bec2b1deff33034f6 GIT binary patch literal 15086 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 Nr__JTFzvMr^FKp4S3v*( literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..57614f9c967596fad0a3989bec2b1deff33034f6 GIT binary patch literal 15086 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 Nr__JTFzvMr^FKp4S3v*( literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..57614f9c967596fad0a3989bec2b1deff33034f6 GIT binary patch literal 15086 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 Nr__JTFzvMr^FKp4S3v*( literal 0 HcmV?d00001 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