diff --git a/examples/angular/row-selection-signal/.devcontainer/devcontainer.json b/examples/angular/row-selection-signal/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..36f47d8762 --- /dev/null +++ b/examples/angular/row-selection-signal/.devcontainer/devcontainer.json @@ -0,0 +1,4 @@ +{ + "name": "Node.js", + "image": "mcr.microsoft.com/devcontainers/javascript-node:18" +} diff --git a/examples/angular/row-selection-signal/.editorconfig b/examples/angular/row-selection-signal/.editorconfig new file mode 100644 index 0000000000..59d9a3a3e7 --- /dev/null +++ b/examples/angular/row-selection-signal/.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-selection-signal/.gitignore b/examples/angular/row-selection-signal/.gitignore new file mode 100644 index 0000000000..0711527ef9 --- /dev/null +++ b/examples/angular/row-selection-signal/.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-selection-signal/README.md b/examples/angular/row-selection-signal/README.md new file mode 100644 index 0000000000..73a201f1eb --- /dev/null +++ b/examples/angular/row-selection-signal/README.md @@ -0,0 +1,27 @@ +# Selection + +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-selection-signal/angular.json b/examples/angular/row-selection-signal/angular.json new file mode 100644 index 0000000000..7bae30f0ba --- /dev/null +++ b/examples/angular/row-selection-signal/angular.json @@ -0,0 +1,81 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "selection": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:application", + "options": { + "outputPath": "dist/selection-signal", + "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": "selection:build:production" + }, + "development": { + "buildTarget": "selection:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "selection: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, + "cache": { + "enabled": false + } + } +} diff --git a/examples/angular/row-selection-signal/package.json b/examples/angular/row-selection-signal/package.json new file mode 100644 index 0000000000..1af5fb9567 --- /dev/null +++ b/examples/angular/row-selection-signal/package.json @@ -0,0 +1,39 @@ +{ + "name": "tanstack-table-example-angular-row-selection-signal", + "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", + "@faker-js/faker": "^8.4.1", + "@tanstack/angular-table": "^8.18.1", + "rxjs": "~7.8.1", + "tslib": "^2.6.2", + "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", + "typescript": "5.4.5" + } +} diff --git a/examples/angular/row-selection-signal/src/app/app.component.html b/examples/angular/row-selection-signal/src/app/app.component.html new file mode 100644 index 0000000000..c2dfb725f7 --- /dev/null +++ b/examples/angular/row-selection-signal/src/app/app.component.html @@ -0,0 +1,152 @@ +
+
+ + + + @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 (!header.isPlaceholder) { + + {{ headerCell }} + + + @if (header.column.getCanFilter()) { +
+ +
+ } + } +
+ + {{ renderCell }} + +
+ + + Page Rows ({{ table.getRowModel().rows.length }}) +
+ +
+
+ + + + + +
Page
+ + {{ table.getState().pagination.pageIndex + 1 }} of + {{ table.getPageCount() }} + +
+ + | Go to page: + + + + +
+
+
+ {{ rowSelectionLength() }} of + {{ table.getPreFilteredRowModel().rows.length }} Total Rows +
+
+
+
+ +
+
+ +
+
+ +
{{ stringifiedRowSelection() }}
+
+
+ + + Age 🥳 + diff --git a/examples/angular/row-selection-signal/src/app/app.component.ts b/examples/angular/row-selection-signal/src/app/app.component.ts new file mode 100644 index 0000000000..5e2e103b4a --- /dev/null +++ b/examples/angular/row-selection-signal/src/app/app.component.ts @@ -0,0 +1,147 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + signal, + TemplateRef, + viewChild, +} from '@angular/core' +import { + ColumnDef, + createAngularTable, + FlexRenderDirective, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + RowSelectionState, +} from '@tanstack/angular-table' +import { FilterComponent } from './filter' +import { makeData, type Person } from './makeData' +import { + TableHeadSelectionComponent, + TableRowSelectionComponent, +} from './selection-column.component' + +@Component({ + selector: 'app-root', + standalone: true, + imports: [FilterComponent, FlexRenderDirective], + templateUrl: './app.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent { + private readonly rowSelection = signal({}) + readonly globalFilter = signal('') + readonly data = signal(makeData(10_000)) + + readonly ageHeaderCell = + viewChild.required>('ageHeaderCell') + + readonly columns: ColumnDef[] = [ + { + id: 'select', + header: () => TableHeadSelectionComponent, + cell: () => TableRowSelectionComponent, + }, + { + header: 'Name', + footer: props => props.column.id, + columns: [ + { + accessorKey: 'firstName', + cell: info => info.getValue(), + footer: props => props.column.id, + header: 'First name', + }, + { + 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: () => this.ageHeaderCell(), + 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, + }, + ], + }, + ], + }, + ] + + table = createAngularTable(() => ({ + data: this.data(), + columns: this.columns, + state: { + rowSelection: this.rowSelection(), + }, + enableRowSelection: true, // enable row selection for all rows + // enableRowSelection: row => row.original.age > 18, // or enable row selection conditionally per row + onRowSelectionChange: updaterOrValue => { + this.rowSelection.set( + typeof updaterOrValue === 'function' + ? updaterOrValue(this.rowSelection()) + : updaterOrValue + ) + }, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getPaginationRowModel: getPaginationRowModel(), + debugTable: true, + })) + + readonly stringifiedRowSelection = computed(() => + JSON.stringify(this.rowSelection(), null, 2) + ) + + readonly rowSelectionLength = computed( + () => Object.keys(this.rowSelection()).length + ) + + onPageInputChange(event: Event): void { + const inputElement = event.target as HTMLInputElement + const page = inputElement.value ? Number(inputElement.value) - 1 : 0 + this.table.setPageIndex(page) + } + + onPageSizeChange(event: any): void { + this.table.setPageSize(Number(event.target.value)) + } + + logSelectedFlatRows(): void { + console.info( + 'table.getSelectedRowModel().flatRows', + this.table.getSelectedRowModel().flatRows + ) + } + + refreshData(): void { + this.data.set(makeData(10_000)) + } +} diff --git a/examples/angular/row-selection-signal/src/app/app.config.ts b/examples/angular/row-selection-signal/src/app/app.config.ts new file mode 100644 index 0000000000..f27099f33c --- /dev/null +++ b/examples/angular/row-selection-signal/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-selection-signal/src/app/filter.ts b/examples/angular/row-selection-signal/src/app/filter.ts new file mode 100644 index 0000000000..cf0b567b36 --- /dev/null +++ b/examples/angular/row-selection-signal/src/app/filter.ts @@ -0,0 +1,75 @@ +import { CommonModule } from '@angular/common' +import { Component, input, OnInit } from '@angular/core' +import { Column } from '@tanstack/angular-table' +import type { Table } from '@tanstack/angular-table' + +@Component({ + selector: 'app-table-filter', + template: ` @if (columnType) { + @if (columnType == 'number') { +
+ + +
+ } @else { + + } + }`, + standalone: true, + imports: [CommonModule], +}) +export class FilterComponent implements OnInit { + column = input.required>() + + table = input.required>() + + columnType!: string + + ngOnInit() { + this.columnType = typeof this.table() + .getPreFilteredRowModel() + .flatRows[0]?.getValue(this.column().id) + } + + getMinValue() { + const minValue = this.column().getFilterValue() as any + + return (minValue?.[0] ?? '') as string + } + + getMaxValue() { + const maxValue = this.column().getFilterValue() as any + return (maxValue?.[1] ?? '') as string + } + + updateMinFilterValue(newValue: string): void { + this.column().setFilterValue((old: any) => { + return [newValue, old?.[1]] + }) + } + + updateMaxFilterValue(newValue: string): void { + this.column().setFilterValue((old: any) => [old?.[0], newValue]) + } +} diff --git a/examples/angular/row-selection-signal/src/app/makeData.ts b/examples/angular/row-selection-signal/src/app/makeData.ts new file mode 100644 index 0000000000..331dd1eb19 --- /dev/null +++ b/examples/angular/row-selection-signal/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/row-selection-signal/src/app/selection-column.component.ts b/examples/angular/row-selection-signal/src/app/selection-column.component.ts new file mode 100644 index 0000000000..d6f6045bd9 --- /dev/null +++ b/examples/angular/row-selection-signal/src/app/selection-column.component.ts @@ -0,0 +1,47 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { Row, Table } from '@tanstack/angular-table' + +@Component({ + template: ` + + `, + host: { + class: 'px-1 block', + }, + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TableHeadSelectionComponent { + // Your component should also reflect the fields you use as props in flexRenderer directive. + // Define the fields as input you want to use in your component + // ie. In this case, you are passing HeaderContext object as props in flexRenderer directive. + // You can define and use the table field, which is defined in HeaderContext. + // Please take note that only signal based input is supported. + + //column = input.required>() + //header = input.required>() + table = input.required>() +} + +@Component({ + template: ` + + `, + host: { + class: 'px-1 block', + }, + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TableRowSelectionComponent { + row = input.required>() +} diff --git a/examples/angular/row-selection-signal/src/assets/.gitkeep b/examples/angular/row-selection-signal/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/angular/row-selection-signal/src/favicon.ico b/examples/angular/row-selection-signal/src/favicon.ico new file mode 100644 index 0000000000..57614f9c96 Binary files /dev/null and b/examples/angular/row-selection-signal/src/favicon.ico differ diff --git a/examples/angular/row-selection-signal/src/index.html b/examples/angular/row-selection-signal/src/index.html new file mode 100644 index 0000000000..27917d2b28 --- /dev/null +++ b/examples/angular/row-selection-signal/src/index.html @@ -0,0 +1,14 @@ + + + + + Selection + + + + + + + + + diff --git a/examples/angular/row-selection-signal/src/main.ts b/examples/angular/row-selection-signal/src/main.ts new file mode 100644 index 0000000000..0c3b92057c --- /dev/null +++ b/examples/angular/row-selection-signal/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-selection-signal/src/styles.scss b/examples/angular/row-selection-signal/src/styles.scss new file mode 100644 index 0000000000..43c09e0f6b --- /dev/null +++ b/examples/angular/row-selection-signal/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/row-selection-signal/tsconfig.app.json b/examples/angular/row-selection-signal/tsconfig.app.json new file mode 100644 index 0000000000..84f1f992d2 --- /dev/null +++ b/examples/angular/row-selection-signal/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-selection-signal/tsconfig.json b/examples/angular/row-selection-signal/tsconfig.json new file mode 100644 index 0000000000..fd2d87ac26 --- /dev/null +++ b/examples/angular/row-selection-signal/tsconfig.json @@ -0,0 +1,30 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "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-selection-signal/tsconfig.spec.json b/examples/angular/row-selection-signal/tsconfig.spec.json new file mode 100644 index 0000000000..47e3dd7551 --- /dev/null +++ b/examples/angular/row-selection-signal/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/packages/angular-table/src/__tests__/flex-render.test.ts b/packages/angular-table/src/__tests__/flex-render.test.ts index fa3cd4fdac..6d678c573c 100644 --- a/packages/angular-table/src/__tests__/flex-render.test.ts +++ b/packages/angular-table/src/__tests__/flex-render.test.ts @@ -1,22 +1,13 @@ -import { describe, expect, test } from 'vitest' -import { - ChangeDetectionStrategy, - ChangeDetectorRef, - Component, - inject, - Input, - input, - type OnInit, - type TemplateRef, - ViewChild, -} from '@angular/core' +import { Component, ViewChild, input, type TemplateRef } from '@angular/core' +import { TestBed, type ComponentFixture } from '@angular/core/testing' import { createColumnHelper } from '@tanstack/table-core' +import { skip } from 'node:test' +import { describe, expect, test } from 'vitest' import { FlexRenderComponent, FlexRenderDirective, injectFlexRenderContext, } from '../flex-render' -import { type ComponentFixture, TestBed } from '@angular/core/testing' import { setFixtureSignalInput, setFixtureSignalInputs } from './test-utils' interface Data { @@ -124,6 +115,37 @@ describe('FlexRenderDirective', () => { expect(fixture.nativeElement.textContent).toEqual('Updated value') }) + + // Skip for now, test framework (using ComponentRef.setInput) cannot recognize signal inputs + // as component inputs + skip('should render custom components', () => { + @Component({ + template: `{{ row().property }}`, + standalone: true, + }) + class FakeComponent { + row = input.required<{ property: string }>() + } + + const fixture = TestBed.createComponent(TestRenderComponent) + setFixtureSignalInputs(fixture, { + content: () => FakeComponent, + context: { + row: { + property: 'Row value', + }, + }, + }) + + expect(fixture.nativeElement.textContent).toEqual('Row value') + + setFixtureSignalInput(fixture, 'context', { + row: { property: 'Updated value' }, + }) + fixture.detectChanges() + + expect(fixture.nativeElement.textContent).toEqual('Updated value') + }) }) @Component({ diff --git a/packages/angular-table/src/flex-render.ts b/packages/angular-table/src/flex-render.ts index ac74a72f83..be1d114dd1 100644 --- a/packages/angular-table/src/flex-render.ts +++ b/packages/angular-table/src/flex-render.ts @@ -2,22 +2,24 @@ import { ChangeDetectorRef, ComponentRef, Directive, - type DoCheck, EmbeddedViewRef, Inject, - inject, InjectionToken, Injector, Input, - type OnInit, TemplateRef, - type Type, + Type, ViewContainerRef, + inject, + isSignal, + type DoCheck, + type OnInit, } from '@angular/core' export type FlexRenderContent> = | string | number + | Type | FlexRenderComponent | TemplateRef<{ $implicit: TProps }> | null @@ -91,6 +93,8 @@ export class FlexRenderDirective> ) } else if (content instanceof FlexRenderComponent) { return this.renderComponent(content) + } else if (content instanceof Type) { + return this.renderCustomComponent(content) } else { return null } @@ -137,6 +141,25 @@ export class FlexRenderDirective> return componentRef } + private renderCustomComponent( + component: Type + ): ComponentRef { + const componentRef = this.viewContainerRef.createComponent(component, { + injector: this.injector, + }) + for (const prop in this.props) { + // Only signal based input can be added here + if ( + componentRef.instance?.hasOwnProperty(prop) && + // @ts-ignore + isSignal(componentRef.instance[prop]) + ) { + componentRef.setInput(prop, this.props[prop]) + } + } + return componentRef + } + private getTemplateRefContext() { const getContext = () => this.props return { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cde631054f..fa8bc288c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -677,6 +677,79 @@ importers: specifier: 5.4.5 version: 5.4.5 + examples/angular/row-selection-signal: + dependencies: + '@angular/animations': + specifier: ^17.3.9 + version: 17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)) + '@angular/common': + specifier: ^17.3.9 + version: 17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5))(rxjs@7.8.1) + '@angular/compiler': + specifier: ^17.3.9 + version: 17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)) + '@angular/core': + specifier: ^17.3.9 + version: 17.3.9(rxjs@7.8.1)(zone.js@0.14.5) + '@angular/forms': + specifier: ^17.3.9 + version: 17.3.9(@angular/common@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5))(rxjs@7.8.1))(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5))(@angular/platform-browser@17.3.9(@angular/animations@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)))(@angular/common@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5))(rxjs@7.8.1))(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)))(rxjs@7.8.1) + '@angular/platform-browser': + specifier: ^17.3.9 + version: 17.3.9(@angular/animations@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)))(@angular/common@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5))(rxjs@7.8.1))(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)) + '@angular/platform-browser-dynamic': + specifier: ^17.3.9 + version: 17.3.9(@angular/common@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5))(rxjs@7.8.1))(@angular/compiler@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)))(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5))(@angular/platform-browser@17.3.9(@angular/animations@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)))(@angular/common@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5))(rxjs@7.8.1))(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5))) + '@faker-js/faker': + specifier: ^8.4.1 + version: 8.4.1 + '@tanstack/angular-table': + specifier: ^8.18.1 + version: link:../../../packages/angular-table + rxjs: + specifier: ~7.8.1 + version: 7.8.1 + tslib: + specifier: ^2.6.2 + version: 2.6.2 + zone.js: + specifier: ~0.14.4 + version: 0.14.5 + devDependencies: + '@angular-devkit/build-angular': + specifier: ^17.3.8 + version: 17.3.8(@angular/compiler-cli@17.3.9(@angular/compiler@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)))(typescript@5.4.5))(@types/express@4.17.21)(@types/node@20.12.7)(chokidar@3.6.0)(karma@6.4.3)(ng-packagr@17.3.0(@angular/compiler-cli@17.3.9(@angular/compiler@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)))(typescript@5.4.5))(tslib@2.6.2)(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.9(@angular/compiler@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.5)))(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) + typescript: + specifier: 5.4.5 + version: 5.4.5 + examples/angular/signal-input: dependencies: '@angular/animations':