diff --git a/examples/angular/sub-components/.devcontainer/devcontainer.json b/examples/angular/sub-components/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..36f47d8762 --- /dev/null +++ b/examples/angular/sub-components/.devcontainer/devcontainer.json @@ -0,0 +1,4 @@ +{ + "name": "Node.js", + "image": "mcr.microsoft.com/devcontainers/javascript-node:18" +} diff --git a/examples/angular/sub-components/.editorconfig b/examples/angular/sub-components/.editorconfig new file mode 100644 index 0000000000..59d9a3a3e7 --- /dev/null +++ b/examples/angular/sub-components/.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/sub-components/.gitignore b/examples/angular/sub-components/.gitignore new file mode 100644 index 0000000000..0711527ef9 --- /dev/null +++ b/examples/angular/sub-components/.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/sub-components/README.md b/examples/angular/sub-components/README.md new file mode 100644 index 0000000000..5da97a87d1 --- /dev/null +++ b/examples/angular/sub-components/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/sub-components/angular.json b/examples/angular/sub-components/angular.json new file mode 100644 index 0000000000..6327dd784f --- /dev/null +++ b/examples/angular/sub-components/angular.json @@ -0,0 +1,83 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "sub-components": { + "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/sub-components", + "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": "sub-components:build:production" + }, + "development": { + "buildTarget": "sub-components:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "sub-components: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/sub-components/package.json b/examples/angular/sub-components/package.json new file mode 100644 index 0000000000..83fe8b6061 --- /dev/null +++ b/examples/angular/sub-components/package.json @@ -0,0 +1,33 @@ +{ + "name": "tanstack-table-example-angular-sub-components", + "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", + "@faker-js/faker": "^8.4.1", + "@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", + "tslib": "^2.6.2", + "typescript": "5.4.5" + } +} diff --git a/examples/angular/sub-components/src/app/app.component.html b/examples/angular/sub-components/src/app/app.component.html new file mode 100644 index 0000000000..0411ad3d30 --- /dev/null +++ b/examples/angular/sub-components/src/app/app.component.html @@ -0,0 +1,71 @@ +
+
+ +
+ + + @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) { + + @for (header of headerGroup.headers; track header.id) { + + } + + } + + + @for (row of table.getRowModel().rows; track row.id) { + + + @for (cell of row.getVisibleCells(); track cell.id) { + + } + + + @if (row.getIsExpanded()) { + + + + + } + } + +
+ @if (!header.isPlaceholder) { + +
+
+ } +
+ +
+
+
+ +
+
+
+ + +
+    
+      {{ row.original | json }}
+    
+  
+
diff --git a/examples/angular/sub-components/src/app/app.component.ts b/examples/angular/sub-components/src/app/app.component.ts new file mode 100644 index 0000000000..5b6372a173 --- /dev/null +++ b/examples/angular/sub-components/src/app/app.component.ts @@ -0,0 +1,123 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + signal, +} from '@angular/core' +import { + ColumnDef, + createAngularTable, + ExpandedState, + flexRenderComponent, + FlexRenderDirective, + getCoreRowModel, + getExpandedRowModel, + getFilteredRowModel, + getPaginationRowModel, +} from '@tanstack/angular-table' +import { makeData, type Person } from './makeData' +import { ReactiveFormsModule } from '@angular/forms' +import { ExpandableCell, ExpanderCell } from './expandable-cell' +import { JsonPipe, NgTemplateOutlet } from '@angular/common' + +const columns: ColumnDef[] = [ + { + header: 'Name', + footer: props => props.column.id, + columns: [ + { + id: 'expander', + header: () => null, + cell: ({ row }) => { + if (!row.getCanExpand()) { + return '🔵' + } + return flexRenderComponent(ExpanderCell, { + inputs: { + expanded: row.getIsExpanded(), + }, + outputs: { + click: row.getToggleExpandedHandler(), + }, + }) + }, + }, + { + accessorKey: 'firstName', + header: 'First Name', + cell: () => flexRenderComponent(ExpandableCell), + 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, + }, + { + header: 'More Info', + columns: [ + { + 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, + ReactiveFormsModule, + JsonPipe, + NgTemplateOutlet, + ], + templateUrl: './app.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent { + readonly data = signal(makeData(10)) + readonly expanded = signal({}) + + readonly table = createAngularTable(() => ({ + data: this.data(), + columns, + state: { + expanded: this.expanded(), + }, + onExpandedChange: updater => + typeof updater === 'function' + ? this.expanded.update(updater) + : this.expanded.set(updater), + getRowCanExpand: () => true, + getCoreRowModel: getCoreRowModel(), + getExpandedRowModel: getExpandedRowModel(), + })) +} diff --git a/examples/angular/sub-components/src/app/app.config.ts b/examples/angular/sub-components/src/app/app.config.ts new file mode 100644 index 0000000000..f27099f33c --- /dev/null +++ b/examples/angular/sub-components/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig } from '@angular/core' + +export const appConfig: ApplicationConfig = { + providers: [], +} diff --git a/examples/angular/sub-components/src/app/expandable-cell.ts b/examples/angular/sub-components/src/app/expandable-cell.ts new file mode 100644 index 0000000000..cc89a29b21 --- /dev/null +++ b/examples/angular/sub-components/src/app/expandable-cell.ts @@ -0,0 +1,51 @@ +import { + ChangeDetectionStrategy, + Component, + input, + output, +} from '@angular/core' +import { + type HeaderContext, + injectFlexRenderContext, + type Table, + CellContext, +} from '@tanstack/angular-table' + +@Component({ + standalone: true, + template: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ExpanderCell { + readonly expanded = input.required() + + readonly click = output() +} + +@Component({ + standalone: true, + template: ` +
+ {{ context.getValue() }} +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, + styles: ` + :host { + > div { + padding-left: calc(2rem * var(--depth, 1)); + } + } + `, +}) +export class ExpandableCell { + readonly context = injectFlexRenderContext>() + + get row() { + return this.context.row + } +} diff --git a/examples/angular/sub-components/src/app/makeData.ts b/examples/angular/sub-components/src/app/makeData.ts new file mode 100644 index 0000000000..331dd1eb19 --- /dev/null +++ b/examples/angular/sub-components/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/sub-components/src/assets/.gitkeep b/examples/angular/sub-components/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/angular/sub-components/src/favicon.ico b/examples/angular/sub-components/src/favicon.ico new file mode 100644 index 0000000000..57614f9c96 Binary files /dev/null and b/examples/angular/sub-components/src/favicon.ico differ diff --git a/examples/angular/sub-components/src/index.html b/examples/angular/sub-components/src/index.html new file mode 100644 index 0000000000..bd21f08bcc --- /dev/null +++ b/examples/angular/sub-components/src/index.html @@ -0,0 +1,14 @@ + + + + + Expanding + + + + + + + + + diff --git a/examples/angular/sub-components/src/main.ts b/examples/angular/sub-components/src/main.ts new file mode 100644 index 0000000000..0c3b92057c --- /dev/null +++ b/examples/angular/sub-components/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/sub-components/src/styles.scss b/examples/angular/sub-components/src/styles.scss new file mode 100644 index 0000000000..43c09e0f6b --- /dev/null +++ b/examples/angular/sub-components/src/styles.scss @@ -0,0 +1,26 @@ +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; +} diff --git a/examples/angular/sub-components/tsconfig.app.json b/examples/angular/sub-components/tsconfig.app.json new file mode 100644 index 0000000000..84f1f992d2 --- /dev/null +++ b/examples/angular/sub-components/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/sub-components/tsconfig.json b/examples/angular/sub-components/tsconfig.json new file mode 100644 index 0000000000..b58d3efc71 --- /dev/null +++ b/examples/angular/sub-components/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/sub-components/tsconfig.spec.json b/examples/angular/sub-components/tsconfig.spec.json new file mode 100644 index 0000000000..47e3dd7551 --- /dev/null +++ b/examples/angular/sub-components/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 cb0d0b6b6b..02ae7d4c45 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -661,27 +661,6 @@ importers: '@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 @@ -1130,6 +1109,61 @@ importers: specifier: 5.4.5 version: 5.4.5 + examples/angular/sub-components: + 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) + '@faker-js/faker': + specifier: ^8.4.1 + version: 8.4.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) + tslib: + specifier: ^2.6.2 + version: 2.6.3 + typescript: + specifier: 5.4.5 + version: 5.4.5 + examples/lit/basic: dependencies: '@tanstack/lit-table':